From a502e047655c31db29601def76ad6539acacf43d Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Tue, 18 Mar 2025 23:37:44 +0000 Subject: [PATCH] Import zlib-ng 2.2.4 --- .codecov.yaml | 27 + .github/workflows/autoclose.yaml | 29 - .shellcheckrc | 1 + CMakeLists.txt | 1435 +++ FAQ.zlib | 373 + INDEX.md | 36 + LICENSE.md | 19 + Makefile.in | 407 + PORTING.md | 111 + README.md | 228 + README.rst | 70 - adler32.c | 69 + adler32_p.h | 70 + arch/arm/Makefile.in | 78 + arch/arm/acle_intrins.h | 35 + arch/arm/adler32_neon.c | 215 + arch/arm/arm_features.c | 115 + arch/arm/arm_features.h | 16 + arch/arm/arm_functions.h | 65 + arch/arm/chunkset_neon.c | 94 + arch/arm/compare256_neon.c | 60 + arch/arm/crc32_acle.c | 76 + arch/arm/neon_intrins.h | 65 + arch/arm/slide_hash_armv6.c | 48 + arch/arm/slide_hash_neon.c | 47 + arch/generic/Makefile.in | 75 + arch/generic/adler32_c.c | 54 + arch/generic/adler32_fold_c.c | 15 + arch/generic/chunk_permute_table.h | 53 + arch/generic/chunkset_c.c | 42 + arch/generic/compare256_c.c | 31 + arch/generic/compare256_p.h | 123 + arch/generic/crc32_braid_c.c | 216 + arch/generic/crc32_fold_c.c | 31 + arch/generic/generic_functions.h | 57 + arch/generic/slide_hash_c.c | 52 + arch/power/Makefile.in | 93 + arch/power/adler32_power8.c | 153 + arch/power/adler32_vmx.c | 186 + arch/power/chunkset_power8.c | 50 + arch/power/compare256_power9.c | 66 + arch/power/crc32_constants.h | 1123 ++ arch/power/crc32_power8.c | 587 + arch/power/power_features.c | 49 + arch/power/power_features.h | 18 + arch/power/power_functions.h | 67 + arch/power/power_intrins.h | 34 + arch/power/slide_hash_power8.c | 12 + arch/power/slide_hash_vmx.c | 10 + arch/power/slide_ppc_tpl.h | 32 + arch/riscv/README.md | 45 + arch/riscv/adler32_rvv.c | 136 + arch/riscv/chunkset_rvv.c | 121 + arch/riscv/compare256_rvv.c | 49 + arch/riscv/riscv_features.c | 71 + arch/riscv/riscv_features.h | 18 + arch/riscv/riscv_functions.h | 49 + arch/riscv/slide_hash_rvv.c | 33 + arch/s390/Makefile.in | 48 + arch/s390/README.md | 265 + arch/s390/crc32-vx.c | 222 + arch/s390/dfltcc_common.h | 119 + arch/s390/dfltcc_deflate.c | 383 + arch/s390/dfltcc_deflate.h | 58 + arch/s390/dfltcc_detail.h | 275 + arch/s390/dfltcc_inflate.c | 191 + arch/s390/dfltcc_inflate.h | 67 + arch/s390/s390_features.c | 14 + arch/s390/s390_features.h | 14 + arch/s390/s390_functions.h | 27 + arch/s390/self-hosted-builder/actions-runner | 59 + .../actions-runner-rebuild.sh | 54 + .../actions-runner.Dockerfile | 54 + .../actions-runner.service | 18 + arch/s390/self-hosted-builder/entrypoint | 30 + arch/x86/Makefile.in | 147 + arch/x86/adler32_avx2.c | 145 + arch/x86/adler32_avx2_p.h | 32 + arch/x86/adler32_avx512.c | 108 + arch/x86/adler32_avx512_p.h | 57 + arch/x86/adler32_avx512_vnni.c | 210 + arch/x86/adler32_sse42.c | 120 + arch/x86/adler32_ssse3.c | 156 + arch/x86/adler32_ssse3_p.h | 29 + arch/x86/avx2_tables.h | 44 + arch/x86/chunkset_avx2.c | 130 + arch/x86/chunkset_avx512.c | 182 + arch/x86/chunkset_sse2.c | 49 + arch/x86/chunkset_ssse3.c | 86 + arch/x86/compare256_avx2.c | 64 + arch/x86/compare256_sse2.c | 97 + arch/x86/crc32_fold_pclmulqdq_tpl.h | 199 + arch/x86/crc32_fold_vpclmulqdq_tpl.h | 107 + arch/x86/crc32_pclmulqdq.c | 30 + arch/x86/crc32_pclmulqdq_tpl.h | 375 + arch/x86/crc32_vpclmulqdq.c | 17 + arch/x86/slide_hash_avx2.c | 40 + arch/x86/slide_hash_sse2.c | 63 + arch/x86/x86_features.c | 117 + arch/x86/x86_features.h | 29 + arch/x86/x86_functions.h | 181 + arch/x86/x86_intrins.h | 92 + arch_functions.h | 29 + chunkset_tpl.h | 283 + cmake/detect-arch.c | 115 + cmake/detect-arch.cmake | 104 + cmake/detect-coverage.cmake | 46 + cmake/detect-install-dirs.cmake | 43 + cmake/detect-intrinsics.cmake | 604 ++ cmake/detect-sanitizer.cmake | 157 + cmake/fallback-macros.cmake | 19 + cmake/toolchain-aarch64.cmake | 24 + cmake/toolchain-arm.cmake | 29 + cmake/toolchain-armhf.cmake | 25 + cmake/toolchain-llvm-mingw-aarch64.cmake | 41 + cmake/toolchain-llvm-mingw-armv7.cmake | 41 + cmake/toolchain-llvm-mingw-i686.cmake | 41 + cmake/toolchain-llvm-mingw-x86_64.cmake | 41 + cmake/toolchain-mingw-i686.cmake | 35 + cmake/toolchain-mingw-x86_64.cmake | 34 + cmake/toolchain-mips.cmake | 29 + cmake/toolchain-mips64.cmake | 29 + cmake/toolchain-powerpc.cmake | 25 + cmake/toolchain-powerpc64-clang.cmake | 16 + cmake/toolchain-powerpc64-power9.cmake | 25 + cmake/toolchain-powerpc64.cmake | 25 + cmake/toolchain-powerpc64le-clang.cmake | 16 + cmake/toolchain-powerpc64le-power9.cmake | 25 + cmake/toolchain-powerpc64le.cmake | 25 + cmake/toolchain-riscv.cmake | 28 + cmake/toolchain-s390x.cmake | 25 + cmake/toolchain-sparc64.cmake | 25 + compare256_rle.h | 133 + compress.c | 98 + configure | 2218 ++++ cpu_features.c | 23 + cpu_features.h | 43 + crc32.c | 42 + crc32.h | 16 + crc32_braid_comb.c | 56 + crc32_braid_comb_p.h | 42 + crc32_braid_p.h | 64 + crc32_braid_tbl.h | 9446 +++++++++++++++++ deflate.c | 1513 +++ deflate.h | 456 + deflate_fast.c | 104 + deflate_huff.c | 45 + deflate_medium.c | 278 + deflate_p.h | 128 + deflate_quick.c | 130 + deflate_rle.c | 84 + deflate_slow.c | 144 + deflate_stored.c | 186 + doc/algorithm.txt | 209 + doc/crc-doc.1.0.pdf | Bin 0 -> 776142 bytes doc/crc-pclmulqdq.pdf | Bin 0 -> 384202 bytes doc/rfc1950.txt | 619 ++ doc/rfc1951.txt | 955 ++ doc/rfc1952.txt | 675 ++ doc/txtvsbin.txt | 107 + fallback_builtins.h | 47 + functable.c | 362 + functable.h | 55 + gzguts.h | 146 + gzlib.c | 531 + gzread.c.in | 606 ++ gzwrite.c | 526 + infback.c | 523 + inffast_tpl.h | 332 + inffixed_tbl.h | 94 + inflate.c | 1462 +++ inflate.h | 172 + inflate_p.h | 215 + inftrees.c | 295 + inftrees.h | 66 + insert_string.c | 21 + insert_string_roll.c | 24 + insert_string_tpl.h | 106 + match_tpl.h | 250 + test/CMakeLists.txt | 262 + test/CVE-2002-0059/test.gz | Bin 0 -> 4610 bytes test/CVE-2004-0797/test.gz | Bin 0 -> 52 bytes test/CVE-2005-1849/test.gz | Bin 0 -> 52 bytes test/CVE-2005-2096/test.gz | Bin 0 -> 52 bytes test/CVE-2018-25032/default.txt | 1 + test/CVE-2018-25032/fixed.txt | 1 + test/GH-1600/packobj.gz | Bin 0 -> 46 bytes test/GH-361/test.txt | 4 + test/GH-364/test.bin | Bin 0 -> 8 bytes test/GH-382/defneg3.dat | 1 + test/GH-751/test.txt | 1 + test/GH-979/pigz-2.6.tar.gz | Bin 0 -> 106840 bytes test/Makefile.in | 82 + test/README.md | 37 + test/abi/ignore | 12 + ...c2a18c1281fc-aarch64-unknown-linux-gnu.abi | 1293 +++ ...c2a18c1281fc-arm-unknown-linux-gnueabi.abi | 1276 +++ ...a18c1281fc-arm-unknown-linux-gnueabihf.abi | 1276 +++ ...806c2a18c1281fc-mips-unknown-linux-gnu.abi | 1271 +++ ...8c1281fc-mips64-unknown-linux-gnuabi64.abi | 1276 +++ ...c2a18c1281fc-powerpc-unknown-linux-gnu.abi | 1286 +++ ...a18c1281fc-powerpc64-unknown-linux-gnu.abi | 1275 +++ ...8c1281fc-powerpc64le-unknown-linux-gnu.abi | 1275 +++ ...06c2a18c1281fc-x86_64-pc-linux-gnu-m32.abi | 1270 +++ ...e93806c2a18c1281fc-x86_64-pc-linux-gnu.abi | 1288 +++ ...4baf80882311-aarch64-unknown-linux-gnu.abi | 1904 ++++ ...4baf80882311-arm-unknown-linux-gnueabi.abi | 1889 ++++ ...af80882311-arm-unknown-linux-gnueabihf.abi | 1881 ++++ ...55e4baf80882311-mips-unknown-linux-gnu.abi | 1241 +++ ...80882311-mips64-unknown-linux-gnuabi64.abi | 1250 +++ ...4baf80882311-powerpc-unknown-linux-gnu.abi | 1895 ++++ ...af80882311-powerpc64-unknown-linux-gnu.abi | 1894 ++++ ...80882311-powerpc64le-unknown-linux-gnu.abi | 1886 ++++ ...5e4baf80882311-x86_64-pc-linux-gnu-m32.abi | 2032 ++++ ...3c155e4baf80882311-x86_64-pc-linux-gnu.abi | 2064 ++++ test/abicheck.md | 59 + test/abicheck.sh | 163 + test/add-subdirectory-project/CMakeLists.txt | 13 + test/add-subdirectory-project/main.c | 7 + test/benchmarks/CMakeLists.txt | 116 + test/benchmarks/README.md | 47 + test/benchmarks/benchmark_adler32.cc | 100 + test/benchmarks/benchmark_adler32_copy.cc | 130 + test/benchmarks/benchmark_compare256.cc | 93 + test/benchmarks/benchmark_compare256_rle.cc | 69 + test/benchmarks/benchmark_compress.cc | 67 + test/benchmarks/benchmark_crc32.cc | 83 + test/benchmarks/benchmark_main.cc | 32 + test/benchmarks/benchmark_png_decode.cc | 126 + test/benchmarks/benchmark_png_encode.cc | 54 + test/benchmarks/benchmark_png_shared.h | 146 + test/benchmarks/benchmark_slidehash.cc | 98 + test/benchmarks/benchmark_uncompress.cc | 94 + test/cmake/compress-and-verify.cmake | 287 + test/cmake/run-and-compare.cmake | 72 + test/cmake/run-and-redirect.cmake | 54 + test/cmake/test-cves.cmake | 33 + test/cmake/test-data.cmake | 68 + test/cmake/test-issues.cmake | 84 + test/cmake/test-tools.cmake | 80 + test/data/fireworks.jpg | Bin 0 -> 123093 bytes test/data/lcet10.txt | 7519 +++++++++++++ test/data/paper-100k.pdf | Bin 0 -> 102400 bytes test/example.c | 1002 ++ test/fuzz/CMakeLists.txt | 49 + test/fuzz/fuzzer_checksum.c | 81 + test/fuzz/fuzzer_compress.c | 82 + test/fuzz/fuzzer_example_dict.c | 164 + test/fuzz/fuzzer_example_flush.c | 119 + test/fuzz/fuzzer_example_large.c | 137 + test/fuzz/fuzzer_example_small.c | 118 + test/fuzz/fuzzer_minigzip.c | 316 + test/fuzz/standalone_fuzz_target_runner.c | 37 + test/gh1235.c | 39 + test/infcover.c | 679 ++ test/minideflate.c | 367 + test/minigzip.c | 367 + test/pigz/CMakeLists.txt | 211 + test/pkgcheck.sh | 180 + test/switchlevels.c | 167 + test/test_adler32.cc | 395 + test/test_compare256.cc | 92 + test/test_compare256_rle.cc | 60 + test/test_compress.cc | 33 + test/test_compress_bound.cc | 59 + test/test_compress_dual.cc | 28 + test/test_cpu_features.h | 12 + test/test_crc32.cc | 265 + test/test_cve-2003-0107.cc | 28 + test/test_deflate_bound.cc | 99 + test/test_deflate_concurrency.cc | 170 + test/test_deflate_copy.cc | 60 + test/test_deflate_dict.cc | 54 + test/test_deflate_hash_head_0.cc | 83 + test/test_deflate_header.cc | 71 + test/test_deflate_params.cc | 143 + test/test_deflate_pending.cc | 66 + test/test_deflate_prime.cc | 91 + test/test_deflate_quick_bi_valid.cc | 80 + test/test_deflate_quick_block_open.cc | 94 + test/test_deflate_tune.cc | 56 + test/test_dict.cc | 98 + test/test_gzio.cc | 106 + test/test_inflate_adler32.cc | 50 + test/test_inflate_copy.cc | 31 + test/test_inflate_sync.cc | 75 + test/test_large_buffers.cc | 87 + test/test_main.cc | 22 + test/test_raw.cc | 58 + test/test_shared.h | 18 + test/test_shared_ng.h | 23 + test/test_small_buffers.cc | 69 + test/test_small_window.cc | 67 + test/test_version.cc | 27 + tools/config.sub | 17 + tools/makecrct.c | 244 + tools/makefixed.c | 89 + tools/maketrees.c | 147 + trees.c | 818 ++ trees.h | 40 + trees_emit.h | 231 + trees_tbl.h | 132 + uncompr.c | 80 + win32/Makefile.a64 | 252 + win32/Makefile.arm | 272 + win32/Makefile.msc | 292 + win32/depcheck.cpp | 321 + win32/replace.vbs | 15 + win32/zlib-ng.def.in | 60 + win32/zlib-ng1.rc | 36 + win32/zlib.def.in | 64 + win32/zlib1.rc | 36 + win32/zlibcompat.def.in | 97 + zbuild.h | 343 + zconf-ng.h.in | 176 + zconf.h.in | 206 + zendian.h | 60 + zlib-config.cmake.in | 12 + zlib-ng-config.cmake.in | 10 + zlib-ng.h.in | 1871 ++++ zlib-ng.map | 111 + zlib.h.in | 1859 ++++ zlib.map | 98 + zlib.pc.cmakein | 14 + zlib.pc.in | 14 + zlib_name_mangling-ng.h.in | 178 + zlib_name_mangling.h.empty | 8 + zlib_name_mangling.h.in | 170 + zmemory.h | 99 + zutil.c | 111 + zutil.h | 140 + zutil_p.h | 46 + 332 files changed, 94367 insertions(+), 99 deletions(-) create mode 100644 .codecov.yaml delete mode 100644 .github/workflows/autoclose.yaml create mode 100644 .shellcheckrc create mode 100644 CMakeLists.txt create mode 100644 FAQ.zlib create mode 100644 INDEX.md create mode 100644 LICENSE.md create mode 100644 Makefile.in create mode 100644 PORTING.md create mode 100644 README.md delete mode 100644 README.rst create mode 100644 adler32.c create mode 100644 adler32_p.h create mode 100644 arch/arm/Makefile.in create mode 100644 arch/arm/acle_intrins.h create mode 100644 arch/arm/adler32_neon.c create mode 100644 arch/arm/arm_features.c create mode 100644 arch/arm/arm_features.h create mode 100644 arch/arm/arm_functions.h create mode 100644 arch/arm/chunkset_neon.c create mode 100644 arch/arm/compare256_neon.c create mode 100644 arch/arm/crc32_acle.c create mode 100644 arch/arm/neon_intrins.h create mode 100644 arch/arm/slide_hash_armv6.c create mode 100644 arch/arm/slide_hash_neon.c create mode 100644 arch/generic/Makefile.in create mode 100644 arch/generic/adler32_c.c create mode 100644 arch/generic/adler32_fold_c.c create mode 100644 arch/generic/chunk_permute_table.h create mode 100644 arch/generic/chunkset_c.c create mode 100644 arch/generic/compare256_c.c create mode 100644 arch/generic/compare256_p.h create mode 100644 arch/generic/crc32_braid_c.c create mode 100644 arch/generic/crc32_fold_c.c create mode 100644 arch/generic/generic_functions.h create mode 100644 arch/generic/slide_hash_c.c create mode 100644 arch/power/Makefile.in create mode 100644 arch/power/adler32_power8.c create mode 100644 arch/power/adler32_vmx.c create mode 100644 arch/power/chunkset_power8.c create mode 100644 arch/power/compare256_power9.c create mode 100644 arch/power/crc32_constants.h create mode 100644 arch/power/crc32_power8.c create mode 100644 arch/power/power_features.c create mode 100644 arch/power/power_features.h create mode 100644 arch/power/power_functions.h create mode 100644 arch/power/power_intrins.h create mode 100644 arch/power/slide_hash_power8.c create mode 100644 arch/power/slide_hash_vmx.c create mode 100644 arch/power/slide_ppc_tpl.h create mode 100644 arch/riscv/README.md create mode 100644 arch/riscv/adler32_rvv.c create mode 100644 arch/riscv/chunkset_rvv.c create mode 100644 arch/riscv/compare256_rvv.c create mode 100644 arch/riscv/riscv_features.c create mode 100644 arch/riscv/riscv_features.h create mode 100644 arch/riscv/riscv_functions.h create mode 100644 arch/riscv/slide_hash_rvv.c create mode 100644 arch/s390/Makefile.in create mode 100644 arch/s390/README.md create mode 100644 arch/s390/crc32-vx.c create mode 100644 arch/s390/dfltcc_common.h create mode 100644 arch/s390/dfltcc_deflate.c create mode 100644 arch/s390/dfltcc_deflate.h create mode 100644 arch/s390/dfltcc_detail.h create mode 100644 arch/s390/dfltcc_inflate.c create mode 100644 arch/s390/dfltcc_inflate.h create mode 100644 arch/s390/s390_features.c create mode 100644 arch/s390/s390_features.h create mode 100644 arch/s390/s390_functions.h create mode 100644 arch/s390/self-hosted-builder/actions-runner create mode 100644 arch/s390/self-hosted-builder/actions-runner-rebuild.sh create mode 100644 arch/s390/self-hosted-builder/actions-runner.Dockerfile create mode 100644 arch/s390/self-hosted-builder/actions-runner.service create mode 100644 arch/s390/self-hosted-builder/entrypoint create mode 100644 arch/x86/Makefile.in create mode 100644 arch/x86/adler32_avx2.c create mode 100644 arch/x86/adler32_avx2_p.h create mode 100644 arch/x86/adler32_avx512.c create mode 100644 arch/x86/adler32_avx512_p.h create mode 100644 arch/x86/adler32_avx512_vnni.c create mode 100644 arch/x86/adler32_sse42.c create mode 100644 arch/x86/adler32_ssse3.c create mode 100644 arch/x86/adler32_ssse3_p.h create mode 100644 arch/x86/avx2_tables.h create mode 100644 arch/x86/chunkset_avx2.c create mode 100644 arch/x86/chunkset_avx512.c create mode 100644 arch/x86/chunkset_sse2.c create mode 100644 arch/x86/chunkset_ssse3.c create mode 100644 arch/x86/compare256_avx2.c create mode 100644 arch/x86/compare256_sse2.c create mode 100644 arch/x86/crc32_fold_pclmulqdq_tpl.h create mode 100644 arch/x86/crc32_fold_vpclmulqdq_tpl.h create mode 100644 arch/x86/crc32_pclmulqdq.c create mode 100644 arch/x86/crc32_pclmulqdq_tpl.h create mode 100644 arch/x86/crc32_vpclmulqdq.c create mode 100644 arch/x86/slide_hash_avx2.c create mode 100644 arch/x86/slide_hash_sse2.c create mode 100644 arch/x86/x86_features.c create mode 100644 arch/x86/x86_features.h create mode 100644 arch/x86/x86_functions.h create mode 100644 arch/x86/x86_intrins.h create mode 100644 arch_functions.h create mode 100644 chunkset_tpl.h create mode 100644 cmake/detect-arch.c create mode 100644 cmake/detect-arch.cmake create mode 100644 cmake/detect-coverage.cmake create mode 100644 cmake/detect-install-dirs.cmake create mode 100644 cmake/detect-intrinsics.cmake create mode 100644 cmake/detect-sanitizer.cmake create mode 100644 cmake/fallback-macros.cmake create mode 100644 cmake/toolchain-aarch64.cmake create mode 100644 cmake/toolchain-arm.cmake create mode 100644 cmake/toolchain-armhf.cmake create mode 100644 cmake/toolchain-llvm-mingw-aarch64.cmake create mode 100644 cmake/toolchain-llvm-mingw-armv7.cmake create mode 100644 cmake/toolchain-llvm-mingw-i686.cmake create mode 100644 cmake/toolchain-llvm-mingw-x86_64.cmake create mode 100644 cmake/toolchain-mingw-i686.cmake create mode 100644 cmake/toolchain-mingw-x86_64.cmake create mode 100644 cmake/toolchain-mips.cmake create mode 100644 cmake/toolchain-mips64.cmake create mode 100644 cmake/toolchain-powerpc.cmake create mode 100644 cmake/toolchain-powerpc64-clang.cmake create mode 100644 cmake/toolchain-powerpc64-power9.cmake create mode 100644 cmake/toolchain-powerpc64.cmake create mode 100644 cmake/toolchain-powerpc64le-clang.cmake create mode 100644 cmake/toolchain-powerpc64le-power9.cmake create mode 100644 cmake/toolchain-powerpc64le.cmake create mode 100644 cmake/toolchain-riscv.cmake create mode 100644 cmake/toolchain-s390x.cmake create mode 100644 cmake/toolchain-sparc64.cmake create mode 100644 compare256_rle.h create mode 100644 compress.c create mode 100644 configure create mode 100644 cpu_features.c create mode 100644 cpu_features.h create mode 100644 crc32.c create mode 100644 crc32.h create mode 100644 crc32_braid_comb.c create mode 100644 crc32_braid_comb_p.h create mode 100644 crc32_braid_p.h create mode 100644 crc32_braid_tbl.h create mode 100644 deflate.c create mode 100644 deflate.h create mode 100644 deflate_fast.c create mode 100644 deflate_huff.c create mode 100644 deflate_medium.c create mode 100644 deflate_p.h create mode 100644 deflate_quick.c create mode 100644 deflate_rle.c create mode 100644 deflate_slow.c create mode 100644 deflate_stored.c create mode 100644 doc/algorithm.txt create mode 100644 doc/crc-doc.1.0.pdf create mode 100644 doc/crc-pclmulqdq.pdf create mode 100644 doc/rfc1950.txt create mode 100644 doc/rfc1951.txt create mode 100644 doc/rfc1952.txt create mode 100644 doc/txtvsbin.txt create mode 100644 fallback_builtins.h create mode 100644 functable.c create mode 100644 functable.h create mode 100644 gzguts.h create mode 100644 gzlib.c create mode 100644 gzread.c.in create mode 100644 gzwrite.c create mode 100644 infback.c create mode 100644 inffast_tpl.h create mode 100644 inffixed_tbl.h create mode 100644 inflate.c create mode 100644 inflate.h create mode 100644 inflate_p.h create mode 100644 inftrees.c create mode 100644 inftrees.h create mode 100644 insert_string.c create mode 100644 insert_string_roll.c create mode 100644 insert_string_tpl.h create mode 100644 match_tpl.h create mode 100644 test/CMakeLists.txt create mode 100644 test/CVE-2002-0059/test.gz create mode 100644 test/CVE-2004-0797/test.gz create mode 100644 test/CVE-2005-1849/test.gz create mode 100644 test/CVE-2005-2096/test.gz create mode 100644 test/CVE-2018-25032/default.txt create mode 100644 test/CVE-2018-25032/fixed.txt create mode 100644 test/GH-1600/packobj.gz create mode 100644 test/GH-361/test.txt create mode 100644 test/GH-364/test.bin create mode 100644 test/GH-382/defneg3.dat create mode 100644 test/GH-751/test.txt create mode 100644 test/GH-979/pigz-2.6.tar.gz create mode 100644 test/Makefile.in create mode 100644 test/README.md create mode 100644 test/abi/ignore create mode 100644 test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-aarch64-unknown-linux-gnu.abi create mode 100644 test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-arm-unknown-linux-gnueabi.abi create mode 100644 test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-arm-unknown-linux-gnueabihf.abi create mode 100644 test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-mips-unknown-linux-gnu.abi create mode 100644 test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-mips64-unknown-linux-gnuabi64.abi create mode 100644 test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc-unknown-linux-gnu.abi create mode 100644 test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc64-unknown-linux-gnu.abi create mode 100644 test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc64le-unknown-linux-gnu.abi create mode 100644 test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-x86_64-pc-linux-gnu-m32.abi create mode 100644 test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-x86_64-pc-linux-gnu.abi create mode 100644 test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-aarch64-unknown-linux-gnu.abi create mode 100644 test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-arm-unknown-linux-gnueabi.abi create mode 100644 test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-arm-unknown-linux-gnueabihf.abi create mode 100644 test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-mips-unknown-linux-gnu.abi create mode 100644 test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-mips64-unknown-linux-gnuabi64.abi create mode 100644 test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc-unknown-linux-gnu.abi create mode 100644 test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc64-unknown-linux-gnu.abi create mode 100644 test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc64le-unknown-linux-gnu.abi create mode 100644 test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-x86_64-pc-linux-gnu-m32.abi create mode 100644 test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-x86_64-pc-linux-gnu.abi create mode 100644 test/abicheck.md create mode 100644 test/abicheck.sh create mode 100644 test/add-subdirectory-project/CMakeLists.txt create mode 100644 test/add-subdirectory-project/main.c create mode 100644 test/benchmarks/CMakeLists.txt create mode 100644 test/benchmarks/README.md create mode 100644 test/benchmarks/benchmark_adler32.cc create mode 100644 test/benchmarks/benchmark_adler32_copy.cc create mode 100644 test/benchmarks/benchmark_compare256.cc create mode 100644 test/benchmarks/benchmark_compare256_rle.cc create mode 100644 test/benchmarks/benchmark_compress.cc create mode 100644 test/benchmarks/benchmark_crc32.cc create mode 100644 test/benchmarks/benchmark_main.cc create mode 100644 test/benchmarks/benchmark_png_decode.cc create mode 100644 test/benchmarks/benchmark_png_encode.cc create mode 100644 test/benchmarks/benchmark_png_shared.h create mode 100644 test/benchmarks/benchmark_slidehash.cc create mode 100644 test/benchmarks/benchmark_uncompress.cc create mode 100644 test/cmake/compress-and-verify.cmake create mode 100644 test/cmake/run-and-compare.cmake create mode 100644 test/cmake/run-and-redirect.cmake create mode 100644 test/cmake/test-cves.cmake create mode 100644 test/cmake/test-data.cmake create mode 100644 test/cmake/test-issues.cmake create mode 100644 test/cmake/test-tools.cmake create mode 100644 test/data/fireworks.jpg create mode 100644 test/data/lcet10.txt create mode 100644 test/data/paper-100k.pdf create mode 100644 test/example.c create mode 100644 test/fuzz/CMakeLists.txt create mode 100644 test/fuzz/fuzzer_checksum.c create mode 100644 test/fuzz/fuzzer_compress.c create mode 100644 test/fuzz/fuzzer_example_dict.c create mode 100644 test/fuzz/fuzzer_example_flush.c create mode 100644 test/fuzz/fuzzer_example_large.c create mode 100644 test/fuzz/fuzzer_example_small.c create mode 100644 test/fuzz/fuzzer_minigzip.c create mode 100644 test/fuzz/standalone_fuzz_target_runner.c create mode 100644 test/gh1235.c create mode 100644 test/infcover.c create mode 100644 test/minideflate.c create mode 100644 test/minigzip.c create mode 100644 test/pigz/CMakeLists.txt create mode 100644 test/pkgcheck.sh create mode 100644 test/switchlevels.c create mode 100644 test/test_adler32.cc create mode 100644 test/test_compare256.cc create mode 100644 test/test_compare256_rle.cc create mode 100644 test/test_compress.cc create mode 100644 test/test_compress_bound.cc create mode 100644 test/test_compress_dual.cc create mode 100644 test/test_cpu_features.h create mode 100644 test/test_crc32.cc create mode 100644 test/test_cve-2003-0107.cc create mode 100644 test/test_deflate_bound.cc create mode 100644 test/test_deflate_concurrency.cc create mode 100644 test/test_deflate_copy.cc create mode 100644 test/test_deflate_dict.cc create mode 100644 test/test_deflate_hash_head_0.cc create mode 100644 test/test_deflate_header.cc create mode 100644 test/test_deflate_params.cc create mode 100644 test/test_deflate_pending.cc create mode 100644 test/test_deflate_prime.cc create mode 100644 test/test_deflate_quick_bi_valid.cc create mode 100644 test/test_deflate_quick_block_open.cc create mode 100644 test/test_deflate_tune.cc create mode 100644 test/test_dict.cc create mode 100644 test/test_gzio.cc create mode 100644 test/test_inflate_adler32.cc create mode 100644 test/test_inflate_copy.cc create mode 100644 test/test_inflate_sync.cc create mode 100644 test/test_large_buffers.cc create mode 100644 test/test_main.cc create mode 100644 test/test_raw.cc create mode 100644 test/test_shared.h create mode 100644 test/test_shared_ng.h create mode 100644 test/test_small_buffers.cc create mode 100644 test/test_small_window.cc create mode 100644 test/test_version.cc create mode 100644 tools/config.sub create mode 100644 tools/makecrct.c create mode 100644 tools/makefixed.c create mode 100644 tools/maketrees.c create mode 100644 trees.c create mode 100644 trees.h create mode 100644 trees_emit.h create mode 100644 trees_tbl.h create mode 100644 uncompr.c create mode 100644 win32/Makefile.a64 create mode 100644 win32/Makefile.arm create mode 100644 win32/Makefile.msc create mode 100644 win32/depcheck.cpp create mode 100644 win32/replace.vbs create mode 100644 win32/zlib-ng.def.in create mode 100644 win32/zlib-ng1.rc create mode 100644 win32/zlib.def.in create mode 100644 win32/zlib1.rc create mode 100644 win32/zlibcompat.def.in create mode 100644 zbuild.h create mode 100644 zconf-ng.h.in create mode 100644 zconf.h.in create mode 100644 zendian.h create mode 100644 zlib-config.cmake.in create mode 100644 zlib-ng-config.cmake.in create mode 100644 zlib-ng.h.in create mode 100644 zlib-ng.map create mode 100644 zlib.h.in create mode 100644 zlib.map create mode 100644 zlib.pc.cmakein create mode 100644 zlib.pc.in create mode 100644 zlib_name_mangling-ng.h.in create mode 100644 zlib_name_mangling.h.empty create mode 100644 zlib_name_mangling.h.in create mode 100644 zmemory.h create mode 100644 zutil.c create mode 100644 zutil.h create mode 100644 zutil_p.h diff --git a/.codecov.yaml b/.codecov.yaml new file mode 100644 index 0000000000..fc17c66a90 --- /dev/null +++ b/.codecov.yaml @@ -0,0 +1,27 @@ +codecov: + max_report_age: off + notify: + wait_for_ci: false + require_ci_to_pass: false +comment: + require_base: false + require_head: false +coverage: + status: + project: + default: + threshold: 0.07 +fixes: +- '/home/actions-runner/_work/zlib-ng/zlib-ng::' +- '/home/actions-runner/_work/zlib-ng/zlib-ng/build/::' +ignore: +- usr/include/.* +- /usr/include/.* +- /build/usr/include/.* +- usr/lib/.* +- /usr/lib/.* +- /build/usr/lib/.* +- usr/lib64/.* +- /usr/lib64/.* +- /build/usr/lib64/.* +- _deps/**/* diff --git a/.github/workflows/autoclose.yaml b/.github/workflows/autoclose.yaml deleted file mode 100644 index fc6a6c1524..0000000000 --- a/.github/workflows/autoclose.yaml +++ /dev/null @@ -1,29 +0,0 @@ -name: Close Pull Requests - -permissions: - pull-requests: write - -on: - pull_request: - types: - - opened - schedule: - - cron: '0 * * * *' - workflow_dispatch: - -jobs: - run: - runs-on: ubuntu-latest - steps: - - name: Close Pull Requests - run: > - for pr in $(gh pr list --repo $REPO_NAME --json number --jq .[].number); do - gh pr close --repo $REPO_NAME --comment "$COMMENT" $pr; - done - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - REPO_NAME: python/cpython-source-deps - COMMENT: > - We do not accept PRs on this repository. Please file an issue at - https://github.com/python/cpython requesting an update to the - source packages in this repository. diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000000..89a1625ff5 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1 @@ +disable=SC2140,SC2086,SC2046,SC2015,SC1097,SC1035,SC1036,SC1007,SC2154,SC2155,SC2000,SC2034,SC2016,SC1091,SC1090,SC2212,SC2143,SC2129,SC2102,SC2069,SC1041,SC1042,SC1044,SC1046,SC1119,SC1110,SC1111,SC1112,SC1102,SC1105,SC1101,SC1004,SC1003,SC1012,SC2068,SC2065,SC2064,SC2063,SC2059,SC2053,SC2048,SC2044,SC2032,SC2031,SC2030,SC2029,SC2025,SC2024,SC2022,SC2018,SC2019,SC2017,SC2014,SC2013,SC2012,SC2009,SC2001,SC2098,SC2096,SC2094,SC2091,SC2092,SC2088,SC2087,SC2076,SC2072,SC2071,SC2223,SC2221,SC2222,SC2217,SC2207,SC2206,SC2205,SC2190,SC2188,SC2187,SC2185,SC2179,SC2178,SC2174,SC2168,SC2167,SC2163,SC2161,SC2160,SC2153,SC2150,SC2148,SC2147,SC2146,SC2142,SC2139,SC2126,SC2123,SC2120,SC2119,SC2117,SC2114,SC1117,SC2164,SC1083,SC2004,SC2125,SC2128,SC2011,SC1008,SC1019,SC2093,SC1132,SC1129,SC2236,SC2237,SC2231,SC2230,SC2229,SC2106,SC2102,SC2243,SC2244,SC2245,SC2247,SC2248,SC2249,SC2250,SC2251,SC2252,SC2181 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..367413062f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,1435 @@ +cmake_minimum_required(VERSION 3.5.1...3.29.0) +if(CMAKE_VERSION VERSION_LESS 3.12) + cmake_policy(VERSION ${CMAKE_VERSION}) +endif() +message(STATUS "Using CMake version ${CMAKE_VERSION}") + +if(POLICY CMP0169) + cmake_policy(SET CMP0169 OLD) # CMake 3.30: call FetchContent_Populate() with just the name of a dependency +endif() + +# If not specified on the command line, enable C11 as the default +# Configuration items that affect the global compiler environment standards +# should be issued before the "project" command. +if(NOT DEFINED CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 11) # The C standard whose features are requested to build this target +endif() +if(NOT DEFINED CMAKE_C_STANDARD_REQUIRED) + set(CMAKE_C_STANDARD_REQUIRED ON) # Boolean describing whether the value of C_STANDARD is a requirement +endif() +if(NOT DEFINED CMAKE_C_EXTENSIONS) + set(CMAKE_C_EXTENSIONS OFF) # Boolean specifying whether compiler specific extensions are requested +endif() +set(VALID_C_STANDARDS "99" "11") +if(NOT CMAKE_C_STANDARD IN_LIST VALID_C_STANDARDS) + MESSAGE(FATAL_ERROR "CMAKE_C_STANDARD:STRING=${CMAKE_C_STANDARD} not in known standards list\n ${VALID_C_STANDARDS}") +endif() + +# Parse the full version number from zlib.h.in and include in ZLIB_FULL_VERSION +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h.in _zlib_h_contents) +string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([0-9]+.[0-9]+.[0-9]+).*\".*" + "\\1" ZLIB_HEADER_VERSION ${_zlib_h_contents}) +string(REGEX REPLACE ".*#define[ \t]+ZLIBNG_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" + "\\1" ZLIBNG_HEADER_VERSION ${_zlib_h_contents}) +message(STATUS "ZLIB_HEADER_VERSION: ${ZLIB_HEADER_VERSION}") +message(STATUS "ZLIBNG_HEADER_VERSION: ${ZLIBNG_HEADER_VERSION}") + +project(zlib VERSION ${ZLIB_HEADER_VERSION} LANGUAGES C) + +include(CheckTypeSize) +include(CheckSymbolExists) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckCSourceCompiles) +include(CheckCSourceRuns) +include(CheckCCompilerFlag) +include(CMakeDependentOption) +include(CMakePackageConfigHelpers) +include(FeatureSummary) + +include(cmake/detect-arch.cmake) +include(cmake/detect-install-dirs.cmake) +include(cmake/detect-coverage.cmake) +include(cmake/detect-intrinsics.cmake) +include(cmake/detect-sanitizer.cmake) +include(cmake/fallback-macros.cmake) + +if(CMAKE_TOOLCHAIN_FILE) + message(STATUS "Using CMake toolchain: ${CMAKE_TOOLCHAIN_FILE}") +endif() + +# Make sure we use an appropriate BUILD_TYPE by default, "Release" to be exact +# this should select the maximum generic optimisation on the current platform (i.e. -O3 for gcc/clang) +get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(NOT GENERATOR_IS_MULTI_CONFIG) + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING + "Choose the type of build, standard options are: Debug Release RelWithDebInfo MinSizeRel." + FORCE) + add_feature_info(CMAKE_BUILD_TYPE 1 "Build type: ${CMAKE_BUILD_TYPE} (default)") + else() + add_feature_info(CMAKE_BUILD_TYPE 1 "Build type: ${CMAKE_BUILD_TYPE} (selected)") + endif() +endif() + +# +# Options parsing +# +option(WITH_GZFILEOP "Compile with support for gzFile related functions" ON) +option(ZLIB_COMPAT "Compile with zlib compatible API" OFF) +option(ZLIB_ENABLE_TESTS "Build test binaries" ON) +option(ZLIBNG_ENABLE_TESTS "Test zlib-ng specific API" ON) +option(WITH_GTEST "Build gtest_zlib" ON) +option(WITH_FUZZERS "Build test/fuzz" OFF) +option(WITH_BENCHMARKS "Build test/benchmarks" OFF) +option(WITH_BENCHMARK_APPS "Build application benchmarks" OFF) +option(WITH_OPTIM "Build with optimisation" ON) +option(WITH_REDUCED_MEM "Reduced memory usage for special cases (reduces performance)" OFF) +option(WITH_NEW_STRATEGIES "Use new strategies" ON) +option(WITH_NATIVE_INSTRUCTIONS + "Instruct the compiler to use the full instruction set on this host (gcc/clang -march=native)" OFF) +option(WITH_RUNTIME_CPU_DETECTION "Build with runtime detection of CPU architecture" ON) +option(WITH_MAINTAINER_WARNINGS "Build with project maintainer warnings" OFF) +option(WITH_CODE_COVERAGE "Enable code coverage reporting" OFF) +option(WITH_INFLATE_STRICT "Build with strict inflate distance checking" OFF) +option(WITH_INFLATE_ALLOW_INVALID_DIST "Build with zero fill for inflate invalid distances" OFF) + +set(ZLIB_SYMBOL_PREFIX "" CACHE STRING "Give this prefix to all publicly exported symbols. +Useful when embedding into a larger library. +Default is no prefix (empty prefix).") + +# Add multi-choice option +set(WITH_SANITIZER AUTO CACHE STRING "Enable sanitizer support") +set_property(CACHE WITH_SANITIZER PROPERTY STRINGS "Memory" "Address" "Undefined" "Thread") + +if(BASEARCH_ARM_FOUND) + option(WITH_ACLE "Build with ACLE" ON) + option(WITH_NEON "Build with NEON intrinsics" ON) + cmake_dependent_option(WITH_ARMV6 "Build with ARMv6 SIMD" ON "NOT ARCH MATCHES \"aarch64\"" OFF) +elseif(BASEARCH_PPC_FOUND) + option(WITH_ALTIVEC "Build with AltiVec (VMX) optimisations for PowerPC" ON) + option(WITH_POWER8 "Build with optimisations for POWER8" ON) + option(WITH_POWER9 "Build with optimisations for POWER9" ON) +elseif(BASEARCH_RISCV_FOUND) + option(WITH_RVV "Build with RVV intrinsics" ON) +elseif(BASEARCH_S360_FOUND) + option(WITH_DFLTCC_DEFLATE "Build with DFLTCC intrinsics for compression on IBM Z" OFF) + option(WITH_DFLTCC_INFLATE "Build with DFLTCC intrinsics for decompression on IBM Z" OFF) + option(WITH_CRC32_VX "Build with vectorized CRC32 on IBM Z" ON) +elseif(BASEARCH_X86_FOUND) + option(WITH_SSE2 "Build with SSE2" ON) + cmake_dependent_option(WITH_SSSE3 "Build with SSSE3" ON "WITH_SSE2" OFF) + cmake_dependent_option(WITH_SSE42 "Build with SSE42" ON "WITH_SSSE3" OFF) + cmake_dependent_option(WITH_PCLMULQDQ "Build with PCLMULQDQ" ON "WITH_SSE42" OFF) + cmake_dependent_option(WITH_AVX2 "Build with AVX2" ON "WITH_SSE42" OFF) + cmake_dependent_option(WITH_AVX512 "Build with AVX512" ON "WITH_AVX2" OFF) + cmake_dependent_option(WITH_AVX512VNNI "Build with AVX512 VNNI extensions" ON "WITH_AVX512" OFF) + cmake_dependent_option(WITH_VPCLMULQDQ "Build with VPCLMULQDQ" ON "WITH_PCLMULQDQ;WITH_AVX512" OFF) +endif() + +option(INSTALL_UTILS "Copy minigzip and minideflate during install" OFF) + +mark_as_advanced(FORCE + ZLIB_SYMBOL_PREFIX + WITH_REDUCED_MEM + WITH_ACLE WITH_NEON + WITH_ARMV6 + WITH_DFLTCC_DEFLATE + WITH_DFLTCC_INFLATE + WITH_CRC32_VX + WITH_AVX2 WITH_SSE2 + WITH_SSSE3 WITH_SSE42 + WITH_PCLMULQDQ + WITH_ALTIVEC + WITH_POWER8 + WITH_POWER9 + WITH_RVV + WITH_INFLATE_STRICT + WITH_INFLATE_ALLOW_INVALID_DIST + INSTALL_UTILS + ) + +if(ZLIB_COMPAT) + add_definitions(-DZLIB_COMPAT) + set(WITH_GZFILEOP ON) + set(SUFFIX "") + set(ZLIB_FULL_VERSION ${ZLIB_HEADER_VERSION}.zlib-ng) + set(EXPORT_NAME ZLIB) +else() + set(SUFFIX "-ng") + set(ZLIB_FULL_VERSION ${ZLIBNG_HEADER_VERSION}) + set(EXPORT_NAME zlib-ng) +endif() + +if(WITH_GZFILEOP) + add_definitions(-DWITH_GZFILEOP) +endif() + +if(CMAKE_C_COMPILER_ID MATCHES "^Intel") + if(CMAKE_HOST_UNIX) + set(WARNFLAGS -Wall) + set(WARNFLAGS_MAINTAINER -Wall -Wcheck -Wremarks) + set(WARNFLAGS_DISABLE) + else() + set(WARNFLAGS /Wall) + set(WARNFLAGS_MAINTAINER /W5) + set(WARNFLAGS_DISABLE) + endif() + check_c_compiler_flag(-diag-disable=10441 HAVE_DIAG_10441) + if(HAVE_DIAG_10441) + list(APPEND WARNFLAGS_DISABLE "-diag-disable=10441") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -diag-disable=10441") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -diag-disable=10441") + endif() +elseif(MSVC) + # Minimum supported MSVC version is 1800 = Visual Studio 12.0/2013 + # See also https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html + if(MSVC_VERSION VERSION_LESS 1800) + message(SEND_ERROR "Unsupported Visual Studio compiler version (requires 2013 or later).") + endif() + # TODO. ICC can be used through MSVC. I'm not sure if we'd ever see that combination + # (who'd use cmake from an IDE...) but checking for ICC before checking for MSVC should + # avoid mistakes. + # /Oi ? + set(WARNFLAGS /W3 /w34242 /WX) + set(WARNFLAGS_MAINTAINER /W4) + set(WARNFLAGS_DISABLE /wd4206 /wd4054 /wd4324) + if(BASEARCH_ARM_FOUND) + add_definitions(-D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE) + if(NOT "${ARCH}" MATCHES "aarch64") + set(NEONFLAG "/arch:VFPv4") + endif() + endif() +elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + # Enable warnings in GCC and Clang + set(WARNFLAGS -Wall) + set(WARNFLAGS_MAINTAINER -Wextra) + set(WARNFLAGS_DISABLE) + # Check whether -fno-lto is available + set(CMAKE_REQUIRED_FLAGS "-fno-lto") + check_c_source_compiles( + "int main() { return 0; }" + FNO_LTO_AVAILABLE FAIL_REGEX "not supported") + set(CMAKE_REQUIRED_FLAGS) + if(FNO_LTO_AVAILABLE) + set(ZNOLTOFLAG "-fno-lto") + endif() + if(NOT WITH_NATIVE_INSTRUCTIONS) + if(BASEARCH_ARM_FOUND) + if("${ARCH}" MATCHES "arm" AND NOT CMAKE_C_FLAGS MATCHES "-mfloat-abi") + # Auto-detect support for ARM floating point ABI + check_include_file(features.h HAVE_FEATURES_H) + if(HAVE_FEATURES_H) + set(CMAKE_REQUIRED_FLAGS -mfloat-abi=softfp) + check_c_source_compiles( + "#include + int main() { return 0; }" + HAVE_FLOATABI_SOFTFP) + if(HAVE_FLOATABI_SOFTFP) + set(FLOATABI -mfloat-abi=softfp) + else() + set(CMAKE_REQUIRED_FLAGS -mfloat-abi=hard) + check_c_source_compiles( + "#include + int main() { return 0; }" + HAVE_FLOATABI_HARD) + if(HAVE_FLOATABI_HARD) + set(FLOATABI -mfloat-abi=hard) + endif() + endif() + set(CMAKE_REQUIRED_FLAGS) + endif() + if(FLOATABI) + message(STATUS "ARM floating point arch: ${FLOATABI}") + add_compile_options(${FLOATABI}) + else() + message(STATUS "ARM floating point arch not auto-detected") + endif() + endif() + endif() + # Disable LTO unless Native Instructions are enabled + if(FNO_LTO_AVAILABLE) + set(NOLTOFLAG ${ZNOLTOFLAG}) + endif() + endif() + if(MINGW) + # Add `-Wno-pedantic-ms-format` only if the toolchain supports it + check_c_compiler_flag(-Wno-pedantic-ms-format HAVE_NO_PEDANTIC_MS_FORMAT) + if(HAVE_NO_PEDANTIC_MS_FORMAT) + list(APPEND WARNFLAGS_DISABLE -Wno-pedantic-ms-format) + endif() + endif() +endif() + +# Set native march/mcpu +if(WITH_NATIVE_INSTRUCTIONS) + if(NATIVE_ARCH_OVERRIDE) + message(STATUS "WARNING: WITH_NATIVE_INSTRUCTIONS enabled, but running with NATIVE_ARCH_OVERRIDE: ${NATIVE_ARCH_OVERRIDE}") + set(NATIVEFLAG "${NATIVE_ARCH_OVERRIDE}") + else() + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + check_c_compiler_flag(-march=native HAVE_MARCH_NATIVE) + if(HAVE_MARCH_NATIVE) + set(NATIVEFLAG "-march=native") + else() + check_c_compiler_flag(-mcpu=native HAVE_MCPU_NATIVE) + if(HAVE_MCPU_NATIVE) + set(NATIVEFLAG "-mcpu=native") + endif() + endif() + # Fall through + endif() + endif() + if(NATIVEFLAG) + # Apply flags to all source files and compilation checks + if(WIN32) + separate_arguments(NATIVEOPTIONS WINDOWS_COMMAND "${NATIVEFLAG}") + else() + separate_arguments(NATIVEOPTIONS UNIX_COMMAND "${NATIVEFLAG}") + endif() + add_compile_options(${NATIVEOPTIONS}) + set(WITH_RUNTIME_CPU_DETECTION OFF) + else() + message(STATUS "Ignoring WITH_NATIVE_INSTRUCTIONS; not implemented yet on this configuration") + set(WITH_NATIVE_INSTRUCTIONS OFF) + endif() +endif() + +# Compile without functable or CPU detection +if(NOT WITH_RUNTIME_CPU_DETECTION) + if(MSVC AND BASEARCH_X86_FOUND) + message(STATUS "WARNING: Microsoft Visual Studio does not support compile time detection of CPU features for \"/arch\" before \"AVX\"") + # Workaround for MSVC. By default MSVC does not define the __SSE*__ macros. + # Fix it if AVX is enabled. + set(CMAKE_REQUIRED_FLAGS "${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#ifndef __AVX__ + # error \"AVX is not enabled.\" + #endif + int main(void) { return 0; }" + MSVC_IS_ENABLED_AVX + ) + set(CMAKE_REQUIRED_FLAGS) + if(MSVC_IS_ENABLED_AVX) + add_definitions( + -D__SSE__=1 + -D__SSE2__=1 + -D__SSE3__=1 + -D__SSSE3__=1 + -D__SSE4_1__=1 + -D__SSE4_2__=1 + -D__PCLMUL__=1 + ) + endif() + endif() + add_definitions(-DDISABLE_RUNTIME_CPU_DETECTION) +endif() + +# Force disable LTO if WITH_NATIVE_INSTRUCTIONS is not active +if(NOT WITH_NATIVE_INSTRUCTIONS) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) + foreach(_cfg_name IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER "${_cfg_name}" _cfg_name_uc) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_${_cfg_name_uc} OFF) + endforeach() +endif() + +# Apply warning compiler flags +if(WITH_MAINTAINER_WARNINGS) + add_compile_options(${WARNFLAGS} ${WARNFLAGS_MAINTAINER} ${WARNFLAGS_DISABLE}) +else() + add_compile_options(${WARNFLAGS} ${WARNFLAGS_DISABLE}) +endif() + +# Set code coverage compiler flags +if(WITH_CODE_COVERAGE) + add_code_coverage() +endif() + +# Replace optimization level 3 added by default with level 2 +if(NOT WITH_CODE_COVERAGE AND NOT MSVC AND NOT CMAKE_C_FLAGS MATCHES "([\\/\\-]O)3") + string(REGEX REPLACE "([\\/\\-]O)3" "\\12" + CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") +endif() + +# Force Visual C++ to use UTF-8 +if(MSVC) + if (NOT CMAKE_C_FLAGS MATCHES "[\\/\\-]utf-8") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8") + endif() + if (NOT CMAKE_CXX_FLAGS MATCHES "[\\/\\-]utf-8") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8") + endif() +endif() + +# +# Check for standard/system includes +# +check_include_file(arm_acle.h HAVE_ARM_ACLE_H) +if(HAVE_ARM_ACLE_H) + add_definitions(-DHAVE_ARM_ACLE_H) +endif() +check_include_file(sys/auxv.h HAVE_SYS_AUXV_H) +if(HAVE_SYS_AUXV_H) + add_definitions(-DHAVE_SYS_AUXV_H) +endif() +check_include_file(sys/sdt.h HAVE_SYS_SDT_H) +if(HAVE_SYS_SDT_H) + add_definitions(-DHAVE_SYS_SDT_H) +endif() +check_include_file(unistd.h HAVE_UNISTD_H) + +# +# Check for Linux includes +# +check_include_file(linux/auxvec.h HAVE_LINUX_AUXVEC_H) +if(HAVE_LINUX_AUXVEC_H) + add_definitions(-DHAVE_LINUX_AUXVEC_H) +endif() + +# +# Check to see if we have large file support +# +set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1 -D__USE_LARGEFILE64) +check_type_size(off64_t OFF64_T) +if(HAVE_OFF64_T) + add_definitions(-D_LARGEFILE64_SOURCE=1 -D__USE_LARGEFILE64) +else() + check_type_size(_off64_t _OFF64_T) + if(HAVE__OFF64_T) + add_definitions(-D_LARGEFILE64_SOURCE=1 -D__USE_LARGEFILE64) + else() + check_type_size(__off64_t __OFF64_T) + endif() +endif() +set(CMAKE_REQUIRED_DEFINITIONS) # clear variable + +# +# Check for fseeko and other optional functions +# +check_function_exists(fseeko HAVE_FSEEKO) +if(NOT HAVE_FSEEKO) + add_definitions(-DNO_FSEEKO) +endif() + +check_function_exists(strerror HAVE_STRERROR) +if(NOT HAVE_STRERROR) + add_definitions(-DNO_STRERROR) +endif() + +set(CMAKE_REQUIRED_DEFINITIONS -D_POSIX_C_SOURCE=200112L) +check_symbol_exists(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) +if(HAVE_POSIX_MEMALIGN) + add_definitions(-DHAVE_POSIX_MEMALIGN) +endif() +set(CMAKE_REQUIRED_DEFINITIONS) + +set(CMAKE_REQUIRED_DEFINITIONS -D_ISOC11_SOURCE=1) +check_symbol_exists(aligned_alloc stdlib.h HAVE_ALIGNED_ALLOC) +if(HAVE_ALIGNED_ALLOC) + add_definitions(-DHAVE_ALIGNED_ALLOC) +endif() +set(CMAKE_REQUIRED_DEFINITIONS) + +if(WITH_SANITIZER STREQUAL "Address") + add_address_sanitizer() +elseif(WITH_SANITIZER STREQUAL "Memory") + add_memory_sanitizer() +elseif(WITH_SANITIZER STREQUAL "Thread") + add_thread_sanitizer() +elseif(WITH_SANITIZER STREQUAL "Undefined") + add_undefined_sanitizer() +endif() + +# +# Check whether compiler supports -fno-semantic-interposition parameter +# +check_c_compiler_flag(-fno-semantic-interposition HAVE_NO_INTERPOSITION) + +# +# Check if we can hide zlib internal symbols that are linked between separate source files using hidden +# +check_c_source_compiles( + "#define Z_INTERNAL __attribute__((visibility (\"hidden\"))) + int Z_INTERNAL foo; + int main() { + return 0; + }" + HAVE_ATTRIBUTE_VISIBILITY_HIDDEN FAIL_REGEX "visibility") +if(HAVE_ATTRIBUTE_VISIBILITY_HIDDEN) + add_definitions(-DHAVE_VISIBILITY_HIDDEN) +endif() + +# +# Check if we can hide zlib internal symbols that are linked between separate source files using internal +# +check_c_source_compiles( + "#define Z_INTERNAL __attribute__((visibility (\"internal\"))) + int Z_INTERNAL foo; + int main() { + return 0; + }" + HAVE_ATTRIBUTE_VISIBILITY_INTERNAL FAIL_REGEX "visibility") +if(HAVE_ATTRIBUTE_VISIBILITY_INTERNAL) + add_definitions(-DHAVE_VISIBILITY_INTERNAL) +endif() + +# +# Check for __attribute__((aligned(x))) support in the compiler +# +check_c_source_compiles( + "int main(void) { + __attribute__((aligned(8))) int test = 0; + (void)test; + return 0; + }" + HAVE_ATTRIBUTE_ALIGNED FAIL_REGEX "aligned") +if(HAVE_ATTRIBUTE_ALIGNED) + add_definitions(-DHAVE_ATTRIBUTE_ALIGNED) +endif() + +# +# Check for __builtin_assume_aligned(x,n) support in the compiler +# +set(CMAKE_REQUIRED_FLAGS ${ZNOLTOFLAG}) +check_c_source_compiles( + "char *test(char *buffer) { + char *abuffer = __builtin_assume_aligned(buffer,64); + return abuffer; + } + int main() { + return 0; + }" + HAVE_BUILTIN_ASSUME_ALIGNED) +if(HAVE_BUILTIN_ASSUME_ALIGNED) + add_definitions(-DHAVE_BUILTIN_ASSUME_ALIGNED) +endif() +set(CMAKE_REQUIRED_FLAGS) + +# +# check for __builtin_ctz() support in the compiler +# +set(CMAKE_REQUIRED_FLAGS ${ZNOLTOFLAG}) +check_c_source_compiles( + "int main(void) { + unsigned int zero = 0; + long test = __builtin_ctz(zero); + (void)test; + return 0; + }" + HAVE_BUILTIN_CTZ +) +if(HAVE_BUILTIN_CTZ) + add_definitions(-DHAVE_BUILTIN_CTZ) +endif() +set(CMAKE_REQUIRED_FLAGS) + +# +# check for __builtin_ctzll() support in the compiler +# +set(CMAKE_REQUIRED_FLAGS ${ZNOLTOFLAG}) +check_c_source_compiles( + "int main(void) { + unsigned int zero = 0; + long test = __builtin_ctzll(zero); + (void)test; + return 0; + }" + HAVE_BUILTIN_CTZLL +) +if(HAVE_BUILTIN_CTZLL) + add_definitions(-DHAVE_BUILTIN_CTZLL) +endif() +set(CMAKE_REQUIRED_FLAGS) + +# +# check for ptrdiff_t support +# +check_c_source_compiles( + "#include + int main() { + ptrdiff_t *a; + (void)a; + return 0; + }" + HAVE_PTRDIFF_T +) +if(NOT HAVE_PTRDIFF_T) + set(NEED_PTRDIFF_T 1) + + check_type_size("void *" SIZEOF_DATA_PTR) + message(STATUS "sizeof(void *) is ${SIZEOF_DATA_PTR} bytes") + + if(${SIZEOF_DATA_PTR} MATCHES "4") + set(PTRDIFF_TYPE "uint32_t") + elseif(${SIZEOF_DATA_PTR} MATCHES "8") + set(PTRDIFF_TYPE "uint64_t") + else() + message(FATAL_ERROR "sizeof(void *) is neither 32 nor 64 bit") + endif() +endif() + +add_compile_options($<$:-DZLIB_DEBUG>) + +if(MSVC) + set(CMAKE_DEBUG_POSTFIX "d") + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) + add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) +endif() + +if(BASEARCH_X86_FOUND) + # FORCE_SSE2 option will only be shown if HAVE_SSE2_INTRIN is true + if("${ARCH}" MATCHES "i[3-6]86") + cmake_dependent_option(FORCE_SSE2 "Always assume CPU is SSE2 capable" OFF "HAVE_SSE2_INTRIN" OFF) + endif() +endif() + +# +# Enable deflate_quick at level 1 +# +if(NOT WITH_NEW_STRATEGIES) + add_definitions(-DNO_QUICK_STRATEGY) +endif() +# +# Enable deflate_medium at level 4-6 +# +if(NOT WITH_NEW_STRATEGIES) + add_definitions(-DNO_MEDIUM_STRATEGY) +endif() +# +# Enable inflate compilation options +# +if(WITH_INFLATE_STRICT) + add_definitions(-DINFLATE_STRICT) + message(STATUS "Inflate strict distance checking enabled") +endif() +if(WITH_INFLATE_ALLOW_INVALID_DIST) + add_definitions(-DINFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR) + message(STATUS "Inflate zero data for invalid distances enabled") +endif() +# +# Enable reduced memory configuration +# +if(WITH_REDUCED_MEM) + add_definitions(-DHASH_SIZE=32768u -DGZBUFSIZE=8192 -DNO_LIT_MEM) + message(STATUS "Configured for reduced memory environment") +endif() + +set(GENERIC_ARCHDIR "arch/generic") + +set(ZLIB_ARCH_SRCS) +set(ZLIB_ARCH_HDRS ${GENERIC_ARCHDIR}/generic_functions.h) + +if(BASEARCH_ARM_FOUND) + set(ARCHDIR "arch/arm") +elseif(BASEARCH_PPC_FOUND) + set(ARCHDIR "arch/power") +elseif(BASEARCH_RISCV_FOUND) + set(ARCHDIR "arch/riscv") +elseif(BASEARCH_S360_FOUND) + set(ARCHDIR "arch/s390") +elseif(BASEARCH_X86_FOUND) + set(ARCHDIR "arch/x86") + if(NOT ${ARCH} MATCHES "x86_64") + add_feature_info(SSE2 1 "Support the SSE2 instruction set, using \"${SSE2FLAG}\"") + endif() +else() + set(ARCHDIR ${GENERIC_ARCHDIR}) + message(STATUS "No optimized architecture: using ${ARCHDIR}") +endif() + +if(WITH_OPTIM) + if(BASEARCH_ARM_FOUND) + add_definitions(-DARM_FEATURES) + if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + if("${ARCH}" MATCHES "aarch64") + check_c_source_compiles( + "#include + int main() { + return (getauxval(AT_HWCAP) & HWCAP_CRC32); + }" + ARM_AUXV_HAS_CRC32 + ) + if(ARM_AUXV_HAS_CRC32) + add_definitions(-DARM_AUXV_HAS_CRC32) + else() + message(STATUS "HWCAP_CRC32 not present in sys/auxv.h; cannot detect support at runtime.") + endif() + else() + check_c_source_compiles( + "#include + int main() { + return (getauxval(AT_HWCAP2) & HWCAP2_CRC32); + }" + ARM_AUXV_HAS_CRC32 + ) + if(ARM_AUXV_HAS_CRC32) + add_definitions(-DARM_AUXV_HAS_CRC32) + else() + check_c_source_compiles( + "#include + #include + int main() { + return (getauxval(AT_HWCAP2) & HWCAP2_CRC32); + }" + ARM_HWCAP_HAS_CRC32 + ) + if (ARM_HWCAP_HAS_CRC32) + add_definitions(-DARM_AUXV_HAS_CRC32 -DARM_ASM_HWCAP) + else() + message(STATUS "HWCAP2_CRC32 not present in sys/auxv.h; cannot detect support at runtime.") + endif() + endif() + check_c_source_compiles( + "#include + int main() { + return (getauxval(AT_HWCAP) & HWCAP_ARM_NEON); + }" + ARM_AUXV_HAS_NEON + ) + if(ARM_AUXV_HAS_NEON) + add_definitions(-DARM_AUXV_HAS_NEON) + else() + check_c_source_compiles( + "#include + int main() { + return (getauxval(AT_HWCAP) & HWCAP_NEON); + }" + ARM_AUXV_HAS_NEON + ) + if (ARM_AUXV_HAS_NEON) + add_definitions(-DARM_AUXV_HAS_NEON) + else() + message(STATUS "Neither HWCAP_ARM_NEON or HWCAP_NEON present in sys/auxv.h; cannot detect support at runtime.") + endif() + endif() + endif() + endif() + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/arm_functions.h) + if(WITH_RUNTIME_CPU_DETECTION) + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/arm_features.h) + list(APPEND ZLIB_ARCH_SRCS ${ARCHDIR}/arm_features.c) + endif() + + if(WITH_ACLE) + check_acle_compiler_flag() + if(HAVE_ACLE_FLAG) + add_definitions(-DARM_ACLE) + set(ACLE_SRCS ${ARCHDIR}/crc32_acle.c) + set_property(SOURCE ${ACLE_SRCS} PROPERTY COMPILE_FLAGS "${ACLEFLAG} ${NOLTOFLAG}") + list(APPEND ZLIB_ARCH_SRCS ${ACLE_SRCS}) + add_feature_info(ACLE_CRC 1 "Support ACLE optimized CRC hash generation, using \"${ACLEFLAG}\"") + else() + set(WITH_ACLE OFF) + endif() + else() + set(WITH_ACLE OFF) + endif() + if(WITH_NEON) + check_neon_compiler_flag() + if(NEON_AVAILABLE) + add_definitions(-DARM_NEON) + set(NEON_SRCS ${ARCHDIR}/adler32_neon.c ${ARCHDIR}/chunkset_neon.c + ${ARCHDIR}/compare256_neon.c ${ARCHDIR}/slide_hash_neon.c) + list(APPEND ZLIB_ARCH_SRCS ${NEON_SRCS}) + set_property(SOURCE ${NEON_SRCS} PROPERTY COMPILE_FLAGS "${NEONFLAG} ${NOLTOFLAG}") + if(MSVC) + add_definitions(-D__ARM_NEON__) + endif() + add_feature_info(NEON_ADLER32 1 "Support NEON instructions in adler32, using \"${NEONFLAG}\"") + add_feature_info(NEON_SLIDEHASH 1 "Support NEON instructions in slide_hash, using \"${NEONFLAG}\"") + check_neon_ld4_intrinsics() + if(NEON_HAS_LD4) + add_definitions(-DARM_NEON_HASLD4) + endif() + else() + set(WITH_NEON OFF) + endif() + endif() + if(WITH_ARMV6) + check_armv6_compiler_flag() + if(HAVE_ARMV6_INLINE_ASM OR HAVE_ARMV6_INTRIN) + add_definitions(-DARM_SIMD) + set(ARMV6_SRCS ${ARCHDIR}/slide_hash_armv6.c) + set_property(SOURCE ${ARMV6_SRCS} PROPERTY COMPILE_FLAGS "${ARMV6FLAG} ${NOLTOFLAG}") + list(APPEND ZLIB_ARCH_SRCS ${ARMV6_SRCS}) + add_feature_info(ARMV6 1 "Support ARMv6 SIMD instructions in slide_hash, using \"${ARMV6FLAG}\"") + if(HAVE_ARMV6_INTRIN) + add_definitions(-DARM_SIMD_INTRIN) + endif() + else() + set(WITH_ARMV6 OFF) + endif() + else() + set(WITH_ARMV6 OFF) + endif() + elseif(BASEARCH_PPC_FOUND) + # Common arch detection code + if(WITH_ALTIVEC) + check_ppc_intrinsics() + endif() + if(WITH_POWER8) + check_power8_intrinsics() + endif() + if(WITH_POWER9) + check_power9_intrinsics() + endif() + if(POWER8_NEED_AUXVEC_H OR POWER9_NEED_AUXVEC_H) + add_definitions(-DPOWER_NEED_AUXVEC_H) + endif() + if(HAVE_POWER8_INTRIN OR HAVE_POWER9_INTRIN) + add_definitions(-DPOWER_FEATURES) + endif() + if(HAVE_VMX OR HAVE_POWER8_INTRIN OR HAVE_POWER9_INTRIN) + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/power_functions.h) + if(WITH_RUNTIME_CPU_DETECTION) + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/power_features.h) + list(APPEND ZLIB_ARCH_SRCS ${ARCHDIR}/power_features.c) + endif() + endif() + # VMX specific options and files + if(WITH_ALTIVEC) + if(HAVE_VMX) + add_definitions(-DPPC_FEATURES) + if(HAVE_ALTIVEC) + add_definitions(-DPPC_VMX) + set(PPC_SRCS ${ARCHDIR}/adler32_vmx.c ${ARCHDIR}/slide_hash_vmx.c) + list(APPEND ZLIB_ARCH_SRCS ${PPC_SRCS}) + add_feature_info(ALTIVEC 1 "Support the AltiVec instruction set, using \"-maltivec\"") + set_property(SOURCE ${PPC_SRCS} PROPERTY COMPILE_FLAGS "${PPCFLAGS}") + else() + set(WITH_ALTIVEC OFF) + endif() + endif() + endif() + # Power8 specific options and files + if(WITH_POWER8) + if(HAVE_POWER8_INTRIN) + add_definitions(-DPOWER8_VSX) + set(POWER8_SRCS ${ARCHDIR}/adler32_power8.c ${ARCHDIR}/chunkset_power8.c ${ARCHDIR}/slide_hash_power8.c) + if("${ARCH}" MATCHES "powerpc64(le)?") + add_definitions(-DPOWER8_VSX_CRC32) + list(APPEND POWER8_SRCS ${ARCHDIR}/crc32_power8.c) + endif() + list(APPEND ZLIB_ARCH_SRCS ${POWER8_SRCS}) + set_property(SOURCE ${POWER8_SRCS} PROPERTY COMPILE_FLAGS "${POWER8FLAG} ${NOLTOFLAG}") + else() + set(WITH_POWER8 OFF) + endif() + endif() + # Power9 specific options and files + if(WITH_POWER9) + if(HAVE_POWER9_INTRIN) + add_definitions(-DPOWER9) + set(POWER9_SRCS ${ARCHDIR}/compare256_power9.c) + list(APPEND ZLIB_ARCH_SRCS ${POWER9_SRCS}) + set_property(SOURCE ${POWER9_SRCS} PROPERTY COMPILE_FLAGS "${POWER9FLAG} ${NOLTOFLAG}") + else() + set(WITH_POWER9 OFF) + endif() + endif() + elseif(BASEARCH_RISCV_FOUND) + if(WITH_RVV) + check_rvv_intrinsics() + if(HAVE_RVV_INTRIN) + add_definitions(-DRISCV_FEATURES) + add_definitions(-DRISCV_RVV) + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/riscv_functions.h) + if(WITH_RUNTIME_CPU_DETECTION) + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/riscv_features.h) + list(APPEND ZLIB_ARCH_SRCS ${ARCHDIR}/riscv_features.c) + endif() + # FIXME: we will not set compile flags for riscv_features.c when + # the kernels update hwcap or hwprobe for riscv + set(RVV_SRCS ${ARCHDIR}/adler32_rvv.c ${ARCHDIR}/chunkset_rvv.c ${ARCHDIR}/compare256_rvv.c ${ARCHDIR}/slide_hash_rvv.c) + if(WITH_RUNTIME_CPU_DETECTION) + list(APPEND RVV_SRCS ${ARCHDIR}/riscv_features.c) + endif() + list(APPEND ZLIB_ARCH_SRCS ${RVV_SRCS}) + set_property(SOURCE ${RVV_SRCS} PROPERTY COMPILE_FLAGS "${RISCVFLAG} ${NOLTOFLAG}") + else() + set(WITH_RVV OFF) + endif() + endif() + elseif(BASEARCH_S360_FOUND) + check_s390_intrinsics() + if(HAVE_S390_INTRIN) + add_definitions(-DS390_FEATURES) + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/s390_functions.h) + if(WITH_RUNTIME_CPU_DETECTION) + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/s390_features.h) + list(APPEND ZLIB_ARCH_SRCS ${ARCHDIR}/s390_features.c) + endif() + endif() + if(WITH_DFLTCC_DEFLATE) + add_definitions(-DS390_DFLTCC_DEFLATE) + list(APPEND ZLIB_ARCH_SRCS ${ARCHDIR}/dfltcc_deflate.c) + endif() + if(WITH_DFLTCC_INFLATE) + add_definitions(-DS390_DFLTCC_INFLATE) + list(APPEND ZLIB_ARCH_SRCS ${ARCHDIR}/dfltcc_inflate.c) + endif() + if(WITH_CRC32_VX) + check_vgfma_intrinsics() + if(HAVE_VGFMA_INTRIN) + add_definitions(-DS390_CRC32_VX) + set(CRC32_VX_SRCS ${ARCHDIR}/crc32-vx.c) + list(APPEND ZLIB_ARCH_SRCS ${CRC32_VX_SRCS}) + set_property(SOURCE ${CRC32_VX_SRCS} PROPERTY COMPILE_FLAGS "${VGFMAFLAG} ${NOLTOFLAG}") + else() + set(WITH_CRC32_VX OFF) + endif() + endif() + elseif(BASEARCH_X86_FOUND) + add_definitions(-DX86_FEATURES) + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/x86_functions.h) + if(WITH_RUNTIME_CPU_DETECTION) + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/x86_features.h) + list(APPEND ZLIB_ARCH_SRCS ${ARCHDIR}/x86_features.c) + endif() + if(MSVC) + list(APPEND ZLIB_ARCH_HDRS fallback_builtins.h) + endif() + check_xsave_intrinsics() + if(HAVE_XSAVE_INTRIN) + add_feature_info(XSAVE 1 "Support XSAVE intrinsics using \"${XSAVEFLAG}\"") + if(WITH_RUNTIME_CPU_DETECTION) + set_property(SOURCE ${ARCHDIR}/x86_features.c PROPERTY COMPILE_FLAGS "${XSAVEFLAG}") + endif() + if(NOT (CMAKE_C_COMPILER_ID MATCHES "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 8.2)) + add_definitions(-DX86_HAVE_XSAVE_INTRIN) + endif() + endif() + if(WITH_SSE2) + check_sse2_intrinsics() + if(HAVE_SSE2_INTRIN) + add_definitions(-DX86_SSE2) + set(SSE2_SRCS ${ARCHDIR}/chunkset_sse2.c ${ARCHDIR}/compare256_sse2.c ${ARCHDIR}/slide_hash_sse2.c) + list(APPEND ZLIB_ARCH_SRCS ${SSE2_SRCS}) + if(NOT ${ARCH} MATCHES "x86_64") + set_property(SOURCE ${SSE2_SRCS} PROPERTY COMPILE_FLAGS "${SSE2FLAG} ${NOLTOFLAG}") + add_feature_info(FORCE_SSE2 FORCE_SSE2 "Assume CPU is SSE2 capable") + if(FORCE_SSE2) + add_definitions(-DX86_NOCHECK_SSE2) + endif() + endif() + else() + set(WITH_SSE2 OFF) + endif() + endif() + if(WITH_SSSE3) + check_ssse3_intrinsics() + if(HAVE_SSSE3_INTRIN AND WITH_SSE2) + add_definitions(-DX86_SSSE3) + set(SSSE3_SRCS ${ARCHDIR}/adler32_ssse3.c ${ARCHDIR}/chunkset_ssse3.c) + add_feature_info(SSSE3_ADLER32 1 "Support SSSE3-accelerated adler32, using \"${SSSE3FLAG}\"") + list(APPEND ZLIB_ARCH_SRCS ${SSSE3_SRCS}) + set_property(SOURCE ${SSSE3_SRCS} PROPERTY COMPILE_FLAGS "${SSSE3FLAG} ${NOLTOFLAG}") + else() + set(WITH_SSSE3 OFF) + endif() + endif() + if(WITH_SSE42) + check_sse42_intrinsics() + if(HAVE_SSE42_INTRIN AND WITH_SSSE3) + add_definitions(-DX86_SSE42) + set(SSE42_SRCS ${ARCHDIR}/adler32_sse42.c) + add_feature_info(SSE42_CRC 1 "Support SSE4.2 optimized adler32 hash generation, using \"${SSE42FLAG}\"") + list(APPEND ZLIB_ARCH_SRCS ${SSE42_SRCS}) + set_property(SOURCE ${SSE42_SRCS} PROPERTY COMPILE_FLAGS "${SSE42FLAG} ${NOLTOFLAG}") + else() + set(WITH_SSE42 OFF) + endif() + endif() + if(WITH_PCLMULQDQ) + check_pclmulqdq_intrinsics() + if(HAVE_PCLMULQDQ_INTRIN AND WITH_SSE42) + add_definitions(-DX86_PCLMULQDQ_CRC) + set(PCLMULQDQ_SRCS ${ARCHDIR}/crc32_pclmulqdq.c) + add_feature_info(PCLMUL_CRC 1 "Support CRC hash generation using PCLMULQDQ, using \"${SSE42FLAG} ${PCLMULFLAG}\"") + list(APPEND ZLIB_ARCH_SRCS ${PCLMULQDQ_SRCS}) + set_property(SOURCE ${PCLMULQDQ_SRCS} PROPERTY COMPILE_FLAGS "${SSE42FLAG} ${PCLMULFLAG} ${NOLTOFLAG}") + else() + set(WITH_PCLMULQDQ OFF) + endif() + endif() + if(WITH_AVX2) + check_avx2_intrinsics() + if(HAVE_AVX2_INTRIN AND WITH_SSE42) + add_definitions(-DX86_AVX2) + set(AVX2_SRCS ${ARCHDIR}/slide_hash_avx2.c) + add_feature_info(AVX2_SLIDEHASH 1 "Support AVX2 optimized slide_hash, using \"${AVX2FLAG}\"") + list(APPEND AVX2_SRCS ${ARCHDIR}/chunkset_avx2.c) + add_feature_info(AVX2_CHUNKSET 1 "Support AVX2 optimized chunkset, using \"${AVX2FLAG}\"") + list(APPEND AVX2_SRCS ${ARCHDIR}/compare256_avx2.c) + add_feature_info(AVX2_COMPARE256 1 "Support AVX2 optimized compare256, using \"${AVX2FLAG}\"") + list(APPEND AVX2_SRCS ${ARCHDIR}/adler32_avx2.c) + add_feature_info(AVX2_ADLER32 1 "Support AVX2-accelerated adler32, using \"${AVX2FLAG}\"") + list(APPEND ZLIB_ARCH_SRCS ${AVX2_SRCS}) + set_property(SOURCE ${AVX2_SRCS} PROPERTY COMPILE_FLAGS "${AVX2FLAG} ${NOLTOFLAG}") + else() + set(WITH_AVX2 OFF) + endif() + endif() + if(WITH_AVX512) + check_avx512_intrinsics() + if(HAVE_AVX512_INTRIN AND WITH_AVX2) + add_definitions(-DX86_AVX512) + list(APPEND AVX512_SRCS ${ARCHDIR}/adler32_avx512.c) + add_feature_info(AVX512_ADLER32 1 "Support AVX512-accelerated adler32, using \"${AVX512FLAG}\"") + list(APPEND AVX512_SRCS ${ARCHDIR}/chunkset_avx512.c) + add_feature_info(AVX512_CHUNKSET 1 "Support AVX512 optimized chunkset, using \"${AVX512FLAG}\"") + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/adler32_avx512_p.h) + list(APPEND ZLIB_ARCH_SRCS ${AVX512_SRCS}) + set_property(SOURCE ${AVX512_SRCS} PROPERTY COMPILE_FLAGS "${AVX512FLAG} ${NOLTOFLAG}") + else() + set(WITH_AVX512 OFF) + endif() + endif() + if(WITH_AVX512VNNI) + check_avx512vnni_intrinsics() + if(HAVE_AVX512VNNI_INTRIN AND WITH_AVX2) + add_definitions(-DX86_AVX512VNNI) + add_feature_info(AVX512VNNI_ADLER32 1 "Support AVX512VNNI adler32, using \"${AVX512VNNIFLAG}\"") + list(APPEND AVX512VNNI_SRCS ${ARCHDIR}/adler32_avx512_vnni.c) + list(APPEND ZLIB_ARCH_SRCS ${AVX512VNNI_SRCS}) + set_property(SOURCE ${AVX512VNNI_SRCS} PROPERTY COMPILE_FLAGS "${AVX512VNNIFLAG} ${NOLTOFLAG}") + else() + set(WITH_AVX512VNNI OFF) + endif() + endif() + if(WITH_VPCLMULQDQ) + check_vpclmulqdq_intrinsics() + if(HAVE_VPCLMULQDQ_INTRIN AND WITH_PCLMULQDQ AND WITH_AVX512) + add_definitions(-DX86_VPCLMULQDQ_CRC) + set(VPCLMULQDQ_SRCS ${ARCHDIR}/crc32_vpclmulqdq.c) + add_feature_info(VPCLMUL_CRC 1 "Support CRC hash generation using VPCLMULQDQ, using \"${PCLMULFLAG} ${VPCLMULFLAG} ${AVX512FLAG}\"") + list(APPEND ZLIB_ARCH_SRCS ${VPCLMULQDQ_SRCS}) + set_property(SOURCE ${VPCLMULQDQ_SRCS} PROPERTY COMPILE_FLAGS "${PCLMULFLAG} ${VPCLMULFLAG} ${AVX512FLAG} ${NOLTOFLAG}") + else() + set(WITH_VPCLMULQDQ OFF) + endif() + endif() + endif() +endif() + +message(STATUS "Architecture-specific source files: ${ZLIB_ARCH_SRCS}") + +#============================================================================ +# zconf.h +#============================================================================ + +macro(generate_cmakein input output) + file(REMOVE ${output}) + file(STRINGS ${input} _lines) + foreach(_line IN LISTS _lines) + string(REGEX REPLACE "#ifdef HAVE_UNISTD_H.*" "@ZCONF_UNISTD_LINE@" _line "${_line}") + string(REGEX REPLACE "#ifdef NEED_PTRDIFF_T.*" "@ZCONF_PTRDIFF_LINE@" _line "${_line}") + if(NEED_PTRDIFF_T) + string(REGEX REPLACE "typedef PTRDIFF_TYPE" "typedef @PTRDIFF_TYPE@" _line "${_line}") + endif() + file(APPEND ${output} "${_line}\n") + endforeach() +endmacro(generate_cmakein) + +generate_cmakein( ${CMAKE_CURRENT_SOURCE_DIR}/zconf${SUFFIX}.h.in ${CMAKE_CURRENT_BINARY_DIR}/zconf${SUFFIX}.h.cmakein ) + +if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) + # If we're doing an out of source build and the user has a zconf.h + # in their source tree... + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf${SUFFIX}.h) + message(STATUS "Renaming") + message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/zconf${SUFFIX}.h") + message(STATUS "to 'zconf${SUFFIX}.h.included' because this file is included with zlib") + message(STATUS "but CMake generates it automatically in the build directory.") + file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/zconf${SUFFIX}.h ${CMAKE_CURRENT_SOURCE_DIR}/zconf${SUFFIX}.h.included) + endif() + + # If we're doing an out of source build and the user has a zconf.h.cmakein + # in their source tree... + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf${SUFFIX}.h.cmakein) + message(STATUS "Renaming") + message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/zconf${SUFFIX}.h.cmakein") + message(STATUS "to 'zconf${SUFFIX}.h.cmakeincluded' because this file is included with zlib") + message(STATUS "but CMake generates it automatically in the build directory.") + file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/zconf${SUFFIX}.h.cmakein ${CMAKE_CURRENT_SOURCE_DIR}/zconf${SUFFIX}.h.cmakeincluded) + endif() +endif() + +# The user is allowed (but discouraged) to set absolute CMAKE_INSTALL_*DIR paths. +# If they do, we copy these non-relocatable paths into the pkg-config file. +if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") + set(PC_INC_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") +else() + set(PC_INC_INSTALL_DIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") +endif() + +if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") + set(PC_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") +else() + set(PC_LIB_INSTALL_DIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") +endif() + +#============================================================================ +# zlib +#============================================================================ + +set(ZLIB_PUBLIC_HDRS + ${CMAKE_CURRENT_BINARY_DIR}/zconf${SUFFIX}.h + ${CMAKE_CURRENT_BINARY_DIR}/zlib_name_mangling${SUFFIX}.h + ${CMAKE_CURRENT_BINARY_DIR}/zlib${SUFFIX}.h +) +set(ZLIB_PRIVATE_HDRS + arch/generic/chunk_permute_table.h + arch/generic/compare256_p.h + arch/generic/generic_functions.h + adler32_p.h + chunkset_tpl.h + compare256_rle.h + arch_functions.h + crc32_braid_p.h + crc32_braid_comb_p.h + crc32_braid_tbl.h + deflate.h + deflate_p.h + functable.h + inffast_tpl.h + inffixed_tbl.h + inflate.h + inflate_p.h + inftrees.h + insert_string_tpl.h + match_tpl.h + trees.h + trees_emit.h + trees_tbl.h + zbuild.h + zendian.h + zutil.h +) +set(ZLIB_SRCS + arch/generic/adler32_c.c + arch/generic/adler32_fold_c.c + arch/generic/chunkset_c.c + arch/generic/compare256_c.c + arch/generic/crc32_braid_c.c + arch/generic/crc32_fold_c.c + arch/generic/slide_hash_c.c + adler32.c + compress.c + crc32.c + crc32_braid_comb.c + deflate.c + deflate_fast.c + deflate_huff.c + deflate_medium.c + deflate_quick.c + deflate_rle.c + deflate_slow.c + deflate_stored.c + functable.c + infback.c + inflate.c + inftrees.c + insert_string.c + insert_string_roll.c + trees.c + uncompr.c + zutil.c +) + +if(WITH_RUNTIME_CPU_DETECTION) + list(APPEND ZLIB_PRIVATE_HDRS cpu_features.h) + list(APPEND ZLIB_SRCS cpu_features.c) +endif() + +set(ZLIB_GZFILE_PRIVATE_HDRS + gzguts.h +) +set(ZLIB_GZFILE_SRCS + gzlib.c + ${CMAKE_CURRENT_BINARY_DIR}/gzread.c + gzwrite.c +) + +set(ZLIB_ALL_SRCS ${ZLIB_SRCS} ${ZLIB_ARCH_HDRS} ${ZLIB_ARCH_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +if(WITH_GZFILEOP) + list(APPEND ZLIB_ALL_SRCS ${ZLIB_GZFILE_PRIVATE_HDRS} ${ZLIB_GZFILE_SRCS}) +endif() + +if(NOT DEFINED BUILD_SHARED_LIBS OR BUILD_SHARED_LIBS) + set(ZLIB_DLL_SRCS win32/zlib${SUFFIX}1.rc) +endif() + +if(NOT DEFINED BUILD_SHARED_LIBS) + add_library(zlib SHARED ${ZLIB_ALL_SRCS} ${ZLIB_DLL_SRCS}) + add_library(zlibstatic STATIC ${ZLIB_ALL_SRCS}) + + set(ZLIB_INSTALL_LIBRARIES zlib zlibstatic) +else() + add_library(zlib ${ZLIB_ALL_SRCS}) + + if(BUILD_SHARED_LIBS) + target_sources(zlib PRIVATE ${ZLIB_DLL_SRCS}) + else() + add_library(zlibstatic ALIAS zlib) + endif() + + set(ZLIB_INSTALL_LIBRARIES zlib) +endif() + +# INFO: Mimics official zlib CMake target +# Generates ZLIB.cmake in case ZLIB_COMPAT=ON and always exports the CMake target ZLIB::ZLIB +# In case ZLIB_COMPAT=OFF, the CMake target and file follows zlib-ng naming convention +if (ZLIB_COMPAT) + if (TARGET zlib) + set_target_properties(zlib PROPERTIES EXPORT_NAME ZLIB) + else() + set_target_properties(zlibstatic PROPERTIES EXPORT_NAME ZLIB) + endif() +endif() + +foreach(ZLIB_INSTALL_LIBRARY ${ZLIB_INSTALL_LIBRARIES}) + if(NOT ZLIB_COMPAT) + target_compile_definitions(${ZLIB_INSTALL_LIBRARY} PUBLIC ZLIBNG_NATIVE_API) + endif() + target_include_directories(${ZLIB_INSTALL_LIBRARY} PUBLIC + "$${CMAKE_CURRENT_SOURCE_DIR}>" + "$") +endforeach() + +if(WIN32) + # Shared library + if(NOT DEFINED BUILD_SHARED_LIBS OR BUILD_SHARED_LIBS) + set_target_properties(zlib PROPERTIES OUTPUT_NAME zlib${SUFFIX}) + endif() + # Static library + if(NOT DEFINED BUILD_SHARED_LIBS) + if(MSVC) + set_target_properties(zlibstatic PROPERTIES OUTPUT_NAME zlibstatic${SUFFIX}) + else() + set_target_properties(zlibstatic PROPERTIES OUTPUT_NAME z${SUFFIX}) + endif() + elseif(NOT BUILD_SHARED_LIBS) + if(MSVC) + set_target_properties(zlib PROPERTIES OUTPUT_NAME zlibstatic${SUFFIX}) + else() + set_target_properties(zlib PROPERTIES OUTPUT_NAME z${SUFFIX}) + endif() + endif() +else() + # On unix-like platforms the library is almost always called libz + set_target_properties(${ZLIB_INSTALL_LIBRARIES} PROPERTIES OUTPUT_NAME z${SUFFIX}) +endif() + +if(NOT DEFINED BUILD_SHARED_LIBS OR BUILD_SHARED_LIBS) + set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) + + if(ZLIB_COMPAT) + set_target_properties(zlib PROPERTIES SOVERSION 1) + else() + set_target_properties(zlib PROPERTIES SOVERSION 2) + endif() + + if(NOT CYGWIN) + # This property causes shared libraries on Linux to have the full version + # encoded into their final filename. We disable this on Cygwin because + # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll + # seems to be the default. + # + # This has no effect with MSVC, on that platform the version info for + # the DLL comes from the resource file win32/zlib1.rc + set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) + endif() + + if(UNIX) + if(HAVE_NO_INTERPOSITION) + set_target_properties(zlib PROPERTIES COMPILE_FLAGS "-fno-semantic-interposition") + endif() + if(NOT APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL AIX) + if(NOT ZLIB_COMPAT) + add_definitions(-DHAVE_SYMVER) + endif() + set_target_properties(zlib PROPERTIES LINK_FLAGS + "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib${SUFFIX}.map\"") + endif() + endif() + if(MSYS) + # Suppress version number from shared library name + set(CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION 0) + elseif(WIN32) + # Creates zlib1.dll when building shared library version + if(ZLIB_COMPAT) + set_target_properties(zlib PROPERTIES SUFFIX "1.dll") + else() + set_target_properties(zlib PROPERTIES SUFFIX "2.dll") + endif() + endif() +endif() + +if(HAVE_UNISTD_H) + SET(ZCONF_UNISTD_LINE "#if 1 /* was set to #if 1 by configure/cmake/etc */") +else() + SET(ZCONF_UNISTD_LINE "#if 0 /* was set to #if 0 by configure/cmake/etc */") +endif() +if(NEED_PTRDIFF_T) + SET(ZCONF_PTRDIFF_LINE "#if 1 /* was set to #if 1 by configure/cmake/etc */") +else() + SET(ZCONF_PTRDIFF_LINE "#ifdef NEED_PTRDIFF_T /* may be set to #if 1 by configure/cmake/etc */") +endif() + +set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib${SUFFIX}.pc) +if(WITH_GZFILEOP) + set(PKG_CONFIG_CFLAGS "-DWITH_GZFILEOP") +endif() +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein + ${ZLIB_PC} @ONLY) +configure_file(${CMAKE_CURRENT_BINARY_DIR}/zconf${SUFFIX}.h.cmakein + ${CMAKE_CURRENT_BINARY_DIR}/zconf${SUFFIX}.h @ONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zlib${SUFFIX}.h.in + ${CMAKE_CURRENT_BINARY_DIR}/zlib${SUFFIX}.h @ONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gzread.c.in + ${CMAKE_CURRENT_BINARY_DIR}/gzread.c @ONLY) + +if (NOT ZLIB_SYMBOL_PREFIX STREQUAL "") + add_feature_info(ZLIB_SYMBOL_PREFIX ON "Publicly exported symbols have a custom prefix") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zlib_name_mangling${SUFFIX}.h.in + ${CMAKE_CURRENT_BINARY_DIR}/zlib_name_mangling${SUFFIX}.h @ONLY) +else() + add_feature_info(ZLIB_SYMBOL_PREFIX OFF "Publicly exported symbols DO NOT have a custom prefix") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zlib_name_mangling.h.empty + ${CMAKE_CURRENT_BINARY_DIR}/zlib_name_mangling${SUFFIX}.h COPYONLY) +endif() +# add_definitions(-DZLIB_SYMBOL_PREFIX=${ZLIB_SYMBOL_PREFIX}) # not needed + + +if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) + install(TARGETS ${ZLIB_INSTALL_LIBRARIES} + EXPORT ${EXPORT_NAME} + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") +endif() +if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/zlib${SUFFIX}.h + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" RENAME zlib${SUFFIX}.h) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/zlib_name_mangling${SUFFIX}.h + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" RENAME zlib_name_mangling${SUFFIX}.h) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/zconf${SUFFIX}.h + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" RENAME zconf${SUFFIX}.h) +endif() +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL) + install(FILES ${ZLIB_PC} DESTINATION "${PKGCONFIG_INSTALL_DIR}") + install(EXPORT ${EXPORT_NAME} + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${EXPORT_NAME}" + NAMESPACE ${EXPORT_NAME}::) + # Use GNU-style variable names + set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) + set(LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}) + if (ZLIB_COMPAT) + set(PACKAGE_CONFIGNAME zlib) + set(PACKAGE_VERSION ${ZLIB_HEADER_VERSION}) + else() + set(PACKAGE_CONFIGNAME zlib-ng) + set(PACKAGE_VERSION ${ZLIBNG_HEADER_VERSION}) + endif() + configure_package_config_file(${PACKAGE_CONFIGNAME}-config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_CONFIGNAME}-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${EXPORT_NAME} + PATH_VARS INCLUDE_INSTALL_DIR LIB_INSTALL_DIR) + write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_CONFIGNAME}-config-version.cmake + VERSION ${PACKAGE_VERSION} + COMPATIBILITY AnyNewerVersion) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_CONFIGNAME}-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_CONFIGNAME}-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${EXPORT_NAME}) +endif() + +#============================================================================ +# Example binaries +#============================================================================ + +if(ZLIB_ENABLE_TESTS) + enable_testing() + + if(BUILD_SHARED_LIBS) + if(ZLIBNG_ENABLE_TESTS) + message(STATUS "Disabling zlib-ng tests because shared libraries are enabled") + set(ZLIBNG_ENABLE_TESTS OFF) + endif() + + if(WITH_BENCHMARKS OR WITH_BENCHMARK_APPS) + message(STATUS "Disabling benchmarks because shared libraries are enabled") + set(WITH_BENCHMARKS OFF) + set(WITH_BENCHMARK_APPS OFF) + endif() + endif() + + add_subdirectory(test) +endif() + +add_feature_info(WITH_GZFILEOP WITH_GZFILEOP "Compile with support for gzFile related functions") +add_feature_info(ZLIB_COMPAT ZLIB_COMPAT "Compile with zlib compatible API") +add_feature_info(ZLIB_ENABLE_TESTS ZLIB_ENABLE_TESTS "Build test binaries") +add_feature_info(ZLIBNG_ENABLE_TESTS ZLIBNG_ENABLE_TESTS "Test zlib-ng specific API") +add_feature_info(WITH_SANITIZER WITH_SANITIZER "Enable sanitizer support") +add_feature_info(WITH_GTEST WITH_GTEST "Build gtest_zlib") +add_feature_info(WITH_FUZZERS WITH_FUZZERS "Build test/fuzz") +add_feature_info(WITH_BENCHMARKS WITH_BENCHMARKS "Build test/benchmarks") +add_feature_info(WITH_BENCHMARK_APPS WITH_BENCHMARK_APPS "Build application benchmarks") +add_feature_info(WITH_OPTIM WITH_OPTIM "Build with optimisation") +add_feature_info(WITH_NEW_STRATEGIES WITH_NEW_STRATEGIES "Use new strategies") +add_feature_info(WITH_NATIVE_INSTRUCTIONS WITH_NATIVE_INSTRUCTIONS + "Instruct the compiler to use the full instruction set on this host (gcc/clang -march=native)") +add_feature_info(WITH_RUNTIME_CPU_DETECTION WITH_RUNTIME_CPU_DETECTION "Build with runtime CPU detection") +add_feature_info(WITH_MAINTAINER_WARNINGS WITH_MAINTAINER_WARNINGS "Build with project maintainer warnings") +add_feature_info(WITH_CODE_COVERAGE WITH_CODE_COVERAGE "Enable code coverage reporting") +add_feature_info(WITH_INFLATE_STRICT WITH_INFLATE_STRICT "Build with strict inflate distance checking") +add_feature_info(WITH_INFLATE_ALLOW_INVALID_DIST WITH_INFLATE_ALLOW_INVALID_DIST "Build with zero fill for inflate invalid distances") + +if(BASEARCH_ARM_FOUND) + add_feature_info(WITH_ACLE WITH_ACLE "Build with ACLE") + add_feature_info(WITH_NEON WITH_NEON "Build with NEON intrinsics") + add_feature_info(WITH_ARMV6 WITH_ARMV6 "Build with ARMv6 SIMD") +elseif(BASEARCH_PPC_FOUND) + add_feature_info(WITH_ALTIVEC WITH_ALTIVEC "Build with AltiVec optimisations") + add_feature_info(WITH_POWER8 WITH_POWER8 "Build with optimisations for POWER8") + add_feature_info(WITH_POWER9 WITH_POWER9 "Build with optimisations for POWER9") +elseif(BASEARCH_RISCV_FOUND) + add_feature_info(WITH_RVV WITH_RVV "Build with RVV intrinsics") +elseif(BASEARCH_S360_FOUND) + add_feature_info(WITH_DFLTCC_DEFLATE WITH_DFLTCC_DEFLATE "Build with DFLTCC intrinsics for compression on IBM Z") + add_feature_info(WITH_DFLTCC_INFLATE WITH_DFLTCC_INFLATE "Build with DFLTCC intrinsics for decompression on IBM Z") + add_feature_info(WITH_CRC32_VX WITH_CRC32_VX "Build with vectorized CRC32 on IBM Z") +elseif(BASEARCH_X86_FOUND) + add_feature_info(WITH_AVX2 WITH_AVX2 "Build with AVX2") + add_feature_info(WITH_AVX512 WITH_AVX512 "Build with AVX512") + add_feature_info(WITH_AVX512VNNI WITH_AVX512VNNI "Build with AVX512 VNNI") + add_feature_info(WITH_SSE2 WITH_SSE2 "Build with SSE2") + add_feature_info(WITH_SSSE3 WITH_SSSE3 "Build with SSSE3") + add_feature_info(WITH_SSE42 WITH_SSE42 "Build with SSE42") + add_feature_info(WITH_PCLMULQDQ WITH_PCLMULQDQ "Build with PCLMULQDQ") + add_feature_info(WITH_VPCLMULQDQ WITH_VPCLMULQDQ "Build with VPCLMULQDQ") +endif() + +add_feature_info(INSTALL_UTILS INSTALL_UTILS "Copy minigzip and minideflate during install") + +FEATURE_SUMMARY(WHAT ALL INCLUDE_QUIET_PACKAGES) + +#============================================================================ +# CPack +#============================================================================ +set(CPACK_GENERATOR "TGZ") +set(CPACK_SOURCE_GENERATOR "TGZ") +set(CPACK_SOURCE_IGNORE_FILES .git/ _CPack_Packages/ "${PROJECT_BINARY_DIR}/") + +set(CPACK_PACKAGE_NAME "zlib${SUFFIX}") +set(CPACK_PACKAGE_VERSION ${ZLIB_FULL_VERSION}) +set(CPACK_PACKAGE_DIRECTORY "${PROJECT_BINARY_DIR}/package") + +if("${PROJECT_BINARY_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}") + message(WARNING "Building to source folder is not recommended. Cpack will be unable to generate source package.") +endif() + +include(CPack) diff --git a/FAQ.zlib b/FAQ.zlib new file mode 100644 index 0000000000..698a4f83f0 --- /dev/null +++ b/FAQ.zlib @@ -0,0 +1,373 @@ +## +# THIS IS AN UNMAINTAINED COPY OF THE ORIGINAL FILE DISTRIBUTED WITH ZLIB 1.2.11 +## + + + + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +https://zlib.net/ which may have more recent information. +The latest zlib FAQ is at https://zlib.net/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. See the + file win32/DLL_FAQ.txt in the zlib distribution. + + 3. Where can I get a Visual Basic interface to zlib? + + See + * https://marknelson.us/1997/01/01/zlib-engine/ + * win32/DLL_FAQ.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR. + + Make sure that before the call of compress(), the length of the compressed + buffer is equal to the available size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR. + + Before making the call, make sure that avail_in and avail_out are not zero. + When setting the parameter flush equal to Z_FINISH, also make sure that + avail_out is big enough to allow processing all pending input. Note that a + Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be + made with more input or output space. A Z_BUF_ERROR may in fact be + unavoidable depending on how the functions are used, since it is not + possible to tell whether or not there is more output pending when + strm.avail_out returns with zero. See https://zlib.net/zlib_how.html for a + heavily annotated example. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h . Examples of zlib usage are in the files test/example.c + and test/minigzip.c, with more in examples/ . + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple package. + zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of zlib. + Please try to reproduce the problem with a small program and send the + corresponding source to us at zlib@gzip.org . Do not send multi-megabyte + data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + Not by itself, no. See the directory contrib/minizip in the zlib + distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + By default a shared (and a static) library is built for Unix. So: + + make distclean + ./configure + make + +14. How do I install a shared zlib library on Unix? + + After the above, then: + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include , it's there. The -lz option will probably link to + it. You can check the version at the top of zlib.h or with the + ZLIB_VERSION symbol defined in zlib.h . + +15. I have a question about OttoPDF. + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site: Joel Hainley, jhainley@myndkryme.com. + +16. Can zlib decode Flate data in an Adobe PDF file? + + Yes. See https://www.pdflib.com/ . To modify PDF forms, see + https://sourceforge.net/projects/acroformtool/ . + +17. Why am I getting this "register_frame_info not found" error on Solaris? + + After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib + generates an error such as: + + ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so: + symbol __register_frame_info: referenced symbol not found + + The symbol __register_frame_info is not part of zlib, it is generated by + the C compiler (cc or gcc). You must recompile applications using zlib + which have this problem. This problem is specific to Solaris. See + http://www.sunfreeware.com/ for Solaris versions of zlib and applications + using zlib. + +18. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip formats + use the same compressed data format internally, but have different headers + and trailers around the compressed data. + +19. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about a + single file, such as the name and last modification date. The zlib format + on the other hand was designed for in-memory and communication channel + applications, and has a much more compact header and trailer and uses a + faster integrity check than gzip. + +20. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode the + gzip format using inflateInit2(). Read zlib.h for more details. + +21. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's *Init* functions + allow for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +22. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +23. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +24. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +25. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +26. Will zlib work on a 64-bit machine? + + Yes. It has been tested on 64-bit machines, and has no dependence on any + data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +27. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format than + does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +28. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically use + Z_FULL_FLUSH, carefully write all the pending data at those points, and + keep an index of those locations, then you can start decompression at those + points. You have to be careful to not use Z_FULL_FLUSH too often, since it + can significantly degrade compression. Alternatively, you can scan a + deflate stream once to generate an index, and then use that index for + random access. See examples/zran.c . + +29. Does zlib work on MVS, OS/390, CICS, etc.? + + It has in the past, but we have not heard of any recent evidence. There + were working ports of zlib 1.1.4 to MVS, but those links no longer work. + If you know of recent, successful applications of zlib on these operating + systems, please let us know. Thanks. + +30. Is there some simpler, easier to read version of inflate I can look at to + understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +31. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + https://www.gzip.org/#faq11 + +32. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit only + if the compiler's "long" type is 32 bits. If the compiler's "long" type is + 64 bits, then the limit is 16 exabytes. + +33. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib is + compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of an 8K string space (or other value as set by + gzbuffer()), other than the caller of gzprintf() assuring that the output + will not exceed 8K. On the other hand, if zlib is compiled to use + snprintf() or vsnprintf(), which should normally be the case, then there is + no vulnerability. The ./configure script will display warnings if an + insecure variation of sprintf() will be used by gzprintf(). Also the + zlibCompileFlags() function will return information on what variant of + sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + https://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability, and versions + 1.2.1 and 1.2.2 were subject to an access exception when decompressing + invalid compressed data. + +34. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: https://zlib.net/ . + +35. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pedantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly as well as contradicted each other. So now, we simply + make sure that the code always works. + +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of deflate + is not affected. This only started showing up recently since zlib 1.2.x + uses malloc() by default for allocations, whereas earlier versions used + calloc(), which zeros out the allocated memory. Even though the code was + correct, versions 1.2.4 and later was changed to not stimulate these + checkers. + +37. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +38. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very + weak and can be broken with freely available programs. To get strong + encryption, use GnuPG, https://www.gnupg.org/ , which already includes zlib + compression. For PKZIP compatible "encryption", look at + http://infozip.sourceforge.net/ + +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion with + the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specification in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +40. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. In + any case, the compression improvements are so modest compared to other more + modern approaches, that it's not worth the effort to implement. + +41. I'm having a problem with the zip functions in zlib, can you help? + + There are no zip functions in zlib. You are probably using minizip by + Giles Vollant, which is found in the contrib directory of zlib. It is not + part of zlib. In fact none of the stuff in contrib is part of zlib. The + files in there are not supported by the zlib authors. You need to contact + the authors of the respective contribution for help. + +42. The match.asm code in contrib is under the GNU General Public License. + Since it's part of zlib, doesn't that mean that all of zlib falls under the + GNU GPL? + + No. The files in contrib are not part of zlib. They were contributed by + other authors and are provided as a convenience to the user within the zlib + distribution. Each item in contrib has its own license. + +43. Is zlib subject to export controls? What is its ECCN? + + zlib is not subject to export controls, and so is classified as EAR99. + +44. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/INDEX.md b/INDEX.md new file mode 100644 index 0000000000..22fd470e63 --- /dev/null +++ b/INDEX.md @@ -0,0 +1,36 @@ +Contents +-------- + +| Name | Description | +|:-----------------|:---------------------------------------------------------------| +| arch/ | Architecture-specific code | +| doc/ | Documentation for formats and algorithms | +| test/example.c | Zlib usages examples for build testing | +| test/minigzip.c | Minimal gzip-like functionality for build testing | +| test/infcover.c | Inflate code coverage for build testing | +| win32/ | Shared library version resources for Windows | +| CMakeLists.txt | Cmake build script | +| configure | Bash configure/build script | +| adler32.c | Compute the Adler-32 checksum of a data stream | +| chunkset.* | Inline functions to copy small data chunks | +| compress.c | Compress a memory buffer | +| deflate.* | Compress data using the deflate algorithm | +| deflate_fast.c | Compress data using the deflate algorithm with fast strategy | +| deflate_medium.c | Compress data using the deflate algorithm with medium strategy | +| deflate_slow.c | Compress data using the deflate algorithm with slow strategy | +| functable.* | Struct containing function pointers to optimized functions | +| gzguts.h | Internal definitions for gzip operations | +| gzlib.c | Functions common to reading and writing gzip files | +| gzread.c | Read gzip files | +| gzwrite.c | Write gzip files | +| infback.* | Inflate using a callback interface | +| inflate.* | Decompress data | +| inffast.* | Decompress data with speed optimizations | +| inffixed_tbl.h | Table for decoding fixed codes | +| inftrees.h | Generate Huffman trees for efficient decoding | +| trees.* | Output deflated data using Huffman coding | +| uncompr.c | Decompress a memory buffer | +| zconf.h.cmakein | zconf.h template for cmake | +| zendian.h | BYTE_ORDER for endian tests | +| zlib.map | Linux symbol information | +| zlib.pc.in | Pkg-config template | diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000..e866d7ac18 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,19 @@ +(C) 1995-2024 Jean-loup Gailly and Mark Adler + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000000..1493124bbf --- /dev/null +++ b/Makefile.in @@ -0,0 +1,407 @@ +# Makefile for zlib +# Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# Normally configure builds both a static and a shared library. +# If you want to build just a static library, use: ./configure --static + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DZLIB_DEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +SFLAGS=-O +LDFLAGS=-L. +LIBNAME1=libz-ng +LIBNAME2=zlib-ng +SUFFIX=-ng +TEST_LIBS=$(LIBNAME1).a +LDSHARED=$(CC) +LDSHAREDFLAGS=-shared +LDVERSIONSCRIPT= + +VER=2.2.4 +VER1=2 + +STATICLIB=$(LIBNAME1).a +SHAREDLIB=$(LIBNAME1).so +SHAREDLIBV=$(LIBNAME1).so.$(VER) +SHAREDLIBM=$(LIBNAME1).so.$(VER1) +IMPORTLIB= +SHAREDTARGET=$(LIBNAME1).so.$(VER) +PKGFILE=$(LIBNAME2).pc + +LIBS=$(STATICLIB) $(SHAREDTARGET) + +AR=ar +ARFLAGS=rc +DEFFILE= +RC= +RCFLAGS= +RCOBJS= +STRIP= +RANLIB=ranlib +LDCONFIG=ldconfig +LDSHAREDLIBC= +EXE= + +SRCDIR=. +INCLUDES=-I$(SRCDIR) + +BUILDDIR=. + +ARCHDIR=arch/generic +ARCH_STATIC_OBJS= +ARCH_SHARED_OBJS= + +prefix = /usr/local +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +libdir = ${exec_prefix}/lib +sharedlibdir = ${libdir} +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 +pkgconfigdir = ${libdir}/pkgconfig + +OBJZ = \ + arch/generic/adler32_c.o \ + arch/generic/adler32_fold_c.o \ + arch/generic/chunkset_c.o \ + arch/generic/compare256_c.o \ + arch/generic/crc32_braid_c.o \ + arch/generic/crc32_fold_c.o \ + arch/generic/slide_hash_c.o \ + adler32.o \ + compress.o \ + crc32.o \ + crc32_braid_comb.o \ + deflate.o \ + deflate_fast.o \ + deflate_huff.o \ + deflate_medium.o \ + deflate_quick.o \ + deflate_rle.o \ + deflate_slow.o \ + deflate_stored.o \ + functable.o \ + infback.o \ + inflate.o \ + inftrees.o \ + insert_string.o \ + insert_string_roll.o \ + trees.o \ + uncompr.o \ + zutil.o \ + cpu_features.o \ + $(ARCH_STATIC_OBJS) + +OBJG = \ + gzlib.o \ + gzread.o \ + gzwrite.o + +TESTOBJG = +OBJC = $(OBJZ) $(OBJG) + +PIC_OBJZ = \ + arch/generic/adler32_c.lo \ + arch/generic/adler32_fold_c.lo \ + arch/generic/chunkset_c.lo \ + arch/generic/compare256_c.lo \ + arch/generic/crc32_braid_c.lo \ + arch/generic/crc32_fold_c.lo \ + arch/generic/slide_hash_c.lo \ + adler32.lo \ + compress.lo \ + crc32.lo \ + crc32_braid_comb.lo \ + deflate.lo \ + deflate_fast.lo \ + deflate_huff.lo \ + deflate_medium.lo \ + deflate_quick.lo \ + deflate_rle.lo \ + deflate_slow.lo \ + deflate_stored.lo \ + functable.lo \ + infback.lo \ + inflate.lo \ + inftrees.lo \ + insert_string.lo \ + insert_string_roll.lo \ + trees.lo \ + uncompr.lo \ + zutil.lo \ + cpu_features.lo \ + $(ARCH_SHARED_OBJS) + +PIC_OBJG = \ + gzlib.lo \ + gzread.lo \ + gzwrite.lo + +PIC_TESTOBJG = +PIC_OBJC = $(PIC_OBJZ) $(PIC_OBJG) + +OBJS = $(OBJC) + +PIC_OBJS = $(PIC_OBJC) + +all: static shared + +static: example$(EXE) minigzip$(EXE) makefixed$(EXE) maketrees$(EXE) makecrct$(EXE) + +shared: examplesh$(EXE) minigzipsh$(EXE) + +check: test + +.SECONDARY: + +$(ARCHDIR)/%.o: $(SRCDIR)/$(ARCHDIR)/%.c + $(MAKE) -C $(ARCHDIR) $(notdir $@) + +$(ARCHDIR)/%.lo: $(SRCDIR)/$(ARCHDIR)/%.c + $(MAKE) -C $(ARCHDIR) $(notdir $@) + +arch/generic/%.o: $(SRCDIR)/arch/generic/%.c + $(MAKE) -C arch/generic $(notdir $@) + +arch/generic/%.lo: $(SRCDIR)/arch/generic/%.c + $(MAKE) -C arch/generic $(notdir $@) + +%.o: $(ARCHDIR)/%.o + -cp $< $@ + +%.lo: $(ARCHDIR)/%.lo + -cp $< $@ + +test: all + $(MAKE) -C test + +infcover.o: $(SRCDIR)/test/infcover.c zlib$(SUFFIX).h zconf$(SUFFIX).h zlib_name_mangling$(SUFFIX).h + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/test/infcover.c + +infcover$(EXE): infcover.o $(STATICLIB) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ infcover.o $(STATICLIB) +ifneq ($(STRIP),) + $(STRIP) $@ +endif + +cover: infcover$(EXE) + rm -f *.gcda + ./infcover + gcov inf*.c + +$(STATICLIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +example.o: + $(CC) $(CFLAGS) -DWITH_GZFILEOP $(INCLUDES) -c -o $@ $(SRCDIR)/test/example.c + +minigzip.o: + $(CC) $(CFLAGS) -DWITH_GZFILEOP $(INCLUDES) -c -o $@ $(SRCDIR)/test/minigzip.c + +makefixed.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/tools/makefixed.c + +maketrees.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/tools/maketrees.c + +makecrct.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/tools/makecrct.c + +zlibrc.o: $(SRCDIR)/win32/zlib$(SUFFIX)1.rc + $(RC) $(RCFLAGS) -o $@ $(SRCDIR)/win32/zlib$(SUFFIX)1.rc + +.SUFFIXES: .lo + +%.o: $(SRCDIR)/%.c + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< + +%.lo: $(SRCDIR)/%.c + $(CC) $(SFLAGS) -DPIC $(INCLUDES) -c -o $@ $< + +gzlib.o: $(SRCDIR)/gzlib.c + $(CC) $(CFLAGS) -DWITH_GZFILEOP $(INCLUDES) -c -o $@ $< + +gzlib.lo: $(SRCDIR)/gzlib.c + $(CC) $(SFLAGS) -DPIC -DWITH_GZFILEOP $(INCLUDES) -c -o $@ $< + +gzread.o: gzread.c + $(CC) $(CFLAGS) -DWITH_GZFILEOP $(INCLUDES) -c -o $@ $< + +gzread.lo: gzread.c + $(CC) $(SFLAGS) -DPIC -DWITH_GZFILEOP $(INCLUDES) -c -o $@ $< + +gzwrite.o: $(SRCDIR)/gzwrite.c + $(CC) $(CFLAGS) -DWITH_GZFILEOP $(INCLUDES) -c -o $@ $< + +gzwrite.lo: $(SRCDIR)/gzwrite.c + $(CC) $(SFLAGS) -DPIC -DWITH_GZFILEOP $(INCLUDES) -c -o $@ $< + +$(SHAREDTARGET): $(PIC_OBJS) $(DEFFILE) $(RCOBJS) +ifneq ($(SHAREDTARGET),) + $(LDSHARED) $(CFLAGS) $(LDSHAREDFLAGS) $(LDVERSIONSCRIPT) $(LDFLAGS) -o $@ $(DEFFILE) $(PIC_OBJS) $(RCOBJS) $(LDSHAREDLIBC) +ifneq ($(STRIP),) + $(STRIP) $@ +endif +ifneq ($(SHAREDLIB),$(SHAREDTARGET)) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) +endif +endif + +example$(EXE): example.o $(TESTOBJG) $(STATICLIB) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ example.o $(TESTOBJG) $(TEST_LIBS) $(LDSHAREDLIBC) +ifneq ($(STRIP),) + $(STRIP) $@ +endif + +minigzip$(EXE): minigzip.o $(TESTOBJG) $(STATICLIB) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ minigzip.o $(TESTOBJG) $(TEST_LIBS) $(LDSHAREDLIBC) +ifneq ($(STRIP),) + $(STRIP) $@ +endif + +minigzipsh$(EXE): minigzip.o $(PIC_TESTOBJG) $(SHAREDTARGET) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ minigzip.o $(PIC_TESTOBJG) $(SHAREDLIB) $(LDSHAREDLIBC) +ifneq ($(STRIP),) + $(STRIP) $@ +endif + + +examplesh$(EXE): example.o $(PIC_TESTOBJG) $(SHAREDTARGET) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ example.o $(PIC_TESTOBJG) $(SHAREDLIB) $(LDSHAREDLIBC) +ifneq ($(STRIP),) + $(STRIP) $@ +endif + +makefixed$(EXE): makefixed.o $(STATICLIB) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ makefixed.o $(TEST_LIBS) $(LDSHAREDLIBC) +ifneq ($(STRIP),) + $(STRIP) $@ +endif + +maketrees$(EXE): maketrees.o $(STATICLIB) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ maketrees.o $(TEST_LIBS) $(LDSHAREDLIBC) +ifneq ($(STRIP),) + $(STRIP) $@ +endif + +makecrct$(EXE): makecrct.o $(STATICLIB) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ makecrct.o $(TEST_LIBS) $(LDSHAREDLIBC) +ifneq ($(STRIP),) + $(STRIP) $@ +endif + +install-shared: $(SHAREDTARGET) +ifneq ($(SHAREDTARGET),) + -@if [ ! -d $(DESTDIR)$(sharedlibdir) ]; then mkdir -p $(DESTDIR)$(sharedlibdir); fi + rm -f $(DESTDIR)$(sharedlibdir)/$(SHAREDTARGET) + cp $(SHAREDTARGET) $(DESTDIR)$(sharedlibdir) + chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDTARGET) +ifneq ($(SHAREDLIB),$(SHAREDTARGET)) + rm -f $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM) + ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB) + ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM) + ($(LDCONFIG) || true) >/dev/null 2>&1 +# ldconfig is for Linux +endif +ifneq ($(IMPORTLIB),) + cp $(IMPORTLIB) $(DESTDIR)$(sharedlibdir) + chmod 644 $(DESTDIR)$(sharedlibdir)/$(IMPORTLIB) +endif +endif + +install-static: $(STATICLIB) + -@if [ ! -d $(DESTDIR)$(libdir) ]; then mkdir -p $(DESTDIR)$(libdir); fi + rm -f $(DESTDIR)$(libdir)/$(STATICLIB) + cp $(STATICLIB) $(DESTDIR)$(libdir) + chmod 644 $(DESTDIR)$(libdir)/$(STATICLIB) + -@($(RANLIB) $(DESTDIR)$(libdir)/$(STATICLIB) || true) >/dev/null 2>&1 +# The ranlib in install-static is needed on NeXTSTEP which checks file times + +install-libs: install-shared install-static + -@if [ ! -d $(DESTDIR)$(man3dir) ]; then mkdir -p $(DESTDIR)$(man3dir); fi + -@if [ ! -d $(DESTDIR)$(pkgconfigdir) ]; then mkdir -p $(DESTDIR)$(pkgconfigdir); fi + rm -f $(DESTDIR)$(pkgconfigdir)/$(PKGFILE) + cp $(PKGFILE) $(DESTDIR)$(pkgconfigdir) + chmod 644 $(DESTDIR)$(pkgconfigdir)/$(PKGFILE) + +install: install-libs + -@if [ ! -d $(DESTDIR)$(includedir) ]; then mkdir -p $(DESTDIR)$(includedir); fi + rm -f $(DESTDIR)$(includedir)/zlib$(SUFFIX).h $(DESTDIR)$(includedir)/zconf$(SUFFIX).h $(DESTDIR)$(includedir)/zlib_name_mangling$(SUFFIX).h + cp zlib$(SUFFIX).h $(DESTDIR)$(includedir)/zlib$(SUFFIX).h + cp zconf$(SUFFIX).h $(DESTDIR)$(includedir)/zconf$(SUFFIX).h + cp zlib_name_mangling$(SUFFIX).h $(DESTDIR)$(includedir)/zlib_name_mangling$(SUFFIX).h + chmod 644 $(DESTDIR)$(includedir)/zlib$(SUFFIX).h $(DESTDIR)$(includedir)/zconf$(SUFFIX).h $(DESTDIR)$(includedir)/zlib_name_mangling$(SUFFIX).h + +uninstall-static: + cd $(DESTDIR)$(libdir) && rm -f $(STATICLIB) + +uninstall-shared: +ifneq ($(SHAREDLIB),) + cd $(DESTDIR)$(sharedlibdir) && rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM) +endif +ifneq ($(IMPORTLIB),) + cd $(DESTDIR)$(sharedlibdir) && rm -f $(IMPORTLIB) +endif + +uninstall: uninstall-static uninstall-shared + cd $(DESTDIR)$(includedir) && rm -f zlib$(SUFFIX).h zconf$(SUFFIX).h zlib_name_mangling$(SUFFIX).h + cd $(DESTDIR)$(pkgconfigdir) && rm -f $(PKGFILE) + +mostlyclean: clean +clean: + @if [ -f $(ARCHDIR)/Makefile ]; then $(MAKE) -C $(ARCHDIR) clean; fi + @if [ -f arch/generic/Makefile ]; then $(MAKE) -C arch/generic clean; fi + @if [ -f test/Makefile ]; then $(MAKE) -C test clean; fi + rm -f *.o *.lo *~ \ + example$(EXE) minigzip$(EXE) minigzipsh$(EXE) \ + infcover makefixed$(EXE) maketrees$(EXE) makecrct$(EXE) \ + $(STATICLIB) $(IMPORTLIB) $(SHAREDLIB) $(SHAREDLIBV) $(SHAREDLIBM) \ + foo.gz so_locations \ + _match.s maketree + rm -rf objs + rm -f *.gcda *.gcno *.gcov + rm -f a.out a.exe + rm -f *._h + rm -rf btmp1 btmp2 pkgtmp1 pkgtmp2 + +maintainer-clean: distclean +distclean: clean + @if [ -f $(ARCHDIR)/Makefile ]; then $(MAKE) -C $(ARCHDIR) distclean; fi + @if [ -f test/Makefile ]; then $(MAKE) -C test distclean; fi + rm -f $(PKGFILE) configure.log zconf.h zconf.h.cmakein zlib$(SUFFIX).h zlib_name_mangling$(SUFFIX).h *.pc gzread.c + -@rm -f .DS_Store +# Reset Makefile if building inside source tree + @if [ -f Makefile.in ]; then \ + printf 'all:\n\t-@echo "Please use ./configure first. Thank you."\n' > Makefile ; \ + printf '\ndistclean:\n\t$(MAKE) -f Makefile.in distclean\n' >> Makefile ; \ + touch -r $(SRCDIR)/Makefile.in Makefile ; fi +# Reset zconf.h and zconf.h.cmakein if building inside source tree + @if [ -f zconf.h.in ]; then \ + cp -p $(SRCDIR)/zconf.h.in zconf.h ; \ + grep -v '^#cmakedefine' $(SRCDIR)/zconf.h.in > zconf.h.cmakein &&\ + touch -r $(SRCDIR)/zconf.h.in zconf.h.cmakein ; fi +# Cleanup these files if building outside source tree + @if [ ! -f README.md ]; then rm -f Makefile; fi +# Remove arch and test directory if building outside source tree + @if [ ! -f $(ARCHDIR)/Makefile.in ]; then rm -rf arch; fi + @if [ ! -f test/Makefile.in ]; then rm -rf test; fi + +tags: + etags $(SRCDIR)/*.[ch] diff --git a/PORTING.md b/PORTING.md new file mode 100644 index 0000000000..208f6ee9e7 --- /dev/null +++ b/PORTING.md @@ -0,0 +1,111 @@ +Porting applications to use zlib-ng +=================================== + +Zlib-ng can be used/compiled in two different modes, that require some +consideration by the application developer. + +Changes from zlib affecting native and compat modes +--------------------------------------------------- +Zlib-ng is not as conservative with memory allocation as Zlib is. + +Where Zlib's inflate will allocate a lower amount of memory depending on +compression level and window size, zlib-ng will always allocate the maximum +amount of memory and possibly leave parts of it unused. +Zlib-ng's deflate will however allocate a lower amount of memory depending +on compression level and window size. + +Zlib-ng also allocates one "big" buffer instead of doing multiple smaller +allocations. This is faster, can lead to better cache locality and reduces +space lost to alignment padding. + +At the time of writing, by default zlib-ng allocates the following amounts +of memory on a 64-bit system (except on S390x that requires ~4KiB more): +- Deflate: 350.272 Bytes +- Inflate: 42.112 Bytes + +**Advantages:** +- All memory is allocated during DeflateInit or InflateInit functions, + leaving the actual deflate/inflate functions free from allocations. +- Zlib-ng can only fail from memory allocation errors during init. +- Time spent doing memory allocation systemcalls is all done during init, + allowing applications to do prepare this before doing latency-sensitive + deflate/inflate later. +- Can reduce wasted memory due to buffer alignment padding both by OS and zlib-ng. +- Potentially improved memory locality. + +**Disadvantages:** +- Zlib-ng allocates a little more memory than zlib does. + +zlib-compat mode +---------------- +Zlib-ng can be compiled in zlib-compat mode, suitable for zlib-replacement +in a single application or system-wide. + +Please note that zlib-ng in zlib-compat mode tries to maintain both API and +ABI compatibility with the original zlib. Any issues regarding compatibility +can be reported as bugs. + +In certain instances you may not be able to simply replace the zlib library/dll +files and expect the application to work. The application may need to be +recompiled against the zlib-ng headers and libs to ensure full compatibility. + +It is also possible for the deflate output stream to differ from the original +zlib due to algorithmic differences between the two libraries. Any tests or +applications that depend on the exact length of the deflate stream being a +certain value will need to be updated. + +**Advantages:** +- Easy to port to, since it only requires a recompile of the application and + no changes to the application code. + +**Disadvantages:** +- Can conflict with a system-installed zlib, as that can often be linked in + by another library you are linking into your application. This can cause + crashes or incorrect output. +- If your application is pre-allocating a memory buffer and you are providing + deflate/inflate init with your own allocator that allocates from that buffer + (looking at you nginx), you should be aware that zlib-ng needs to allocate + more memory than stock zlib needs. The same problem exists with Intel’s and + Cloudflare’s zlib forks. Doing this is not recommended since it makes it + very hard to maintain compatibility over time. + +**Build Considerations:** +- Compile against the *zlib.h* provided by zlib-ng +- Configuration header is named *zconf.h* +- Static library is *libz.a* on Unix and macOS, or *zlib.lib* on Windows +- Shared library is *libz.so* on Unix, *libz.dylib* on macOS, or *zlib1.dll* + on Windows +- Type `z_size_t` is *unsigned __int64* on 64-bit Windows, and *unsigned long* on 32-bit Windows, Unix and macOS +- Type `z_uintmax_t` is *unsigned long* in zlib-compat mode, and *size_t* with zlib-ng API + +zlib-ng native mode +------------------- +Zlib-ng in native mode is suitable for co-existing with the standard zlib +library, allowing applications to implement support and testing separately. + +The zlib-ng native has implemented some modernization and simplifications +in its API, intended to make life easier for application developers. + +**Advantages:** +- Does not conflict with other zlib implementations, and can co-exist as a + system library along with zlib. +- In certain places zlib-ng native uses more appropriate data types, removing + the need for some workarounds in the API compared to zlib. + +**Disadvantages:** +- Requires minor changes to applications to use the prefixed zlib-ng + function calls and structs. Usually this means a small prefix `zng_` has to be added. + +**Build Considerations:** +- Compile against *zlib-ng.h* +- Configuration header is named *zconf-ng.h* +- Static library is *libz-ng.a* on Unix and macOS, or *zlib-ng.lib* on Windows +- Shared library is *libz-ng.so* on Unix, *libz-ng.dylib* on macOS, or + *zlib-ng2.dll* on Windows +- Type `z_size_t` is *size_t* + +zlib-ng compile-time detection +------------------------------ + +To distinguish zlib-ng from other zlib implementations at compile-time check for the +existence of `ZLIBNG_VERSION` defined in the zlib header. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..28aad7f1dc --- /dev/null +++ b/README.md @@ -0,0 +1,228 @@ +| CI | Stable | Develop | +|:---|:-------|:--------| +| GitHub Actions | [![Stable CMake](https://github.com/zlib-ng/zlib-ng/actions/workflows/cmake.yml/badge.svg?branch=stable)](https://github.com/zlib-ng/zlib-ng/actions/workflows/cmake.yml?query=branch%3Astable)
[![Stable Configure](https://github.com/zlib-ng/zlib-ng/actions/workflows/configure.yml/badge.svg?branch=stable)](https://github.com/zlib-ng/zlib-ng/actions/workflows/configure.yml?query=branch%3Astable)
[![Stable NMake](https://github.com/zlib-ng/zlib-ng/actions/workflows/nmake.yml/badge.svg?branch=stable)](https://github.com/zlib-ng/zlib-ng/actions/workflows/nmake.yml?query=branch%3Astable) | [![Develop CMake](https://github.com/zlib-ng/zlib-ng/actions/workflows/cmake.yml/badge.svg?branch=develop)](https://github.com/zlib-ng/zlib-ng/actions/workflows/cmake.yml?query=branch%3Adevelop)
[![Develop Configure](https://github.com/zlib-ng/zlib-ng/actions/workflows/configure.yml/badge.svg?branch=develop)](https://github.com/zlib-ng/zlib-ng/actions/workflows/configure.yml?query=branch%3Adevelop)
[![Develop NMake](https://github.com/zlib-ng/zlib-ng/actions/workflows/nmake.yml/badge.svg?branch=develop)](https://github.com/zlib-ng/zlib-ng/actions/workflows/nmake.yml?query=branch%3Adevelop) | +| CodeFactor | [![CodeFactor](https://www.codefactor.io/repository/github/zlib-ng/zlib-ng/badge/stable)](https://www.codefactor.io/repository/github/zlib-ng/zlib-ng/overview/stable) | [![CodeFactor](https://www.codefactor.io/repository/github/zlib-ng/zlib-ng/badge/develop)](https://www.codefactor.io/repository/github/zlib-ng/zlib-ng/overview/develop) | +| OSS-Fuzz | [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/zlib-ng.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:zlib-ng) | [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/zlib-ng.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:zlib-ng) | +| Codecov | [![codecov](https://codecov.io/github/zlib-ng/zlib-ng/branch/stable/graph/badge.svg?token=uKsgK9LIuC)](https://codecov.io/github/zlib-ng/zlib-ng/tree/stable) | [![codecov](https://codecov.io/github/zlib-ng/zlib-ng/branch/develop/graph/badge.svg?token=uKsgK9LIuC)](https://codecov.io/github/zlib-ng/zlib-ng/tree/develop) | + +## zlib-ng +*zlib data compression library for the next generation systems* + +Maintained by Hans Kristian Rosbach + aka Dead2 (zlib-ng àt circlestorm dót org) + +Features +-------- + +* Zlib compatible API with support for dual-linking +* Modernized native API based on zlib API for ease of porting +* Modern C11 syntax and a clean code layout +* Deflate medium and quick algorithms based on Intel’s zlib fork +* Support for CPU intrinsics when available + * Adler32 implementation using SSSE3, AVX2, AVX512, AVX512-VNNI, Neon, VMX & VSX + * CRC32-B implementation using PCLMULQDQ, VPCLMULQDQ, ACLE, & IBM Z + * Slide hash implementations using SSE2, AVX2, ARMv6, Neon, VMX & VSX + * Compare256 implementations using SSE2, AVX2, Neon, POWER9 & RVV + * Inflate chunk copying using SSE2, SSSE3, AVX, Neon & VSX + * Support for hardware-accelerated deflate using IBM Z DFLTCC +* Safe unaligned memory read/writes and large bit buffer improvements +* Includes improvements from Cloudflare and Intel forks +* Configure, CMake, and NMake build system support +* Comprehensive set of CMake unit tests +* Code sanitizers, fuzzing, and coverage +* GitHub Actions continuous integration on Windows, macOS, and Linux + * Emulated CI for ARM, AARCH64, PPC, PPC64, RISCV, SPARC64, S390x using qemu + + +History +------- + +The motivation for this fork was seeing several 3rd party contributions with new optimizations not getting +implemented into the official zlib repository. + +Mark Adler has been maintaining zlib for a very long time, and he has done a great job and hopefully he will continue +for a long time yet. The idea of zlib-ng is not to replace zlib, but to co-exist as a drop-in replacement with a +lower threshold for code change. + +zlib has a long history and is incredibly portable, even supporting many systems that predate the Internet.
+That is great, but it can complicate further development and maintainability. The zlib code contains many workarounds +for really old compilers or to accommodate systems with limitations such as operating in a 16-bit environment. + +Many of these workarounds are only maintenance burdens, some of them are pretty huge code-wise. With many workarounds +cluttered throughout the code, it makes it harder for new programmers with an idea/interest for zlib to contribute. + +I decided to make a fork, merge all the Intel optimizations, some of the Cloudflare optimizations, plus a couple other +smaller patches. Then started cleaning out workarounds, various dead code, all contrib and example code.
+The result is a better performing and easier to maintain zlib-ng. + +A lot of improvements have gone into zlib-ng since its start, and numerous people and companies have contributed both +small and big improvements, or valuable testing. + + +Build +----- +Please read LICENSE.md, it is very simple and very liberal. + +There are two ways to build zlib-ng: + +### Cmake + +To build zlib-ng using the cross-platform makefile generator cmake. + +``` +cmake . +cmake --build . --config Release +ctest --verbose -C Release +``` + +Alternatively, you can use the cmake configuration GUI tool ccmake: + +``` +ccmake . +``` + +### Configure + +To build zlib-ng using the bash configure script: + +``` +./configure +make +make test +``` + +Build Options +------------- + +| CMake | configure | Description | Default | +|:---------------------------|:-------------------------|:------------------------------------------------------------------------------------|---------| +| ZLIB_COMPAT | --zlib-compat | Compile with zlib compatible API | OFF | +| ZLIB_ENABLE_TESTS | | Build test binaries | ON | +| WITH_GZFILEOP | --without-gzfileops | Compile with support for gzFile related functions | ON | +| WITH_OPTIM | --without-optimizations | Build with optimisations | ON | +| WITH_NEW_STRATEGIES | --without-new-strategies | Use new strategies | ON | +| WITH_NATIVE_INSTRUCTIONS | | Compiles with full instruction set supported on this host (gcc/clang -march=native) | OFF | +| WITH_RUNTIME_CPU_DETECTION | | Compiles with runtime CPU detection | ON | +| WITH_SANITIZER | | Build with sanitizer (memory, address, undefined) | OFF | +| WITH_GTEST | | Build gtest_zlib | ON | +| WITH_FUZZERS | | Build test/fuzz | OFF | +| WITH_BENCHMARKS | | Build test/benchmarks | OFF | +| WITH_MAINTAINER_WARNINGS | | Build with project maintainer warnings | OFF | +| WITH_CODE_COVERAGE | | Enable code coverage reporting | OFF | + + +Install +------- + +WARNING: We do not recommend manually installing unless you really know what you are doing, because this can +potentially override the system default zlib library, and any incompatibility or wrong configuration of zlib-ng +can make the whole system unusable, requiring recovery or reinstall. +If you still want a manual install, we recommend using the /opt/ path prefix. + +For Linux distros, an alternative way to use zlib-ng (if compiled in zlib-compat mode) instead of zlib, is through +the use of the _LD_PRELOAD_ environment variable. If the program is dynamically linked with zlib, then the program +will temporarily attempt to use zlib-ng instead, without risking system-wide instability. + +``` +LD_PRELOAD=/opt/zlib-ng/libz.so.1.2.13.zlib-ng /usr/bin/program +``` + +### Cmake + +To install zlib-ng system-wide using cmake: + +```sh or powershell +cmake --build . --target install +``` + +### Configure + +To install zlib-ng system-wide using the configure script: + +```sh +make install +``` + +### CPack + +After building with cmake, an installation package can be created using cpack. By default a tgz package is created, +but you can append `-G ` to each command to generate alternative packages types (TGZ, ZIP, RPM, DEB). To easily +create a rpm or deb package, you would use `-G RPM` or `-G DEB` respectively. + +```sh or powershell +cd build +cpack --config CPackConfig.cmake +cpack --config CPackSourceConfig.cmake +``` + +### Vcpkg + +Alternatively, you can build and install zlib-ng using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager: + +```sh or powershell +git clone https://github.com/Microsoft/vcpkg.git +cd vcpkg +./bootstrap-vcpkg.sh # "./bootstrap-vcpkg.bat" for powershell +./vcpkg integrate install +./vcpkg install zlib-ng +``` + +The zlib-ng port in vcpkg is kept up to date by Microsoft team members and community contributors. +If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. + +Contributing +------------ + +Zlib-ng is aiming to be open to contributions, and we would be delighted to receive pull requests on github. +Help with testing and reviewing pull requests etc is also very much appreciated. + +Please check the Wiki for more info: [Contributing](https://github.com/zlib-ng/zlib-ng/wiki/Contributing) + +Acknowledgments +---------------- + +Thanks go out to all the people and companies who have taken the time to contribute +code reviews, testing and/or patches. Zlib-ng would not have been nearly as good without you. + +The deflate format used by zlib was defined by Phil Katz.
+The deflate and zlib specifications were written by L. Peter Deutsch. + +zlib was originally created by Jean-loup Gailly (compression) and Mark Adler (decompression). + + +Advanced Build Options +---------------------- + +| CMake | configure | Description | Default | +|:--------------------------------|:----------------------|:--------------------------------------------------------------------|------------------------| +| FORCE_SSE2 | --force-sse2 | Skip runtime check for SSE2 instructions (Always on for x86_64) | OFF (x86) | +| WITH_AVX2 | | Build with AVX2 intrinsics | ON | +| WITH_AVX512 | | Build with AVX512 intrinsics | ON | +| WITH_AVX512VNNI | | Build with AVX512VNNI intrinsics | ON | +| WITH_SSE2 | | Build with SSE2 intrinsics | ON | +| WITH_SSSE3 | | Build with SSSE3 intrinsics | ON | +| WITH_SSE42 | | Build with SSE42 intrinsics | ON | +| WITH_PCLMULQDQ | | Build with PCLMULQDQ intrinsics | ON | +| WITH_VPCLMULQDQ | --without-vpclmulqdq | Build with VPCLMULQDQ intrinsics | ON | +| WITH_ACLE | --without-acle | Build with ACLE intrinsics | ON | +| WITH_NEON | --without-neon | Build with NEON intrinsics | ON | +| WITH_ARMV6 | --without-armv6 | Build with ARMv6 intrinsics | ON | +| WITH_ALTIVEC | --without-altivec | Build with AltiVec (VMX) intrinsics | ON | +| WITH_POWER8 | --without-power8 | Build with POWER8 optimisations | ON | +| WITH_RVV | | Build with RVV intrinsics | ON | +| WITH_CRC32_VX | --without-crc32-vx | Build with vectorized CRC32 on IBM Z | ON | +| WITH_DFLTCC_DEFLATE | --with-dfltcc-deflate | Build with DFLTCC intrinsics for compression on IBM Z | OFF | +| WITH_DFLTCC_INFLATE | --with-dfltcc-inflate | Build with DFLTCC intrinsics for decompression on IBM Z | OFF | +| WITH_INFLATE_STRICT | | Build with strict inflate distance checking | OFF | +| WITH_INFLATE_ALLOW_INVALID_DIST | | Build with zero fill for inflate invalid distances | OFF | +| INSTALL_UTILS | | Copy minigzip and minideflate during install | OFF | +| ZLIBNG_ENABLE_TESTS | | Test zlib-ng specific API | ON | + + +Related Projects +---------------- + +* Fork of the popular minizip https://github.com/zlib-ng/minizip-ng +* Python tool to benchmark minigzip/minideflate https://github.com/zlib-ng/deflatebench +* Python tool to benchmark pigz https://github.com/zlib-ng/pigzbench +* 3rd party patches for zlib-ng compatibility https://github.com/zlib-ng/patches diff --git a/README.rst b/README.rst deleted file mode 100644 index 7ed2fbba65..0000000000 --- a/README.rst +++ /dev/null @@ -1,70 +0,0 @@ -cpython-source-deps -=================== - -Source for packages that the CPython build process depends on. - -It is currently expected that this will only be useful on Windows, -and in any case you should never need to clone this repository -unless you are updating its contents. - -.. contents:: - -Updating Source Dependencies ----------------------------- - -The procedure for updating the different source dependencies are similar. Below -is an example for updating SQLite:: - - -1. Fork and clone this repository. - -2. Checkout a new branch off the ``sqlite`` branch. Assuming this repo is set - as your ``upstream``:: - - git checkout -b -sqlite upstream/sqlite - -3. Download SQLite source from `sqlite.org `_. - -4. Unzip it to the branch checked out in step 2. - -5. Commit and push the changes. - -6. Create the PR, with ``sqlite`` as the base branch. - -Once the PR has been merged, tag the commit as -``sqlite-``. - -For updating each project to be updated, follow the above instructions with -appropriate substitutions. For ``sqlite``, ``bzip2``, ``xz``, and ``zlib``, -that's it! - -For ``openssl``, ``tcl``/``tk``, and ``libffi``, builds of each should also be -checked into `cpython-bin-deps `_ -for use in the CPython Windows build. Each one has a ``prepare_.bat`` -script in the ``cpython`` ``PCbuild`` directory that will take care of building -the project. Note, though, that builds checked into ``cpython-bin-deps`` need -to be signed by the release signing key, so it is generally up to a member of -the release management team to create those builds. - - -Download links --------------- - -- ``bzip2``: https://www.sourceware.org/bzip2/downloads.html -- ``libffi`` : https://github.com/libffi/libffi -- ``mpdecimal`` : https://www.bytereef.org/mpdecimal/download.html -- ``openssl``: https://www.openssl.org/source/ -- ``sqlite``: https://www.sqlite.org/download.html -- ``tcl``/``tk``: https://tcl.tk/software/tcltk/download.html -- ``xz``: https://github.com/tukaani-project/xz -- ``zlib``: https://zlib.net/ - -Tagging the commit ------------------- - -Using the ``sqlite`` branch as an example:: - - git checkout -b sqlite-tag upstream/sqlite - git tag sqlite-3.21.0.0 # replace 3.21.0.0 with the correct version. - git push --tags upstream - diff --git a/adler32.c b/adler32.c new file mode 100644 index 0000000000..1a643ed53b --- /dev/null +++ b/adler32.c @@ -0,0 +1,69 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "functable.h" +#include "adler32_p.h" + +#ifdef ZLIB_COMPAT +unsigned long Z_EXPORT PREFIX(adler32_z)(unsigned long adler, const unsigned char *buf, size_t len) { + return (unsigned long)FUNCTABLE_CALL(adler32)((uint32_t)adler, buf, len); +} +#else +uint32_t Z_EXPORT PREFIX(adler32_z)(uint32_t adler, const unsigned char *buf, size_t len) { + return FUNCTABLE_CALL(adler32)(adler, buf, len); +} +#endif + +/* ========================================================================= */ +#ifdef ZLIB_COMPAT +unsigned long Z_EXPORT PREFIX(adler32)(unsigned long adler, const unsigned char *buf, unsigned int len) { + return (unsigned long)FUNCTABLE_CALL(adler32)((uint32_t)adler, buf, len); +} +#else +uint32_t Z_EXPORT PREFIX(adler32)(uint32_t adler, const unsigned char *buf, uint32_t len) { + return FUNCTABLE_CALL(adler32)(adler, buf, len); +} +#endif + +/* ========================================================================= */ +static uint32_t adler32_combine_(uint32_t adler1, uint32_t adler2, z_off64_t len2) { + uint32_t sum1; + uint32_t sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffff; + + /* the derivation of this formula is left as an exercise for the reader */ + len2 %= BASE; /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + sum2 %= BASE; + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +#ifdef ZLIB_COMPAT +unsigned long Z_EXPORT PREFIX(adler32_combine)(unsigned long adler1, unsigned long adler2, z_off_t len2) { + return (unsigned long)adler32_combine_((uint32_t)adler1, (uint32_t)adler2, len2); +} + +unsigned long Z_EXPORT PREFIX4(adler32_combine)(unsigned long adler1, unsigned long adler2, z_off64_t len2) { + return (unsigned long)adler32_combine_((uint32_t)adler1, (uint32_t)adler2, len2); +} +#else +uint32_t Z_EXPORT PREFIX4(adler32_combine)(uint32_t adler1, uint32_t adler2, z_off64_t len2) { + return adler32_combine_(adler1, adler2, len2); +} +#endif diff --git a/adler32_p.h b/adler32_p.h new file mode 100644 index 0000000000..38ba2ad721 --- /dev/null +++ b/adler32_p.h @@ -0,0 +1,70 @@ +/* adler32_p.h -- Private inline functions and macros shared with + * different computation of the Adler-32 checksum + * of a data stream. + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef ADLER32_P_H +#define ADLER32_P_H + +#define BASE 65521U /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(sum1, sum2, buf, i) {(sum1) += buf[(i)]; (sum2) += (sum1);} +#define DO2(sum1, sum2, buf, i) {DO1(sum1, sum2, buf, i); DO1(sum1, sum2, buf, i+1);} +#define DO4(sum1, sum2, buf, i) {DO2(sum1, sum2, buf, i); DO2(sum1, sum2, buf, i+2);} +#define DO8(sum1, sum2, buf, i) {DO4(sum1, sum2, buf, i); DO4(sum1, sum2, buf, i+4);} +#define DO16(sum1, sum2, buf) {DO8(sum1, sum2, buf, 0); DO8(sum1, sum2, buf, 8);} + +static inline uint32_t adler32_len_1(uint32_t adler, const uint8_t *buf, uint32_t sum2) { + adler += buf[0]; + adler %= BASE; + sum2 += adler; + sum2 %= BASE; + return adler | (sum2 << 16); +} + +static inline uint32_t adler32_len_16(uint32_t adler, const uint8_t *buf, size_t len, uint32_t sum2) { + while (len) { + --len; + adler += *buf++; + sum2 += adler; + } + adler %= BASE; + sum2 %= BASE; /* only added so many BASE's */ + /* return recombined sums */ + return adler | (sum2 << 16); +} + +static inline uint32_t adler32_copy_len_16(uint32_t adler, const uint8_t *buf, uint8_t *dst, size_t len, uint32_t sum2) { + while (len--) { + *dst = *buf++; + adler += *dst++; + sum2 += adler; + } + adler %= BASE; + sum2 %= BASE; /* only added so many BASE's */ + /* return recombined sums */ + return adler | (sum2 << 16); +} + +static inline uint32_t adler32_len_64(uint32_t adler, const uint8_t *buf, size_t len, uint32_t sum2) { +#ifdef UNROLL_MORE + while (len >= 16) { + len -= 16; + DO16(adler, sum2, buf); + buf += 16; +#else + while (len >= 8) { + len -= 8; + DO8(adler, sum2, buf, 0); + buf += 8; +#endif + } + /* Process tail (len < 16). */ + return adler32_len_16(adler, buf, len, sum2); +} + +#endif /* ADLER32_P_H */ diff --git a/arch/arm/Makefile.in b/arch/arm/Makefile.in new file mode 100644 index 0000000000..b6f0aaf211 --- /dev/null +++ b/arch/arm/Makefile.in @@ -0,0 +1,78 @@ +# Makefile for zlib +# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler +# For conditions of distribution and use, see copyright notice in zlib.h + +CC= +CFLAGS= +SFLAGS= +INCLUDES= +SUFFIX= + +ACLEFLAG= +NEONFLAG= +ARMV6FLAG= +NOLTOFLAG= + +SRCDIR=. +SRCTOP=../.. +TOPDIR=$(SRCTOP) + +all: \ + adler32_neon.o adler32_neon.lo \ + arm_features.o arm_features.lo \ + chunkset_neon.o chunkset_neon.lo \ + compare256_neon.o compare256_neon.lo \ + crc32_acle.o crc32_acle.lo \ + slide_hash_neon.o slide_hash_neon.lo \ + slide_hash_armv6.o slide_hash_armv6.lo \ + +adler32_neon.o: + $(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_neon.c + +adler32_neon.lo: + $(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_neon.c + +arm_features.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/arm_features.c + +arm_features.lo: + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/arm_features.c + +chunkset_neon.o: + $(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_neon.c + +chunkset_neon.lo: + $(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_neon.c + +compare256_neon.o: + $(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_neon.c + +compare256_neon.lo: + $(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_neon.c + +crc32_acle.o: + $(CC) $(CFLAGS) $(ACLEFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_acle.c + +crc32_acle.lo: + $(CC) $(SFLAGS) $(ACLEFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_acle.c + +slide_hash_neon.o: + $(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_neon.c + +slide_hash_neon.lo: + $(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_neon.c + +slide_hash_armv6.o: + $(CC) $(CFLAGS) $(ARMV6FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_armv6.c + +slide_hash_armv6.lo: + $(CC) $(SFLAGS) $(ARMV6FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_armv6.c + +mostlyclean: clean +clean: + rm -f *.o *.lo *~ + rm -rf objs + rm -f *.gcda *.gcno *.gcov + +distclean: clean + rm -f Makefile diff --git a/arch/arm/acle_intrins.h b/arch/arm/acle_intrins.h new file mode 100644 index 0000000000..a67cf3aabd --- /dev/null +++ b/arch/arm/acle_intrins.h @@ -0,0 +1,35 @@ +#ifndef ARM_ACLE_INTRINS_H +#define ARM_ACLE_INTRINS_H + +#include +#ifdef _MSC_VER +# include +#elif defined(HAVE_ARM_ACLE_H) +# include +#endif + +#ifdef ARM_ACLE +#if defined(__aarch64__) +# define Z_TARGET_CRC Z_TARGET("+crc") +#else +# define Z_TARGET_CRC +#endif +#endif + +#ifdef ARM_SIMD +#ifdef _MSC_VER +typedef uint32_t uint16x2_t; + +#define __uqsub16 _arm_uqsub16 +#elif !defined(ARM_SIMD_INTRIN) +typedef uint32_t uint16x2_t; + +static inline uint16x2_t __uqsub16(uint16x2_t __a, uint16x2_t __b) { + uint16x2_t __c; + __asm__ __volatile__("uqsub16 %0, %1, %2" : "=r" (__c) : "r"(__a), "r"(__b)); + return __c; +} +#endif +#endif + +#endif // include guard ARM_ACLE_INTRINS_H diff --git a/arch/arm/adler32_neon.c b/arch/arm/adler32_neon.c new file mode 100644 index 0000000000..8e46b38017 --- /dev/null +++ b/arch/arm/adler32_neon.c @@ -0,0 +1,215 @@ +/* Copyright (C) 1995-2011, 2016 Mark Adler + * Copyright (C) 2017 ARM Holdings Inc. + * Authors: + * Adenilson Cavalcanti + * Adam Stylinski + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#ifdef ARM_NEON +#include "neon_intrins.h" +#include "zbuild.h" +#include "adler32_p.h" + +static void NEON_accum32(uint32_t *s, const uint8_t *buf, size_t len) { + static const uint16_t ALIGNED_(16) taps[64] = { + 64, 63, 62, 61, 60, 59, 58, 57, + 56, 55, 54, 53, 52, 51, 50, 49, + 48, 47, 46, 45, 44, 43, 42, 41, + 40, 39, 38, 37, 36, 35, 34, 33, + 32, 31, 30, 29, 28, 27, 26, 25, + 24, 23, 22, 21, 20, 19, 18, 17, + 16, 15, 14, 13, 12, 11, 10, 9, + 8, 7, 6, 5, 4, 3, 2, 1 }; + + uint32x4_t adacc = vdupq_n_u32(0); + uint32x4_t s2acc = vdupq_n_u32(0); + uint32x4_t s2acc_0 = vdupq_n_u32(0); + uint32x4_t s2acc_1 = vdupq_n_u32(0); + uint32x4_t s2acc_2 = vdupq_n_u32(0); + + adacc = vsetq_lane_u32(s[0], adacc, 0); + s2acc = vsetq_lane_u32(s[1], s2acc, 0); + + uint32x4_t s3acc = vdupq_n_u32(0); + uint32x4_t adacc_prev = adacc; + + uint16x8_t s2_0, s2_1, s2_2, s2_3; + s2_0 = s2_1 = s2_2 = s2_3 = vdupq_n_u16(0); + + uint16x8_t s2_4, s2_5, s2_6, s2_7; + s2_4 = s2_5 = s2_6 = s2_7 = vdupq_n_u16(0); + + size_t num_iter = len >> 2; + int rem = len & 3; + + for (size_t i = 0; i < num_iter; ++i) { + uint8x16x4_t d0_d3 = vld1q_u8_x4(buf); + + /* Unfortunately it doesn't look like there's a direct sum 8 bit to 32 + * bit instruction, we'll have to make due summing to 16 bits first */ + uint16x8x2_t hsum, hsum_fold; + hsum.val[0] = vpaddlq_u8(d0_d3.val[0]); + hsum.val[1] = vpaddlq_u8(d0_d3.val[1]); + + hsum_fold.val[0] = vpadalq_u8(hsum.val[0], d0_d3.val[2]); + hsum_fold.val[1] = vpadalq_u8(hsum.val[1], d0_d3.val[3]); + + adacc = vpadalq_u16(adacc, hsum_fold.val[0]); + s3acc = vaddq_u32(s3acc, adacc_prev); + adacc = vpadalq_u16(adacc, hsum_fold.val[1]); + + /* If we do straight widening additions to the 16 bit values, we don't incur + * the usual penalties of a pairwise add. We can defer the multiplications + * until the very end. These will not overflow because we are incurring at + * most 408 loop iterations (NMAX / 64), and a given lane is only going to be + * summed into once. This means for the maximum input size, the largest value + * we will see is 255 * 102 = 26010, safely under uint16 max */ + s2_0 = vaddw_u8(s2_0, vget_low_u8(d0_d3.val[0])); + s2_1 = vaddw_high_u8(s2_1, d0_d3.val[0]); + s2_2 = vaddw_u8(s2_2, vget_low_u8(d0_d3.val[1])); + s2_3 = vaddw_high_u8(s2_3, d0_d3.val[1]); + s2_4 = vaddw_u8(s2_4, vget_low_u8(d0_d3.val[2])); + s2_5 = vaddw_high_u8(s2_5, d0_d3.val[2]); + s2_6 = vaddw_u8(s2_6, vget_low_u8(d0_d3.val[3])); + s2_7 = vaddw_high_u8(s2_7, d0_d3.val[3]); + + adacc_prev = adacc; + buf += 64; + } + + s3acc = vshlq_n_u32(s3acc, 6); + + if (rem) { + uint32x4_t s3acc_0 = vdupq_n_u32(0); + while (rem--) { + uint8x16_t d0 = vld1q_u8(buf); + uint16x8_t adler; + adler = vpaddlq_u8(d0); + s2_6 = vaddw_u8(s2_6, vget_low_u8(d0)); + s2_7 = vaddw_high_u8(s2_7, d0); + adacc = vpadalq_u16(adacc, adler); + s3acc_0 = vaddq_u32(s3acc_0, adacc_prev); + adacc_prev = adacc; + buf += 16; + } + + s3acc_0 = vshlq_n_u32(s3acc_0, 4); + s3acc = vaddq_u32(s3acc_0, s3acc); + } + + uint16x8x4_t t0_t3 = vld1q_u16_x4(taps); + uint16x8x4_t t4_t7 = vld1q_u16_x4(taps + 32); + + s2acc = vmlal_high_u16(s2acc, t0_t3.val[0], s2_0); + s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[0]), vget_low_u16(s2_0)); + s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[1], s2_1); + s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[1]), vget_low_u16(s2_1)); + + s2acc = vmlal_high_u16(s2acc, t0_t3.val[2], s2_2); + s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[2]), vget_low_u16(s2_2)); + s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[3], s2_3); + s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[3]), vget_low_u16(s2_3)); + + s2acc = vmlal_high_u16(s2acc, t4_t7.val[0], s2_4); + s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[0]), vget_low_u16(s2_4)); + s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[1], s2_5); + s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[1]), vget_low_u16(s2_5)); + + s2acc = vmlal_high_u16(s2acc, t4_t7.val[2], s2_6); + s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[2]), vget_low_u16(s2_6)); + s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[3], s2_7); + s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[3]), vget_low_u16(s2_7)); + + s2acc = vaddq_u32(s2acc_0, s2acc); + s2acc_2 = vaddq_u32(s2acc_1, s2acc_2); + s2acc = vaddq_u32(s2acc, s2acc_2); + + uint32x2_t adacc2, s2acc2, as; + s2acc = vaddq_u32(s2acc, s3acc); + adacc2 = vpadd_u32(vget_low_u32(adacc), vget_high_u32(adacc)); + s2acc2 = vpadd_u32(vget_low_u32(s2acc), vget_high_u32(s2acc)); + as = vpadd_u32(adacc2, s2acc2); + s[0] = vget_lane_u32(as, 0); + s[1] = vget_lane_u32(as, 1); +} + +static void NEON_handle_tail(uint32_t *pair, const uint8_t *buf, size_t len) { + unsigned int i; + for (i = 0; i < len; ++i) { + pair[0] += buf[i]; + pair[1] += pair[0]; + } +} + +Z_INTERNAL uint32_t adler32_neon(uint32_t adler, const uint8_t *buf, size_t len) { + /* split Adler-32 into component sums */ + uint32_t sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) + return adler32_len_1(adler, buf, sum2); + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) + return adler32_len_16(adler, buf, len, sum2); + + uint32_t pair[2]; + int n = NMAX; + unsigned int done = 0; + + /* Split Adler-32 into component sums, it can be supplied by + * the caller sites (e.g. in a PNG file). + */ + pair[0] = adler; + pair[1] = sum2; + + /* If memory is not SIMD aligned, do scalar sums to an aligned + * offset, provided that doing so doesn't completely eliminate + * SIMD operation. Aligned loads are still faster on ARM, even + * though there's no explicit aligned load instruction */ + unsigned int align_offset = ((uintptr_t)buf & 15); + unsigned int align_adj = (align_offset) ? 16 - align_offset : 0; + + if (align_offset && len >= (16 + align_adj)) { + NEON_handle_tail(pair, buf, align_adj); + n -= align_adj; + done += align_adj; + + } else { + /* If here, we failed the len criteria test, it wouldn't be + * worthwhile to do scalar aligning sums */ + align_adj = 0; + } + + while (done < len) { + int remaining = (int)(len - done); + n = MIN(remaining, (done == align_adj) ? n : NMAX); + + if (n < 16) + break; + + NEON_accum32(pair, buf + done, n >> 4); + pair[0] %= BASE; + pair[1] %= BASE; + + int actual_nsums = (n >> 4) << 4; + done += actual_nsums; + } + + /* Handle the tail elements. */ + if (done < len) { + NEON_handle_tail(pair, (buf + done), len - done); + pair[0] %= BASE; + pair[1] %= BASE; + } + + /* D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. */ + return (pair[1] << 16) | pair[0]; +} + +#endif diff --git a/arch/arm/arm_features.c b/arch/arm/arm_features.c new file mode 100644 index 0000000000..d0d49764f4 --- /dev/null +++ b/arch/arm/arm_features.c @@ -0,0 +1,115 @@ +#include "zbuild.h" +#include "arm_features.h" + +#if defined(__linux__) && defined(HAVE_SYS_AUXV_H) +# include +# ifdef ARM_ASM_HWCAP +# include +# endif +#elif defined(__FreeBSD__) && defined(__aarch64__) +# include +# ifndef ID_AA64ISAR0_CRC32_VAL +# define ID_AA64ISAR0_CRC32_VAL ID_AA64ISAR0_CRC32 +# endif +#elif defined(__OpenBSD__) && defined(__aarch64__) +# include +# include +# include +# include +#elif defined(__APPLE__) +# if !defined(_DARWIN_C_SOURCE) +# define _DARWIN_C_SOURCE /* enable types aliases (eg u_int) */ +# endif +# include +#elif defined(_WIN32) +# include +#endif + +static int arm_has_crc32() { +#if defined(__linux__) && defined(ARM_AUXV_HAS_CRC32) +# ifdef HWCAP_CRC32 + return (getauxval(AT_HWCAP) & HWCAP_CRC32) != 0 ? 1 : 0; +# else + return (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0 ? 1 : 0; +# endif +#elif defined(__FreeBSD__) && defined(__aarch64__) + return getenv("QEMU_EMULATING") == NULL + && ID_AA64ISAR0_CRC32_VAL(READ_SPECIALREG(id_aa64isar0_el1)) >= ID_AA64ISAR0_CRC32_BASE; +#elif defined(__OpenBSD__) && defined(__aarch64__) + int hascrc32 = 0; + int isar0_mib[] = { CTL_MACHDEP, CPU_ID_AA64ISAR0 }; + uint64_t isar0 = 0; + size_t len = sizeof(isar0); + if (sysctl(isar0_mib, 2, &isar0, &len, NULL, 0) != -1) { + if (ID_AA64ISAR0_CRC32(isar0) >= ID_AA64ISAR0_CRC32_BASE) + hascrc32 = 1; + } + return hascrc32; +#elif defined(__APPLE__) + int hascrc32; + size_t size = sizeof(hascrc32); + return sysctlbyname("hw.optional.armv8_crc32", &hascrc32, &size, NULL, 0) == 0 + && hascrc32 == 1; +#elif defined(_WIN32) + return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); +#elif defined(ARM_NOCHECK_ACLE) + return 1; +#else + return 0; +#endif +} + +/* AArch64 has neon. */ +#if !defined(__aarch64__) && !defined(_M_ARM64) && !defined(_M_ARM64EC) +static inline int arm_has_neon() { +#if defined(__linux__) && defined(ARM_AUXV_HAS_NEON) +# ifdef HWCAP_ARM_NEON + return (getauxval(AT_HWCAP) & HWCAP_ARM_NEON) != 0 ? 1 : 0; +# else + return (getauxval(AT_HWCAP) & HWCAP_NEON) != 0 ? 1 : 0; +# endif +#elif defined(__APPLE__) + int hasneon; + size_t size = sizeof(hasneon); + return sysctlbyname("hw.optional.neon", &hasneon, &size, NULL, 0) == 0 + && hasneon == 1; +#elif defined(_M_ARM) && defined(WINAPI_FAMILY_PARTITION) +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) + return 1; /* Always supported */ +# endif +#endif + +#if defined(ARM_NOCHECK_NEON) + return 1; +#else + return 0; +#endif +} +#endif + +/* AArch64 does not have ARMv6 SIMD. */ +#if !defined(__aarch64__) && !defined(_M_ARM64) && !defined(_M_ARM64EC) +static inline int arm_has_simd() { +#if defined(__linux__) && defined(HAVE_SYS_AUXV_H) + const char *platform = (const char *)getauxval(AT_PLATFORM); + return strncmp(platform, "v6l", 3) == 0 + || strncmp(platform, "v7l", 3) == 0 + || strncmp(platform, "v8l", 3) == 0; +#elif defined(ARM_NOCHECK_SIMD) + return 1; +#else + return 0; +#endif +} +#endif + +void Z_INTERNAL arm_check_features(struct arm_cpu_features *features) { +#if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) + features->has_simd = 0; /* never available */ + features->has_neon = 1; /* always available */ +#else + features->has_simd = arm_has_simd(); + features->has_neon = arm_has_neon(); +#endif + features->has_crc32 = arm_has_crc32(); +} diff --git a/arch/arm/arm_features.h b/arch/arm/arm_features.h new file mode 100644 index 0000000000..d968e02fbb --- /dev/null +++ b/arch/arm/arm_features.h @@ -0,0 +1,16 @@ +/* arm_features.h -- check for ARM features. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef ARM_FEATURES_H_ +#define ARM_FEATURES_H_ + +struct arm_cpu_features { + int has_simd; + int has_neon; + int has_crc32; +}; + +void Z_INTERNAL arm_check_features(struct arm_cpu_features *features); + +#endif /* ARM_FEATURES_H_ */ diff --git a/arch/arm/arm_functions.h b/arch/arm/arm_functions.h new file mode 100644 index 0000000000..b256c37bff --- /dev/null +++ b/arch/arm/arm_functions.h @@ -0,0 +1,65 @@ +/* arm_functions.h -- ARM implementations for arch-specific functions. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef ARM_FUNCTIONS_H_ +#define ARM_FUNCTIONS_H_ + +#ifdef ARM_NEON +uint32_t adler32_neon(uint32_t adler, const uint8_t *buf, size_t len); +uint32_t chunksize_neon(void); +uint8_t* chunkmemset_safe_neon(uint8_t *out, uint8_t *from, unsigned len, unsigned left); + +# ifdef HAVE_BUILTIN_CTZLL +uint32_t compare256_neon(const uint8_t *src0, const uint8_t *src1); +uint32_t longest_match_neon(deflate_state *const s, Pos cur_match); +uint32_t longest_match_slow_neon(deflate_state *const s, Pos cur_match); +# endif +void slide_hash_neon(deflate_state *s); +void inflate_fast_neon(PREFIX3(stream) *strm, uint32_t start); +#endif + +#ifdef ARM_ACLE +uint32_t crc32_acle(uint32_t crc, const uint8_t *buf, size_t len); +#endif + +#ifdef ARM_SIMD +void slide_hash_armv6(deflate_state *s); +#endif + + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +// ARM - SIMD +# if (defined(ARM_SIMD) && defined(__ARM_FEATURE_SIMD32)) || defined(ARM_NOCHECK_SIMD) +# undef native_slide_hash +# define native_slide_hash slide_hash_armv6 +# endif +// ARM - NEON +# if (defined(ARM_NEON) && (defined(__ARM_NEON__) || defined(__ARM_NEON))) || ARM_NOCHECK_NEON +# undef native_adler32 +# define native_adler32 adler32_neon +# undef native_chunkmemset_safe +# define native_chunkmemset_safe chunkmemset_safe_neon +# undef native_chunksize +# define native_chunksize chunksize_neon +# undef native_inflate_fast +# define native_inflate_fast inflate_fast_neon +# undef native_slide_hash +# define native_slide_hash slide_hash_neon +# ifdef HAVE_BUILTIN_CTZLL +# undef native_compare256 +# define native_compare256 compare256_neon +# undef native_longest_match +# define native_longest_match longest_match_neon +# undef native_longest_match_slow +# define native_longest_match_slow longest_match_slow_neon +# endif +# endif +// ARM - ACLE +# if defined(ARM_ACLE) && (defined(__ARM_ACLE) || defined(__ARM_FEATURE_CRC32)) +# undef native_crc32 +# define native_crc32 crc32_acle +# endif +#endif + +#endif /* ARM_FUNCTIONS_H_ */ diff --git a/arch/arm/chunkset_neon.c b/arch/arm/chunkset_neon.c new file mode 100644 index 0000000000..68c9fef699 --- /dev/null +++ b/arch/arm/chunkset_neon.c @@ -0,0 +1,94 @@ +/* chunkset_neon.c -- NEON inline functions to copy small data chunks. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef ARM_NEON +#include "neon_intrins.h" +#include "zbuild.h" +#include "zmemory.h" +#include "arch/generic/chunk_permute_table.h" + +typedef uint8x16_t chunk_t; + +#define HAVE_CHUNKMEMSET_2 +#define HAVE_CHUNKMEMSET_4 +#define HAVE_CHUNKMEMSET_8 +#define HAVE_CHUNK_MAG + +static const lut_rem_pair perm_idx_lut[13] = { + {0, 1}, /* 3 */ + {0, 0}, /* don't care */ + {1 * 32, 1}, /* 5 */ + {2 * 32, 4}, /* 6 */ + {3 * 32, 2}, /* 7 */ + {0 * 32, 0}, /* don't care */ + {4 * 32, 7}, /* 9 */ + {5 * 32, 6}, /* 10 */ + {6 * 32, 5}, /* 11 */ + {7 * 32, 4}, /* 12 */ + {8 * 32, 3}, /* 13 */ + {9 * 32, 2}, /* 14 */ + {10 * 32, 1},/* 15 */ +}; + +static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { + *chunk = vreinterpretq_u8_u16(vdupq_n_u16(zng_memread_2(from))); +} + +static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { + *chunk = vreinterpretq_u8_u32(vdupq_n_u32(zng_memread_4(from))); +} + +static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { + *chunk = vreinterpretq_u8_u64(vdupq_n_u64(zng_memread_8(from))); +} + +#define CHUNKSIZE chunksize_neon +#define CHUNKCOPY chunkcopy_neon +#define CHUNKUNROLL chunkunroll_neon +#define CHUNKMEMSET chunkmemset_neon +#define CHUNKMEMSET_SAFE chunkmemset_safe_neon + +static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { + *chunk = vld1q_u8(s); +} + +static inline void storechunk(uint8_t *out, chunk_t *chunk) { + vst1q_u8(out, *chunk); +} + +static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, uint32_t *chunk_rem, uint32_t dist) { + lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; + *chunk_rem = lut_rem.remval; + + /* See note in chunkset_ssse3.c for why this is ok */ + __msan_unpoison(buf + dist, 16 - dist); + + /* This version of table is only available on aarch64 */ +#if defined(_M_ARM64) || defined(_M_ARM64EC) || defined(__aarch64__) + uint8x16_t ret_vec = vld1q_u8(buf); + + uint8x16_t perm_vec = vld1q_u8(permute_table + lut_rem.idx); + return vqtbl1q_u8(ret_vec, perm_vec); +#else + uint8x8_t ret0, ret1, a, b, perm_vec0, perm_vec1; + perm_vec0 = vld1_u8(permute_table + lut_rem.idx); + perm_vec1 = vld1_u8(permute_table + lut_rem.idx + 8); + a = vld1_u8(buf); + b = vld1_u8(buf + 8); + ret0 = vtbl1_u8(a, perm_vec0); + uint8x8x2_t ab; + ab.val[0] = a; + ab.val[1] = b; + ret1 = vtbl2_u8(ab, perm_vec1); + return vcombine_u8(ret0, ret1); +#endif +} + +#include "chunkset_tpl.h" + +#define INFLATE_FAST inflate_fast_neon + +#include "inffast_tpl.h" + +#endif diff --git a/arch/arm/compare256_neon.c b/arch/arm/compare256_neon.c new file mode 100644 index 0000000000..3d05152f34 --- /dev/null +++ b/arch/arm/compare256_neon.c @@ -0,0 +1,60 @@ +/* compare256_neon.c - NEON version of compare256 + * Copyright (C) 2022 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zmemory.h" +#include "deflate.h" +#include "fallback_builtins.h" + +#if defined(ARM_NEON) && defined(HAVE_BUILTIN_CTZLL) +#include "neon_intrins.h" + +static inline uint32_t compare256_neon_static(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0; + + do { + uint8x16_t a, b, cmp; + uint64_t lane; + + a = vld1q_u8(src0); + b = vld1q_u8(src1); + + cmp = veorq_u8(a, b); + + lane = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 0); + if (lane) { + uint32_t match_byte = (uint32_t)__builtin_ctzll(lane) / 8; + return len + match_byte; + } + len += 8; + lane = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 1); + if (lane) { + uint32_t match_byte = (uint32_t)__builtin_ctzll(lane) / 8; + return len + match_byte; + } + len += 8; + + src0 += 16, src1 += 16; + } while (len < 256); + + return 256; +} + +Z_INTERNAL uint32_t compare256_neon(const uint8_t *src0, const uint8_t *src1) { + return compare256_neon_static(src0, src1); +} + +#define LONGEST_MATCH longest_match_neon +#define COMPARE256 compare256_neon_static + +#include "match_tpl.h" + +#define LONGEST_MATCH_SLOW +#define LONGEST_MATCH longest_match_slow_neon +#define COMPARE256 compare256_neon_static + +#include "match_tpl.h" + +#endif diff --git a/arch/arm/crc32_acle.c b/arch/arm/crc32_acle.c new file mode 100644 index 0000000000..a3a1fefc03 --- /dev/null +++ b/arch/arm/crc32_acle.c @@ -0,0 +1,76 @@ +/* crc32_acle.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler + * Copyright (C) 2016 Yang Zhang + * For conditions of distribution and use, see copyright notice in zlib.h + * +*/ + +#ifdef ARM_ACLE +#include "acle_intrins.h" +#include "zbuild.h" + +Z_INTERNAL Z_TARGET_CRC uint32_t crc32_acle(uint32_t crc, const uint8_t *buf, size_t len) { + Z_REGISTER uint32_t c; + Z_REGISTER uint16_t buf2; + Z_REGISTER uint32_t buf4; + Z_REGISTER uint64_t buf8; + + c = ~crc; + + if (UNLIKELY(len == 1)) { + c = __crc32b(c, *buf); + c = ~c; + return c; + } + + if ((ptrdiff_t)buf & (sizeof(uint64_t) - 1)) { + if (len && ((ptrdiff_t)buf & 1)) { + c = __crc32b(c, *buf++); + len--; + } + + if ((len >= sizeof(uint16_t)) && ((ptrdiff_t)buf & (sizeof(uint32_t) - 1))) { + buf2 = *((uint16_t*)buf); + c = __crc32h(c, buf2); + buf += sizeof(uint16_t); + len -= sizeof(uint16_t); + } + + if ((len >= sizeof(uint32_t)) && ((ptrdiff_t)buf & (sizeof(uint64_t) - 1))) { + buf4 = *((uint32_t*)buf); + c = __crc32w(c, buf4); + len -= sizeof(uint32_t); + buf += sizeof(uint32_t); + } + + } + + while (len >= sizeof(uint64_t)) { + buf8 = *((uint64_t*)buf); + c = __crc32d(c, buf8); + len -= sizeof(uint64_t); + buf += sizeof(uint64_t); + } + + if (len >= sizeof(uint32_t)) { + buf4 = *((uint32_t*)buf); + c = __crc32w(c, buf4); + len -= sizeof(uint32_t); + buf += sizeof(uint32_t); + } + + if (len >= sizeof(uint16_t)) { + buf2 = *((uint16_t*)buf); + c = __crc32h(c, buf2); + len -= sizeof(uint16_t); + buf += sizeof(uint16_t); + } + + if (len) { + c = __crc32b(c, *buf); + } + + c = ~c; + return c; +} +#endif diff --git a/arch/arm/neon_intrins.h b/arch/arm/neon_intrins.h new file mode 100644 index 0000000000..5dc242d521 --- /dev/null +++ b/arch/arm/neon_intrins.h @@ -0,0 +1,65 @@ +#ifndef ARM_NEON_INTRINS_H +#define ARM_NEON_INTRINS_H + +#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC)) +/* arm64_neon.h is MSVC specific */ +# include +#else +# include +#endif + +#if defined(ARM_NEON) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(_M_ARM64EC) +/* Compatibility shim for the _high family of functions */ +#define vmull_high_u8(a, b) vmull_u8(vget_high_u8(a), vget_high_u8(b)) +#define vmlal_high_u8(a, b, c) vmlal_u8(a, vget_high_u8(b), vget_high_u8(c)) +#define vmlal_high_u16(a, b, c) vmlal_u16(a, vget_high_u16(b), vget_high_u16(c)) +#define vaddw_high_u8(a, b) vaddw_u8(a, vget_high_u8(b)) +#endif + +#ifdef ARM_NEON + +#define vqsubq_u16_x4_x1(out, a, b) do { \ + out.val[0] = vqsubq_u16(a.val[0], b); \ + out.val[1] = vqsubq_u16(a.val[1], b); \ + out.val[2] = vqsubq_u16(a.val[2], b); \ + out.val[3] = vqsubq_u16(a.val[3], b); \ +} while (0) + +# if defined(__clang__) && defined(__arm__) && defined(__ANDROID__) +/* Clang for 32-bit Android has too strict alignment requirement (:256) for x4 NEON intrinsics */ +# undef ARM_NEON_HASLD4 +# undef vld1q_u16_x4 +# undef vld1q_u8_x4 +# undef vst1q_u16_x4 +# endif + +# ifndef ARM_NEON_HASLD4 + +static inline uint16x8x4_t vld1q_u16_x4(uint16_t const *a) { + uint16x8x4_t ret; + ret.val[0] = vld1q_u16(a); + ret.val[1] = vld1q_u16(a+8); + ret.val[2] = vld1q_u16(a+16); + ret.val[3] = vld1q_u16(a+24); + return ret; +} + +static inline uint8x16x4_t vld1q_u8_x4(uint8_t const *a) { + uint8x16x4_t ret; + ret.val[0] = vld1q_u8(a); + ret.val[1] = vld1q_u8(a+16); + ret.val[2] = vld1q_u8(a+32); + ret.val[3] = vld1q_u8(a+48); + return ret; +} + +static inline void vst1q_u16_x4(uint16_t *p, uint16x8x4_t a) { + vst1q_u16(p, a.val[0]); + vst1q_u16(p + 8, a.val[1]); + vst1q_u16(p + 16, a.val[2]); + vst1q_u16(p + 24, a.val[3]); +} +# endif // HASLD4 check +#endif + +#endif // include guard ARM_NEON_INTRINS_H diff --git a/arch/arm/slide_hash_armv6.c b/arch/arm/slide_hash_armv6.c new file mode 100644 index 0000000000..da4f51e0af --- /dev/null +++ b/arch/arm/slide_hash_armv6.c @@ -0,0 +1,48 @@ +/* slide_hash_armv6.c -- Optimized hash table shifting for ARMv6 with support for SIMD instructions + * Copyright (C) 2023 Cameron Cawley + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#if defined(ARM_SIMD) +#include "acle_intrins.h" +#include "zbuild.h" +#include "deflate.h" + +/* SIMD version of hash_chain rebase */ +static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) { + Z_REGISTER uint16x2_t v; + uint16x2_t p0, p1, p2, p3; + Z_REGISTER size_t n; + + size_t size = entries*sizeof(table[0]); + Assert((size % (sizeof(uint16x2_t) * 4) == 0), "hash table size err"); + + Assert(sizeof(Pos) == 2, "Wrong Pos size"); + v = wsize | (wsize << 16); + + n = size / (sizeof(uint16x2_t) * 4); + do { + p0 = *((const uint16x2_t *)(table)); + p1 = *((const uint16x2_t *)(table+2)); + p2 = *((const uint16x2_t *)(table+4)); + p3 = *((const uint16x2_t *)(table+6)); + p0 = __uqsub16(p0, v); + p1 = __uqsub16(p1, v); + p2 = __uqsub16(p2, v); + p3 = __uqsub16(p3, v); + *((uint16x2_t *)(table)) = p0; + *((uint16x2_t *)(table+2)) = p1; + *((uint16x2_t *)(table+4)) = p2; + *((uint16x2_t *)(table+6)) = p3; + table += 8; + } while (--n); +} + +Z_INTERNAL void slide_hash_armv6(deflate_state *s) { + Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + uint16_t wsize = (uint16_t)s->w_size; + + slide_hash_chain(s->head, HASH_SIZE, wsize); + slide_hash_chain(s->prev, wsize, wsize); +} +#endif diff --git a/arch/arm/slide_hash_neon.c b/arch/arm/slide_hash_neon.c new file mode 100644 index 0000000000..f319f98790 --- /dev/null +++ b/arch/arm/slide_hash_neon.c @@ -0,0 +1,47 @@ +/* slide_hash_neon.c -- Optimized hash table shifting for ARM with support for NEON instructions + * Copyright (C) 2017-2020 Mika T. Lindqvist + * + * Authors: + * Mika T. Lindqvist + * Jun He + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef ARM_NEON +#include "neon_intrins.h" +#include "zbuild.h" +#include "deflate.h" + +/* SIMD version of hash_chain rebase */ +static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) { + Z_REGISTER uint16x8_t v; + uint16x8x4_t p0, p1; + Z_REGISTER size_t n; + + size_t size = entries*sizeof(table[0]); + Assert((size % sizeof(uint16x8_t) * 8 == 0), "hash table size err"); + + Assert(sizeof(Pos) == 2, "Wrong Pos size"); + v = vdupq_n_u16(wsize); + + n = size / (sizeof(uint16x8_t) * 8); + do { + p0 = vld1q_u16_x4(table); + p1 = vld1q_u16_x4(table+32); + vqsubq_u16_x4_x1(p0, p0, v); + vqsubq_u16_x4_x1(p1, p1, v); + vst1q_u16_x4(table, p0); + vst1q_u16_x4(table+32, p1); + table += 64; + } while (--n); +} + +Z_INTERNAL void slide_hash_neon(deflate_state *s) { + Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + uint16_t wsize = (uint16_t)s->w_size; + + slide_hash_chain(s->head, HASH_SIZE, wsize); + slide_hash_chain(s->prev, wsize, wsize); +} +#endif diff --git a/arch/generic/Makefile.in b/arch/generic/Makefile.in new file mode 100644 index 0000000000..2522d7d0cb --- /dev/null +++ b/arch/generic/Makefile.in @@ -0,0 +1,75 @@ +# Makefile for zlib-ng +# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler +# Copyright (C) 2024 Hans Kristian Rosbach +# For conditions of distribution and use, see copyright notice in zlib.h + +CC= +CFLAGS= +SFLAGS= +INCLUDES= + +SRCDIR=. +SRCTOP=../.. +TOPDIR=$(SRCTOP) + +all: \ + adler32_c.o adler32_c.lo \ + adler32_fold_c.o adler32_fold_c.lo \ + chunkset_c.o chunkset_c.lo \ + compare256_c.o compare256_c.lo \ + crc32_braid_c.o crc32_braid_c.lo \ + crc32_fold_c.o crc32_fold_c.lo \ + slide_hash_c.o slide_hash_c.lo + + +adler32_c.o: $(SRCDIR)/adler32_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/adler32_p.h + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_c.c + +adler32_c.lo: $(SRCDIR)/adler32_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/adler32_p.h + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_c.c + +adler32_fold_c.o: $(SRCDIR)/adler32_fold_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/functable.h + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_fold_c.c + +adler32_fold_c.lo: $(SRCDIR)/adler32_fold_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/functable.h + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_fold_c.c + +chunkset_c.o: $(SRCDIR)/chunkset_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/chunkset_tpl.h $(SRCTOP)/inffast_tpl.h + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_c.c + +chunkset_c.lo: $(SRCDIR)/chunkset_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/chunkset_tpl.h $(SRCTOP)/inffast_tpl.h + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_c.c + +compare256_c.o: $(SRCDIR)/compare256_c.c $(SRCTOP)/zbuild.h $(SRCDIR)/compare256_p.h $(SRCTOP)/zmemory.h $(SRCTOP)/deflate.h $(SRCTOP)/fallback_builtins.h + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_c.c + +compare256_c.lo: $(SRCDIR)/compare256_c.c $(SRCTOP)/zbuild.h $(SRCDIR)/compare256_p.h $(SRCTOP)/zmemory.h $(SRCTOP)/deflate.h $(SRCTOP)/fallback_builtins.h + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_c.c + +crc32_braid_c.o: $(SRCDIR)/crc32_braid_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/crc32_braid_p.h $(SRCTOP)/crc32_braid_tbl.h + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_braid_c.c + +crc32_braid_c.lo: $(SRCDIR)/crc32_braid_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/crc32_braid_p.h $(SRCTOP)/crc32_braid_tbl.h + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_braid_c.c + +crc32_fold_c.o: $(SRCDIR)/crc32_fold_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/functable.h + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_fold_c.c + +crc32_fold_c.lo: $(SRCDIR)/crc32_fold_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/functable.h + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_fold_c.c + +slide_hash_c.o: $(SRCDIR)/slide_hash_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/deflate.h + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_c.c + +slide_hash_c.lo: $(SRCDIR)/slide_hash_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/deflate.h + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_c.c + + +mostlyclean: clean +clean: + rm -f *.o *.lo *~ + rm -rf objs + rm -f *.gcda *.gcno *.gcov + +distclean: clean + rm -f Makefile diff --git a/arch/generic/adler32_c.c b/arch/generic/adler32_c.c new file mode 100644 index 0000000000..64258c89b4 --- /dev/null +++ b/arch/generic/adler32_c.c @@ -0,0 +1,54 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "functable.h" +#include "adler32_p.h" + +/* ========================================================================= */ +Z_INTERNAL uint32_t adler32_c(uint32_t adler, const uint8_t *buf, size_t len) { + uint32_t sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (UNLIKELY(len == 1)) + return adler32_len_1(adler, buf, sum2); + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (UNLIKELY(buf == NULL)) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (UNLIKELY(len < 16)) + return adler32_len_16(adler, buf, len, sum2); + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; +#ifdef UNROLL_MORE + n = NMAX / 16; /* NMAX is divisible by 16 */ +#else + n = NMAX / 8; /* NMAX is divisible by 8 */ +#endif + do { +#ifdef UNROLL_MORE + DO16(adler, sum2, buf); /* 16 sums unrolled */ + buf += 16; +#else + DO8(adler, sum2, buf, 0); /* 8 sums unrolled */ + buf += 8; +#endif + } while (--n); + adler %= BASE; + sum2 %= BASE; + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + return adler32_len_64(adler, buf, len, sum2); +} diff --git a/arch/generic/adler32_fold_c.c b/arch/generic/adler32_fold_c.c new file mode 100644 index 0000000000..397dd10400 --- /dev/null +++ b/arch/generic/adler32_fold_c.c @@ -0,0 +1,15 @@ +/* adler32_fold.c -- adler32 folding interface + * Copyright (C) 2022 Adam Stylinski + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "functable.h" + +#include + +Z_INTERNAL uint32_t adler32_fold_copy_c(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { + adler = FUNCTABLE_CALL(adler32)(adler, src, len); + memcpy(dst, src, len); + return adler; +} diff --git a/arch/generic/chunk_permute_table.h b/arch/generic/chunk_permute_table.h new file mode 100644 index 0000000000..bad66ccc77 --- /dev/null +++ b/arch/generic/chunk_permute_table.h @@ -0,0 +1,53 @@ +/* chunk_permute_table.h - shared AVX/SSSE3 permutation table for use with chunkmemset family of functions. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef CHUNK_PERMUTE_TABLE_H_ +#define CHUNK_PERMUTE_TABLE_H_ + +#include "zbuild.h" + +/* Need entries for all numbers not an even modulus for 1, 2, 4, 8, 16 & 32 */ +static const ALIGNED_(32) uint8_t permute_table[26*32] = { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, /* dist 3 */ + 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, /* dist 5 */ + 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, /* dist 6 */ + 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, /* dist 7 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, /* dist 9 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, /* dist 10 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* dist 11 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, /* dist 12 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, /* dist 13 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1, 2, 3, /* dist 14 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 1, /* dist 15 */ + + /* Beyond dists of 15 means we have to permute from a vector > len(m128i). Because AVX couldn't permute + * beyond 128 bit lanes until AVX512 for sub 4-byte sequences, we have to do some math here for an eventual + * blend with a comparison. That means we need to wrap the indices with yet another derived table. For simplicity, + * we'll use absolute indexing here to derive a blend vector. This is actually a lot simpler with ARM's TBL, but, + * this is what we're dealt. + */ + + 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* dist 17 */ + 16, 17, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, /* dist 18 */ + 16, 17, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, /* dist 19 */ + 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* dist 20 */ + 16, 17, 18, 19, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, /* dist 21 */ + 16, 17, 18, 19, 20, 21, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* dist 22 */ + 16, 17, 18, 19, 20, 21, 22, 0, 1, 2, 3, 4, 5, 6, 7, 8, /* dist 23 */ + 16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5, 6, 7, /* dist 24 */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 1, 2, 3, 4, 5, 6, /* dist 25 */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 1, 2, 3, 4, 5, /* dist 26 */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 1, 2, 3, 4, /* dist 27 */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0, 1, 2, 3, /* dist 28 */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 1, 2, /* dist 29 */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 1, /* dist 30 */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 0, /* dist 31 */ +}; + +typedef struct lut_rem_pair_s { + uint16_t idx; + uint16_t remval; +} lut_rem_pair; + +#endif diff --git a/arch/generic/chunkset_c.c b/arch/generic/chunkset_c.c new file mode 100644 index 0000000000..0a585e6caa --- /dev/null +++ b/arch/generic/chunkset_c.c @@ -0,0 +1,42 @@ +/* chunkset.c -- inline functions to copy small data chunks. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zmemory.h" + +typedef uint64_t chunk_t; + +#define CHUNK_SIZE 8 + +#define HAVE_CHUNKMEMSET_4 +#define HAVE_CHUNKMEMSET_8 + +static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { + uint32_t tmp = zng_memread_4(from); + *chunk = tmp | ((chunk_t)tmp << 32); +} + +static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { + *chunk = zng_memread_8(from); +} + +static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { + *chunk = zng_memread_8(s); +} + +static inline void storechunk(uint8_t *out, chunk_t *chunk) { + zng_memwrite_8(out, *chunk); +} + +#define CHUNKSIZE chunksize_c +#define CHUNKCOPY chunkcopy_c +#define CHUNKUNROLL chunkunroll_c +#define CHUNKMEMSET chunkmemset_c +#define CHUNKMEMSET_SAFE chunkmemset_safe_c + +#include "chunkset_tpl.h" + +#define INFLATE_FAST inflate_fast_c + +#include "inffast_tpl.h" diff --git a/arch/generic/compare256_c.c b/arch/generic/compare256_c.c new file mode 100644 index 0000000000..ad535523a5 --- /dev/null +++ b/arch/generic/compare256_c.c @@ -0,0 +1,31 @@ +/* compare256.c -- 256 byte memory comparison with match length return + * Copyright (C) 2020 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "compare256_p.h" + +// Set optimal COMPARE256 function variant +#if OPTIMAL_CMP == 8 +# define COMPARE256 compare256_8 +#elif defined(HAVE_BUILTIN_CTZLL) +# define COMPARE256 compare256_64 +#elif defined(HAVE_BUILTIN_CTZ) +# define COMPARE256 compare256_32 +#else +# define COMPARE256 compare256_16 +#endif + +Z_INTERNAL uint32_t compare256_c(const uint8_t *src0, const uint8_t *src1) { + return COMPARE256(src0, src1); +} + +// Generate longest_match_c +#define LONGEST_MATCH longest_match_c +#include "match_tpl.h" + +// Generate longest_match_slow_c +#define LONGEST_MATCH_SLOW +#define LONGEST_MATCH longest_match_slow_c +#include "match_tpl.h" diff --git a/arch/generic/compare256_p.h b/arch/generic/compare256_p.h new file mode 100644 index 0000000000..ac934841d4 --- /dev/null +++ b/arch/generic/compare256_p.h @@ -0,0 +1,123 @@ +/* compare256_p.h -- 256 byte memory comparison with match length return + * Copyright (C) 2020 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zmemory.h" +#include "deflate.h" +#include "fallback_builtins.h" + +/* 8-bit integer comparison */ +static inline uint32_t compare256_8(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0; + + do { + if (*src0 != *src1) + return len; + src0 += 1, src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src0 += 1, src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src0 += 1, src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src0 += 1, src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src0 += 1, src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src0 += 1, src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src0 += 1, src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src0 += 1, src1 += 1, len += 1; + } while (len < 256); + + return 256; +} + +/* 16-bit integer comparison */ +static inline uint32_t compare256_16(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0; + + do { + if (zng_memcmp_2(src0, src1) != 0) + return len + (*src0 == *src1); + src0 += 2, src1 += 2, len += 2; + + if (zng_memcmp_2(src0, src1) != 0) + return len + (*src0 == *src1); + src0 += 2, src1 += 2, len += 2; + + if (zng_memcmp_2(src0, src1) != 0) + return len + (*src0 == *src1); + src0 += 2, src1 += 2, len += 2; + + if (zng_memcmp_2(src0, src1) != 0) + return len + (*src0 == *src1); + src0 += 2, src1 += 2, len += 2; + } while (len < 256); + + return 256; +} + +#ifdef HAVE_BUILTIN_CTZ +/* 32-bit integer comparison */ +static inline uint32_t compare256_32(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0; + + do { + uint32_t sv, mv, diff; + + sv = zng_memread_4(src0); + mv = zng_memread_4(src1); + + diff = sv ^ mv; + if (diff) { +# if BYTE_ORDER == LITTLE_ENDIAN + uint32_t match_byte = __builtin_ctz(diff) / 8; +# else + uint32_t match_byte = __builtin_clz(diff) / 8; +# endif + return len + match_byte; + } + + src0 += 4, src1 += 4, len += 4; + } while (len < 256); + + return 256; +} +#endif + +#ifdef HAVE_BUILTIN_CTZLL +/* 64-bit integer comparison */ +static inline uint32_t compare256_64(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0; + + do { + uint64_t sv, mv, diff; + + sv = zng_memread_8(src0); + mv = zng_memread_8(src1); + + diff = sv ^ mv; + if (diff) { +# if BYTE_ORDER == LITTLE_ENDIAN + uint64_t match_byte = __builtin_ctzll(diff) / 8; +# else + uint64_t match_byte = __builtin_clzll(diff) / 8; +# endif + return len + (uint32_t)match_byte; + } + + src0 += 8, src1 += 8, len += 8; + } while (len < 256); + + return 256; +} +#endif diff --git a/arch/generic/crc32_braid_c.c b/arch/generic/crc32_braid_c.c new file mode 100644 index 0000000000..f80071042d --- /dev/null +++ b/arch/generic/crc32_braid_c.c @@ -0,0 +1,216 @@ +/* crc32_braid.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * This interleaved implementation of a CRC makes use of pipelined multiple + * arithmetic-logic units, commonly found in modern CPU cores. It is due to + * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. + */ + +#include "zbuild.h" +#include "crc32_braid_p.h" +#include "crc32_braid_tbl.h" + +/* + A CRC of a message is computed on N braids of words in the message, where + each word consists of W bytes (4 or 8). If N is 3, for example, then three + running sparse CRCs are calculated respectively on each braid, at these + indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ... + This is done starting at a word boundary, and continues until as many blocks + of N * W bytes as are available have been processed. The results are combined + into a single CRC at the end. For this code, N must be in the range 1..6 and + W must be 4 or 8. The upper limit on N can be increased if desired by adding + more #if blocks, extending the patterns apparent in the code. In addition, + crc32 tables would need to be regenerated, if the maximum N value is increased. + + N and W are chosen empirically by benchmarking the execution time on a given + processor. The choices for N and W below were based on testing on Intel Kaby + Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64 + Octeon II processors. The Intel, AMD, and ARM processors were all fastest + with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4. + They were all tested with either gcc or clang, all using the -O3 optimization + level. Your mileage may vary. +*/ + +/* ========================================================================= */ +#ifdef W +/* + Return the CRC of the W bytes in the word_t data, taking the + least-significant byte of the word as the first byte of data, without any pre + or post conditioning. This is used to combine the CRCs of each braid. + */ +#if BYTE_ORDER == LITTLE_ENDIAN +static uint32_t crc_word(z_word_t data) { + int k; + for (k = 0; k < W; k++) + data = (data >> 8) ^ crc_table[data & 0xff]; + return (uint32_t)data; +} +#elif BYTE_ORDER == BIG_ENDIAN +static z_word_t crc_word(z_word_t data) { + int k; + for (k = 0; k < W; k++) + data = (data << 8) ^ + crc_big_table[(data >> ((W - 1) << 3)) & 0xff]; + return data; +} +#endif /* BYTE_ORDER */ + +#endif /* W */ + +/* ========================================================================= */ +Z_INTERNAL uint32_t PREFIX(crc32_braid)(uint32_t crc, const uint8_t *buf, size_t len) { + uint32_t c; + + /* Pre-condition the CRC */ + c = (~crc) & 0xffffffff; + +#ifdef W + /* If provided enough bytes, do a braided CRC calculation. */ + if (len >= N * W + W - 1) { + size_t blks; + z_word_t const *words; + int k; + + /* Compute the CRC up to a z_word_t boundary. */ + while (len && ((uintptr_t)buf & (W - 1)) != 0) { + len--; + DO1; + } + + /* Compute the CRC on as many N z_word_t blocks as are available. */ + blks = len / (N * W); + len -= blks * N * W; + words = (z_word_t const *)buf; + + z_word_t crc0, word0, comb; +#if N > 1 + z_word_t crc1, word1; +#if N > 2 + z_word_t crc2, word2; +#if N > 3 + z_word_t crc3, word3; +#if N > 4 + z_word_t crc4, word4; +#if N > 5 + z_word_t crc5, word5; +#endif +#endif +#endif +#endif +#endif + /* Initialize the CRC for each braid. */ + crc0 = ZSWAPWORD(c); +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + /* Process the first blks-1 blocks, computing the CRCs on each braid independently. */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should get unrolled. */ + crc0 = BRAID_TABLE[0][word0 & 0xff]; +#if N > 1 + crc1 = BRAID_TABLE[0][word1 & 0xff]; +#if N > 2 + crc2 = BRAID_TABLE[0][word2 & 0xff]; +#if N > 3 + crc3 = BRAID_TABLE[0][word3 & 0xff]; +#if N > 4 + crc4 = BRAID_TABLE[0][word4 & 0xff]; +#if N > 5 + crc5 = BRAID_TABLE[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= BRAID_TABLE[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= BRAID_TABLE[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= BRAID_TABLE[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= BRAID_TABLE[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= BRAID_TABLE[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= BRAID_TABLE[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* Process the last block, combining the CRCs of the N braids at the same time. */ + comb = crc_word(crc0 ^ words[0]); +#if N > 1 + comb = crc_word(crc1 ^ words[1] ^ comb); +#if N > 2 + comb = crc_word(crc2 ^ words[2] ^ comb); +#if N > 3 + comb = crc_word(crc3 ^ words[3] ^ comb); +#if N > 4 + comb = crc_word(crc4 ^ words[4] ^ comb); +#if N > 5 + comb = crc_word(crc5 ^ words[5] ^ comb); +#endif +#endif +#endif +#endif +#endif + words += N; + Assert(comb <= UINT32_MAX, "comb should fit in uint32_t"); + c = (uint32_t)ZSWAPWORD(comb); + + /* Update the pointer to the remaining bytes to process. */ + buf = (const unsigned char *)words; + } + +#endif /* W */ + + /* Complete the computation of the CRC on any remaining bytes. */ + while (len >= 8) { + len -= 8; + DO8; + } + while (len) { + len--; + DO1; + } + + /* Return the CRC, post-conditioned. */ + return c ^ 0xffffffff; +} diff --git a/arch/generic/crc32_fold_c.c b/arch/generic/crc32_fold_c.c new file mode 100644 index 0000000000..43930e97c6 --- /dev/null +++ b/arch/generic/crc32_fold_c.c @@ -0,0 +1,31 @@ +/* crc32_fold.c -- crc32 folding interface + * Copyright (C) 2021 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#include "zbuild.h" +#include "zutil.h" +#include "functable.h" +#include "crc32.h" + +Z_INTERNAL uint32_t crc32_fold_reset_c(crc32_fold *crc) { + crc->value = CRC32_INITIAL_VALUE; + return crc->value; +} + +Z_INTERNAL void crc32_fold_copy_c(crc32_fold *crc, uint8_t *dst, const uint8_t *src, size_t len) { + crc->value = FUNCTABLE_CALL(crc32)(crc->value, src, len); + memcpy(dst, src, len); +} + +Z_INTERNAL void crc32_fold_c(crc32_fold *crc, const uint8_t *src, size_t len, uint32_t init_crc) { + /* Note: while this is basically the same thing as the vanilla CRC function, we still need + * a functable entry for it so that we can generically dispatch to this function with the + * same arguments for the versions that _do_ do a folding CRC but we don't want a copy. The + * init_crc is an unused argument in this context */ + Z_UNUSED(init_crc); + crc->value = FUNCTABLE_CALL(crc32)(crc->value, src, len); +} + +Z_INTERNAL uint32_t crc32_fold_final_c(crc32_fold *crc) { + return crc->value; +} diff --git a/arch/generic/generic_functions.h b/arch/generic/generic_functions.h new file mode 100644 index 0000000000..b0366baece --- /dev/null +++ b/arch/generic/generic_functions.h @@ -0,0 +1,57 @@ +/* generic_functions.h -- generic C implementations for arch-specific functions. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef GENERIC_FUNCTIONS_H_ +#define GENERIC_FUNCTIONS_H_ + +#include "zendian.h" + +Z_INTERNAL uint32_t crc32_fold_reset_c(crc32_fold *crc); +Z_INTERNAL void crc32_fold_copy_c(crc32_fold *crc, uint8_t *dst, const uint8_t *src, size_t len); +Z_INTERNAL void crc32_fold_c(crc32_fold *crc, const uint8_t *src, size_t len, uint32_t init_crc); +Z_INTERNAL uint32_t crc32_fold_final_c(crc32_fold *crc); + +Z_INTERNAL uint32_t adler32_fold_copy_c(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); + + +typedef uint32_t (*adler32_func)(uint32_t adler, const uint8_t *buf, size_t len); +typedef uint32_t (*compare256_func)(const uint8_t *src0, const uint8_t *src1); +typedef uint32_t (*crc32_func)(uint32_t crc32, const uint8_t *buf, size_t len); + +uint32_t adler32_c(uint32_t adler, const uint8_t *buf, size_t len); + +uint32_t chunksize_c(void); +uint8_t* chunkmemset_safe_c(uint8_t *out, uint8_t *from, unsigned len, unsigned left); +void inflate_fast_c(PREFIX3(stream) *strm, uint32_t start); + +uint32_t PREFIX(crc32_braid)(uint32_t crc, const uint8_t *buf, size_t len); + +uint32_t compare256_c(const uint8_t *src0, const uint8_t *src1); + +typedef void (*slide_hash_func)(deflate_state *s); + +void slide_hash_c(deflate_state *s); + +uint32_t longest_match_c(deflate_state *const s, Pos cur_match); +uint32_t longest_match_slow_c(deflate_state *const s, Pos cur_match); + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +// Generic code +# define native_adler32 adler32_c +# define native_adler32_fold_copy adler32_fold_copy_c +# define native_chunkmemset_safe chunkmemset_safe_c +# define native_chunksize chunksize_c +# define native_crc32 PREFIX(crc32_braid) +# define native_crc32_fold crc32_fold_c +# define native_crc32_fold_copy crc32_fold_copy_c +# define native_crc32_fold_final crc32_fold_final_c +# define native_crc32_fold_reset crc32_fold_reset_c +# define native_inflate_fast inflate_fast_c +# define native_slide_hash slide_hash_c +# define native_longest_match longest_match_c +# define native_longest_match_slow longest_match_slow_c +# define native_compare256 compare256_c +#endif + +#endif diff --git a/arch/generic/slide_hash_c.c b/arch/generic/slide_hash_c.c new file mode 100644 index 0000000000..8345b9e36b --- /dev/null +++ b/arch/generic/slide_hash_c.c @@ -0,0 +1,52 @@ +/* slide_hash.c -- slide hash table C implementation + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "deflate.h" + +/* =========================================================================== + * Slide the hash table when sliding the window down (could be avoided with 32 + * bit values at the expense of memory usage). We slide even when level == 0 to + * keep the hash table consistent if we switch back to level > 0 later. + */ +static inline void slide_hash_c_chain(Pos *table, uint32_t entries, uint16_t wsize) { +#ifdef NOT_TWEAK_COMPILER + table += entries; + do { + unsigned m; + m = *--table; + *table = (Pos)(m >= wsize ? m-wsize : 0); + /* If entries is not on any hash chain, prev[entries] is garbage but + * its value will never be used. + */ + } while (--entries); +#else + { + /* As of I make this change, gcc (4.8.*) isn't able to vectorize + * this hot loop using saturated-subtraction on x86-64 architecture. + * To avoid this defect, we can change the loop such that + * o. the pointer advance forward, and + * o. demote the variable 'm' to be local to the loop, and + * choose type "Pos" (instead of 'unsigned int') for the + * variable to avoid unnecessary zero-extension. + */ + unsigned int i; + Pos *q = table; + for (i = 0; i < entries; i++) { + Pos m = *q; + Pos t = (Pos)wsize; + *q++ = (Pos)(m >= t ? m-t: 0); + } + } +#endif /* NOT_TWEAK_COMPILER */ +} + +Z_INTERNAL void slide_hash_c(deflate_state *s) { + uint16_t wsize = (uint16_t)s->w_size; + + slide_hash_c_chain(s->head, HASH_SIZE, wsize); + slide_hash_c_chain(s->prev, wsize, wsize); +} diff --git a/arch/power/Makefile.in b/arch/power/Makefile.in new file mode 100644 index 0000000000..e2bec5e510 --- /dev/null +++ b/arch/power/Makefile.in @@ -0,0 +1,93 @@ +# Makefile for POWER-specific files +# Copyright (C) 2020 Matheus Castanho , IBM +# Copyright (C) 2021 Mika T. Lindqvist +# For conditions of distribution and use, see copyright notice in zlib.h + +CC= +CFLAGS= +SFLAGS= +INCLUDES= +SUFFIX= + +P8FLAGS=-mcpu=power8 +P9FLAGS=-mcpu=power9 +PPCFLAGS=-maltivec +NOLTOFLAG= + +SRCDIR=. +SRCTOP=../.. +TOPDIR=$(SRCTOP) + +all: power_features.o \ + power_features.lo \ + adler32_power8.o \ + adler32_power8.lo \ + adler32_vmx.o \ + adler32_vmx.lo \ + chunkset_power8.o \ + chunkset_power8.lo \ + compare256_power9.o \ + compare256_power9.lo \ + crc32_power8.o \ + crc32_power8.lo \ + slide_hash_power8.o \ + slide_hash_power8.lo \ + slide_hash_vmx.o \ + slide_hash_vmx.lo + +power_features.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/power_features.c + +power_features.lo: + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/power_features.c + +adler32_power8.o: + $(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_power8.c + +adler32_power8.lo: + $(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_power8.c + +adler32_vmx.o: + $(CC) $(CFLAGS) $(PPCFLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_vmx.c + +adler32_vmx.lo: + $(CC) $(SFLAGS) $(PPCFLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_vmx.c + +chunkset_power8.o: + $(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_power8.c + +chunkset_power8.lo: + $(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_power8.c + +compare256_power9.o: + $(CC) $(CFLAGS) $(P9FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_power9.c + +compare256_power9.lo: + $(CC) $(SFLAGS) $(P9FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_power9.c + +crc32_power8.o: + $(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_power8.c + +crc32_power8.lo: + $(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_power8.c + +slide_hash_power8.o: + $(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_power8.c + +slide_hash_power8.lo: + $(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_power8.c + +slide_hash_vmx.o: + $(CC) $(CFLAGS) ${PPCFLAGS} $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_vmx.c + +slide_hash_vmx.lo: + $(CC) $(SFLAGS) ${PPCFLAGS} $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_vmx.c + +mostlyclean: clean +clean: + rm -f *.o *.lo *~ + rm -rf objs + rm -f *.gcda *.gcno *.gcov + +distclean: clean + rm -f Makefile diff --git a/arch/power/adler32_power8.c b/arch/power/adler32_power8.c new file mode 100644 index 0000000000..4aaea9f50b --- /dev/null +++ b/arch/power/adler32_power8.c @@ -0,0 +1,153 @@ +/* Adler32 for POWER8 using VSX instructions. + * Copyright (C) 2020 IBM Corporation + * Author: Rogerio Alves + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Calculate adler32 checksum for 16 bytes at once using POWER8+ VSX (vector) + * instructions. + * + * If adler32 do 1 byte at time on the first iteration s1 is s1_0 (_n means + * iteration n) is the initial value of adler - at start _0 is 1 unless + * adler initial value is different than 1. So s1_1 = s1_0 + c[0] after + * the first calculation. For the iteration s1_2 = s1_1 + c[1] and so on. + * Hence, for iteration N, s1_N = s1_(N-1) + c[N] is the value of s1 on + * after iteration N. + * + * Therefore, for s2 and iteration N, s2_N = s2_0 + N*s1_N + N*c[0] + + * N-1*c[1] + ... + c[N] + * + * In a more general way: + * + * s1_N = s1_0 + sum(i=1 to N)c[i] + * s2_N = s2_0 + N*s1 + sum (i=1 to N)(N-i+1)*c[i] + * + * Where s1_N, s2_N are the values for s1, s2 after N iterations. So if we + * can process N-bit at time we can do this at once. + * + * Since VSX can support 16-bit vector instructions, we can process + * 16-bit at time using N = 16 we have: + * + * s1 = s1_16 = s1_(16-1) + c[16] = s1_0 + sum(i=1 to 16)c[i] + * s2 = s2_16 = s2_0 + 16*s1 + sum(i=1 to 16)(16-i+1)*c[i] + * + * After the first iteration we calculate the adler32 checksum for 16 bytes. + * + * For more background about adler32 please check the RFC: + * https://www.ietf.org/rfc/rfc1950.txt + */ + +#ifdef POWER8_VSX + +#include +#include "zbuild.h" +#include "adler32_p.h" + +/* Vector across sum unsigned int (saturate). */ +static inline vector unsigned int vec_sumsu(vector unsigned int __a, vector unsigned int __b) { + __b = vec_sld(__a, __a, 8); + __b = vec_add(__b, __a); + __a = vec_sld(__b, __b, 4); + __a = vec_add(__a, __b); + + return __a; +} + +Z_INTERNAL uint32_t adler32_power8(uint32_t adler, const uint8_t *buf, size_t len) { + uint32_t s1 = adler & 0xffff; + uint32_t s2 = (adler >> 16) & 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (UNLIKELY(len == 1)) + return adler32_len_1(s1, buf, s2); + + /* If buffer is empty or len=0 we need to return adler initial value. */ + if (UNLIKELY(buf == NULL)) + return 1; + + /* This is faster than VSX code for len < 64. */ + if (len < 64) + return adler32_len_64(s1, buf, len, s2); + + /* Use POWER VSX instructions for len >= 64. */ + const vector unsigned int v_zeros = { 0 }; + const vector unsigned char v_mul = {16, 15, 14, 13, 12, 11, 10, 9, 8, 7, + 6, 5, 4, 3, 2, 1}; + const vector unsigned char vsh = vec_splat_u8(4); + const vector unsigned int vmask = {0xffffffff, 0x0, 0x0, 0x0}; + vector unsigned int vs1 = { 0 }; + vector unsigned int vs2 = { 0 }; + vector unsigned int vs1_save = { 0 }; + vector unsigned int vsum1, vsum2; + vector unsigned char vbuf; + int n; + + vs1[0] = s1; + vs2[0] = s2; + + /* Do length bigger than NMAX in blocks of NMAX size. */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; + do { + vbuf = vec_xl(0, (unsigned char *) buf); + vsum1 = vec_sum4s(vbuf, v_zeros); /* sum(i=1 to 16) buf[i]. */ + /* sum(i=1 to 16) buf[i]*(16-i+1). */ + vsum2 = vec_msum(vbuf, v_mul, v_zeros); + /* Save vs1. */ + vs1_save = vec_add(vs1_save, vs1); + /* Accumulate the sums. */ + vs1 = vec_add(vsum1, vs1); + vs2 = vec_add(vsum2, vs2); + + buf += 16; + } while (--n); + /* Once each block of NMAX size. */ + vs1 = vec_sumsu(vs1, vsum1); + vs1_save = vec_sll(vs1_save, vsh); /* 16*vs1_save. */ + vs2 = vec_add(vs1_save, vs2); + vs2 = vec_sumsu(vs2, vsum2); + + /* vs1[0] = (s1_i + sum(i=1 to 16)buf[i]) mod 65521. */ + vs1[0] = vs1[0] % BASE; + /* vs2[0] = s2_i + 16*s1_save + + sum(i=1 to 16)(16-i+1)*buf[i] mod 65521. */ + vs2[0] = vs2[0] % BASE; + + vs1 = vec_and(vs1, vmask); + vs2 = vec_and(vs2, vmask); + vs1_save = v_zeros; + } + + /* len is less than NMAX one modulo is needed. */ + if (len >= 16) { + while (len >= 16) { + len -= 16; + + vbuf = vec_xl(0, (unsigned char *) buf); + + vsum1 = vec_sum4s(vbuf, v_zeros); /* sum(i=1 to 16) buf[i]. */ + /* sum(i=1 to 16) buf[i]*(16-i+1). */ + vsum2 = vec_msum(vbuf, v_mul, v_zeros); + /* Save vs1. */ + vs1_save = vec_add(vs1_save, vs1); + /* Accumulate the sums. */ + vs1 = vec_add(vsum1, vs1); + vs2 = vec_add(vsum2, vs2); + + buf += 16; + } + /* Since the size will be always less than NMAX we do this once. */ + vs1 = vec_sumsu(vs1, vsum1); + vs1_save = vec_sll(vs1_save, vsh); /* 16*vs1_save. */ + vs2 = vec_add(vs1_save, vs2); + vs2 = vec_sumsu(vs2, vsum2); + } + /* Copy result back to s1, s2 (mod 65521). */ + s1 = vs1[0] % BASE; + s2 = vs2[0] % BASE; + + /* Process tail (len < 16). */ + return adler32_len_16(s1, buf, len, s2); +} + +#endif /* POWER8_VSX */ diff --git a/arch/power/adler32_vmx.c b/arch/power/adler32_vmx.c new file mode 100644 index 0000000000..3470c28a12 --- /dev/null +++ b/arch/power/adler32_vmx.c @@ -0,0 +1,186 @@ +/* adler32_vmx.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011 Mark Adler + * Copyright (C) 2017-2023 Mika T. Lindqvist + * Copyright (C) 2021 Adam Stylinski + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef PPC_VMX +#include +#include "zbuild.h" +#include "zendian.h" +#include "adler32_p.h" + +#define vmx_zero() (vec_splat_u32(0)) + +static inline void vmx_handle_head_or_tail(uint32_t *pair, const uint8_t *buf, size_t len) { + unsigned int i; + for (i = 0; i < len; ++i) { + pair[0] += buf[i]; + pair[1] += pair[0]; + } +} + +static void vmx_accum32(uint32_t *s, const uint8_t *buf, size_t len) { + /* Different taps for the separable components of sums */ + const vector unsigned char t0 = {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49}; + const vector unsigned char t1 = {48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33}; + const vector unsigned char t2 = {32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17}; + const vector unsigned char t3 = {16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + /* As silly and inefficient as it seems, creating 1 permutation vector to permute + * a 2 element vector from a single load + a subsequent shift is just barely faster + * than doing 2 indexed insertions into zero initialized vectors from unaligned memory. */ + const vector unsigned char s0_perm = {0, 1, 2, 3, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; + const vector unsigned char shift_vec = vec_sl(vec_splat_u8(8), vec_splat_u8(2)); + vector unsigned int adacc, s2acc; + vector unsigned int pair_vec = vec_ld(0, s); + adacc = vec_perm(pair_vec, pair_vec, s0_perm); +#if BYTE_ORDER == LITTLE_ENDIAN + s2acc = vec_sro(pair_vec, shift_vec); +#else + s2acc = vec_slo(pair_vec, shift_vec); +#endif + + vector unsigned int zero = vmx_zero(); + vector unsigned int s3acc = zero; + vector unsigned int s3acc_0 = zero; + vector unsigned int adacc_prev = adacc; + vector unsigned int adacc_prev_0 = zero; + + vector unsigned int s2acc_0 = zero; + vector unsigned int s2acc_1 = zero; + vector unsigned int s2acc_2 = zero; + + /* Maintain a running sum of a second half, this might help use break yet another + * data dependency bubble in the sum */ + vector unsigned int adacc_0 = zero; + + int num_iter = len / 4; + int rem = len & 3; + + for (int i = 0; i < num_iter; ++i) { + vector unsigned char d0 = vec_ld(0, buf); + vector unsigned char d1 = vec_ld(16, buf); + vector unsigned char d2 = vec_ld(32, buf); + vector unsigned char d3 = vec_ld(48, buf); + + /* The core operation of the loop, basically + * what is being unrolled below */ + adacc = vec_sum4s(d0, adacc); + s3acc = vec_add(s3acc, adacc_prev); + s3acc_0 = vec_add(s3acc_0, adacc_prev_0); + s2acc = vec_msum(t0, d0, s2acc); + + /* interleave dependent sums in here */ + adacc_0 = vec_sum4s(d1, adacc_0); + s2acc_0 = vec_msum(t1, d1, s2acc_0); + adacc = vec_sum4s(d2, adacc); + s2acc_1 = vec_msum(t2, d2, s2acc_1); + s2acc_2 = vec_msum(t3, d3, s2acc_2); + adacc_0 = vec_sum4s(d3, adacc_0); + + adacc_prev = adacc; + adacc_prev_0 = adacc_0; + buf += 64; + } + + adacc = vec_add(adacc, adacc_0); + s3acc = vec_add(s3acc, s3acc_0); + s3acc = vec_sl(s3acc, vec_splat_u32(6)); + + if (rem) { + adacc_prev = vec_add(adacc_prev_0, adacc_prev); + adacc_prev = vec_sl(adacc_prev, vec_splat_u32(4)); + while (rem--) { + vector unsigned char d0 = vec_ld(0, buf); + adacc = vec_sum4s(d0, adacc); + s3acc = vec_add(s3acc, adacc_prev); + s2acc = vec_msum(t3, d0, s2acc); + adacc_prev = vec_sl(adacc, vec_splat_u32(4)); + buf += 16; + } + } + + + /* Sum up independent second sums */ + s2acc = vec_add(s2acc, s2acc_0); + s2acc_2 = vec_add(s2acc_1, s2acc_2); + s2acc = vec_add(s2acc, s2acc_2); + + s2acc = vec_add(s2acc, s3acc); + + adacc = vec_add(adacc, vec_sld(adacc, adacc, 8)); + s2acc = vec_add(s2acc, vec_sld(s2acc, s2acc, 8)); + adacc = vec_add(adacc, vec_sld(adacc, adacc, 4)); + s2acc = vec_add(s2acc, vec_sld(s2acc, s2acc, 4)); + + vec_ste(adacc, 0, s); + vec_ste(s2acc, 0, s+1); +} + +Z_INTERNAL uint32_t adler32_vmx(uint32_t adler, const uint8_t *buf, size_t len) { + uint32_t sum2; + uint32_t pair[16] ALIGNED_(16); + memset(&pair[2], 0, 14); + int n = NMAX; + unsigned int done = 0, i; + + /* Split Adler-32 into component sums, it can be supplied by + * the caller sites (e.g. in a PNG file). + */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + pair[0] = adler; + pair[1] = sum2; + + /* in case user likes doing a byte at a time, keep it fast */ + if (UNLIKELY(len == 1)) + return adler32_len_1(adler, buf, sum2); + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (UNLIKELY(buf == NULL)) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (UNLIKELY(len < 16)) + return adler32_len_16(adler, buf, len, sum2); + + // Align buffer + unsigned int al = 0; + if ((uintptr_t)buf & 0xf) { + al = 16-((uintptr_t)buf & 0xf); + if (al > len) { + al=len; + } + vmx_handle_head_or_tail(pair, buf, al); + + done += al; + /* Rather than rebasing, we can reduce the max sums for the + * first round only */ + n -= al; + } + for (i = al; i < len; i += n) { + int remaining = (int)(len-i); + n = MIN(remaining, (i == al) ? n : NMAX); + + if (n < 16) + break; + + vmx_accum32(pair, buf + i, n / 16); + pair[0] %= BASE; + pair[1] %= BASE; + + done += (n / 16) * 16; + } + + /* Handle the tail elements. */ + if (done < len) { + vmx_handle_head_or_tail(pair, (buf + done), len - done); + pair[0] %= BASE; + pair[1] %= BASE; + } + + /* D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. */ + return (pair[1] << 16) | pair[0]; +} +#endif diff --git a/arch/power/chunkset_power8.c b/arch/power/chunkset_power8.c new file mode 100644 index 0000000000..673fe0e112 --- /dev/null +++ b/arch/power/chunkset_power8.c @@ -0,0 +1,50 @@ +/* chunkset_power8.c -- VSX inline functions to copy small data chunks. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef POWER8_VSX +#include +#include "zbuild.h" +#include "zmemory.h" + +typedef vector unsigned char chunk_t; + +#define CHUNK_SIZE 16 + +#define HAVE_CHUNKMEMSET_2 +#define HAVE_CHUNKMEMSET_4 +#define HAVE_CHUNKMEMSET_8 + +static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { + *chunk = (vector unsigned char)vec_splats(zng_memread_2(from)); +} + +static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { + *chunk = (vector unsigned char)vec_splats(zng_memread_4(from)); +} + +static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { + *chunk = (vector unsigned char)vec_splats((unsigned long long)zng_memread_8(from)); +} + +static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { + *chunk = vec_xl(0, s); +} + +static inline void storechunk(uint8_t *out, chunk_t *chunk) { + vec_xst(*chunk, 0, out); +} + +#define CHUNKSIZE chunksize_power8 +#define CHUNKCOPY chunkcopy_power8 +#define CHUNKUNROLL chunkunroll_power8 +#define CHUNKMEMSET chunkmemset_power8 +#define CHUNKMEMSET_SAFE chunkmemset_safe_power8 + +#include "chunkset_tpl.h" + +#define INFLATE_FAST inflate_fast_power8 + +#include "inffast_tpl.h" + +#endif diff --git a/arch/power/compare256_power9.c b/arch/power/compare256_power9.c new file mode 100644 index 0000000000..2875719c47 --- /dev/null +++ b/arch/power/compare256_power9.c @@ -0,0 +1,66 @@ +/* compare256_power9.c - Power9 version of compare256 + * Copyright (C) 2019 Matheus Castanho , IBM + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef POWER9 +#include +#include "zbuild.h" +#include "zmemory.h" +#include "deflate.h" +#include "zendian.h" + +/* Older versions of GCC misimplemented semantics for these bit counting builtins. + * https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=3f30f2d1dbb3228b8468b26239fe60c2974ce2ac */ +#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 12) +#if BYTE_ORDER == LITTLE_ENDIAN +# define zng_vec_vctzlsbb(vc, len) len = __builtin_vec_vctzlsbb(vc) +#else +# define zng_vec_vctzlsbb(vc, len) len = __builtin_vec_vclzlsbb(vc) +#endif +#else +# define zng_vec_vctzlsbb(vc, len) len = vec_cntlz_lsbb(vc) +#endif + +static inline uint32_t compare256_power9_static(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0, cmplen; + + do { + vector unsigned char vsrc0, vsrc1, vc; + + vsrc0 = *((vector unsigned char *)src0); + vsrc1 = *((vector unsigned char *)src1); + + /* Compare 16 bytes at a time. Each byte of vc will be either + * all ones or all zeroes, depending on the result of the comparison. */ + vc = (vector unsigned char)vec_cmpne(vsrc0, vsrc1); + + /* Since the index of matching bytes will contain only zeroes + * on vc (since we used cmpne), counting the number of consecutive + * bytes where LSB == 0 is the same as counting the length of the match. */ + zng_vec_vctzlsbb(vc, cmplen); + if (cmplen != 16) + return len + cmplen; + + src0 += 16, src1 += 16, len += 16; + } while (len < 256); + + return 256; +} + +Z_INTERNAL uint32_t compare256_power9(const uint8_t *src0, const uint8_t *src1) { + return compare256_power9_static(src0, src1); +} + +#define LONGEST_MATCH longest_match_power9 +#define COMPARE256 compare256_power9_static + +#include "match_tpl.h" + +#define LONGEST_MATCH_SLOW +#define LONGEST_MATCH longest_match_slow_power9 +#define COMPARE256 compare256_power9_static + +#include "match_tpl.h" + +#endif diff --git a/arch/power/crc32_constants.h b/arch/power/crc32_constants.h new file mode 100644 index 0000000000..8c8f2153b6 --- /dev/null +++ b/arch/power/crc32_constants.h @@ -0,0 +1,1123 @@ +/* Constants table used by crc32_power8.c + * Copyright (C) 2021 IBM Corporation + * + * This file was automatically generated, DO NOT EDIT IT MANUALLY. + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zendian.h" +#include "zbuild.h" + +/* Reduce 262144 kbits to 1024 bits */ +static const __vector unsigned long long vcrc_const[255] ALIGNED_(16) = { +#if BYTE_ORDER == LITTLE_ENDIAN + /* x^261120 mod p(x)` << 1, x^261184 mod p(x)` << 1 */ + { 0x0000000099ea94a8, 0x00000001651797d2 }, + /* x^260096 mod p(x)` << 1, x^260160 mod p(x)` << 1 */ + { 0x00000000945a8420, 0x0000000021e0d56c }, + /* x^259072 mod p(x)` << 1, x^259136 mod p(x)` << 1 */ + { 0x0000000030762706, 0x000000000f95ecaa }, + /* x^258048 mod p(x)` << 1, x^258112 mod p(x)` << 1 */ + { 0x00000001a52fc582, 0x00000001ebd224ac }, + /* x^257024 mod p(x)` << 1, x^257088 mod p(x)` << 1 */ + { 0x00000001a4a7167a, 0x000000000ccb97ca }, + /* x^256000 mod p(x)` << 1, x^256064 mod p(x)` << 1 */ + { 0x000000000c18249a, 0x00000001006ec8a8 }, + /* x^254976 mod p(x)` << 1, x^255040 mod p(x)` << 1 */ + { 0x00000000a924ae7c, 0x000000014f58f196 }, + /* x^253952 mod p(x)` << 1, x^254016 mod p(x)` << 1 */ + { 0x00000001e12ccc12, 0x00000001a7192ca6 }, + /* x^252928 mod p(x)` << 1, x^252992 mod p(x)` << 1 */ + { 0x00000000a0b9d4ac, 0x000000019a64bab2 }, + /* x^251904 mod p(x)` << 1, x^251968 mod p(x)` << 1 */ + { 0x0000000095e8ddfe, 0x0000000014f4ed2e }, + /* x^250880 mod p(x)` << 1, x^250944 mod p(x)` << 1 */ + { 0x00000000233fddc4, 0x000000011092b6a2 }, + /* x^249856 mod p(x)` << 1, x^249920 mod p(x)` << 1 */ + { 0x00000001b4529b62, 0x00000000c8a1629c }, + /* x^248832 mod p(x)` << 1, x^248896 mod p(x)` << 1 */ + { 0x00000001a7fa0e64, 0x000000017bf32e8e }, + /* x^247808 mod p(x)` << 1, x^247872 mod p(x)` << 1 */ + { 0x00000001b5334592, 0x00000001f8cc6582 }, + /* x^246784 mod p(x)` << 1, x^246848 mod p(x)` << 1 */ + { 0x000000011f8ee1b4, 0x000000008631ddf0 }, + /* x^245760 mod p(x)` << 1, x^245824 mod p(x)` << 1 */ + { 0x000000006252e632, 0x000000007e5a76d0 }, + /* x^244736 mod p(x)` << 1, x^244800 mod p(x)` << 1 */ + { 0x00000000ab973e84, 0x000000002b09b31c }, + /* x^243712 mod p(x)` << 1, x^243776 mod p(x)` << 1 */ + { 0x000000007734f5ec, 0x00000001b2df1f84 }, + /* x^242688 mod p(x)` << 1, x^242752 mod p(x)` << 1 */ + { 0x000000007c547798, 0x00000001d6f56afc }, + /* x^241664 mod p(x)` << 1, x^241728 mod p(x)` << 1 */ + { 0x000000007ec40210, 0x00000001b9b5e70c }, + /* x^240640 mod p(x)` << 1, x^240704 mod p(x)` << 1 */ + { 0x00000001ab1695a8, 0x0000000034b626d2 }, + /* x^239616 mod p(x)` << 1, x^239680 mod p(x)` << 1 */ + { 0x0000000090494bba, 0x000000014c53479a }, + /* x^238592 mod p(x)` << 1, x^238656 mod p(x)` << 1 */ + { 0x00000001123fb816, 0x00000001a6d179a4 }, + /* x^237568 mod p(x)` << 1, x^237632 mod p(x)` << 1 */ + { 0x00000001e188c74c, 0x000000015abd16b4 }, + /* x^236544 mod p(x)` << 1, x^236608 mod p(x)` << 1 */ + { 0x00000001c2d3451c, 0x00000000018f9852 }, + /* x^235520 mod p(x)` << 1, x^235584 mod p(x)` << 1 */ + { 0x00000000f55cf1ca, 0x000000001fb3084a }, + /* x^234496 mod p(x)` << 1, x^234560 mod p(x)` << 1 */ + { 0x00000001a0531540, 0x00000000c53dfb04 }, + /* x^233472 mod p(x)` << 1, x^233536 mod p(x)` << 1 */ + { 0x0000000132cd7ebc, 0x00000000e10c9ad6 }, + /* x^232448 mod p(x)` << 1, x^232512 mod p(x)` << 1 */ + { 0x0000000073ab7f36, 0x0000000025aa994a }, + /* x^231424 mod p(x)` << 1, x^231488 mod p(x)` << 1 */ + { 0x0000000041aed1c2, 0x00000000fa3a74c4 }, + /* x^230400 mod p(x)` << 1, x^230464 mod p(x)` << 1 */ + { 0x0000000136c53800, 0x0000000033eb3f40 }, + /* x^229376 mod p(x)` << 1, x^229440 mod p(x)` << 1 */ + { 0x0000000126835a30, 0x000000017193f296 }, + /* x^228352 mod p(x)` << 1, x^228416 mod p(x)` << 1 */ + { 0x000000006241b502, 0x0000000043f6c86a }, + /* x^227328 mod p(x)` << 1, x^227392 mod p(x)` << 1 */ + { 0x00000000d5196ad4, 0x000000016b513ec6 }, + /* x^226304 mod p(x)` << 1, x^226368 mod p(x)` << 1 */ + { 0x000000009cfa769a, 0x00000000c8f25b4e }, + /* x^225280 mod p(x)` << 1, x^225344 mod p(x)` << 1 */ + { 0x00000000920e5df4, 0x00000001a45048ec }, + /* x^224256 mod p(x)` << 1, x^224320 mod p(x)` << 1 */ + { 0x0000000169dc310e, 0x000000000c441004 }, + /* x^223232 mod p(x)` << 1, x^223296 mod p(x)` << 1 */ + { 0x0000000009fc331c, 0x000000000e17cad6 }, + /* x^222208 mod p(x)` << 1, x^222272 mod p(x)` << 1 */ + { 0x000000010d94a81e, 0x00000001253ae964 }, + /* x^221184 mod p(x)` << 1, x^221248 mod p(x)` << 1 */ + { 0x0000000027a20ab2, 0x00000001d7c88ebc }, + /* x^220160 mod p(x)` << 1, x^220224 mod p(x)` << 1 */ + { 0x0000000114f87504, 0x00000001e7ca913a }, + /* x^219136 mod p(x)` << 1, x^219200 mod p(x)` << 1 */ + { 0x000000004b076d96, 0x0000000033ed078a }, + /* x^218112 mod p(x)` << 1, x^218176 mod p(x)` << 1 */ + { 0x00000000da4d1e74, 0x00000000e1839c78 }, + /* x^217088 mod p(x)` << 1, x^217152 mod p(x)` << 1 */ + { 0x000000001b81f672, 0x00000001322b267e }, + /* x^216064 mod p(x)` << 1, x^216128 mod p(x)` << 1 */ + { 0x000000009367c988, 0x00000000638231b6 }, + /* x^215040 mod p(x)` << 1, x^215104 mod p(x)` << 1 */ + { 0x00000001717214ca, 0x00000001ee7f16f4 }, + /* x^214016 mod p(x)` << 1, x^214080 mod p(x)` << 1 */ + { 0x000000009f47d820, 0x0000000117d9924a }, + /* x^212992 mod p(x)` << 1, x^213056 mod p(x)` << 1 */ + { 0x000000010d9a47d2, 0x00000000e1a9e0c4 }, + /* x^211968 mod p(x)` << 1, x^212032 mod p(x)` << 1 */ + { 0x00000000a696c58c, 0x00000001403731dc }, + /* x^210944 mod p(x)` << 1, x^211008 mod p(x)` << 1 */ + { 0x000000002aa28ec6, 0x00000001a5ea9682 }, + /* x^209920 mod p(x)` << 1, x^209984 mod p(x)` << 1 */ + { 0x00000001fe18fd9a, 0x0000000101c5c578 }, + /* x^208896 mod p(x)` << 1, x^208960 mod p(x)` << 1 */ + { 0x000000019d4fc1ae, 0x00000000dddf6494 }, + /* x^207872 mod p(x)` << 1, x^207936 mod p(x)` << 1 */ + { 0x00000001ba0e3dea, 0x00000000f1c3db28 }, + /* x^206848 mod p(x)` << 1, x^206912 mod p(x)` << 1 */ + { 0x0000000074b59a5e, 0x000000013112fb9c }, + /* x^205824 mod p(x)` << 1, x^205888 mod p(x)` << 1 */ + { 0x00000000f2b5ea98, 0x00000000b680b906 }, + /* x^204800 mod p(x)` << 1, x^204864 mod p(x)` << 1 */ + { 0x0000000187132676, 0x000000001a282932 }, + /* x^203776 mod p(x)` << 1, x^203840 mod p(x)` << 1 */ + { 0x000000010a8c6ad4, 0x0000000089406e7e }, + /* x^202752 mod p(x)` << 1, x^202816 mod p(x)` << 1 */ + { 0x00000001e21dfe70, 0x00000001def6be8c }, + /* x^201728 mod p(x)` << 1, x^201792 mod p(x)` << 1 */ + { 0x00000001da0050e4, 0x0000000075258728 }, + /* x^200704 mod p(x)` << 1, x^200768 mod p(x)` << 1 */ + { 0x00000000772172ae, 0x000000019536090a }, + /* x^199680 mod p(x)` << 1, x^199744 mod p(x)` << 1 */ + { 0x00000000e47724aa, 0x00000000f2455bfc }, + /* x^198656 mod p(x)` << 1, x^198720 mod p(x)` << 1 */ + { 0x000000003cd63ac4, 0x000000018c40baf4 }, + /* x^197632 mod p(x)` << 1, x^197696 mod p(x)` << 1 */ + { 0x00000001bf47d352, 0x000000004cd390d4 }, + /* x^196608 mod p(x)` << 1, x^196672 mod p(x)` << 1 */ + { 0x000000018dc1d708, 0x00000001e4ece95a }, + /* x^195584 mod p(x)` << 1, x^195648 mod p(x)` << 1 */ + { 0x000000002d4620a4, 0x000000001a3ee918 }, + /* x^194560 mod p(x)` << 1, x^194624 mod p(x)` << 1 */ + { 0x0000000058fd1740, 0x000000007c652fb8 }, + /* x^193536 mod p(x)` << 1, x^193600 mod p(x)` << 1 */ + { 0x00000000dadd9bfc, 0x000000011c67842c }, + /* x^192512 mod p(x)` << 1, x^192576 mod p(x)` << 1 */ + { 0x00000001ea2140be, 0x00000000254f759c }, + /* x^191488 mod p(x)` << 1, x^191552 mod p(x)` << 1 */ + { 0x000000009de128ba, 0x000000007ece94ca }, + /* x^190464 mod p(x)` << 1, x^190528 mod p(x)` << 1 */ + { 0x000000013ac3aa8e, 0x0000000038f258c2 }, + /* x^189440 mod p(x)` << 1, x^189504 mod p(x)` << 1 */ + { 0x0000000099980562, 0x00000001cdf17b00 }, + /* x^188416 mod p(x)` << 1, x^188480 mod p(x)` << 1 */ + { 0x00000001c1579c86, 0x000000011f882c16 }, + /* x^187392 mod p(x)` << 1, x^187456 mod p(x)` << 1 */ + { 0x0000000068dbbf94, 0x0000000100093fc8 }, + /* x^186368 mod p(x)` << 1, x^186432 mod p(x)` << 1 */ + { 0x000000004509fb04, 0x00000001cd684f16 }, + /* x^185344 mod p(x)` << 1, x^185408 mod p(x)` << 1 */ + { 0x00000001202f6398, 0x000000004bc6a70a }, + /* x^184320 mod p(x)` << 1, x^184384 mod p(x)` << 1 */ + { 0x000000013aea243e, 0x000000004fc7e8e4 }, + /* x^183296 mod p(x)` << 1, x^183360 mod p(x)` << 1 */ + { 0x00000001b4052ae6, 0x0000000130103f1c }, + /* x^182272 mod p(x)` << 1, x^182336 mod p(x)` << 1 */ + { 0x00000001cd2a0ae8, 0x0000000111b0024c }, + /* x^181248 mod p(x)` << 1, x^181312 mod p(x)` << 1 */ + { 0x00000001fe4aa8b4, 0x000000010b3079da }, + /* x^180224 mod p(x)` << 1, x^180288 mod p(x)` << 1 */ + { 0x00000001d1559a42, 0x000000010192bcc2 }, + /* x^179200 mod p(x)` << 1, x^179264 mod p(x)` << 1 */ + { 0x00000001f3e05ecc, 0x0000000074838d50 }, + /* x^178176 mod p(x)` << 1, x^178240 mod p(x)` << 1 */ + { 0x0000000104ddd2cc, 0x000000001b20f520 }, + /* x^177152 mod p(x)` << 1, x^177216 mod p(x)` << 1 */ + { 0x000000015393153c, 0x0000000050c3590a }, + /* x^176128 mod p(x)` << 1, x^176192 mod p(x)` << 1 */ + { 0x0000000057e942c6, 0x00000000b41cac8e }, + /* x^175104 mod p(x)` << 1, x^175168 mod p(x)` << 1 */ + { 0x000000012c633850, 0x000000000c72cc78 }, + /* x^174080 mod p(x)` << 1, x^174144 mod p(x)` << 1 */ + { 0x00000000ebcaae4c, 0x0000000030cdb032 }, + /* x^173056 mod p(x)` << 1, x^173120 mod p(x)` << 1 */ + { 0x000000013ee532a6, 0x000000013e09fc32 }, + /* x^172032 mod p(x)` << 1, x^172096 mod p(x)` << 1 */ + { 0x00000001bf0cbc7e, 0x000000001ed624d2 }, + /* x^171008 mod p(x)` << 1, x^171072 mod p(x)` << 1 */ + { 0x00000000d50b7a5a, 0x00000000781aee1a }, + /* x^169984 mod p(x)` << 1, x^170048 mod p(x)` << 1 */ + { 0x0000000002fca6e8, 0x00000001c4d8348c }, + /* x^168960 mod p(x)` << 1, x^169024 mod p(x)` << 1 */ + { 0x000000007af40044, 0x0000000057a40336 }, + /* x^167936 mod p(x)` << 1, x^168000 mod p(x)` << 1 */ + { 0x0000000016178744, 0x0000000085544940 }, + /* x^166912 mod p(x)` << 1, x^166976 mod p(x)` << 1 */ + { 0x000000014c177458, 0x000000019cd21e80 }, + /* x^165888 mod p(x)` << 1, x^165952 mod p(x)` << 1 */ + { 0x000000011b6ddf04, 0x000000013eb95bc0 }, + /* x^164864 mod p(x)` << 1, x^164928 mod p(x)` << 1 */ + { 0x00000001f3e29ccc, 0x00000001dfc9fdfc }, + /* x^163840 mod p(x)` << 1, x^163904 mod p(x)` << 1 */ + { 0x0000000135ae7562, 0x00000000cd028bc2 }, + /* x^162816 mod p(x)` << 1, x^162880 mod p(x)` << 1 */ + { 0x0000000190ef812c, 0x0000000090db8c44 }, + /* x^161792 mod p(x)` << 1, x^161856 mod p(x)` << 1 */ + { 0x0000000067a2c786, 0x000000010010a4ce }, + /* x^160768 mod p(x)` << 1, x^160832 mod p(x)` << 1 */ + { 0x0000000048b9496c, 0x00000001c8f4c72c }, + /* x^159744 mod p(x)` << 1, x^159808 mod p(x)` << 1 */ + { 0x000000015a422de6, 0x000000001c26170c }, + /* x^158720 mod p(x)` << 1, x^158784 mod p(x)` << 1 */ + { 0x00000001ef0e3640, 0x00000000e3fccf68 }, + /* x^157696 mod p(x)` << 1, x^157760 mod p(x)` << 1 */ + { 0x00000001006d2d26, 0x00000000d513ed24 }, + /* x^156672 mod p(x)` << 1, x^156736 mod p(x)` << 1 */ + { 0x00000001170d56d6, 0x00000000141beada }, + /* x^155648 mod p(x)` << 1, x^155712 mod p(x)` << 1 */ + { 0x00000000a5fb613c, 0x000000011071aea0 }, + /* x^154624 mod p(x)` << 1, x^154688 mod p(x)` << 1 */ + { 0x0000000040bbf7fc, 0x000000012e19080a }, + /* x^153600 mod p(x)` << 1, x^153664 mod p(x)` << 1 */ + { 0x000000016ac3a5b2, 0x0000000100ecf826 }, + /* x^152576 mod p(x)` << 1, x^152640 mod p(x)` << 1 */ + { 0x00000000abf16230, 0x0000000069b09412 }, + /* x^151552 mod p(x)` << 1, x^151616 mod p(x)` << 1 */ + { 0x00000001ebe23fac, 0x0000000122297bac }, + /* x^150528 mod p(x)` << 1, x^150592 mod p(x)` << 1 */ + { 0x000000008b6a0894, 0x00000000e9e4b068 }, + /* x^149504 mod p(x)` << 1, x^149568 mod p(x)` << 1 */ + { 0x00000001288ea478, 0x000000004b38651a }, + /* x^148480 mod p(x)` << 1, x^148544 mod p(x)` << 1 */ + { 0x000000016619c442, 0x00000001468360e2 }, + /* x^147456 mod p(x)` << 1, x^147520 mod p(x)` << 1 */ + { 0x0000000086230038, 0x00000000121c2408 }, + /* x^146432 mod p(x)` << 1, x^146496 mod p(x)` << 1 */ + { 0x000000017746a756, 0x00000000da7e7d08 }, + /* x^145408 mod p(x)` << 1, x^145472 mod p(x)` << 1 */ + { 0x0000000191b8f8f8, 0x00000001058d7652 }, + /* x^144384 mod p(x)` << 1, x^144448 mod p(x)` << 1 */ + { 0x000000008e167708, 0x000000014a098a90 }, + /* x^143360 mod p(x)` << 1, x^143424 mod p(x)` << 1 */ + { 0x0000000148b22d54, 0x0000000020dbe72e }, + /* x^142336 mod p(x)` << 1, x^142400 mod p(x)` << 1 */ + { 0x0000000044ba2c3c, 0x000000011e7323e8 }, + /* x^141312 mod p(x)` << 1, x^141376 mod p(x)` << 1 */ + { 0x00000000b54d2b52, 0x00000000d5d4bf94 }, + /* x^140288 mod p(x)` << 1, x^140352 mod p(x)` << 1 */ + { 0x0000000005a4fd8a, 0x0000000199d8746c }, + /* x^139264 mod p(x)` << 1, x^139328 mod p(x)` << 1 */ + { 0x0000000139f9fc46, 0x00000000ce9ca8a0 }, + /* x^138240 mod p(x)` << 1, x^138304 mod p(x)` << 1 */ + { 0x000000015a1fa824, 0x00000000136edece }, + /* x^137216 mod p(x)` << 1, x^137280 mod p(x)` << 1 */ + { 0x000000000a61ae4c, 0x000000019b92a068 }, + /* x^136192 mod p(x)` << 1, x^136256 mod p(x)` << 1 */ + { 0x0000000145e9113e, 0x0000000071d62206 }, + /* x^135168 mod p(x)` << 1, x^135232 mod p(x)` << 1 */ + { 0x000000006a348448, 0x00000000dfc50158 }, + /* x^134144 mod p(x)` << 1, x^134208 mod p(x)` << 1 */ + { 0x000000004d80a08c, 0x00000001517626bc }, + /* x^133120 mod p(x)` << 1, x^133184 mod p(x)` << 1 */ + { 0x000000014b6837a0, 0x0000000148d1e4fa }, + /* x^132096 mod p(x)` << 1, x^132160 mod p(x)` << 1 */ + { 0x000000016896a7fc, 0x0000000094d8266e }, + /* x^131072 mod p(x)` << 1, x^131136 mod p(x)` << 1 */ + { 0x000000014f187140, 0x00000000606c5e34 }, + /* x^130048 mod p(x)` << 1, x^130112 mod p(x)` << 1 */ + { 0x000000019581b9da, 0x000000019766beaa }, + /* x^129024 mod p(x)` << 1, x^129088 mod p(x)` << 1 */ + { 0x00000001091bc984, 0x00000001d80c506c }, + /* x^128000 mod p(x)` << 1, x^128064 mod p(x)` << 1 */ + { 0x000000001067223c, 0x000000001e73837c }, + /* x^126976 mod p(x)` << 1, x^127040 mod p(x)` << 1 */ + { 0x00000001ab16ea02, 0x0000000064d587de }, + /* x^125952 mod p(x)` << 1, x^126016 mod p(x)` << 1 */ + { 0x000000013c4598a8, 0x00000000f4a507b0 }, + /* x^124928 mod p(x)` << 1, x^124992 mod p(x)` << 1 */ + { 0x00000000b3735430, 0x0000000040e342fc }, + /* x^123904 mod p(x)` << 1, x^123968 mod p(x)` << 1 */ + { 0x00000001bb3fc0c0, 0x00000001d5ad9c3a }, + /* x^122880 mod p(x)` << 1, x^122944 mod p(x)` << 1 */ + { 0x00000001570ae19c, 0x0000000094a691a4 }, + /* x^121856 mod p(x)` << 1, x^121920 mod p(x)` << 1 */ + { 0x00000001ea910712, 0x00000001271ecdfa }, + /* x^120832 mod p(x)` << 1, x^120896 mod p(x)` << 1 */ + { 0x0000000167127128, 0x000000009e54475a }, + /* x^119808 mod p(x)` << 1, x^119872 mod p(x)` << 1 */ + { 0x0000000019e790a2, 0x00000000c9c099ee }, + /* x^118784 mod p(x)` << 1, x^118848 mod p(x)` << 1 */ + { 0x000000003788f710, 0x000000009a2f736c }, + /* x^117760 mod p(x)` << 1, x^117824 mod p(x)` << 1 */ + { 0x00000001682a160e, 0x00000000bb9f4996 }, + /* x^116736 mod p(x)` << 1, x^116800 mod p(x)` << 1 */ + { 0x000000007f0ebd2e, 0x00000001db688050 }, + /* x^115712 mod p(x)` << 1, x^115776 mod p(x)` << 1 */ + { 0x000000002b032080, 0x00000000e9b10af4 }, + /* x^114688 mod p(x)` << 1, x^114752 mod p(x)` << 1 */ + { 0x00000000cfd1664a, 0x000000012d4545e4 }, + /* x^113664 mod p(x)` << 1, x^113728 mod p(x)` << 1 */ + { 0x00000000aa1181c2, 0x000000000361139c }, + /* x^112640 mod p(x)` << 1, x^112704 mod p(x)` << 1 */ + { 0x00000000ddd08002, 0x00000001a5a1a3a8 }, + /* x^111616 mod p(x)` << 1, x^111680 mod p(x)` << 1 */ + { 0x00000000e8dd0446, 0x000000006844e0b0 }, + /* x^110592 mod p(x)` << 1, x^110656 mod p(x)` << 1 */ + { 0x00000001bbd94a00, 0x00000000c3762f28 }, + /* x^109568 mod p(x)` << 1, x^109632 mod p(x)` << 1 */ + { 0x00000000ab6cd180, 0x00000001d26287a2 }, + /* x^108544 mod p(x)` << 1, x^108608 mod p(x)` << 1 */ + { 0x0000000031803ce2, 0x00000001f6f0bba8 }, + /* x^107520 mod p(x)` << 1, x^107584 mod p(x)` << 1 */ + { 0x0000000024f40b0c, 0x000000002ffabd62 }, + /* x^106496 mod p(x)` << 1, x^106560 mod p(x)` << 1 */ + { 0x00000001ba1d9834, 0x00000000fb4516b8 }, + /* x^105472 mod p(x)` << 1, x^105536 mod p(x)` << 1 */ + { 0x0000000104de61aa, 0x000000018cfa961c }, + /* x^104448 mod p(x)` << 1, x^104512 mod p(x)` << 1 */ + { 0x0000000113e40d46, 0x000000019e588d52 }, + /* x^103424 mod p(x)` << 1, x^103488 mod p(x)` << 1 */ + { 0x00000001415598a0, 0x00000001180f0bbc }, + /* x^102400 mod p(x)` << 1, x^102464 mod p(x)` << 1 */ + { 0x00000000bf6c8c90, 0x00000000e1d9177a }, + /* x^101376 mod p(x)` << 1, x^101440 mod p(x)` << 1 */ + { 0x00000001788b0504, 0x0000000105abc27c }, + /* x^100352 mod p(x)` << 1, x^100416 mod p(x)` << 1 */ + { 0x0000000038385d02, 0x00000000972e4a58 }, + /* x^99328 mod p(x)` << 1, x^99392 mod p(x)` << 1 */ + { 0x00000001b6c83844, 0x0000000183499a5e }, + /* x^98304 mod p(x)` << 1, x^98368 mod p(x)` << 1 */ + { 0x0000000051061a8a, 0x00000001c96a8cca }, + /* x^97280 mod p(x)` << 1, x^97344 mod p(x)` << 1 */ + { 0x000000017351388a, 0x00000001a1a5b60c }, + /* x^96256 mod p(x)` << 1, x^96320 mod p(x)` << 1 */ + { 0x0000000132928f92, 0x00000000e4b6ac9c }, + /* x^95232 mod p(x)` << 1, x^95296 mod p(x)` << 1 */ + { 0x00000000e6b4f48a, 0x00000001807e7f5a }, + /* x^94208 mod p(x)` << 1, x^94272 mod p(x)` << 1 */ + { 0x0000000039d15e90, 0x000000017a7e3bc8 }, + /* x^93184 mod p(x)` << 1, x^93248 mod p(x)` << 1 */ + { 0x00000000312d6074, 0x00000000d73975da }, + /* x^92160 mod p(x)` << 1, x^92224 mod p(x)` << 1 */ + { 0x000000017bbb2cc4, 0x000000017375d038 }, + /* x^91136 mod p(x)` << 1, x^91200 mod p(x)` << 1 */ + { 0x000000016ded3e18, 0x00000000193680bc }, + /* x^90112 mod p(x)` << 1, x^90176 mod p(x)` << 1 */ + { 0x00000000f1638b16, 0x00000000999b06f6 }, + /* x^89088 mod p(x)` << 1, x^89152 mod p(x)` << 1 */ + { 0x00000001d38b9ecc, 0x00000001f685d2b8 }, + /* x^88064 mod p(x)` << 1, x^88128 mod p(x)` << 1 */ + { 0x000000018b8d09dc, 0x00000001f4ecbed2 }, + /* x^87040 mod p(x)` << 1, x^87104 mod p(x)` << 1 */ + { 0x00000000e7bc27d2, 0x00000000ba16f1a0 }, + /* x^86016 mod p(x)` << 1, x^86080 mod p(x)` << 1 */ + { 0x00000000275e1e96, 0x0000000115aceac4 }, + /* x^84992 mod p(x)` << 1, x^85056 mod p(x)` << 1 */ + { 0x00000000e2e3031e, 0x00000001aeff6292 }, + /* x^83968 mod p(x)` << 1, x^84032 mod p(x)` << 1 */ + { 0x00000001041c84d8, 0x000000009640124c }, + /* x^82944 mod p(x)` << 1, x^83008 mod p(x)` << 1 */ + { 0x00000000706ce672, 0x0000000114f41f02 }, + /* x^81920 mod p(x)` << 1, x^81984 mod p(x)` << 1 */ + { 0x000000015d5070da, 0x000000009c5f3586 }, + /* x^80896 mod p(x)` << 1, x^80960 mod p(x)` << 1 */ + { 0x0000000038f9493a, 0x00000001878275fa }, + /* x^79872 mod p(x)` << 1, x^79936 mod p(x)` << 1 */ + { 0x00000000a3348a76, 0x00000000ddc42ce8 }, + /* x^78848 mod p(x)` << 1, x^78912 mod p(x)` << 1 */ + { 0x00000001ad0aab92, 0x0000000181d2c73a }, + /* x^77824 mod p(x)` << 1, x^77888 mod p(x)` << 1 */ + { 0x000000019e85f712, 0x0000000141c9320a }, + /* x^76800 mod p(x)` << 1, x^76864 mod p(x)` << 1 */ + { 0x000000005a871e76, 0x000000015235719a }, + /* x^75776 mod p(x)` << 1, x^75840 mod p(x)` << 1 */ + { 0x000000017249c662, 0x00000000be27d804 }, + /* x^74752 mod p(x)` << 1, x^74816 mod p(x)` << 1 */ + { 0x000000003a084712, 0x000000006242d45a }, + /* x^73728 mod p(x)` << 1, x^73792 mod p(x)` << 1 */ + { 0x00000000ed438478, 0x000000009a53638e }, + /* x^72704 mod p(x)` << 1, x^72768 mod p(x)` << 1 */ + { 0x00000000abac34cc, 0x00000001001ecfb6 }, + /* x^71680 mod p(x)` << 1, x^71744 mod p(x)` << 1 */ + { 0x000000005f35ef3e, 0x000000016d7c2d64 }, + /* x^70656 mod p(x)` << 1, x^70720 mod p(x)` << 1 */ + { 0x0000000047d6608c, 0x00000001d0ce46c0 }, + /* x^69632 mod p(x)` << 1, x^69696 mod p(x)` << 1 */ + { 0x000000002d01470e, 0x0000000124c907b4 }, + /* x^68608 mod p(x)` << 1, x^68672 mod p(x)` << 1 */ + { 0x0000000158bbc7b0, 0x0000000018a555ca }, + /* x^67584 mod p(x)` << 1, x^67648 mod p(x)` << 1 */ + { 0x00000000c0a23e8e, 0x000000006b0980bc }, + /* x^66560 mod p(x)` << 1, x^66624 mod p(x)` << 1 */ + { 0x00000001ebd85c88, 0x000000008bbba964 }, + /* x^65536 mod p(x)` << 1, x^65600 mod p(x)` << 1 */ + { 0x000000019ee20bb2, 0x00000001070a5a1e }, + /* x^64512 mod p(x)` << 1, x^64576 mod p(x)` << 1 */ + { 0x00000001acabf2d6, 0x000000002204322a }, + /* x^63488 mod p(x)` << 1, x^63552 mod p(x)` << 1 */ + { 0x00000001b7963d56, 0x00000000a27524d0 }, + /* x^62464 mod p(x)` << 1, x^62528 mod p(x)` << 1 */ + { 0x000000017bffa1fe, 0x0000000020b1e4ba }, + /* x^61440 mod p(x)` << 1, x^61504 mod p(x)` << 1 */ + { 0x000000001f15333e, 0x0000000032cc27fc }, + /* x^60416 mod p(x)` << 1, x^60480 mod p(x)` << 1 */ + { 0x000000018593129e, 0x0000000044dd22b8 }, + /* x^59392 mod p(x)` << 1, x^59456 mod p(x)` << 1 */ + { 0x000000019cb32602, 0x00000000dffc9e0a }, + /* x^58368 mod p(x)` << 1, x^58432 mod p(x)` << 1 */ + { 0x0000000142b05cc8, 0x00000001b7a0ed14 }, + /* x^57344 mod p(x)` << 1, x^57408 mod p(x)` << 1 */ + { 0x00000001be49e7a4, 0x00000000c7842488 }, + /* x^56320 mod p(x)` << 1, x^56384 mod p(x)` << 1 */ + { 0x0000000108f69d6c, 0x00000001c02a4fee }, + /* x^55296 mod p(x)` << 1, x^55360 mod p(x)` << 1 */ + { 0x000000006c0971f0, 0x000000003c273778 }, + /* x^54272 mod p(x)` << 1, x^54336 mod p(x)` << 1 */ + { 0x000000005b16467a, 0x00000001d63f8894 }, + /* x^53248 mod p(x)` << 1, x^53312 mod p(x)` << 1 */ + { 0x00000001551a628e, 0x000000006be557d6 }, + /* x^52224 mod p(x)` << 1, x^52288 mod p(x)` << 1 */ + { 0x000000019e42ea92, 0x000000006a7806ea }, + /* x^51200 mod p(x)` << 1, x^51264 mod p(x)` << 1 */ + { 0x000000012fa83ff2, 0x000000016155aa0c }, + /* x^50176 mod p(x)` << 1, x^50240 mod p(x)` << 1 */ + { 0x000000011ca9cde0, 0x00000000908650ac }, + /* x^49152 mod p(x)` << 1, x^49216 mod p(x)` << 1 */ + { 0x00000000c8e5cd74, 0x00000000aa5a8084 }, + /* x^48128 mod p(x)` << 1, x^48192 mod p(x)` << 1 */ + { 0x0000000096c27f0c, 0x0000000191bb500a }, + /* x^47104 mod p(x)` << 1, x^47168 mod p(x)` << 1 */ + { 0x000000002baed926, 0x0000000064e9bed0 }, + /* x^46080 mod p(x)` << 1, x^46144 mod p(x)` << 1 */ + { 0x000000017c8de8d2, 0x000000009444f302 }, + /* x^45056 mod p(x)` << 1, x^45120 mod p(x)` << 1 */ + { 0x00000000d43d6068, 0x000000019db07d3c }, + /* x^44032 mod p(x)` << 1, x^44096 mod p(x)` << 1 */ + { 0x00000000cb2c4b26, 0x00000001359e3e6e }, + /* x^43008 mod p(x)` << 1, x^43072 mod p(x)` << 1 */ + { 0x0000000145b8da26, 0x00000001e4f10dd2 }, + /* x^41984 mod p(x)` << 1, x^42048 mod p(x)` << 1 */ + { 0x000000018fff4b08, 0x0000000124f5735e }, + /* x^40960 mod p(x)` << 1, x^41024 mod p(x)` << 1 */ + { 0x0000000150b58ed0, 0x0000000124760a4c }, + /* x^39936 mod p(x)` << 1, x^40000 mod p(x)` << 1 */ + { 0x00000001549f39bc, 0x000000000f1fc186 }, + /* x^38912 mod p(x)` << 1, x^38976 mod p(x)` << 1 */ + { 0x00000000ef4d2f42, 0x00000000150e4cc4 }, + /* x^37888 mod p(x)` << 1, x^37952 mod p(x)` << 1 */ + { 0x00000001b1468572, 0x000000002a6204e8 }, + /* x^36864 mod p(x)` << 1, x^36928 mod p(x)` << 1 */ + { 0x000000013d7403b2, 0x00000000beb1d432 }, + /* x^35840 mod p(x)` << 1, x^35904 mod p(x)` << 1 */ + { 0x00000001a4681842, 0x0000000135f3f1f0 }, + /* x^34816 mod p(x)` << 1, x^34880 mod p(x)` << 1 */ + { 0x0000000167714492, 0x0000000074fe2232 }, + /* x^33792 mod p(x)` << 1, x^33856 mod p(x)` << 1 */ + { 0x00000001e599099a, 0x000000001ac6e2ba }, + /* x^32768 mod p(x)` << 1, x^32832 mod p(x)` << 1 */ + { 0x00000000fe128194, 0x0000000013fca91e }, + /* x^31744 mod p(x)` << 1, x^31808 mod p(x)` << 1 */ + { 0x0000000077e8b990, 0x0000000183f4931e }, + /* x^30720 mod p(x)` << 1, x^30784 mod p(x)` << 1 */ + { 0x00000001a267f63a, 0x00000000b6d9b4e4 }, + /* x^29696 mod p(x)` << 1, x^29760 mod p(x)` << 1 */ + { 0x00000001945c245a, 0x00000000b5188656 }, + /* x^28672 mod p(x)` << 1, x^28736 mod p(x)` << 1 */ + { 0x0000000149002e76, 0x0000000027a81a84 }, + /* x^27648 mod p(x)` << 1, x^27712 mod p(x)` << 1 */ + { 0x00000001bb8310a4, 0x0000000125699258 }, + /* x^26624 mod p(x)` << 1, x^26688 mod p(x)` << 1 */ + { 0x000000019ec60bcc, 0x00000001b23de796 }, + /* x^25600 mod p(x)` << 1, x^25664 mod p(x)` << 1 */ + { 0x000000012d8590ae, 0x00000000fe4365dc }, + /* x^24576 mod p(x)` << 1, x^24640 mod p(x)` << 1 */ + { 0x0000000065b00684, 0x00000000c68f497a }, + /* x^23552 mod p(x)` << 1, x^23616 mod p(x)` << 1 */ + { 0x000000015e5aeadc, 0x00000000fbf521ee }, + /* x^22528 mod p(x)` << 1, x^22592 mod p(x)` << 1 */ + { 0x00000000b77ff2b0, 0x000000015eac3378 }, + /* x^21504 mod p(x)` << 1, x^21568 mod p(x)` << 1 */ + { 0x0000000188da2ff6, 0x0000000134914b90 }, + /* x^20480 mod p(x)` << 1, x^20544 mod p(x)` << 1 */ + { 0x0000000063da929a, 0x0000000016335cfe }, + /* x^19456 mod p(x)` << 1, x^19520 mod p(x)` << 1 */ + { 0x00000001389caa80, 0x000000010372d10c }, + /* x^18432 mod p(x)` << 1, x^18496 mod p(x)` << 1 */ + { 0x000000013db599d2, 0x000000015097b908 }, + /* x^17408 mod p(x)` << 1, x^17472 mod p(x)` << 1 */ + { 0x0000000122505a86, 0x00000001227a7572 }, + /* x^16384 mod p(x)` << 1, x^16448 mod p(x)` << 1 */ + { 0x000000016bd72746, 0x000000009a8f75c0 }, + /* x^15360 mod p(x)` << 1, x^15424 mod p(x)` << 1 */ + { 0x00000001c3faf1d4, 0x00000000682c77a2 }, + /* x^14336 mod p(x)` << 1, x^14400 mod p(x)` << 1 */ + { 0x00000001111c826c, 0x00000000231f091c }, + /* x^13312 mod p(x)` << 1, x^13376 mod p(x)` << 1 */ + { 0x00000000153e9fb2, 0x000000007d4439f2 }, + /* x^12288 mod p(x)` << 1, x^12352 mod p(x)` << 1 */ + { 0x000000002b1f7b60, 0x000000017e221efc }, + /* x^11264 mod p(x)` << 1, x^11328 mod p(x)` << 1 */ + { 0x00000000b1dba570, 0x0000000167457c38 }, + /* x^10240 mod p(x)` << 1, x^10304 mod p(x)` << 1 */ + { 0x00000001f6397b76, 0x00000000bdf081c4 }, + /* x^9216 mod p(x)` << 1, x^9280 mod p(x)` << 1 */ + { 0x0000000156335214, 0x000000016286d6b0 }, + /* x^8192 mod p(x)` << 1, x^8256 mod p(x)` << 1 */ + { 0x00000001d70e3986, 0x00000000c84f001c }, + /* x^7168 mod p(x)` << 1, x^7232 mod p(x)` << 1 */ + { 0x000000003701a774, 0x0000000064efe7c0 }, + /* x^6144 mod p(x)` << 1, x^6208 mod p(x)` << 1 */ + { 0x00000000ac81ef72, 0x000000000ac2d904 }, + /* x^5120 mod p(x)` << 1, x^5184 mod p(x)` << 1 */ + { 0x0000000133212464, 0x00000000fd226d14 }, + /* x^4096 mod p(x)` << 1, x^4160 mod p(x)` << 1 */ + { 0x00000000e4e45610, 0x000000011cfd42e0 }, + /* x^3072 mod p(x)` << 1, x^3136 mod p(x)` << 1 */ + { 0x000000000c1bd370, 0x000000016e5a5678 }, + /* x^2048 mod p(x)` << 1, x^2112 mod p(x)` << 1 */ + { 0x00000001a7b9e7a6, 0x00000001d888fe22 }, + /* x^1024 mod p(x)` << 1, x^1088 mod p(x)` << 1 */ + { 0x000000007d657a10, 0x00000001af77fcd4 } +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* x^261120 mod p(x)` << 1, x^261184 mod p(x)` << 1 */ + { 0x00000001651797d2, 0x0000000099ea94a8 }, + /* x^260096 mod p(x)` << 1, x^260160 mod p(x)` << 1 */ + { 0x0000000021e0d56c, 0x00000000945a8420 }, + /* x^259072 mod p(x)` << 1, x^259136 mod p(x)` << 1 */ + { 0x000000000f95ecaa, 0x0000000030762706 }, + /* x^258048 mod p(x)` << 1, x^258112 mod p(x)` << 1 */ + { 0x00000001ebd224ac, 0x00000001a52fc582 }, + /* x^257024 mod p(x)` << 1, x^257088 mod p(x)` << 1 */ + { 0x000000000ccb97ca, 0x00000001a4a7167a }, + /* x^256000 mod p(x)` << 1, x^256064 mod p(x)` << 1 */ + { 0x00000001006ec8a8, 0x000000000c18249a }, + /* x^254976 mod p(x)` << 1, x^255040 mod p(x)` << 1 */ + { 0x000000014f58f196, 0x00000000a924ae7c }, + /* x^253952 mod p(x)` << 1, x^254016 mod p(x)` << 1 */ + { 0x00000001a7192ca6, 0x00000001e12ccc12 }, + /* x^252928 mod p(x)` << 1, x^252992 mod p(x)` << 1 */ + { 0x000000019a64bab2, 0x00000000a0b9d4ac }, + /* x^251904 mod p(x)` << 1, x^251968 mod p(x)` << 1 */ + { 0x0000000014f4ed2e, 0x0000000095e8ddfe }, + /* x^250880 mod p(x)` << 1, x^250944 mod p(x)` << 1 */ + { 0x000000011092b6a2, 0x00000000233fddc4 }, + /* x^249856 mod p(x)` << 1, x^249920 mod p(x)` << 1 */ + { 0x00000000c8a1629c, 0x00000001b4529b62 }, + /* x^248832 mod p(x)` << 1, x^248896 mod p(x)` << 1 */ + { 0x000000017bf32e8e, 0x00000001a7fa0e64 }, + /* x^247808 mod p(x)` << 1, x^247872 mod p(x)` << 1 */ + { 0x00000001f8cc6582, 0x00000001b5334592 }, + /* x^246784 mod p(x)` << 1, x^246848 mod p(x)` << 1 */ + { 0x000000008631ddf0, 0x000000011f8ee1b4 }, + /* x^245760 mod p(x)` << 1, x^245824 mod p(x)` << 1 */ + { 0x000000007e5a76d0, 0x000000006252e632 }, + /* x^244736 mod p(x)` << 1, x^244800 mod p(x)` << 1 */ + { 0x000000002b09b31c, 0x00000000ab973e84 }, + /* x^243712 mod p(x)` << 1, x^243776 mod p(x)` << 1 */ + { 0x00000001b2df1f84, 0x000000007734f5ec }, + /* x^242688 mod p(x)` << 1, x^242752 mod p(x)` << 1 */ + { 0x00000001d6f56afc, 0x000000007c547798 }, + /* x^241664 mod p(x)` << 1, x^241728 mod p(x)` << 1 */ + { 0x00000001b9b5e70c, 0x000000007ec40210 }, + /* x^240640 mod p(x)` << 1, x^240704 mod p(x)` << 1 */ + { 0x0000000034b626d2, 0x00000001ab1695a8 }, + /* x^239616 mod p(x)` << 1, x^239680 mod p(x)` << 1 */ + { 0x000000014c53479a, 0x0000000090494bba }, + /* x^238592 mod p(x)` << 1, x^238656 mod p(x)` << 1 */ + { 0x00000001a6d179a4, 0x00000001123fb816 }, + /* x^237568 mod p(x)` << 1, x^237632 mod p(x)` << 1 */ + { 0x000000015abd16b4, 0x00000001e188c74c }, + /* x^236544 mod p(x)` << 1, x^236608 mod p(x)` << 1 */ + { 0x00000000018f9852, 0x00000001c2d3451c }, + /* x^235520 mod p(x)` << 1, x^235584 mod p(x)` << 1 */ + { 0x000000001fb3084a, 0x00000000f55cf1ca }, + /* x^234496 mod p(x)` << 1, x^234560 mod p(x)` << 1 */ + { 0x00000000c53dfb04, 0x00000001a0531540 }, + /* x^233472 mod p(x)` << 1, x^233536 mod p(x)` << 1 */ + { 0x00000000e10c9ad6, 0x0000000132cd7ebc }, + /* x^232448 mod p(x)` << 1, x^232512 mod p(x)` << 1 */ + { 0x0000000025aa994a, 0x0000000073ab7f36 }, + /* x^231424 mod p(x)` << 1, x^231488 mod p(x)` << 1 */ + { 0x00000000fa3a74c4, 0x0000000041aed1c2 }, + /* x^230400 mod p(x)` << 1, x^230464 mod p(x)` << 1 */ + { 0x0000000033eb3f40, 0x0000000136c53800 }, + /* x^229376 mod p(x)` << 1, x^229440 mod p(x)` << 1 */ + { 0x000000017193f296, 0x0000000126835a30 }, + /* x^228352 mod p(x)` << 1, x^228416 mod p(x)` << 1 */ + { 0x0000000043f6c86a, 0x000000006241b502 }, + /* x^227328 mod p(x)` << 1, x^227392 mod p(x)` << 1 */ + { 0x000000016b513ec6, 0x00000000d5196ad4 }, + /* x^226304 mod p(x)` << 1, x^226368 mod p(x)` << 1 */ + { 0x00000000c8f25b4e, 0x000000009cfa769a }, + /* x^225280 mod p(x)` << 1, x^225344 mod p(x)` << 1 */ + { 0x00000001a45048ec, 0x00000000920e5df4 }, + /* x^224256 mod p(x)` << 1, x^224320 mod p(x)` << 1 */ + { 0x000000000c441004, 0x0000000169dc310e }, + /* x^223232 mod p(x)` << 1, x^223296 mod p(x)` << 1 */ + { 0x000000000e17cad6, 0x0000000009fc331c }, + /* x^222208 mod p(x)` << 1, x^222272 mod p(x)` << 1 */ + { 0x00000001253ae964, 0x000000010d94a81e }, + /* x^221184 mod p(x)` << 1, x^221248 mod p(x)` << 1 */ + { 0x00000001d7c88ebc, 0x0000000027a20ab2 }, + /* x^220160 mod p(x)` << 1, x^220224 mod p(x)` << 1 */ + { 0x00000001e7ca913a, 0x0000000114f87504 }, + /* x^219136 mod p(x)` << 1, x^219200 mod p(x)` << 1 */ + { 0x0000000033ed078a, 0x000000004b076d96 }, + /* x^218112 mod p(x)` << 1, x^218176 mod p(x)` << 1 */ + { 0x00000000e1839c78, 0x00000000da4d1e74 }, + /* x^217088 mod p(x)` << 1, x^217152 mod p(x)` << 1 */ + { 0x00000001322b267e, 0x000000001b81f672 }, + /* x^216064 mod p(x)` << 1, x^216128 mod p(x)` << 1 */ + { 0x00000000638231b6, 0x000000009367c988 }, + /* x^215040 mod p(x)` << 1, x^215104 mod p(x)` << 1 */ + { 0x00000001ee7f16f4, 0x00000001717214ca }, + /* x^214016 mod p(x)` << 1, x^214080 mod p(x)` << 1 */ + { 0x0000000117d9924a, 0x000000009f47d820 }, + /* x^212992 mod p(x)` << 1, x^213056 mod p(x)` << 1 */ + { 0x00000000e1a9e0c4, 0x000000010d9a47d2 }, + /* x^211968 mod p(x)` << 1, x^212032 mod p(x)` << 1 */ + { 0x00000001403731dc, 0x00000000a696c58c }, + /* x^210944 mod p(x)` << 1, x^211008 mod p(x)` << 1 */ + { 0x00000001a5ea9682, 0x000000002aa28ec6 }, + /* x^209920 mod p(x)` << 1, x^209984 mod p(x)` << 1 */ + { 0x0000000101c5c578, 0x00000001fe18fd9a }, + /* x^208896 mod p(x)` << 1, x^208960 mod p(x)` << 1 */ + { 0x00000000dddf6494, 0x000000019d4fc1ae }, + /* x^207872 mod p(x)` << 1, x^207936 mod p(x)` << 1 */ + { 0x00000000f1c3db28, 0x00000001ba0e3dea }, + /* x^206848 mod p(x)` << 1, x^206912 mod p(x)` << 1 */ + { 0x000000013112fb9c, 0x0000000074b59a5e }, + /* x^205824 mod p(x)` << 1, x^205888 mod p(x)` << 1 */ + { 0x00000000b680b906, 0x00000000f2b5ea98 }, + /* x^204800 mod p(x)` << 1, x^204864 mod p(x)` << 1 */ + { 0x000000001a282932, 0x0000000187132676 }, + /* x^203776 mod p(x)` << 1, x^203840 mod p(x)` << 1 */ + { 0x0000000089406e7e, 0x000000010a8c6ad4 }, + /* x^202752 mod p(x)` << 1, x^202816 mod p(x)` << 1 */ + { 0x00000001def6be8c, 0x00000001e21dfe70 }, + /* x^201728 mod p(x)` << 1, x^201792 mod p(x)` << 1 */ + { 0x0000000075258728, 0x00000001da0050e4 }, + /* x^200704 mod p(x)` << 1, x^200768 mod p(x)` << 1 */ + { 0x000000019536090a, 0x00000000772172ae }, + /* x^199680 mod p(x)` << 1, x^199744 mod p(x)` << 1 */ + { 0x00000000f2455bfc, 0x00000000e47724aa }, + /* x^198656 mod p(x)` << 1, x^198720 mod p(x)` << 1 */ + { 0x000000018c40baf4, 0x000000003cd63ac4 }, + /* x^197632 mod p(x)` << 1, x^197696 mod p(x)` << 1 */ + { 0x000000004cd390d4, 0x00000001bf47d352 }, + /* x^196608 mod p(x)` << 1, x^196672 mod p(x)` << 1 */ + { 0x00000001e4ece95a, 0x000000018dc1d708 }, + /* x^195584 mod p(x)` << 1, x^195648 mod p(x)` << 1 */ + { 0x000000001a3ee918, 0x000000002d4620a4 }, + /* x^194560 mod p(x)` << 1, x^194624 mod p(x)` << 1 */ + { 0x000000007c652fb8, 0x0000000058fd1740 }, + /* x^193536 mod p(x)` << 1, x^193600 mod p(x)` << 1 */ + { 0x000000011c67842c, 0x00000000dadd9bfc }, + /* x^192512 mod p(x)` << 1, x^192576 mod p(x)` << 1 */ + { 0x00000000254f759c, 0x00000001ea2140be }, + /* x^191488 mod p(x)` << 1, x^191552 mod p(x)` << 1 */ + { 0x000000007ece94ca, 0x000000009de128ba }, + /* x^190464 mod p(x)` << 1, x^190528 mod p(x)` << 1 */ + { 0x0000000038f258c2, 0x000000013ac3aa8e }, + /* x^189440 mod p(x)` << 1, x^189504 mod p(x)` << 1 */ + { 0x00000001cdf17b00, 0x0000000099980562 }, + /* x^188416 mod p(x)` << 1, x^188480 mod p(x)` << 1 */ + { 0x000000011f882c16, 0x00000001c1579c86 }, + /* x^187392 mod p(x)` << 1, x^187456 mod p(x)` << 1 */ + { 0x0000000100093fc8, 0x0000000068dbbf94 }, + /* x^186368 mod p(x)` << 1, x^186432 mod p(x)` << 1 */ + { 0x00000001cd684f16, 0x000000004509fb04 }, + /* x^185344 mod p(x)` << 1, x^185408 mod p(x)` << 1 */ + { 0x000000004bc6a70a, 0x00000001202f6398 }, + /* x^184320 mod p(x)` << 1, x^184384 mod p(x)` << 1 */ + { 0x000000004fc7e8e4, 0x000000013aea243e }, + /* x^183296 mod p(x)` << 1, x^183360 mod p(x)` << 1 */ + { 0x0000000130103f1c, 0x00000001b4052ae6 }, + /* x^182272 mod p(x)` << 1, x^182336 mod p(x)` << 1 */ + { 0x0000000111b0024c, 0x00000001cd2a0ae8 }, + /* x^181248 mod p(x)` << 1, x^181312 mod p(x)` << 1 */ + { 0x000000010b3079da, 0x00000001fe4aa8b4 }, + /* x^180224 mod p(x)` << 1, x^180288 mod p(x)` << 1 */ + { 0x000000010192bcc2, 0x00000001d1559a42 }, + /* x^179200 mod p(x)` << 1, x^179264 mod p(x)` << 1 */ + { 0x0000000074838d50, 0x00000001f3e05ecc }, + /* x^178176 mod p(x)` << 1, x^178240 mod p(x)` << 1 */ + { 0x000000001b20f520, 0x0000000104ddd2cc }, + /* x^177152 mod p(x)` << 1, x^177216 mod p(x)` << 1 */ + { 0x0000000050c3590a, 0x000000015393153c }, + /* x^176128 mod p(x)` << 1, x^176192 mod p(x)` << 1 */ + { 0x00000000b41cac8e, 0x0000000057e942c6 }, + /* x^175104 mod p(x)` << 1, x^175168 mod p(x)` << 1 */ + { 0x000000000c72cc78, 0x000000012c633850 }, + /* x^174080 mod p(x)` << 1, x^174144 mod p(x)` << 1 */ + { 0x0000000030cdb032, 0x00000000ebcaae4c }, + /* x^173056 mod p(x)` << 1, x^173120 mod p(x)` << 1 */ + { 0x000000013e09fc32, 0x000000013ee532a6 }, + /* x^172032 mod p(x)` << 1, x^172096 mod p(x)` << 1 */ + { 0x000000001ed624d2, 0x00000001bf0cbc7e }, + /* x^171008 mod p(x)` << 1, x^171072 mod p(x)` << 1 */ + { 0x00000000781aee1a, 0x00000000d50b7a5a }, + /* x^169984 mod p(x)` << 1, x^170048 mod p(x)` << 1 */ + { 0x00000001c4d8348c, 0x0000000002fca6e8 }, + /* x^168960 mod p(x)` << 1, x^169024 mod p(x)` << 1 */ + { 0x0000000057a40336, 0x000000007af40044 }, + /* x^167936 mod p(x)` << 1, x^168000 mod p(x)` << 1 */ + { 0x0000000085544940, 0x0000000016178744 }, + /* x^166912 mod p(x)` << 1, x^166976 mod p(x)` << 1 */ + { 0x000000019cd21e80, 0x000000014c177458 }, + /* x^165888 mod p(x)` << 1, x^165952 mod p(x)` << 1 */ + { 0x000000013eb95bc0, 0x000000011b6ddf04 }, + /* x^164864 mod p(x)` << 1, x^164928 mod p(x)` << 1 */ + { 0x00000001dfc9fdfc, 0x00000001f3e29ccc }, + /* x^163840 mod p(x)` << 1, x^163904 mod p(x)` << 1 */ + { 0x00000000cd028bc2, 0x0000000135ae7562 }, + /* x^162816 mod p(x)` << 1, x^162880 mod p(x)` << 1 */ + { 0x0000000090db8c44, 0x0000000190ef812c }, + /* x^161792 mod p(x)` << 1, x^161856 mod p(x)` << 1 */ + { 0x000000010010a4ce, 0x0000000067a2c786 }, + /* x^160768 mod p(x)` << 1, x^160832 mod p(x)` << 1 */ + { 0x00000001c8f4c72c, 0x0000000048b9496c }, + /* x^159744 mod p(x)` << 1, x^159808 mod p(x)` << 1 */ + { 0x000000001c26170c, 0x000000015a422de6 }, + /* x^158720 mod p(x)` << 1, x^158784 mod p(x)` << 1 */ + { 0x00000000e3fccf68, 0x00000001ef0e3640 }, + /* x^157696 mod p(x)` << 1, x^157760 mod p(x)` << 1 */ + { 0x00000000d513ed24, 0x00000001006d2d26 }, + /* x^156672 mod p(x)` << 1, x^156736 mod p(x)` << 1 */ + { 0x00000000141beada, 0x00000001170d56d6 }, + /* x^155648 mod p(x)` << 1, x^155712 mod p(x)` << 1 */ + { 0x000000011071aea0, 0x00000000a5fb613c }, + /* x^154624 mod p(x)` << 1, x^154688 mod p(x)` << 1 */ + { 0x000000012e19080a, 0x0000000040bbf7fc }, + /* x^153600 mod p(x)` << 1, x^153664 mod p(x)` << 1 */ + { 0x0000000100ecf826, 0x000000016ac3a5b2 }, + /* x^152576 mod p(x)` << 1, x^152640 mod p(x)` << 1 */ + { 0x0000000069b09412, 0x00000000abf16230 }, + /* x^151552 mod p(x)` << 1, x^151616 mod p(x)` << 1 */ + { 0x0000000122297bac, 0x00000001ebe23fac }, + /* x^150528 mod p(x)` << 1, x^150592 mod p(x)` << 1 */ + { 0x00000000e9e4b068, 0x000000008b6a0894 }, + /* x^149504 mod p(x)` << 1, x^149568 mod p(x)` << 1 */ + { 0x000000004b38651a, 0x00000001288ea478 }, + /* x^148480 mod p(x)` << 1, x^148544 mod p(x)` << 1 */ + { 0x00000001468360e2, 0x000000016619c442 }, + /* x^147456 mod p(x)` << 1, x^147520 mod p(x)` << 1 */ + { 0x00000000121c2408, 0x0000000086230038 }, + /* x^146432 mod p(x)` << 1, x^146496 mod p(x)` << 1 */ + { 0x00000000da7e7d08, 0x000000017746a756 }, + /* x^145408 mod p(x)` << 1, x^145472 mod p(x)` << 1 */ + { 0x00000001058d7652, 0x0000000191b8f8f8 }, + /* x^144384 mod p(x)` << 1, x^144448 mod p(x)` << 1 */ + { 0x000000014a098a90, 0x000000008e167708 }, + /* x^143360 mod p(x)` << 1, x^143424 mod p(x)` << 1 */ + { 0x0000000020dbe72e, 0x0000000148b22d54 }, + /* x^142336 mod p(x)` << 1, x^142400 mod p(x)` << 1 */ + { 0x000000011e7323e8, 0x0000000044ba2c3c }, + /* x^141312 mod p(x)` << 1, x^141376 mod p(x)` << 1 */ + { 0x00000000d5d4bf94, 0x00000000b54d2b52 }, + /* x^140288 mod p(x)` << 1, x^140352 mod p(x)` << 1 */ + { 0x0000000199d8746c, 0x0000000005a4fd8a }, + /* x^139264 mod p(x)` << 1, x^139328 mod p(x)` << 1 */ + { 0x00000000ce9ca8a0, 0x0000000139f9fc46 }, + /* x^138240 mod p(x)` << 1, x^138304 mod p(x)` << 1 */ + { 0x00000000136edece, 0x000000015a1fa824 }, + /* x^137216 mod p(x)` << 1, x^137280 mod p(x)` << 1 */ + { 0x000000019b92a068, 0x000000000a61ae4c }, + /* x^136192 mod p(x)` << 1, x^136256 mod p(x)` << 1 */ + { 0x0000000071d62206, 0x0000000145e9113e }, + /* x^135168 mod p(x)` << 1, x^135232 mod p(x)` << 1 */ + { 0x00000000dfc50158, 0x000000006a348448 }, + /* x^134144 mod p(x)` << 1, x^134208 mod p(x)` << 1 */ + { 0x00000001517626bc, 0x000000004d80a08c }, + /* x^133120 mod p(x)` << 1, x^133184 mod p(x)` << 1 */ + { 0x0000000148d1e4fa, 0x000000014b6837a0 }, + /* x^132096 mod p(x)` << 1, x^132160 mod p(x)` << 1 */ + { 0x0000000094d8266e, 0x000000016896a7fc }, + /* x^131072 mod p(x)` << 1, x^131136 mod p(x)` << 1 */ + { 0x00000000606c5e34, 0x000000014f187140 }, + /* x^130048 mod p(x)` << 1, x^130112 mod p(x)` << 1 */ + { 0x000000019766beaa, 0x000000019581b9da }, + /* x^129024 mod p(x)` << 1, x^129088 mod p(x)` << 1 */ + { 0x00000001d80c506c, 0x00000001091bc984 }, + /* x^128000 mod p(x)` << 1, x^128064 mod p(x)` << 1 */ + { 0x000000001e73837c, 0x000000001067223c }, + /* x^126976 mod p(x)` << 1, x^127040 mod p(x)` << 1 */ + { 0x0000000064d587de, 0x00000001ab16ea02 }, + /* x^125952 mod p(x)` << 1, x^126016 mod p(x)` << 1 */ + { 0x00000000f4a507b0, 0x000000013c4598a8 }, + /* x^124928 mod p(x)` << 1, x^124992 mod p(x)` << 1 */ + { 0x0000000040e342fc, 0x00000000b3735430 }, + /* x^123904 mod p(x)` << 1, x^123968 mod p(x)` << 1 */ + { 0x00000001d5ad9c3a, 0x00000001bb3fc0c0 }, + /* x^122880 mod p(x)` << 1, x^122944 mod p(x)` << 1 */ + { 0x0000000094a691a4, 0x00000001570ae19c }, + /* x^121856 mod p(x)` << 1, x^121920 mod p(x)` << 1 */ + { 0x00000001271ecdfa, 0x00000001ea910712 }, + /* x^120832 mod p(x)` << 1, x^120896 mod p(x)` << 1 */ + { 0x000000009e54475a, 0x0000000167127128 }, + /* x^119808 mod p(x)` << 1, x^119872 mod p(x)` << 1 */ + { 0x00000000c9c099ee, 0x0000000019e790a2 }, + /* x^118784 mod p(x)` << 1, x^118848 mod p(x)` << 1 */ + { 0x000000009a2f736c, 0x000000003788f710 }, + /* x^117760 mod p(x)` << 1, x^117824 mod p(x)` << 1 */ + { 0x00000000bb9f4996, 0x00000001682a160e }, + /* x^116736 mod p(x)` << 1, x^116800 mod p(x)` << 1 */ + { 0x00000001db688050, 0x000000007f0ebd2e }, + /* x^115712 mod p(x)` << 1, x^115776 mod p(x)` << 1 */ + { 0x00000000e9b10af4, 0x000000002b032080 }, + /* x^114688 mod p(x)` << 1, x^114752 mod p(x)` << 1 */ + { 0x000000012d4545e4, 0x00000000cfd1664a }, + /* x^113664 mod p(x)` << 1, x^113728 mod p(x)` << 1 */ + { 0x000000000361139c, 0x00000000aa1181c2 }, + /* x^112640 mod p(x)` << 1, x^112704 mod p(x)` << 1 */ + { 0x00000001a5a1a3a8, 0x00000000ddd08002 }, + /* x^111616 mod p(x)` << 1, x^111680 mod p(x)` << 1 */ + { 0x000000006844e0b0, 0x00000000e8dd0446 }, + /* x^110592 mod p(x)` << 1, x^110656 mod p(x)` << 1 */ + { 0x00000000c3762f28, 0x00000001bbd94a00 }, + /* x^109568 mod p(x)` << 1, x^109632 mod p(x)` << 1 */ + { 0x00000001d26287a2, 0x00000000ab6cd180 }, + /* x^108544 mod p(x)` << 1, x^108608 mod p(x)` << 1 */ + { 0x00000001f6f0bba8, 0x0000000031803ce2 }, + /* x^107520 mod p(x)` << 1, x^107584 mod p(x)` << 1 */ + { 0x000000002ffabd62, 0x0000000024f40b0c }, + /* x^106496 mod p(x)` << 1, x^106560 mod p(x)` << 1 */ + { 0x00000000fb4516b8, 0x00000001ba1d9834 }, + /* x^105472 mod p(x)` << 1, x^105536 mod p(x)` << 1 */ + { 0x000000018cfa961c, 0x0000000104de61aa }, + /* x^104448 mod p(x)` << 1, x^104512 mod p(x)` << 1 */ + { 0x000000019e588d52, 0x0000000113e40d46 }, + /* x^103424 mod p(x)` << 1, x^103488 mod p(x)` << 1 */ + { 0x00000001180f0bbc, 0x00000001415598a0 }, + /* x^102400 mod p(x)` << 1, x^102464 mod p(x)` << 1 */ + { 0x00000000e1d9177a, 0x00000000bf6c8c90 }, + /* x^101376 mod p(x)` << 1, x^101440 mod p(x)` << 1 */ + { 0x0000000105abc27c, 0x00000001788b0504 }, + /* x^100352 mod p(x)` << 1, x^100416 mod p(x)` << 1 */ + { 0x00000000972e4a58, 0x0000000038385d02 }, + /* x^99328 mod p(x)` << 1, x^99392 mod p(x)` << 1 */ + { 0x0000000183499a5e, 0x00000001b6c83844 }, + /* x^98304 mod p(x)` << 1, x^98368 mod p(x)` << 1 */ + { 0x00000001c96a8cca, 0x0000000051061a8a }, + /* x^97280 mod p(x)` << 1, x^97344 mod p(x)` << 1 */ + { 0x00000001a1a5b60c, 0x000000017351388a }, + /* x^96256 mod p(x)` << 1, x^96320 mod p(x)` << 1 */ + { 0x00000000e4b6ac9c, 0x0000000132928f92 }, + /* x^95232 mod p(x)` << 1, x^95296 mod p(x)` << 1 */ + { 0x00000001807e7f5a, 0x00000000e6b4f48a }, + /* x^94208 mod p(x)` << 1, x^94272 mod p(x)` << 1 */ + { 0x000000017a7e3bc8, 0x0000000039d15e90 }, + /* x^93184 mod p(x)` << 1, x^93248 mod p(x)` << 1 */ + { 0x00000000d73975da, 0x00000000312d6074 }, + /* x^92160 mod p(x)` << 1, x^92224 mod p(x)` << 1 */ + { 0x000000017375d038, 0x000000017bbb2cc4 }, + /* x^91136 mod p(x)` << 1, x^91200 mod p(x)` << 1 */ + { 0x00000000193680bc, 0x000000016ded3e18 }, + /* x^90112 mod p(x)` << 1, x^90176 mod p(x)` << 1 */ + { 0x00000000999b06f6, 0x00000000f1638b16 }, + /* x^89088 mod p(x)` << 1, x^89152 mod p(x)` << 1 */ + { 0x00000001f685d2b8, 0x00000001d38b9ecc }, + /* x^88064 mod p(x)` << 1, x^88128 mod p(x)` << 1 */ + { 0x00000001f4ecbed2, 0x000000018b8d09dc }, + /* x^87040 mod p(x)` << 1, x^87104 mod p(x)` << 1 */ + { 0x00000000ba16f1a0, 0x00000000e7bc27d2 }, + /* x^86016 mod p(x)` << 1, x^86080 mod p(x)` << 1 */ + { 0x0000000115aceac4, 0x00000000275e1e96 }, + /* x^84992 mod p(x)` << 1, x^85056 mod p(x)` << 1 */ + { 0x00000001aeff6292, 0x00000000e2e3031e }, + /* x^83968 mod p(x)` << 1, x^84032 mod p(x)` << 1 */ + { 0x000000009640124c, 0x00000001041c84d8 }, + /* x^82944 mod p(x)` << 1, x^83008 mod p(x)` << 1 */ + { 0x0000000114f41f02, 0x00000000706ce672 }, + /* x^81920 mod p(x)` << 1, x^81984 mod p(x)` << 1 */ + { 0x000000009c5f3586, 0x000000015d5070da }, + /* x^80896 mod p(x)` << 1, x^80960 mod p(x)` << 1 */ + { 0x00000001878275fa, 0x0000000038f9493a }, + /* x^79872 mod p(x)` << 1, x^79936 mod p(x)` << 1 */ + { 0x00000000ddc42ce8, 0x00000000a3348a76 }, + /* x^78848 mod p(x)` << 1, x^78912 mod p(x)` << 1 */ + { 0x0000000181d2c73a, 0x00000001ad0aab92 }, + /* x^77824 mod p(x)` << 1, x^77888 mod p(x)` << 1 */ + { 0x0000000141c9320a, 0x000000019e85f712 }, + /* x^76800 mod p(x)` << 1, x^76864 mod p(x)` << 1 */ + { 0x000000015235719a, 0x000000005a871e76 }, + /* x^75776 mod p(x)` << 1, x^75840 mod p(x)` << 1 */ + { 0x00000000be27d804, 0x000000017249c662 }, + /* x^74752 mod p(x)` << 1, x^74816 mod p(x)` << 1 */ + { 0x000000006242d45a, 0x000000003a084712 }, + /* x^73728 mod p(x)` << 1, x^73792 mod p(x)` << 1 */ + { 0x000000009a53638e, 0x00000000ed438478 }, + /* x^72704 mod p(x)` << 1, x^72768 mod p(x)` << 1 */ + { 0x00000001001ecfb6, 0x00000000abac34cc }, + /* x^71680 mod p(x)` << 1, x^71744 mod p(x)` << 1 */ + { 0x000000016d7c2d64, 0x000000005f35ef3e }, + /* x^70656 mod p(x)` << 1, x^70720 mod p(x)` << 1 */ + { 0x00000001d0ce46c0, 0x0000000047d6608c }, + /* x^69632 mod p(x)` << 1, x^69696 mod p(x)` << 1 */ + { 0x0000000124c907b4, 0x000000002d01470e }, + /* x^68608 mod p(x)` << 1, x^68672 mod p(x)` << 1 */ + { 0x0000000018a555ca, 0x0000000158bbc7b0 }, + /* x^67584 mod p(x)` << 1, x^67648 mod p(x)` << 1 */ + { 0x000000006b0980bc, 0x00000000c0a23e8e }, + /* x^66560 mod p(x)` << 1, x^66624 mod p(x)` << 1 */ + { 0x000000008bbba964, 0x00000001ebd85c88 }, + /* x^65536 mod p(x)` << 1, x^65600 mod p(x)` << 1 */ + { 0x00000001070a5a1e, 0x000000019ee20bb2 }, + /* x^64512 mod p(x)` << 1, x^64576 mod p(x)` << 1 */ + { 0x000000002204322a, 0x00000001acabf2d6 }, + /* x^63488 mod p(x)` << 1, x^63552 mod p(x)` << 1 */ + { 0x00000000a27524d0, 0x00000001b7963d56 }, + /* x^62464 mod p(x)` << 1, x^62528 mod p(x)` << 1 */ + { 0x0000000020b1e4ba, 0x000000017bffa1fe }, + /* x^61440 mod p(x)` << 1, x^61504 mod p(x)` << 1 */ + { 0x0000000032cc27fc, 0x000000001f15333e }, + /* x^60416 mod p(x)` << 1, x^60480 mod p(x)` << 1 */ + { 0x0000000044dd22b8, 0x000000018593129e }, + /* x^59392 mod p(x)` << 1, x^59456 mod p(x)` << 1 */ + { 0x00000000dffc9e0a, 0x000000019cb32602 }, + /* x^58368 mod p(x)` << 1, x^58432 mod p(x)` << 1 */ + { 0x00000001b7a0ed14, 0x0000000142b05cc8 }, + /* x^57344 mod p(x)` << 1, x^57408 mod p(x)` << 1 */ + { 0x00000000c7842488, 0x00000001be49e7a4 }, + /* x^56320 mod p(x)` << 1, x^56384 mod p(x)` << 1 */ + { 0x00000001c02a4fee, 0x0000000108f69d6c }, + /* x^55296 mod p(x)` << 1, x^55360 mod p(x)` << 1 */ + { 0x000000003c273778, 0x000000006c0971f0 }, + /* x^54272 mod p(x)` << 1, x^54336 mod p(x)` << 1 */ + { 0x00000001d63f8894, 0x000000005b16467a }, + /* x^53248 mod p(x)` << 1, x^53312 mod p(x)` << 1 */ + { 0x000000006be557d6, 0x00000001551a628e }, + /* x^52224 mod p(x)` << 1, x^52288 mod p(x)` << 1 */ + { 0x000000006a7806ea, 0x000000019e42ea92 }, + /* x^51200 mod p(x)` << 1, x^51264 mod p(x)` << 1 */ + { 0x000000016155aa0c, 0x000000012fa83ff2 }, + /* x^50176 mod p(x)` << 1, x^50240 mod p(x)` << 1 */ + { 0x00000000908650ac, 0x000000011ca9cde0 }, + /* x^49152 mod p(x)` << 1, x^49216 mod p(x)` << 1 */ + { 0x00000000aa5a8084, 0x00000000c8e5cd74 }, + /* x^48128 mod p(x)` << 1, x^48192 mod p(x)` << 1 */ + { 0x0000000191bb500a, 0x0000000096c27f0c }, + /* x^47104 mod p(x)` << 1, x^47168 mod p(x)` << 1 */ + { 0x0000000064e9bed0, 0x000000002baed926 }, + /* x^46080 mod p(x)` << 1, x^46144 mod p(x)` << 1 */ + { 0x000000009444f302, 0x000000017c8de8d2 }, + /* x^45056 mod p(x)` << 1, x^45120 mod p(x)` << 1 */ + { 0x000000019db07d3c, 0x00000000d43d6068 }, + /* x^44032 mod p(x)` << 1, x^44096 mod p(x)` << 1 */ + { 0x00000001359e3e6e, 0x00000000cb2c4b26 }, + /* x^43008 mod p(x)` << 1, x^43072 mod p(x)` << 1 */ + { 0x00000001e4f10dd2, 0x0000000145b8da26 }, + /* x^41984 mod p(x)` << 1, x^42048 mod p(x)` << 1 */ + { 0x0000000124f5735e, 0x000000018fff4b08 }, + /* x^40960 mod p(x)` << 1, x^41024 mod p(x)` << 1 */ + { 0x0000000124760a4c, 0x0000000150b58ed0 }, + /* x^39936 mod p(x)` << 1, x^40000 mod p(x)` << 1 */ + { 0x000000000f1fc186, 0x00000001549f39bc }, + /* x^38912 mod p(x)` << 1, x^38976 mod p(x)` << 1 */ + { 0x00000000150e4cc4, 0x00000000ef4d2f42 }, + /* x^37888 mod p(x)` << 1, x^37952 mod p(x)` << 1 */ + { 0x000000002a6204e8, 0x00000001b1468572 }, + /* x^36864 mod p(x)` << 1, x^36928 mod p(x)` << 1 */ + { 0x00000000beb1d432, 0x000000013d7403b2 }, + /* x^35840 mod p(x)` << 1, x^35904 mod p(x)` << 1 */ + { 0x0000000135f3f1f0, 0x00000001a4681842 }, + /* x^34816 mod p(x)` << 1, x^34880 mod p(x)` << 1 */ + { 0x0000000074fe2232, 0x0000000167714492 }, + /* x^33792 mod p(x)` << 1, x^33856 mod p(x)` << 1 */ + { 0x000000001ac6e2ba, 0x00000001e599099a }, + /* x^32768 mod p(x)` << 1, x^32832 mod p(x)` << 1 */ + { 0x0000000013fca91e, 0x00000000fe128194 }, + /* x^31744 mod p(x)` << 1, x^31808 mod p(x)` << 1 */ + { 0x0000000183f4931e, 0x0000000077e8b990 }, + /* x^30720 mod p(x)` << 1, x^30784 mod p(x)` << 1 */ + { 0x00000000b6d9b4e4, 0x00000001a267f63a }, + /* x^29696 mod p(x)` << 1, x^29760 mod p(x)` << 1 */ + { 0x00000000b5188656, 0x00000001945c245a }, + /* x^28672 mod p(x)` << 1, x^28736 mod p(x)` << 1 */ + { 0x0000000027a81a84, 0x0000000149002e76 }, + /* x^27648 mod p(x)` << 1, x^27712 mod p(x)` << 1 */ + { 0x0000000125699258, 0x00000001bb8310a4 }, + /* x^26624 mod p(x)` << 1, x^26688 mod p(x)` << 1 */ + { 0x00000001b23de796, 0x000000019ec60bcc }, + /* x^25600 mod p(x)` << 1, x^25664 mod p(x)` << 1 */ + { 0x00000000fe4365dc, 0x000000012d8590ae }, + /* x^24576 mod p(x)` << 1, x^24640 mod p(x)` << 1 */ + { 0x00000000c68f497a, 0x0000000065b00684 }, + /* x^23552 mod p(x)` << 1, x^23616 mod p(x)` << 1 */ + { 0x00000000fbf521ee, 0x000000015e5aeadc }, + /* x^22528 mod p(x)` << 1, x^22592 mod p(x)` << 1 */ + { 0x000000015eac3378, 0x00000000b77ff2b0 }, + /* x^21504 mod p(x)` << 1, x^21568 mod p(x)` << 1 */ + { 0x0000000134914b90, 0x0000000188da2ff6 }, + /* x^20480 mod p(x)` << 1, x^20544 mod p(x)` << 1 */ + { 0x0000000016335cfe, 0x0000000063da929a }, + /* x^19456 mod p(x)` << 1, x^19520 mod p(x)` << 1 */ + { 0x000000010372d10c, 0x00000001389caa80 }, + /* x^18432 mod p(x)` << 1, x^18496 mod p(x)` << 1 */ + { 0x000000015097b908, 0x000000013db599d2 }, + /* x^17408 mod p(x)` << 1, x^17472 mod p(x)` << 1 */ + { 0x00000001227a7572, 0x0000000122505a86 }, + /* x^16384 mod p(x)` << 1, x^16448 mod p(x)` << 1 */ + { 0x000000009a8f75c0, 0x000000016bd72746 }, + /* x^15360 mod p(x)` << 1, x^15424 mod p(x)` << 1 */ + { 0x00000000682c77a2, 0x00000001c3faf1d4 }, + /* x^14336 mod p(x)` << 1, x^14400 mod p(x)` << 1 */ + { 0x00000000231f091c, 0x00000001111c826c }, + /* x^13312 mod p(x)` << 1, x^13376 mod p(x)` << 1 */ + { 0x000000007d4439f2, 0x00000000153e9fb2 }, + /* x^12288 mod p(x)` << 1, x^12352 mod p(x)` << 1 */ + { 0x000000017e221efc, 0x000000002b1f7b60 }, + /* x^11264 mod p(x)` << 1, x^11328 mod p(x)` << 1 */ + { 0x0000000167457c38, 0x00000000b1dba570 }, + /* x^10240 mod p(x)` << 1, x^10304 mod p(x)` << 1 */ + { 0x00000000bdf081c4, 0x00000001f6397b76 }, + /* x^9216 mod p(x)` << 1, x^9280 mod p(x)` << 1 */ + { 0x000000016286d6b0, 0x0000000156335214 }, + /* x^8192 mod p(x)` << 1, x^8256 mod p(x)` << 1 */ + { 0x00000000c84f001c, 0x00000001d70e3986 }, + /* x^7168 mod p(x)` << 1, x^7232 mod p(x)` << 1 */ + { 0x0000000064efe7c0, 0x000000003701a774 }, + /* x^6144 mod p(x)` << 1, x^6208 mod p(x)` << 1 */ + { 0x000000000ac2d904, 0x00000000ac81ef72 }, + /* x^5120 mod p(x)` << 1, x^5184 mod p(x)` << 1 */ + { 0x00000000fd226d14, 0x0000000133212464 }, + /* x^4096 mod p(x)` << 1, x^4160 mod p(x)` << 1 */ + { 0x000000011cfd42e0, 0x00000000e4e45610 }, + /* x^3072 mod p(x)` << 1, x^3136 mod p(x)` << 1 */ + { 0x000000016e5a5678, 0x000000000c1bd370 }, + /* x^2048 mod p(x)` << 1, x^2112 mod p(x)` << 1 */ + { 0x00000001d888fe22, 0x00000001a7b9e7a6 }, + /* x^1024 mod p(x)` << 1, x^1088 mod p(x)` << 1 */ + { 0x00000001af77fcd4, 0x000000007d657a10 } +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ +}; + +/* Reduce final 1024-2048 bits to 64 bits, shifting 32 bits to include the trailing 32 bits of zeros */ + +static const __vector unsigned long long vcrc_short_const[16] ALIGNED_(16) = { +#if BYTE_ORDER == LITTLE_ENDIAN + /* x^1952 mod p(x) , x^1984 mod p(x) , x^2016 mod p(x) , x^2048 mod p(x) */ + { 0x99168a18ec447f11, 0xed837b2613e8221e }, + /* x^1824 mod p(x) , x^1856 mod p(x) , x^1888 mod p(x) , x^1920 mod p(x) */ + { 0xe23e954e8fd2cd3c, 0xc8acdd8147b9ce5a }, + /* x^1696 mod p(x) , x^1728 mod p(x) , x^1760 mod p(x) , x^1792 mod p(x) */ + { 0x92f8befe6b1d2b53, 0xd9ad6d87d4277e25 }, + /* x^1568 mod p(x) , x^1600 mod p(x) , x^1632 mod p(x) , x^1664 mod p(x) */ + { 0xf38a3556291ea462, 0xc10ec5e033fbca3b }, + /* x^1440 mod p(x) , x^1472 mod p(x) , x^1504 mod p(x) , x^1536 mod p(x) */ + { 0x974ac56262b6ca4b, 0xc0b55b0e82e02e2f }, + /* x^1312 mod p(x) , x^1344 mod p(x) , x^1376 mod p(x) , x^1408 mod p(x) */ + { 0x855712b3784d2a56, 0x71aa1df0e172334d }, + /* x^1184 mod p(x) , x^1216 mod p(x) , x^1248 mod p(x) , x^1280 mod p(x) */ + { 0xa5abe9f80eaee722, 0xfee3053e3969324d }, + /* x^1056 mod p(x) , x^1088 mod p(x) , x^1120 mod p(x) , x^1152 mod p(x) */ + { 0x1fa0943ddb54814c, 0xf44779b93eb2bd08 }, + /* x^928 mod p(x) , x^960 mod p(x) , x^992 mod p(x) , x^1024 mod p(x) */ + { 0xa53ff440d7bbfe6a, 0xf5449b3f00cc3374 }, + /* x^800 mod p(x) , x^832 mod p(x) , x^864 mod p(x) , x^896 mod p(x) */ + { 0xebe7e3566325605c, 0x6f8346e1d777606e }, + /* x^672 mod p(x) , x^704 mod p(x) , x^736 mod p(x) , x^768 mod p(x) */ + { 0xc65a272ce5b592b8, 0xe3ab4f2ac0b95347 }, + /* x^544 mod p(x) , x^576 mod p(x) , x^608 mod p(x) , x^640 mod p(x) */ + { 0x5705a9ca4721589f, 0xaa2215ea329ecc11 }, + /* x^416 mod p(x) , x^448 mod p(x) , x^480 mod p(x) , x^512 mod p(x) */ + { 0xe3720acb88d14467, 0x1ed8f66ed95efd26 }, + /* x^288 mod p(x) , x^320 mod p(x) , x^352 mod p(x) , x^384 mod p(x) */ + { 0xba1aca0315141c31, 0x78ed02d5a700e96a }, + /* x^160 mod p(x) , x^192 mod p(x) , x^224 mod p(x) , x^256 mod p(x) */ + { 0xad2a31b3ed627dae, 0xba8ccbe832b39da3 }, + /* x^32 mod p(x) , x^64 mod p(x) , x^96 mod p(x) , x^128 mod p(x) */ + { 0x6655004fa06a2517, 0xedb88320b1e6b092 } +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* x^1952 mod p(x) , x^1984 mod p(x) , x^2016 mod p(x) , x^2048 mod p(x) */ + { 0xed837b2613e8221e, 0x99168a18ec447f11 }, + /* x^1824 mod p(x) , x^1856 mod p(x) , x^1888 mod p(x) , x^1920 mod p(x) */ + { 0xc8acdd8147b9ce5a, 0xe23e954e8fd2cd3c }, + /* x^1696 mod p(x) , x^1728 mod p(x) , x^1760 mod p(x) , x^1792 mod p(x) */ + { 0xd9ad6d87d4277e25, 0x92f8befe6b1d2b53 }, + /* x^1568 mod p(x) , x^1600 mod p(x) , x^1632 mod p(x) , x^1664 mod p(x) */ + { 0xc10ec5e033fbca3b, 0xf38a3556291ea462 }, + /* x^1440 mod p(x) , x^1472 mod p(x) , x^1504 mod p(x) , x^1536 mod p(x) */ + { 0xc0b55b0e82e02e2f, 0x974ac56262b6ca4b }, + /* x^1312 mod p(x) , x^1344 mod p(x) , x^1376 mod p(x) , x^1408 mod p(x) */ + { 0x71aa1df0e172334d, 0x855712b3784d2a56 }, + /* x^1184 mod p(x) , x^1216 mod p(x) , x^1248 mod p(x) , x^1280 mod p(x) */ + { 0xfee3053e3969324d, 0xa5abe9f80eaee722 }, + /* x^1056 mod p(x) , x^1088 mod p(x) , x^1120 mod p(x) , x^1152 mod p(x) */ + { 0xf44779b93eb2bd08, 0x1fa0943ddb54814c }, + /* x^928 mod p(x) , x^960 mod p(x) , x^992 mod p(x) , x^1024 mod p(x) */ + { 0xf5449b3f00cc3374, 0xa53ff440d7bbfe6a }, + /* x^800 mod p(x) , x^832 mod p(x) , x^864 mod p(x) , x^896 mod p(x) */ + { 0x6f8346e1d777606e, 0xebe7e3566325605c }, + /* x^672 mod p(x) , x^704 mod p(x) , x^736 mod p(x) , x^768 mod p(x) */ + { 0xe3ab4f2ac0b95347, 0xc65a272ce5b592b8 }, + /* x^544 mod p(x) , x^576 mod p(x) , x^608 mod p(x) , x^640 mod p(x) */ + { 0xaa2215ea329ecc11, 0x5705a9ca4721589f }, + /* x^416 mod p(x) , x^448 mod p(x) , x^480 mod p(x) , x^512 mod p(x) */ + { 0x1ed8f66ed95efd26, 0xe3720acb88d14467 }, + /* x^288 mod p(x) , x^320 mod p(x) , x^352 mod p(x) , x^384 mod p(x) */ + { 0x78ed02d5a700e96a, 0xba1aca0315141c31 }, + /* x^160 mod p(x) , x^192 mod p(x) , x^224 mod p(x) , x^256 mod p(x) */ + { 0xba8ccbe832b39da3, 0xad2a31b3ed627dae }, + /* x^32 mod p(x) , x^64 mod p(x) , x^96 mod p(x) , x^128 mod p(x) */ + { 0xedb88320b1e6b092, 0x6655004fa06a2517 } +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ +}; + +/* Barrett constants */ +/* 33 bit reflected Barrett constant m - (4^32)/n */ + +static const __vector unsigned long long v_Barrett_const[2] ALIGNED_(16) = { + /* x^64 div p(x) */ +#if BYTE_ORDER == LITTLE_ENDIAN + { 0x00000001f7011641, 0x0000000000000000 }, + { 0x00000001db710641, 0x0000000000000000 } +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + { 0x0000000000000000, 0x00000001f7011641 }, + { 0x0000000000000000, 0x00000001db710641 } +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ +}; diff --git a/arch/power/crc32_power8.c b/arch/power/crc32_power8.c new file mode 100644 index 0000000000..28c59b663c --- /dev/null +++ b/arch/power/crc32_power8.c @@ -0,0 +1,587 @@ +/* crc32 for POWER8 using VSX instructions + * Copyright (C) 2021 IBM Corporation + * + * Author: Rogerio Alves + * + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Calculate the checksum of data that is 16 byte aligned and a multiple of + * 16 bytes. + * + * The first step is to reduce it to 1024 bits. We do this in 8 parallel + * chunks in order to mask the latency of the vpmsum instructions. If we + * have more than 32 kB of data to checksum we repeat this step multiple + * times, passing in the previous 1024 bits. + * + * The next step is to reduce the 1024 bits to 64 bits. This step adds + * 32 bits of 0s to the end - this matches what a CRC does. We just + * calculate constants that land the data in this 32 bits. + * + * We then use fixed point Barrett reduction to compute a mod n over GF(2) + * for n = CRC using POWER8 instructions. We use x = 32. + * + * http://en.wikipedia.org/wiki/Barrett_reduction + * + * This code uses gcc vector builtins instead using assembly directly. + */ + +#include +#include "zendian.h" +#include "zbuild.h" + +#include "crc32_constants.h" +#include "crc32_braid_tbl.h" + +#include "power_intrins.h" + +#define MAX_SIZE 32768 +#define VMX_ALIGN 16 +#define VMX_ALIGN_MASK (VMX_ALIGN-1) + +static unsigned int crc32_align(unsigned int crc, const unsigned char *p, unsigned long len) { + while (len--) + crc = crc_table[(crc ^ *p++) & 0xff] ^ (crc >> 8); + return crc; +} + +static unsigned int ALIGNED_(32) __crc32_vpmsum(unsigned int crc, const void* p, unsigned long len); + +Z_INTERNAL uint32_t crc32_power8(uint32_t crc, const unsigned char *p, size_t _len) { + unsigned int prealign; + unsigned int tail; + + unsigned long len = (unsigned long) _len; + + if (p == (const unsigned char *) 0x0) + return 0; + + crc ^= 0xffffffff; + + if (len < VMX_ALIGN + VMX_ALIGN_MASK) { + crc = crc32_align(crc, p, len); + goto out; + } + + if ((unsigned long)p & VMX_ALIGN_MASK) { + prealign = VMX_ALIGN - ((unsigned long)p & VMX_ALIGN_MASK); + crc = crc32_align(crc, p, prealign); + len -= prealign; + p += prealign; + } + + crc = __crc32_vpmsum(crc, p, len & ~VMX_ALIGN_MASK); + + tail = len & VMX_ALIGN_MASK; + if (tail) { + p += len & ~VMX_ALIGN_MASK; + crc = crc32_align(crc, p, tail); + } + +out: + crc ^= 0xffffffff; + + return crc; +} + +/* When we have a load-store in a single-dispatch group and address overlap + * such that forward is not allowed (load-hit-store) the group must be flushed. + * A group ending NOP prevents the flush. + */ +#define GROUP_ENDING_NOP __asm__("ori 2,2,0" ::: "memory") + +#if BYTE_ORDER == BIG_ENDIAN +#define BYTESWAP_DATA +#endif + +#ifdef BYTESWAP_DATA +#define VEC_PERM(vr, va, vb, vc) vr = vec_perm(va, vb, (__vector unsigned char) vc) +#if BYTE_ORDER == LITTLE_ENDIAN +/* Byte reverse permute constant LE. */ +static const __vector unsigned long long vperm_const ALIGNED_(16) = { 0x08090A0B0C0D0E0FUL, 0x0001020304050607UL }; +#else +static const __vector unsigned long long vperm_const ALIGNED_(16) = { 0x0F0E0D0C0B0A0908UL, 0X0706050403020100UL }; +#endif +#else +#define VEC_PERM(vr, va, vb, vc) +#endif + +static unsigned int ALIGNED_(32) __crc32_vpmsum(unsigned int crc, const void* p, unsigned long len) { + + const __vector unsigned long long vzero = {0,0}; + const __vector unsigned long long vones = {0xffffffffffffffffUL, 0xffffffffffffffffUL}; + + const __vector unsigned long long vmask_32bit = + (__vector unsigned long long)vec_sld((__vector unsigned char)vzero, (__vector unsigned char)vones, 4); + + const __vector unsigned long long vmask_64bit = + (__vector unsigned long long)vec_sld((__vector unsigned char)vzero, (__vector unsigned char)vones, 8); + + __vector unsigned long long vcrc; + + __vector unsigned long long vconst1, vconst2; + + /* vdata0-vdata7 will contain our data (p). */ + __vector unsigned long long vdata0, vdata1, vdata2, vdata3, vdata4, vdata5, vdata6, vdata7; + + /* v0-v7 will contain our checksums */ + __vector unsigned long long v0 = {0,0}; + __vector unsigned long long v1 = {0,0}; + __vector unsigned long long v2 = {0,0}; + __vector unsigned long long v3 = {0,0}; + __vector unsigned long long v4 = {0,0}; + __vector unsigned long long v5 = {0,0}; + __vector unsigned long long v6 = {0,0}; + __vector unsigned long long v7 = {0,0}; + + + /* Vector auxiliary variables. */ + __vector unsigned long long va0, va1, va2, va3, va4, va5, va6, va7; + + unsigned int offset; /* Constant table offset. */ + + unsigned long i; /* Counter. */ + unsigned long chunks; + + unsigned long block_size; + int next_block = 0; + + /* Align by 128 bits. The last 128 bit block will be processed at end. */ + unsigned long length = len & 0xFFFFFFFFFFFFFF80UL; + + vcrc = (__vector unsigned long long)__builtin_pack_vector_int128(0UL, crc); + + /* Short version. */ + if (len < 256) { + /* Calculate where in the constant table we need to start. */ + offset = 256 - len; + + vconst1 = vec_ld(offset, vcrc_short_const); + vdata0 = vec_ld(0, (__vector unsigned long long*) p); + VEC_PERM(vdata0, vdata0, vconst1, vperm_const); + + /* xor initial value */ + vdata0 = vec_xor(vdata0, vcrc); + + vdata0 = (__vector unsigned long long) __builtin_crypto_vpmsumw( + (__vector unsigned int)vdata0, (__vector unsigned int)vconst1); + v0 = vec_xor(v0, vdata0); + + for (i = 16; i < len; i += 16) { + vconst1 = vec_ld(offset + i, vcrc_short_const); + vdata0 = vec_ld(i, (__vector unsigned long long*) p); + VEC_PERM(vdata0, vdata0, vconst1, vperm_const); + vdata0 = (__vector unsigned long long) __builtin_crypto_vpmsumw( + (__vector unsigned int)vdata0, (__vector unsigned int)vconst1); + v0 = vec_xor(v0, vdata0); + } + } else { + + /* Load initial values. */ + vdata0 = vec_ld(0, (__vector unsigned long long*) p); + vdata1 = vec_ld(16, (__vector unsigned long long*) p); + + VEC_PERM(vdata0, vdata0, vdata0, vperm_const); + VEC_PERM(vdata1, vdata1, vdata1, vperm_const); + + vdata2 = vec_ld(32, (__vector unsigned long long*) p); + vdata3 = vec_ld(48, (__vector unsigned long long*) p); + + VEC_PERM(vdata2, vdata2, vdata2, vperm_const); + VEC_PERM(vdata3, vdata3, vdata3, vperm_const); + + vdata4 = vec_ld(64, (__vector unsigned long long*) p); + vdata5 = vec_ld(80, (__vector unsigned long long*) p); + + VEC_PERM(vdata4, vdata4, vdata4, vperm_const); + VEC_PERM(vdata5, vdata5, vdata5, vperm_const); + + vdata6 = vec_ld(96, (__vector unsigned long long*) p); + vdata7 = vec_ld(112, (__vector unsigned long long*) p); + + VEC_PERM(vdata6, vdata6, vdata6, vperm_const); + VEC_PERM(vdata7, vdata7, vdata7, vperm_const); + + /* xor in initial value */ + vdata0 = vec_xor(vdata0, vcrc); + + p = (char *)p + 128; + + do { + /* Checksum in blocks of MAX_SIZE. */ + block_size = length; + if (block_size > MAX_SIZE) { + block_size = MAX_SIZE; + } + + length = length - block_size; + + /* + * Work out the offset into the constants table to start at. Each + * constant is 16 bytes, and it is used against 128 bytes of input + * data - 128 / 16 = 8 + */ + offset = (MAX_SIZE/8) - (block_size/8); + /* We reduce our final 128 bytes in a separate step */ + chunks = (block_size/128)-1; + + vconst1 = vec_ld(offset, vcrc_const); + + va0 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata0, + (__vector unsigned long long)vconst1); + va1 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata1, + (__vector unsigned long long)vconst1); + va2 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata2, + (__vector unsigned long long)vconst1); + va3 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata3, + (__vector unsigned long long)vconst1); + va4 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata4, + (__vector unsigned long long)vconst1); + va5 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata5, + (__vector unsigned long long)vconst1); + va6 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata6, + (__vector unsigned long long)vconst1); + va7 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata7, + (__vector unsigned long long)vconst1); + + if (chunks > 1) { + offset += 16; + vconst2 = vec_ld(offset, vcrc_const); + GROUP_ENDING_NOP; + + vdata0 = vec_ld(0, (__vector unsigned long long*) p); + VEC_PERM(vdata0, vdata0, vdata0, vperm_const); + + vdata1 = vec_ld(16, (__vector unsigned long long*) p); + VEC_PERM(vdata1, vdata1, vdata1, vperm_const); + + vdata2 = vec_ld(32, (__vector unsigned long long*) p); + VEC_PERM(vdata2, vdata2, vdata2, vperm_const); + + vdata3 = vec_ld(48, (__vector unsigned long long*) p); + VEC_PERM(vdata3, vdata3, vdata3, vperm_const); + + vdata4 = vec_ld(64, (__vector unsigned long long*) p); + VEC_PERM(vdata4, vdata4, vdata4, vperm_const); + + vdata5 = vec_ld(80, (__vector unsigned long long*) p); + VEC_PERM(vdata5, vdata5, vdata5, vperm_const); + + vdata6 = vec_ld(96, (__vector unsigned long long*) p); + VEC_PERM(vdata6, vdata6, vdata6, vperm_const); + + vdata7 = vec_ld(112, (__vector unsigned long long*) p); + VEC_PERM(vdata7, vdata7, vdata7, vperm_const); + + p = (char *)p + 128; + + /* + * main loop. Each iteration calculates the CRC for a 128-byte + * block. + */ + for (i = 0; i < chunks-2; i++) { + vconst1 = vec_ld(offset, vcrc_const); + offset += 16; + GROUP_ENDING_NOP; + + v0 = vec_xor(v0, va0); + va0 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata0, + (__vector unsigned long long)vconst2); + vdata0 = vec_ld(0, (__vector unsigned long long*) p); + VEC_PERM(vdata0, vdata0, vdata0, vperm_const); + GROUP_ENDING_NOP; + + v1 = vec_xor(v1, va1); + va1 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata1, + (__vector unsigned long long)vconst2); + vdata1 = vec_ld(16, (__vector unsigned long long*) p); + VEC_PERM(vdata1, vdata1, vdata1, vperm_const); + GROUP_ENDING_NOP; + + v2 = vec_xor(v2, va2); + va2 = __builtin_crypto_vpmsumd((__vector unsigned long long) + vdata2, (__vector unsigned long long)vconst2); + vdata2 = vec_ld(32, (__vector unsigned long long*) p); + VEC_PERM(vdata2, vdata2, vdata2, vperm_const); + GROUP_ENDING_NOP; + + v3 = vec_xor(v3, va3); + va3 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata3, + (__vector unsigned long long)vconst2); + vdata3 = vec_ld(48, (__vector unsigned long long*) p); + VEC_PERM(vdata3, vdata3, vdata3, vperm_const); + + vconst2 = vec_ld(offset, vcrc_const); + GROUP_ENDING_NOP; + + v4 = vec_xor(v4, va4); + va4 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata4, + (__vector unsigned long long)vconst1); + vdata4 = vec_ld(64, (__vector unsigned long long*) p); + VEC_PERM(vdata4, vdata4, vdata4, vperm_const); + GROUP_ENDING_NOP; + + v5 = vec_xor(v5, va5); + va5 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata5, + (__vector unsigned long long)vconst1); + vdata5 = vec_ld(80, (__vector unsigned long long*) p); + VEC_PERM(vdata5, vdata5, vdata5, vperm_const); + GROUP_ENDING_NOP; + + v6 = vec_xor(v6, va6); + va6 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata6, + (__vector unsigned long long)vconst1); + vdata6 = vec_ld(96, (__vector unsigned long long*) p); + VEC_PERM(vdata6, vdata6, vdata6, vperm_const); + GROUP_ENDING_NOP; + + v7 = vec_xor(v7, va7); + va7 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata7, + (__vector unsigned long long)vconst1); + vdata7 = vec_ld(112, (__vector unsigned long long*) p); + VEC_PERM(vdata7, vdata7, vdata7, vperm_const); + + p = (char *)p + 128; + } + + /* First cool down */ + vconst1 = vec_ld(offset, vcrc_const); + offset += 16; + + v0 = vec_xor(v0, va0); + va0 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata0, + (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v1 = vec_xor(v1, va1); + va1 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata1, + (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v2 = vec_xor(v2, va2); + va2 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata2, + (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v3 = vec_xor(v3, va3); + va3 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata3, + (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v4 = vec_xor(v4, va4); + va4 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata4, + (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v5 = vec_xor(v5, va5); + va5 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata5, + (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v6 = vec_xor(v6, va6); + va6 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata6, + (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v7 = vec_xor(v7, va7); + va7 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata7, + (__vector unsigned long long)vconst1); + }/* else */ + + /* Second cool down. */ + v0 = vec_xor(v0, va0); + v1 = vec_xor(v1, va1); + v2 = vec_xor(v2, va2); + v3 = vec_xor(v3, va3); + v4 = vec_xor(v4, va4); + v5 = vec_xor(v5, va5); + v6 = vec_xor(v6, va6); + v7 = vec_xor(v7, va7); + + /* + * vpmsumd produces a 96 bit result in the least significant bits + * of the register. Since we are bit reflected we have to shift it + * left 32 bits so it occupies the least significant bits in the + * bit reflected domain. + */ + v0 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, + (__vector unsigned char)vzero, 4); + v1 = (__vector unsigned long long)vec_sld((__vector unsigned char)v1, + (__vector unsigned char)vzero, 4); + v2 = (__vector unsigned long long)vec_sld((__vector unsigned char)v2, + (__vector unsigned char)vzero, 4); + v3 = (__vector unsigned long long)vec_sld((__vector unsigned char)v3, + (__vector unsigned char)vzero, 4); + v4 = (__vector unsigned long long)vec_sld((__vector unsigned char)v4, + (__vector unsigned char)vzero, 4); + v5 = (__vector unsigned long long)vec_sld((__vector unsigned char)v5, + (__vector unsigned char)vzero, 4); + v6 = (__vector unsigned long long)vec_sld((__vector unsigned char)v6, + (__vector unsigned char)vzero, 4); + v7 = (__vector unsigned long long)vec_sld((__vector unsigned char)v7, + (__vector unsigned char)vzero, 4); + + /* xor with the last 1024 bits. */ + va0 = vec_ld(0, (__vector unsigned long long*) p); + VEC_PERM(va0, va0, va0, vperm_const); + + va1 = vec_ld(16, (__vector unsigned long long*) p); + VEC_PERM(va1, va1, va1, vperm_const); + + va2 = vec_ld(32, (__vector unsigned long long*) p); + VEC_PERM(va2, va2, va2, vperm_const); + + va3 = vec_ld(48, (__vector unsigned long long*) p); + VEC_PERM(va3, va3, va3, vperm_const); + + va4 = vec_ld(64, (__vector unsigned long long*) p); + VEC_PERM(va4, va4, va4, vperm_const); + + va5 = vec_ld(80, (__vector unsigned long long*) p); + VEC_PERM(va5, va5, va5, vperm_const); + + va6 = vec_ld(96, (__vector unsigned long long*) p); + VEC_PERM(va6, va6, va6, vperm_const); + + va7 = vec_ld(112, (__vector unsigned long long*) p); + VEC_PERM(va7, va7, va7, vperm_const); + + p = (char *)p + 128; + + vdata0 = vec_xor(v0, va0); + vdata1 = vec_xor(v1, va1); + vdata2 = vec_xor(v2, va2); + vdata3 = vec_xor(v3, va3); + vdata4 = vec_xor(v4, va4); + vdata5 = vec_xor(v5, va5); + vdata6 = vec_xor(v6, va6); + vdata7 = vec_xor(v7, va7); + + /* Check if we have more blocks to process */ + next_block = 0; + if (length != 0) { + next_block = 1; + + /* zero v0-v7 */ + v0 = vec_xor(v0, v0); + v1 = vec_xor(v1, v1); + v2 = vec_xor(v2, v2); + v3 = vec_xor(v3, v3); + v4 = vec_xor(v4, v4); + v5 = vec_xor(v5, v5); + v6 = vec_xor(v6, v6); + v7 = vec_xor(v7, v7); + } + length = length + 128; + + } while (next_block); + + /* Calculate how many bytes we have left. */ + length = (len & 127); + + /* Calculate where in (short) constant table we need to start. */ + offset = 128 - length; + + v0 = vec_ld(offset, vcrc_short_const); + v1 = vec_ld(offset + 16, vcrc_short_const); + v2 = vec_ld(offset + 32, vcrc_short_const); + v3 = vec_ld(offset + 48, vcrc_short_const); + v4 = vec_ld(offset + 64, vcrc_short_const); + v5 = vec_ld(offset + 80, vcrc_short_const); + v6 = vec_ld(offset + 96, vcrc_short_const); + v7 = vec_ld(offset + 112, vcrc_short_const); + + offset += 128; + + v0 = (__vector unsigned long long)__builtin_crypto_vpmsumw( + (__vector unsigned int)vdata0, (__vector unsigned int)v0); + v1 = (__vector unsigned long long)__builtin_crypto_vpmsumw( + (__vector unsigned int)vdata1, (__vector unsigned int)v1); + v2 = (__vector unsigned long long)__builtin_crypto_vpmsumw( + (__vector unsigned int)vdata2, (__vector unsigned int)v2); + v3 = (__vector unsigned long long)__builtin_crypto_vpmsumw( + (__vector unsigned int)vdata3, (__vector unsigned int)v3); + v4 = (__vector unsigned long long)__builtin_crypto_vpmsumw( + (__vector unsigned int)vdata4, (__vector unsigned int)v4); + v5 = (__vector unsigned long long)__builtin_crypto_vpmsumw( + (__vector unsigned int)vdata5, (__vector unsigned int)v5); + v6 = (__vector unsigned long long)__builtin_crypto_vpmsumw( + (__vector unsigned int)vdata6, (__vector unsigned int)v6); + v7 = (__vector unsigned long long)__builtin_crypto_vpmsumw( + (__vector unsigned int)vdata7, (__vector unsigned int)v7); + + /* Now reduce the tail (0-112 bytes). */ + for (i = 0; i < length; i+=16) { + vdata0 = vec_ld(i,(__vector unsigned long long*)p); + VEC_PERM(vdata0, vdata0, vdata0, vperm_const); + va0 = vec_ld(offset + i,vcrc_short_const); + va0 = (__vector unsigned long long)__builtin_crypto_vpmsumw( + (__vector unsigned int)vdata0, (__vector unsigned int)va0); + v0 = vec_xor(v0, va0); + } + + /* xor all parallel chunks together. */ + v0 = vec_xor(v0, v1); + v2 = vec_xor(v2, v3); + v4 = vec_xor(v4, v5); + v6 = vec_xor(v6, v7); + + v0 = vec_xor(v0, v2); + v4 = vec_xor(v4, v6); + + v0 = vec_xor(v0, v4); + } + + /* Barrett Reduction */ + vconst1 = vec_ld(0, v_Barrett_const); + vconst2 = vec_ld(16, v_Barrett_const); + + v1 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, + (__vector unsigned char)v0, 8); + v0 = vec_xor(v1,v0); + + /* shift left one bit */ + __vector unsigned char vsht_splat = vec_splat_u8 (1); + v0 = (__vector unsigned long long)vec_sll((__vector unsigned char)v0, vsht_splat); + + v0 = vec_and(v0, vmask_64bit); + + /* + * The reflected version of Barrett reduction. Instead of bit + * reflecting our data (which is expensive to do), we bit reflect our + * constants and our algorithm, which means the intermediate data in + * our vector registers goes from 0-63 instead of 63-0. We can reflect + * the algorithm because we don't carry in mod 2 arithmetic. + */ + + /* bottom 32 bits of a */ + v1 = vec_and(v0, vmask_32bit); + + /* ma */ + v1 = __builtin_crypto_vpmsumd((__vector unsigned long long)v1, + (__vector unsigned long long)vconst1); + + /* bottom 32bits of ma */ + v1 = vec_and(v1, vmask_32bit); + /* qn */ + v1 = __builtin_crypto_vpmsumd((__vector unsigned long long)v1, + (__vector unsigned long long)vconst2); + /* a - qn, subtraction is xor in GF(2) */ + v0 = vec_xor (v0, v1); + + /* + * Since we are bit reflected, the result (ie the low 32 bits) is in + * the high 32 bits. We just need to shift it left 4 bytes + * V0 [ 0 1 X 3 ] + * V0 [ 0 X 2 3 ] + */ + + /* shift result into top 64 bits of */ + v0 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, + (__vector unsigned char)vzero, 4); + +#if BYTE_ORDER == BIG_ENDIAN + return v0[0]; +#else + return v0[1]; +#endif +} diff --git a/arch/power/power_features.c b/arch/power/power_features.c new file mode 100644 index 0000000000..4939d1c18f --- /dev/null +++ b/arch/power/power_features.c @@ -0,0 +1,49 @@ +/* power_features.c - POWER feature check + * Copyright (C) 2020 Matheus Castanho , IBM + * Copyright (C) 2021-2024 Mika T. Lindqvist + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef HAVE_SYS_AUXV_H +# include +#endif +#ifdef POWER_NEED_AUXVEC_H +# include +#endif +#ifdef __FreeBSD__ +# include +#endif +#include "zbuild.h" +#include "power_features.h" + +void Z_INTERNAL power_check_features(struct power_cpu_features *features) { +#ifdef PPC_FEATURES + unsigned long hwcap; +#ifdef __FreeBSD__ + elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); +#else + hwcap = getauxval(AT_HWCAP); +#endif + + if (hwcap & PPC_FEATURE_HAS_ALTIVEC) + features->has_altivec = 1; +#endif + +#ifdef POWER_FEATURES + unsigned long hwcap2; +#ifdef __FreeBSD__ + elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2)); +#else + hwcap2 = getauxval(AT_HWCAP2); +#endif + +#ifdef POWER8_VSX + if (hwcap2 & PPC_FEATURE2_ARCH_2_07) + features->has_arch_2_07 = 1; +#endif +#ifdef POWER9 + if (hwcap2 & PPC_FEATURE2_ARCH_3_00) + features->has_arch_3_00 = 1; +#endif +#endif +} diff --git a/arch/power/power_features.h b/arch/power/power_features.h new file mode 100644 index 0000000000..1ff51de5dd --- /dev/null +++ b/arch/power/power_features.h @@ -0,0 +1,18 @@ +/* power_features.h -- check for POWER CPU features + * Copyright (C) 2020 Matheus Castanho , IBM + * Copyright (C) 2021 Mika T. Lindqvist + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef POWER_FEATURES_H_ +#define POWER_FEATURES_H_ + +struct power_cpu_features { + int has_altivec; + int has_arch_2_07; + int has_arch_3_00; +}; + +void Z_INTERNAL power_check_features(struct power_cpu_features *features); + +#endif /* POWER_FEATURES_H_ */ diff --git a/arch/power/power_functions.h b/arch/power/power_functions.h new file mode 100644 index 0000000000..44d36af834 --- /dev/null +++ b/arch/power/power_functions.h @@ -0,0 +1,67 @@ +/* power_functions.h -- POWER implementations for arch-specific functions. + * Copyright (C) 2020 Matheus Castanho , IBM + * Copyright (C) 2021 Mika T. Lindqvist + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef POWER_FUNCTIONS_H_ +#define POWER_FUNCTIONS_H_ + +#ifdef PPC_VMX +uint32_t adler32_vmx(uint32_t adler, const uint8_t *buf, size_t len); +void slide_hash_vmx(deflate_state *s); +#endif + +#ifdef POWER8_VSX +uint32_t adler32_power8(uint32_t adler, const uint8_t *buf, size_t len); +uint32_t chunksize_power8(void); +uint8_t* chunkmemset_safe_power8(uint8_t *out, uint8_t *from, unsigned len, unsigned left); +uint32_t crc32_power8(uint32_t crc, const uint8_t *buf, size_t len); +void slide_hash_power8(deflate_state *s); +void inflate_fast_power8(PREFIX3(stream) *strm, uint32_t start); +#endif + +#ifdef POWER9 +uint32_t compare256_power9(const uint8_t *src0, const uint8_t *src1); +uint32_t longest_match_power9(deflate_state *const s, Pos cur_match); +uint32_t longest_match_slow_power9(deflate_state *const s, Pos cur_match); +#endif + + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +// Power - VMX +# if defined(PPC_VMX) && defined(__ALTIVEC__) +# undef native_adler32 +# define native_adler32 adler32_vmx +# undef native_slide_hash +# define native_slide_hash slide_hash_vmx +# endif +// Power8 - VSX +# if defined(POWER8_VSX) && defined(_ARCH_PWR8) && defined(__VSX__) +# undef native_adler32 +# define native_adler32 adler32_power8 +# undef native_chunkmemset_safe +# define native_chunkmemset_safe chunkmemset_safe_power8 +# undef native_chunksize +# define native_chunksize chunksize_power8 +# undef native_inflate_fast +# define native_inflate_fast inflate_fast_power8 +# undef native_slide_hash +# define native_slide_hash slide_hash_power8 +# endif +# if defined(POWER8_VSX_CRC32) && defined(_ARCH_PWR8) && defined(__VSX__) +# undef native_crc32 +# define native_crc32 crc32_power8 +# endif +// Power9 +# if defined(POWER9) && defined(_ARCH_PWR9) +# undef native_compare256 +# define native_compare256 compare256_power9 +# undef native_longest_match +# define native_longest_match longest_match_power9 +# undef native_longest_match_slow +# define native_longest_match_slow longest_match_slow_power9 +# endif +#endif + +#endif /* POWER_FUNCTIONS_H_ */ diff --git a/arch/power/power_intrins.h b/arch/power/power_intrins.h new file mode 100644 index 0000000000..cf71986563 --- /dev/null +++ b/arch/power/power_intrins.h @@ -0,0 +1,34 @@ +/* Helper functions to work around issues with clang builtins + * Copyright (C) 2021 IBM Corporation + * + * Authors: + * Daniel Black + * Rogerio Alves + * Tulio Magno Quites Machado Filho + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef POWER_INTRINS_H +#define POWER_INTRINS_H + +#if defined (__clang__) +/* + * These stubs fix clang incompatibilities with GCC builtins. + */ + +#ifndef __builtin_crypto_vpmsumw +#define __builtin_crypto_vpmsumw __builtin_crypto_vpmsumb +#endif +#ifndef __builtin_crypto_vpmsumd +#define __builtin_crypto_vpmsumd __builtin_crypto_vpmsumb +#endif + +static inline __vector unsigned long long __attribute__((overloadable)) +vec_ld(int __a, const __vector unsigned long long* __b) { + return (__vector unsigned long long)__builtin_altivec_lvx(__a, __b); +} + +#endif + +#endif diff --git a/arch/power/slide_hash_power8.c b/arch/power/slide_hash_power8.c new file mode 100644 index 0000000000..d01e0acd56 --- /dev/null +++ b/arch/power/slide_hash_power8.c @@ -0,0 +1,12 @@ +/* Optimized slide_hash for POWER processors + * Copyright (C) 2019-2020 IBM Corporation + * Author: Matheus Castanho + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef POWER8_VSX + +#define SLIDE_PPC slide_hash_power8 +#include "slide_ppc_tpl.h" + +#endif /* POWER8_VSX */ diff --git a/arch/power/slide_hash_vmx.c b/arch/power/slide_hash_vmx.c new file mode 100644 index 0000000000..5a87ef7d9a --- /dev/null +++ b/arch/power/slide_hash_vmx.c @@ -0,0 +1,10 @@ +/* Optimized slide_hash for PowerPC processors with VMX instructions + * Copyright (C) 2017-2021 Mika T. Lindqvist + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#ifdef PPC_VMX + +#define SLIDE_PPC slide_hash_vmx +#include "slide_ppc_tpl.h" + +#endif /* PPC_VMX */ diff --git a/arch/power/slide_ppc_tpl.h b/arch/power/slide_ppc_tpl.h new file mode 100644 index 0000000000..680a7f8e2a --- /dev/null +++ b/arch/power/slide_ppc_tpl.h @@ -0,0 +1,32 @@ +/* Optimized slide_hash for PowerPC processors + * Copyright (C) 2017-2021 Mika T. Lindqvist + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include "zbuild.h" +#include "deflate.h" + +static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) { + const vector unsigned short vmx_wsize = vec_splats(wsize); + Pos *p = table; + + do { + vector unsigned short value, result; + + value = vec_ld(0, p); + result = vec_subs(value, vmx_wsize); + vec_st(result, 0, p); + + p += 8; + entries -= 8; + } while (entries > 0); +} + +void Z_INTERNAL SLIDE_PPC(deflate_state *s) { + Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + uint16_t wsize = (uint16_t)s->w_size; + + slide_hash_chain(s->head, HASH_SIZE, wsize); + slide_hash_chain(s->prev, wsize, wsize); +} diff --git a/arch/riscv/README.md b/arch/riscv/README.md new file mode 100644 index 0000000000..013095c373 --- /dev/null +++ b/arch/riscv/README.md @@ -0,0 +1,45 @@ +# Building RISC-V Target with Cmake # + +> **Warning** +> Runtime rvv detection (using `hwcap`) requires linux kernel 6.5 or newer. +> +> When running on older kernels, we fall back to compile-time detection, potentially this can cause crashes if rvv is enabled at compile but not supported by the target cpu. +> Therefore if older kernel support is needed, rvv should be disabled if the target cpu does not support it. +## Prerequisite: Build RISC-V Clang Toolchain and QEMU ## + +If you don't have prebuilt clang and riscv64 qemu, you can refer to the [script](https://github.com/sifive/prepare-riscv-toolchain-qemu/blob/main/prepare_riscv_toolchain_qemu.sh) to get the source. Copy the script to the zlib-ng root directory, and run it to download the source and build them. Modify the content according to your conditions (e.g., toolchain version). + +```bash +./prepare_riscv_toolchain_qemu.sh +``` + +After running script, clang & qemu are built in `build-toolchain-qemu/riscv-clang/` & `build-toolchain-qemu/riscv-qemu/`. + +`build-toolchain-qemu/riscv-clang/` is your `TOOLCHAIN_PATH`. +`build-toolchain-qemu/riscv-qemu/bin/qemu-riscv64` is your `QEMU_PATH`. + +You can also download the prebuilt toolchain & qemu from [the release page](https://github.com/sifive/prepare-riscv-toolchain-qemu/releases), and enjoy using them. + +## Cross-Compile for RISC-V Target ## + +```bash +cmake -G Ninja -B ./build-riscv \ + -D CMAKE_TOOLCHAIN_FILE=./cmake/toolchain-riscv.cmake \ + -D CMAKE_INSTALL_PREFIX=./build-riscv/install \ + -D TOOLCHAIN_PATH={TOOLCHAIN_PATH} \ + -D QEMU_PATH={QEMU_PATH} \ + . + +cmake --build ./build-riscv +``` + +Disable the option if there is no RVV support: +``` +-D WITH_RVV=OFF +``` + +## Run Unittests on User Mode QEMU ## + +```bash +cd ./build-riscv && ctest --verbose +``` diff --git a/arch/riscv/adler32_rvv.c b/arch/riscv/adler32_rvv.c new file mode 100644 index 0000000000..d822d75af6 --- /dev/null +++ b/arch/riscv/adler32_rvv.c @@ -0,0 +1,136 @@ +/* adler32_rvv.c - RVV version of adler32 + * Copyright (C) 2023 SiFive, Inc. All rights reserved. + * Contributed by Alex Chiang + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef RISCV_RVV + +#include +#include + +#include "zbuild.h" +#include "adler32_p.h" + +static inline uint32_t adler32_rvv_impl(uint32_t adler, uint8_t* restrict dst, const uint8_t *src, size_t len, int COPY) { + /* split Adler-32 into component sums */ + uint32_t sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + if (COPY) memcpy(dst, src, 1); + return adler32_len_1(adler, src, sum2); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (src == NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + if (COPY) memcpy(dst, src, len); + return adler32_len_16(adler, src, len, sum2); + } + + size_t left = len; + size_t vl = __riscv_vsetvlmax_e8m1(); + vl = vl > 256 ? 256 : vl; + vuint32m4_t v_buf32_accu = __riscv_vmv_v_x_u32m4(0, vl); + vuint32m4_t v_adler32_prev_accu = __riscv_vmv_v_x_u32m4(0, vl); + vuint16m2_t v_buf16_accu; + + /* + * We accumulate 8-bit data, and to prevent overflow, we have to use a 32-bit accumulator. + * However, adding 8-bit data into a 32-bit accumulator isn't efficient. We use 16-bit & 32-bit + * accumulators to boost performance. + * + * The block_size is the largest multiple of vl that <= 256, because overflow would occur when + * vl > 256 (255 * 256 <= UINT16_MAX). + * + * We accumulate 8-bit data into a 16-bit accumulator and then + * move the data into the 32-bit accumulator at the last iteration. + */ + size_t block_size = (256 / vl) * vl; + size_t nmax_limit = (NMAX / block_size); + size_t cnt = 0; + while (left >= block_size) { + v_buf16_accu = __riscv_vmv_v_x_u16m2(0, vl); + size_t subprob = block_size; + while (subprob > 0) { + vuint8m1_t v_buf8 = __riscv_vle8_v_u8m1(src, vl); + if (COPY) __riscv_vse8_v_u8m1(dst, v_buf8, vl); + v_adler32_prev_accu = __riscv_vwaddu_wv_u32m4(v_adler32_prev_accu, v_buf16_accu, vl); + v_buf16_accu = __riscv_vwaddu_wv_u16m2(v_buf16_accu, v_buf8, vl); + src += vl; + if (COPY) dst += vl; + subprob -= vl; + } + v_adler32_prev_accu = __riscv_vmacc_vx_u32m4(v_adler32_prev_accu, block_size / vl, v_buf32_accu, vl); + v_buf32_accu = __riscv_vwaddu_wv_u32m4(v_buf32_accu, v_buf16_accu, vl); + left -= block_size; + /* do modulo once each block of NMAX size */ + if (++cnt >= nmax_limit) { + v_adler32_prev_accu = __riscv_vremu_vx_u32m4(v_adler32_prev_accu, BASE, vl); + v_buf32_accu = __riscv_vremu_vx_u32m4(v_buf32_accu, BASE, vl); + cnt = 0; + } + } + /* the left len <= 256 now, we can use 16-bit accum safely */ + v_buf16_accu = __riscv_vmv_v_x_u16m2(0, vl); + size_t res = left; + while (left >= vl) { + vuint8m1_t v_buf8 = __riscv_vle8_v_u8m1(src, vl); + if (COPY) __riscv_vse8_v_u8m1(dst, v_buf8, vl); + v_adler32_prev_accu = __riscv_vwaddu_wv_u32m4(v_adler32_prev_accu, v_buf16_accu, vl); + v_buf16_accu = __riscv_vwaddu_wv_u16m2(v_buf16_accu, v_buf8, vl); + src += vl; + if (COPY) dst += vl; + left -= vl; + } + v_adler32_prev_accu = __riscv_vmacc_vx_u32m4(v_adler32_prev_accu, res / vl, v_buf32_accu, vl); + v_adler32_prev_accu = __riscv_vremu_vx_u32m4(v_adler32_prev_accu, BASE, vl); + v_buf32_accu = __riscv_vwaddu_wv_u32m4(v_buf32_accu, v_buf16_accu, vl); + + vuint32m4_t v_seq = __riscv_vid_v_u32m4(vl); + vuint32m4_t v_rev_seq = __riscv_vrsub_vx_u32m4(v_seq, vl, vl); + vuint32m4_t v_sum32_accu = __riscv_vmul_vv_u32m4(v_buf32_accu, v_rev_seq, vl); + + v_sum32_accu = __riscv_vadd_vv_u32m4(v_sum32_accu, __riscv_vmul_vx_u32m4(v_adler32_prev_accu, vl, vl), vl); + + vuint32m1_t v_sum2_sum = __riscv_vmv_s_x_u32m1(0, vl); + v_sum2_sum = __riscv_vredsum_vs_u32m4_u32m1(v_sum32_accu, v_sum2_sum, vl); + uint32_t sum2_sum = __riscv_vmv_x_s_u32m1_u32(v_sum2_sum) % BASE; + + sum2 += (sum2_sum + adler * ((len - left) % BASE)); + + vuint32m1_t v_adler_sum = __riscv_vmv_s_x_u32m1(0, vl); + v_adler_sum = __riscv_vredsum_vs_u32m4_u32m1(v_buf32_accu, v_adler_sum, vl); + uint32_t adler_sum = __riscv_vmv_x_s_u32m1_u32(v_adler_sum) % BASE; + + adler += adler_sum; + + sum2 %= BASE; + adler %= BASE; + + while (left--) { + if (COPY) *dst++ = *src; + adler += *src++; + sum2 += adler; + } + + sum2 %= BASE; + adler %= BASE; + + return adler | (sum2 << 16); +} + +Z_INTERNAL uint32_t adler32_fold_copy_rvv(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { + return adler32_rvv_impl(adler, dst, src, len, 1); +} + +Z_INTERNAL uint32_t adler32_rvv(uint32_t adler, const uint8_t *buf, size_t len) { + return adler32_rvv_impl(adler, NULL, buf, len, 0); +} + +#endif // RISCV_RVV diff --git a/arch/riscv/chunkset_rvv.c b/arch/riscv/chunkset_rvv.c new file mode 100644 index 0000000000..ee43bde2f7 --- /dev/null +++ b/arch/riscv/chunkset_rvv.c @@ -0,0 +1,121 @@ +/* chunkset_rvv.c - RVV version of chunkset + * Copyright (C) 2023 SiFive, Inc. All rights reserved. + * Contributed by Alex Chiang + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#include +#include "zbuild.h" + +/* + * RISC-V glibc would enable RVV optimized memcpy at runtime by IFUNC, + * so we prefer using large size chunk and copy memory as much as possible. + */ +#define CHUNK_SIZE 32 + +#define HAVE_CHUNKMEMSET_2 +#define HAVE_CHUNKMEMSET_4 +#define HAVE_CHUNKMEMSET_8 + +#define CHUNK_MEMSET_RVV_IMPL(elen) \ +do { \ + size_t vl, len = CHUNK_SIZE / sizeof(uint##elen##_t); \ + uint##elen##_t val = *(uint##elen##_t*)from; \ + uint##elen##_t* chunk_p = (uint##elen##_t*)chunk; \ + do { \ + vl = __riscv_vsetvl_e##elen##m4(len); \ + vuint##elen##m4_t v_val = __riscv_vmv_v_x_u##elen##m4(val, vl); \ + __riscv_vse##elen##_v_u##elen##m4(chunk_p, v_val, vl); \ + len -= vl; chunk_p += vl; \ + } while (len > 0); \ +} while (0) + +/* We don't have a 32-byte datatype for RISC-V arch. */ +typedef struct chunk_s { + uint64_t data[4]; +} chunk_t; + +static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { + CHUNK_MEMSET_RVV_IMPL(16); +} + +static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { + CHUNK_MEMSET_RVV_IMPL(32); +} + +static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { + CHUNK_MEMSET_RVV_IMPL(64); +} + +static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { + memcpy(chunk->data, (uint8_t *)s, CHUNK_SIZE); +} + +static inline void storechunk(uint8_t *out, chunk_t *chunk) { + memcpy(out, chunk->data, CHUNK_SIZE); +} + +#define CHUNKSIZE chunksize_rvv +#define CHUNKCOPY chunkcopy_rvv +#define CHUNKUNROLL chunkunroll_rvv +#define CHUNKMEMSET chunkmemset_rvv +#define CHUNKMEMSET_SAFE chunkmemset_safe_rvv + +#define HAVE_CHUNKCOPY + +/* + * Assuming that the length is non-zero, and that `from` lags `out` by at least + * sizeof chunk_t bytes, please see the comments in chunkset_tpl.h. + * + * We load/store a single chunk once in the `CHUNKCOPY`. + * However, RISC-V glibc would enable RVV optimized memcpy at runtime by IFUNC, + * such that, we prefer copy large memory size once to make good use of the the RVV advance. + * + * To be aligned to the other platforms, we didn't modify `CHUNKCOPY` method a lot, + * but we still copy as much memory as possible for some conditions. + * + * case 1: out - from >= len (no overlap) + * We can use memcpy to copy `len` size once + * because the memory layout would be the same. + * + * case 2: overlap + * We copy N chunks using memcpy at once, aiming to achieve our goal: + * to copy as much memory as possible. + * + * After using a single memcpy to copy N chunks, we have to use series of + * loadchunk and storechunk to ensure the result is correct. + */ +static inline uint8_t* CHUNKCOPY(uint8_t *out, uint8_t const *from, unsigned len) { + Assert(len > 0, "chunkcopy should never have a length 0"); + int32_t align = ((len - 1) % sizeof(chunk_t)) + 1; + memcpy(out, from, sizeof(chunk_t)); + out += align; + from += align; + len -= align; + ptrdiff_t dist = out - from; + if (dist >= len) { + memcpy(out, from, len); + out += len; + from += len; + return out; + } + if (dist >= sizeof(chunk_t)) { + dist = (dist / sizeof(chunk_t)) * sizeof(chunk_t); + memcpy(out, from, dist); + out += dist; + from += dist; + len -= dist; + } + while (len > 0) { + memcpy(out, from, sizeof(chunk_t)); + out += sizeof(chunk_t); + from += sizeof(chunk_t); + len -= sizeof(chunk_t); + } + return out; +} + +#include "chunkset_tpl.h" + +#define INFLATE_FAST inflate_fast_rvv + +#include "inffast_tpl.h" diff --git a/arch/riscv/compare256_rvv.c b/arch/riscv/compare256_rvv.c new file mode 100644 index 0000000000..3ddb4db080 --- /dev/null +++ b/arch/riscv/compare256_rvv.c @@ -0,0 +1,49 @@ +/* compare256_rvv.c - RVV version of compare256 + * Copyright (C) 2023 SiFive, Inc. All rights reserved. + * Contributed by Alex Chiang + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef RISCV_RVV + +#include "zbuild.h" +#include "zmemory.h" +#include "deflate.h" +#include "fallback_builtins.h" + +#include + +static inline uint32_t compare256_rvv_static(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0; + size_t vl; + long found_diff; + do { + vl = __riscv_vsetvl_e8m4(256 - len); + vuint8m4_t v_src0 = __riscv_vle8_v_u8m4(src0, vl); + vuint8m4_t v_src1 = __riscv_vle8_v_u8m4(src1, vl); + vbool2_t v_mask = __riscv_vmsne_vv_u8m4_b2(v_src0, v_src1, vl); + found_diff = __riscv_vfirst_m_b2(v_mask, vl); + if (found_diff >= 0) + return len + (uint32_t)found_diff; + src0 += vl, src1 += vl, len += vl; + } while (len < 256); + + return 256; +} + +Z_INTERNAL uint32_t compare256_rvv(const uint8_t *src0, const uint8_t *src1) { + return compare256_rvv_static(src0, src1); +} + +#define LONGEST_MATCH longest_match_rvv +#define COMPARE256 compare256_rvv_static + +#include "match_tpl.h" + +#define LONGEST_MATCH_SLOW +#define LONGEST_MATCH longest_match_slow_rvv +#define COMPARE256 compare256_rvv_static + +#include "match_tpl.h" + +#endif // RISCV_RVV diff --git a/arch/riscv/riscv_features.c b/arch/riscv/riscv_features.c new file mode 100644 index 0000000000..f9957d19cc --- /dev/null +++ b/arch/riscv/riscv_features.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +#if defined(__linux__) && defined(HAVE_SYS_AUXV_H) +# include +#endif + +#include "zbuild.h" +#include "riscv_features.h" + +#define ISA_V_HWCAP (1 << ('v' - 'a')) + +int Z_INTERNAL is_kernel_version_greater_or_equal_to_6_5() { + struct utsname buffer; + if (uname(&buffer) == -1) { + // uname failed + return 0; + } + + int major, minor; + if (sscanf(buffer.release, "%d.%d", &major, &minor) != 2) { + // Something bad with uname() + return 0; + } + + if (major > 6 || (major == 6 && minor >= 5)) + return 1; + return 0; +} + +void Z_INTERNAL riscv_check_features_compile_time(struct riscv_cpu_features *features) { +#if defined(__riscv_v) && defined(__linux__) + features->has_rvv = 1; +#else + features->has_rvv = 0; +#endif +} + +void Z_INTERNAL riscv_check_features_runtime(struct riscv_cpu_features *features) { +#if defined(__linux__) && defined(HAVE_SYS_AUXV_H) + unsigned long hw_cap = getauxval(AT_HWCAP); +#else + unsigned long hw_cap = 0; +#endif + features->has_rvv = hw_cap & ISA_V_HWCAP; +} + +void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features) { + if (is_kernel_version_greater_or_equal_to_6_5()) + riscv_check_features_runtime(features); + else + riscv_check_features_compile_time(features); + if (features->has_rvv) { + size_t e8m1_vec_len; + intptr_t vtype_reg_val; + // Check that a vuint8m1_t vector is at least 16 bytes and that tail + // agnostic and mask agnostic mode are supported + // + __asm__ volatile( + "vsetvli %0, zero, e8, m1, ta, ma\n\t" + "csrr %1, vtype" + : "=r"(e8m1_vec_len), "=r"(vtype_reg_val)); + + // The RVV target is supported if the VILL bit of VTYPE (the MSB bit of + // VTYPE) is not set and the length of a vuint8m1_t vector is at least 16 + // bytes + features->has_rvv = (vtype_reg_val >= 0 && e8m1_vec_len >= 16); + } +} diff --git a/arch/riscv/riscv_features.h b/arch/riscv/riscv_features.h new file mode 100644 index 0000000000..b1593acc25 --- /dev/null +++ b/arch/riscv/riscv_features.h @@ -0,0 +1,18 @@ +/* riscv_features.h -- check for riscv features. + * + * Copyright (C) 2023 SiFive, Inc. All rights reserved. + * Contributed by Alex Chiang + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef RISCV_FEATURES_H_ +#define RISCV_FEATURES_H_ + +struct riscv_cpu_features { + int has_rvv; +}; + +void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features); + +#endif /* RISCV_FEATURES_H_ */ diff --git a/arch/riscv/riscv_functions.h b/arch/riscv/riscv_functions.h new file mode 100644 index 0000000000..1792b9d259 --- /dev/null +++ b/arch/riscv/riscv_functions.h @@ -0,0 +1,49 @@ +/* riscv_functions.h -- RISCV implementations for arch-specific functions. + * + * Copyright (C) 2023 SiFive, Inc. All rights reserved. + * Contributed by Alex Chiang + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef RISCV_FUNCTIONS_H_ +#define RISCV_FUNCTIONS_H_ + +#ifdef RISCV_RVV +uint32_t adler32_rvv(uint32_t adler, const uint8_t *buf, size_t len); +uint32_t adler32_fold_copy_rvv(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); +uint32_t chunksize_rvv(void); +uint8_t* chunkmemset_safe_rvv(uint8_t *out, uint8_t *from, unsigned len, unsigned left); +uint32_t compare256_rvv(const uint8_t *src0, const uint8_t *src1); + +uint32_t longest_match_rvv(deflate_state *const s, Pos cur_match); +uint32_t longest_match_slow_rvv(deflate_state *const s, Pos cur_match); +void slide_hash_rvv(deflate_state *s); +void inflate_fast_rvv(PREFIX3(stream) *strm, uint32_t start); +#endif + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +// RISCV - RVV +# if defined(RISCV_RVV) && defined(__riscv_v) && defined(__linux__) +# undef native_adler32 +# define native_adler32 adler32_rvv +# undef native_adler32_fold_copy +# define native_adler32_fold_copy adler32_fold_copy_rvv +# undef native_chunkmemset_safe +# define native_chunkmemset_safe chunkmemset_safe_rvv +# undef native_chunksize +# define native_chunksize chunksize_rvv +# undef native_compare256 +# define native_compare256 compare256_rvv +# undef native_inflate_fast +# define native_inflate_fast inflate_fast_rvv +# undef native_longest_match +# define native_longest_match longest_match_rvv +# undef native_longest_match_slow +# define native_longest_match_slow longest_match_slow_rvv +# undef native_slide_hash +# define native_slide_hash slide_hash_rvv +# endif +#endif + +#endif /* RISCV_FUNCTIONS_H_ */ diff --git a/arch/riscv/slide_hash_rvv.c b/arch/riscv/slide_hash_rvv.c new file mode 100644 index 0000000000..6f53d7a13a --- /dev/null +++ b/arch/riscv/slide_hash_rvv.c @@ -0,0 +1,33 @@ +/* slide_hash_rvv.c - RVV version of slide_hash + * Copyright (C) 2023 SiFive, Inc. All rights reserved. + * Contributed by Alex Chiang + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef RISCV_RVV + +#include + +#include "zbuild.h" +#include "deflate.h" + +static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) { + size_t vl; + while (entries > 0) { + vl = __riscv_vsetvl_e16m4(entries); + vuint16m4_t v_tab = __riscv_vle16_v_u16m4(table, vl); + vuint16m4_t v_diff = __riscv_vssubu_vx_u16m4(v_tab, wsize, vl); + __riscv_vse16_v_u16m4(table, v_diff, vl); + table += vl, entries -= vl; + } +} + +Z_INTERNAL void slide_hash_rvv(deflate_state *s) { + Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + uint16_t wsize = (uint16_t)s->w_size; + + slide_hash_chain(s->head, HASH_SIZE, wsize); + slide_hash_chain(s->prev, wsize, wsize); +} + +#endif // RISCV_RVV diff --git a/arch/s390/Makefile.in b/arch/s390/Makefile.in new file mode 100644 index 0000000000..e994157df2 --- /dev/null +++ b/arch/s390/Makefile.in @@ -0,0 +1,48 @@ +# Makefile for zlib-ng +# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler +# For conditions of distribution and use, see copyright notice in zlib.h + +CC= +CFLAGS= +SFLAGS= +INCLUDES= +SUFFIX= +VGFMAFLAG= +NOLTOFLAG= + +SRCDIR=. +SRCTOP=../.. +TOPDIR=$(SRCTOP) + +s390_features.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/s390_features.c + +s390_features.lo: + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/s390_features.c + +dfltcc_deflate.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_deflate.c + +dfltcc_deflate.lo: + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_deflate.c + +dfltcc_inflate.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_inflate.c + +dfltcc_inflate.lo: + $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_inflate.c + +crc32-vx.o: + $(CC) $(CFLAGS) $(VGFMAFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32-vx.c + +crc32-vx.lo: + $(CC) $(SFLAGS) $(VGFMAFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32-vx.c + +mostlyclean: clean +clean: + rm -f *.o *.lo *~ + rm -rf objs + rm -f *.gcda *.gcno *.gcov + +distclean: clean + rm -f Makefile diff --git a/arch/s390/README.md b/arch/s390/README.md new file mode 100644 index 0000000000..c56ffd7654 --- /dev/null +++ b/arch/s390/README.md @@ -0,0 +1,265 @@ +# Introduction + +This directory contains SystemZ deflate hardware acceleration support. +It can be enabled using the following build commands: + + $ ./configure --with-dfltcc-deflate --with-dfltcc-inflate + $ make + +or + + $ cmake -DWITH_DFLTCC_DEFLATE=1 -DWITH_DFLTCC_INFLATE=1 . + $ make + +When built like this, zlib-ng would compress using hardware on level 1, +and using software on all other levels. Decompression will always happen +in hardware. In order to enable hardware compression for levels 1-6 +(i.e. to make it used by default) one could add +`-DDFLTCC_LEVEL_MASK=0x7e` to CFLAGS when building zlib-ng. + +SystemZ deflate hardware acceleration is available on [IBM z15]( +https://www.ibm.com/products/z15) and newer machines under the name [ +"Integrated Accelerator for zEnterprise Data Compression"]( +https://www.ibm.com/support/z-content-solutions/compression/). The +programming interface to it is a machine instruction called DEFLATE +CONVERSION CALL (DFLTCC). It is documented in Chapter 26 of [Principles +of Operation](https://publibfp.dhe.ibm.com/epubs/pdf/a227832c.pdf). Both +the code and the rest of this document refer to this feature simply as +"DFLTCC". + +# Performance + +Performance figures are published [here]( +https://github.com/iii-i/zlib-ng/wiki/Performance-with-dfltcc-patch-applied-and-dfltcc-support-built-on-dfltcc-enabled-machine +). The compression speed-up can be as high as 110x and the decompression +speed-up can be as high as 15x. + +# Limitations + +Two DFLTCC compression calls with identical inputs are not guaranteed to +produce identical outputs. Therefore care should be taken when using +hardware compression when reproducible results are desired. In +particular, zlib-ng-specific `zng_deflateSetParams` call allows setting +`Z_DEFLATE_REPRODUCIBLE` parameter, which disables DFLTCC support for a +particular stream. + +DFLTCC does not support every single zlib-ng feature, in particular: + +* `inflate(Z_BLOCK)` and `inflate(Z_TREES)` +* `inflateMark()` +* `inflatePrime()` +* `inflateSyncPoint()` + +When used, these functions will either switch to software, or, in case +this is not possible, gracefully fail. + +# Code structure + +All SystemZ-specific code lives in `arch/s390` directory and is +integrated with the rest of zlib-ng using hook macros. + +## Hook macros + +DFLTCC takes as arguments a parameter block, an input buffer, an output +buffer, and a window. Parameter blocks are stored alongside zlib states; +buffers are forwarded from the caller; and window - which must be +4k-aligned and is always 64k large, is managed using the `PAD_WINDOW()`, +`WINDOW_PAD_SIZE`, `HINT_ALIGNED_WINDOW` and `DEFLATE_ADJUST_WINDOW_SIZE()` +and `INFLATE_ADJUST_WINDOW_SIZE()` hooks. + +Software and hardware window formats do not match, therefore, +`deflateSetDictionary()`, `deflateGetDictionary()`, `inflateSetDictionary()` +and `inflateGetDictionary()` need special handling, which is triggered using +`DEFLATE_SET_DICTIONARY_HOOK()`, `DEFLATE_GET_DICTIONARY_HOOK()`, +`INFLATE_SET_DICTIONARY_HOOK()` and `INFLATE_GET_DICTIONARY_HOOK()` macros. + +`deflateResetKeep()` and `inflateResetKeep()` update the DFLTCC +parameter block using `DEFLATE_RESET_KEEP_HOOK()` and +`INFLATE_RESET_KEEP_HOOK()` macros. + +`INFLATE_PRIME_HOOK()`, `INFLATE_MARK_HOOK()` and +`INFLATE_SYNC_POINT_HOOK()` macros make the respective unsupported +calls gracefully fail. + +`DEFLATE_PARAMS_HOOK()` implements switching between hardware and +software compression mid-stream using `deflateParams()`. Switching +normally entails flushing the current block, which might not be possible +in low memory situations. `deflateParams()` uses `DEFLATE_DONE()` hook +in order to detect and gracefully handle such situations. + +The algorithm implemented in hardware has different compression ratio +than the one implemented in software. `DEFLATE_BOUND_ADJUST_COMPLEN()` +and `DEFLATE_NEED_CONSERVATIVE_BOUND()` macros make `deflateBound()` +return the correct results for the hardware implementation. + +Actual compression and decompression are handled by `DEFLATE_HOOK()` and +`INFLATE_TYPEDO_HOOK()` macros. Since inflation with DFLTCC manages the +window on its own, calling `updatewindow()` is suppressed using +`INFLATE_NEED_UPDATEWINDOW()` macro. + +In addition to compression, DFLTCC computes CRC-32 and Adler-32 +checksums, therefore, whenever it's used, software checksumming is +suppressed using `DEFLATE_NEED_CHECKSUM()` and `INFLATE_NEED_CHECKSUM()` +macros. + +While software always produces reproducible compression results, this +is not the case for DFLTCC. Therefore, zlib-ng users are given the +ability to specify whether or not reproducible compression results +are required. While it is always possible to specify this setting +before the compression begins, it is not always possible to do so in +the middle of a deflate stream - the exact conditions for that are +determined by `DEFLATE_CAN_SET_REPRODUCIBLE()` macro. + +## SystemZ-specific code + +When zlib-ng is built with DFLTCC, the hooks described above are +converted to calls to functions, which are implemented in +`arch/s390/dfltcc_*` files. The functions can be grouped in three broad +categories: + +* Base DFLTCC support, e.g. wrapping the machine instruction - `dfltcc()`. +* Translating between software and hardware data formats, e.g. + `dfltcc_deflate_set_dictionary()`. +* Translating between software and hardware state machines, e.g. + `dfltcc_deflate()` and `dfltcc_inflate()`. + +The functions from the first two categories are fairly simple, however, +various quirks in both software and hardware state machines make the +functions from the third category quite complicated. + +### `dfltcc_deflate()` function + +This function is called by `deflate()` and has the following +responsibilities: + +* Checking whether DFLTCC can be used with the current stream. If this + is not the case, then it returns `0`, making `deflate()` use some + other function in order to compress in software. Otherwise it returns + `1`. +* Block management and Huffman table generation. DFLTCC ends blocks only + when explicitly instructed to do so by the software. Furthermore, + whether to use fixed or dynamic Huffman tables must also be determined + by the software. Since looking at data in order to gather statistics + would negate performance benefits, the following approach is used: the + first `DFLTCC_FIRST_FHT_BLOCK_SIZE` bytes are placed into a fixed + block, and every next `DFLTCC_BLOCK_SIZE` bytes are placed into + dynamic blocks. +* Writing EOBS. Block Closing Control bit in the parameter block + instructs DFLTCC to write EOBS, however, certain conditions need to be + met: input data length must be non-zero or Continuation Flag must be + set. To put this in simpler terms, DFLTCC will silently refuse to + write EOBS if this is the only thing that it is asked to do. Since the + code has to be able to emit EOBS in software anyway, in order to avoid + tricky corner cases Block Closing Control is never used. Whether to + write EOBS is instead controlled by `soft_bcc` variable. +* Triggering block post-processing. Depending on flush mode, `deflate()` + must perform various additional actions when a block or a stream ends. + `dfltcc_deflate()` informs `deflate()` about this using + `block_state *result` parameter. +* Converting software state fields into hardware parameter block fields, + and vice versa. For example, `wrap` and Check Value Type or `bi_valid` + and Sub-Byte Boundary. Certain fields cannot be translated and must + persist untouched in the parameter block between calls, for example, + Continuation Flag or Continuation State Buffer. +* Handling flush modes and low-memory situations. These aspects are + quite intertwined and pervasive. The general idea here is that the + code must not do anything in software - whether explicitly by e.g. + calling `send_eobs()`, or implicitly - by returning to `deflate()` + with certain return and `*result` values, when Continuation Flag is + set. +* Ending streams. When a new block is started and flush mode is + `Z_FINISH`, Block Header Final parameter block bit is used to mark + this block as final. However, sometimes an empty final block is + needed, and, unfortunately, just like with EOBS, DFLTCC will silently + refuse to do this. The general idea of DFLTCC implementation is to + rely as much as possible on the existing code. Here in order to do + this, the code pretends that it does not support DFLTCC, which makes + `deflate()` call a software compression function, which writes an + empty final block. Whether this is required is controlled by + `need_empty_block` variable. +* Error handling. This is simply converting + Operation-Ending-Supplemental Code to string. Errors can only happen + due to things like memory corruption, and therefore they don't affect + the `deflate()` return code. + +### `dfltcc_inflate()` function + +This function is called by `inflate()` from the `TYPEDO` state (that is, +when all the metadata is parsed and the stream is positioned at the type +bits of deflate block header) and it's responsible for the following: + +* Falling back to software when flush mode is `Z_BLOCK` or `Z_TREES`. + Unfortunately, there is no way to ask DFLTCC to stop decompressing on + block or tree boundary. +* `inflate()` decompression loop management. This is controlled using + the return value, which can be either `DFLTCC_INFLATE_BREAK` or + `DFLTCC_INFLATE_CONTINUE`. +* Converting software state fields into hardware parameter block fields, + and vice versa. For example, `whave` and History Length or `wnext` and + History Offset. +* Ending streams. This instructs `inflate()` to return `Z_STREAM_END` + and is controlled by `last` state field. +* Error handling. Like deflate, error handling comprises + Operation-Ending-Supplemental Code to string conversion. Unlike + deflate, errors may happen due to bad inputs, therefore they are + propagated to `inflate()` by setting `mode` field to `MEM` or `BAD`. + +# Testing + +Given complexity of DFLTCC machine instruction, it is not clear whether +QEMU TCG will ever support it. At the time of writing, one has to have +access to an IBM z15+ VM or LPAR in order to test DFLTCC support. Since +DFLTCC is a non-privileged instruction, neither special VM/LPAR +configuration nor root are required. + +zlib-ng CI uses an IBM-provided z15 self-hosted builder for the DFLTCC +testing. There is no official IBM Z GitHub Actions runner, so we build +one inspired by `anup-kodlekere/gaplib`. +Future updates to actions-runner might need an updated patch. The .net +version number patch has been separated into a separate file to avoid a +need for constantly changing the patch. + +## Configuring the builder. + +### Install prerequisites. +``` +sudo dnf install podman +``` + +### Create a config file, needs github personal access token. +Access token needs permissions; Repo Admin RW, Org Self-hosted runners RW. +For details, consult +https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-a-repository + +#### Create file /etc/actions-runner: +``` +REPO=/ +PAT_TOKEN= +``` + +#### Set permissions on /etc/actions-runner: +``` +chmod 600 /etc/actions-runner +``` + +### Add actions-runner service. +``` +sudo cp self-hosted-builder/actions-runner.service /etc/systemd/system/ +sudo systemctl daemon-reload +``` + +### Autostart actions-runner. +``` +$ sudo systemctl enable --now actions-runner +``` + +### Add auto-rebuild cronjob +``` +sudo cp self-hosted-builder/actions-runner-rebuild.sh /etc/cron.weekly/ +chmod +x /etc/cron.weekly/actions-runner-rebuild.sh +``` + +## Building / Rebuilding the container +``` +sudo /etc/cron.weekly/actions-runner-rebuild.sh +``` diff --git a/arch/s390/crc32-vx.c b/arch/s390/crc32-vx.c new file mode 100644 index 0000000000..b3dcbf7030 --- /dev/null +++ b/arch/s390/crc32-vx.c @@ -0,0 +1,222 @@ +/* + * Hardware-accelerated CRC-32 variants for Linux on z Systems + * + * Use the z/Architecture Vector Extension Facility to accelerate the + * computing of bitreflected CRC-32 checksums. + * + * This CRC-32 implementation algorithm is bitreflected and processes + * the least-significant bit first (Little-Endian). + * + * This code was originally written by Hendrik Brueckner + * for use in the Linux kernel and has been + * relicensed under the zlib license. + */ + +#include "zbuild.h" +#include "arch_functions.h" + +#include + +typedef unsigned char uv16qi __attribute__((vector_size(16))); +typedef unsigned int uv4si __attribute__((vector_size(16))); +typedef unsigned long long uv2di __attribute__((vector_size(16))); + +static uint32_t crc32_le_vgfm_16(uint32_t crc, const uint8_t *buf, size_t len) { + /* + * The CRC-32 constant block contains reduction constants to fold and + * process particular chunks of the input data stream in parallel. + * + * For the CRC-32 variants, the constants are precomputed according to + * these definitions: + * + * R1 = [(x4*128+32 mod P'(x) << 32)]' << 1 + * R2 = [(x4*128-32 mod P'(x) << 32)]' << 1 + * R3 = [(x128+32 mod P'(x) << 32)]' << 1 + * R4 = [(x128-32 mod P'(x) << 32)]' << 1 + * R5 = [(x64 mod P'(x) << 32)]' << 1 + * R6 = [(x32 mod P'(x) << 32)]' << 1 + * + * The bitreflected Barret reduction constant, u', is defined as + * the bit reversal of floor(x**64 / P(x)). + * + * where P(x) is the polynomial in the normal domain and the P'(x) is the + * polynomial in the reversed (bitreflected) domain. + * + * CRC-32 (IEEE 802.3 Ethernet, ...) polynomials: + * + * P(x) = 0x04C11DB7 + * P'(x) = 0xEDB88320 + */ + const uv16qi perm_le2be = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; /* BE->LE mask */ + const uv2di r2r1 = {0x1C6E41596, 0x154442BD4}; /* R2, R1 */ + const uv2di r4r3 = {0x0CCAA009E, 0x1751997D0}; /* R4, R3 */ + const uv2di r5 = {0, 0x163CD6124}; /* R5 */ + const uv2di ru_poly = {0, 0x1F7011641}; /* u' */ + const uv2di crc_poly = {0, 0x1DB710641}; /* P'(x) << 1 */ + + /* + * Load the initial CRC value. + * + * The CRC value is loaded into the rightmost word of the + * vector register and is later XORed with the LSB portion + * of the loaded input data. + */ + uv2di v0 = {0, 0}; + v0 = (uv2di)vec_insert(crc, (uv4si)v0, 3); + + /* Load a 64-byte data chunk and XOR with CRC */ + uv2di v1 = vec_perm(((uv2di *)buf)[0], ((uv2di *)buf)[0], perm_le2be); + uv2di v2 = vec_perm(((uv2di *)buf)[1], ((uv2di *)buf)[1], perm_le2be); + uv2di v3 = vec_perm(((uv2di *)buf)[2], ((uv2di *)buf)[2], perm_le2be); + uv2di v4 = vec_perm(((uv2di *)buf)[3], ((uv2di *)buf)[3], perm_le2be); + + v1 ^= v0; + buf += 64; + len -= 64; + + while (len >= 64) { + /* Load the next 64-byte data chunk */ + uv16qi part1 = vec_perm(((uv16qi *)buf)[0], ((uv16qi *)buf)[0], perm_le2be); + uv16qi part2 = vec_perm(((uv16qi *)buf)[1], ((uv16qi *)buf)[1], perm_le2be); + uv16qi part3 = vec_perm(((uv16qi *)buf)[2], ((uv16qi *)buf)[2], perm_le2be); + uv16qi part4 = vec_perm(((uv16qi *)buf)[3], ((uv16qi *)buf)[3], perm_le2be); + + /* + * Perform a GF(2) multiplication of the doublewords in V1 with + * the R1 and R2 reduction constants in V0. The intermediate result + * is then folded (accumulated) with the next data chunk in PART1 and + * stored in V1. Repeat this step for the register contents + * in V2, V3, and V4 respectively. + */ + v1 = (uv2di)vec_gfmsum_accum_128(r2r1, v1, part1); + v2 = (uv2di)vec_gfmsum_accum_128(r2r1, v2, part2); + v3 = (uv2di)vec_gfmsum_accum_128(r2r1, v3, part3); + v4 = (uv2di)vec_gfmsum_accum_128(r2r1, v4, part4); + + buf += 64; + len -= 64; + } + + /* + * Fold V1 to V4 into a single 128-bit value in V1. Multiply V1 with R3 + * and R4 and accumulating the next 128-bit chunk until a single 128-bit + * value remains. + */ + v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v2); + v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v3); + v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v4); + + while (len >= 16) { + /* Load next data chunk */ + v2 = vec_perm(*(uv2di *)buf, *(uv2di *)buf, perm_le2be); + + /* Fold next data chunk */ + v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v2); + + buf += 16; + len -= 16; + } + + /* + * Set up a vector register for byte shifts. The shift value must + * be loaded in bits 1-4 in byte element 7 of a vector register. + * Shift by 8 bytes: 0x40 + * Shift by 4 bytes: 0x20 + */ + uv16qi v9 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + v9 = vec_insert((unsigned char)0x40, v9, 7); + + /* + * Prepare V0 for the next GF(2) multiplication: shift V0 by 8 bytes + * to move R4 into the rightmost doubleword and set the leftmost + * doubleword to 0x1. + */ + v0 = vec_srb(r4r3, (uv2di)v9); + v0[0] = 1; + + /* + * Compute GF(2) product of V1 and V0. The rightmost doubleword + * of V1 is multiplied with R4. The leftmost doubleword of V1 is + * multiplied by 0x1 and is then XORed with rightmost product. + * Implicitly, the intermediate leftmost product becomes padded + */ + v1 = (uv2di)vec_gfmsum_128(v0, v1); + + /* + * Now do the final 32-bit fold by multiplying the rightmost word + * in V1 with R5 and XOR the result with the remaining bits in V1. + * + * To achieve this by a single VGFMAG, right shift V1 by a word + * and store the result in V2 which is then accumulated. Use the + * vector unpack instruction to load the rightmost half of the + * doubleword into the rightmost doubleword element of V1; the other + * half is loaded in the leftmost doubleword. + * The vector register with CONST_R5 contains the R5 constant in the + * rightmost doubleword and the leftmost doubleword is zero to ignore + * the leftmost product of V1. + */ + v9 = vec_insert((unsigned char)0x20, v9, 7); + v2 = vec_srb(v1, (uv2di)v9); + v1 = vec_unpackl((uv4si)v1); /* Split rightmost doubleword */ + v1 = (uv2di)vec_gfmsum_accum_128(r5, v1, (uv16qi)v2); + + /* + * Apply a Barret reduction to compute the final 32-bit CRC value. + * + * The input values to the Barret reduction are the degree-63 polynomial + * in V1 (R(x)), degree-32 generator polynomial, and the reduction + * constant u. The Barret reduction result is the CRC value of R(x) mod + * P(x). + * + * The Barret reduction algorithm is defined as: + * + * 1. T1(x) = floor( R(x) / x^32 ) GF2MUL u + * 2. T2(x) = floor( T1(x) / x^32 ) GF2MUL P(x) + * 3. C(x) = R(x) XOR T2(x) mod x^32 + * + * Note: The leftmost doubleword of vector register containing + * CONST_RU_POLY is zero and, thus, the intermediate GF(2) product + * is zero and does not contribute to the final result. + */ + + /* T1(x) = floor( R(x) / x^32 ) GF2MUL u */ + v2 = vec_unpackl((uv4si)v1); + v2 = (uv2di)vec_gfmsum_128(ru_poly, v2); + + /* + * Compute the GF(2) product of the CRC polynomial with T1(x) in + * V2 and XOR the intermediate result, T2(x), with the value in V1. + * The final result is stored in word element 2 of V2. + */ + v2 = vec_unpackl((uv4si)v2); + v2 = (uv2di)vec_gfmsum_accum_128(crc_poly, v2, (uv16qi)v1); + + return ((uv4si)v2)[2]; +} + +#define VX_MIN_LEN 64 +#define VX_ALIGNMENT 16L +#define VX_ALIGN_MASK (VX_ALIGNMENT - 1) + +uint32_t Z_INTERNAL crc32_s390_vx(uint32_t crc, const unsigned char *buf, size_t len) { + size_t prealign, aligned, remaining; + + if (len < VX_MIN_LEN + VX_ALIGN_MASK) + return PREFIX(crc32_braid)(crc, buf, len); + + if ((uintptr_t)buf & VX_ALIGN_MASK) { + prealign = VX_ALIGNMENT - ((uintptr_t)buf & VX_ALIGN_MASK); + len -= prealign; + crc = PREFIX(crc32_braid)(crc, buf, prealign); + buf += prealign; + } + aligned = len & ~VX_ALIGN_MASK; + remaining = len & VX_ALIGN_MASK; + + crc = crc32_le_vgfm_16(crc ^ 0xffffffff, buf, aligned) ^ 0xffffffff; + + if (remaining) + crc = PREFIX(crc32_braid)(crc, buf + aligned, remaining); + + return crc; +} diff --git a/arch/s390/dfltcc_common.h b/arch/s390/dfltcc_common.h new file mode 100644 index 0000000000..a6527ab5df --- /dev/null +++ b/arch/s390/dfltcc_common.h @@ -0,0 +1,119 @@ +#ifndef DFLTCC_COMMON_H +#define DFLTCC_COMMON_H + +#include "zutil.h" + +/* + Parameter Block for Query Available Functions. + */ +struct dfltcc_qaf_param { + char fns[16]; + char reserved1[8]; + char fmts[2]; + char reserved2[6]; +} ALIGNED_(8); + +/* + Parameter Block for Generate Dynamic-Huffman Table, Compress and Expand. + */ +struct dfltcc_param_v0 { + uint16_t pbvn; /* Parameter-Block-Version Number */ + uint8_t mvn; /* Model-Version Number */ + uint8_t ribm; /* Reserved for IBM use */ + uint32_t reserved32 : 31; + uint32_t cf : 1; /* Continuation Flag */ + uint8_t reserved64[8]; + uint32_t nt : 1; /* New Task */ + uint32_t reserved129 : 1; + uint32_t cvt : 1; /* Check Value Type */ + uint32_t reserved131 : 1; + uint32_t htt : 1; /* Huffman-Table Type */ + uint32_t bcf : 1; /* Block-Continuation Flag */ + uint32_t bcc : 1; /* Block Closing Control */ + uint32_t bhf : 1; /* Block Header Final */ + uint32_t reserved136 : 1; + uint32_t reserved137 : 1; + uint32_t dhtgc : 1; /* DHT Generation Control */ + uint32_t reserved139 : 5; + uint32_t reserved144 : 5; + uint32_t sbb : 3; /* Sub-Byte Boundary */ + uint8_t oesc; /* Operation-Ending-Supplemental Code */ + uint32_t reserved160 : 12; + uint32_t ifs : 4; /* Incomplete-Function Status */ + uint16_t ifl; /* Incomplete-Function Length */ + uint8_t reserved192[8]; + uint8_t reserved256[8]; + uint8_t reserved320[4]; + uint16_t hl; /* History Length */ + uint32_t reserved368 : 1; + uint16_t ho : 15; /* History Offset */ + uint32_t cv; /* Check Value */ + uint32_t eobs : 15; /* End-of-block Symbol */ + uint32_t reserved431: 1; + uint8_t eobl : 4; /* End-of-block Length */ + uint32_t reserved436 : 12; + uint32_t reserved448 : 4; + uint16_t cdhtl : 12; /* Compressed-Dynamic-Huffman Table + Length */ + uint8_t reserved464[6]; + uint8_t cdht[288]; /* Compressed-Dynamic-Huffman Table */ + uint8_t reserved[24]; + uint8_t ribm2[8]; /* Reserved for IBM use */ + uint8_t csb[1152]; /* Continuation-State Buffer */ +} ALIGNED_(8); + +/* + Extension of inflate_state and deflate_state. + */ +struct dfltcc_state { + struct dfltcc_param_v0 param; /* Parameter block. */ + struct dfltcc_qaf_param af; /* Available functions. */ + char msg[64]; /* Buffer for strm->msg */ +}; + +typedef struct { + struct dfltcc_state common; + uint16_t level_mask; /* Levels on which to use DFLTCC */ + uint32_t block_size; /* New block each X bytes */ + size_t block_threshold; /* New block after total_in > X */ + uint32_t dht_threshold; /* New block only if avail_in >= X */ +} arch_deflate_state; + +typedef struct { + struct dfltcc_state common; +} arch_inflate_state; + +/* + History buffer size. + */ +#define HB_BITS 15 +#define HB_SIZE (1 << HB_BITS) + +/* + Sizes of deflate block parts. + */ +#define DFLTCC_BLOCK_HEADER_BITS 3 +#define DFLTCC_HLITS_COUNT_BITS 5 +#define DFLTCC_HDISTS_COUNT_BITS 5 +#define DFLTCC_HCLENS_COUNT_BITS 4 +#define DFLTCC_MAX_HCLENS 19 +#define DFLTCC_HCLEN_BITS 3 +#define DFLTCC_MAX_HLITS 286 +#define DFLTCC_MAX_HDISTS 30 +#define DFLTCC_MAX_HLIT_HDIST_BITS 7 +#define DFLTCC_MAX_SYMBOL_BITS 16 +#define DFLTCC_MAX_EOBS_BITS 15 +#define DFLTCC_MAX_PADDING_BITS 7 + +#define DEFLATE_BOUND_COMPLEN(source_len) \ + ((DFLTCC_BLOCK_HEADER_BITS + \ + DFLTCC_HLITS_COUNT_BITS + \ + DFLTCC_HDISTS_COUNT_BITS + \ + DFLTCC_HCLENS_COUNT_BITS + \ + DFLTCC_MAX_HCLENS * DFLTCC_HCLEN_BITS + \ + (DFLTCC_MAX_HLITS + DFLTCC_MAX_HDISTS) * DFLTCC_MAX_HLIT_HDIST_BITS + \ + (source_len) * DFLTCC_MAX_SYMBOL_BITS + \ + DFLTCC_MAX_EOBS_BITS + \ + DFLTCC_MAX_PADDING_BITS) >> 3) + +#endif diff --git a/arch/s390/dfltcc_deflate.c b/arch/s390/dfltcc_deflate.c new file mode 100644 index 0000000000..90b4b96e9c --- /dev/null +++ b/arch/s390/dfltcc_deflate.c @@ -0,0 +1,383 @@ +/* dfltcc_deflate.c - IBM Z DEFLATE CONVERSION CALL compression support. */ + +/* + Use the following commands to build zlib-ng with DFLTCC compression support: + + $ ./configure --with-dfltcc-deflate + or + + $ cmake -DWITH_DFLTCC_DEFLATE=1 . + + and then + + $ make +*/ + +#include "zbuild.h" +#include "deflate.h" +#include "trees_emit.h" +#include "dfltcc_deflate.h" +#include "dfltcc_detail.h" + +void Z_INTERNAL PREFIX(dfltcc_reset_deflate_state)(PREFIX3(streamp) strm) { + deflate_state *state = (deflate_state *)strm->state; + arch_deflate_state *dfltcc_state = &state->arch; + + dfltcc_reset_state(&dfltcc_state->common); + + /* Initialize tuning parameters */ + dfltcc_state->level_mask = DFLTCC_LEVEL_MASK; + dfltcc_state->block_size = DFLTCC_BLOCK_SIZE; + dfltcc_state->block_threshold = DFLTCC_FIRST_FHT_BLOCK_SIZE; + dfltcc_state->dht_threshold = DFLTCC_DHT_MIN_SAMPLE_SIZE; +} + +static inline int dfltcc_can_deflate_with_params(PREFIX3(streamp) strm, int level, uInt window_bits, int strategy, + int reproducible) { + deflate_state *state = (deflate_state *)strm->state; + arch_deflate_state *dfltcc_state = &state->arch; + + /* Unsupported compression settings */ + if ((dfltcc_state->level_mask & (1 << level)) == 0) + return 0; + if (window_bits != HB_BITS) + return 0; + if (strategy != Z_FIXED && strategy != Z_DEFAULT_STRATEGY) + return 0; + if (reproducible) + return 0; + + /* Unsupported hardware */ + if (!is_bit_set(dfltcc_state->common.af.fns, DFLTCC_GDHT) || + !is_bit_set(dfltcc_state->common.af.fns, DFLTCC_CMPR) || + !is_bit_set(dfltcc_state->common.af.fmts, DFLTCC_FMT0)) + return 0; + + return 1; +} + +int Z_INTERNAL PREFIX(dfltcc_can_deflate)(PREFIX3(streamp) strm) { + deflate_state *state = (deflate_state *)strm->state; + + return dfltcc_can_deflate_with_params(strm, state->level, state->w_bits, state->strategy, state->reproducible); +} + +static inline void dfltcc_gdht(PREFIX3(streamp) strm) { + deflate_state *state = (deflate_state *)strm->state; + struct dfltcc_param_v0 *param = &state->arch.common.param; + size_t avail_in = strm->avail_in; + + dfltcc(DFLTCC_GDHT, param, NULL, NULL, &strm->next_in, &avail_in, NULL); +} + +static inline dfltcc_cc dfltcc_cmpr(PREFIX3(streamp) strm) { + deflate_state *state = (deflate_state *)strm->state; + struct dfltcc_param_v0 *param = &state->arch.common.param; + size_t avail_in = strm->avail_in; + size_t avail_out = strm->avail_out; + dfltcc_cc cc; + + cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR, + param, &strm->next_out, &avail_out, + &strm->next_in, &avail_in, state->window); + strm->total_in += (strm->avail_in - avail_in); + strm->total_out += (strm->avail_out - avail_out); + strm->avail_in = avail_in; + strm->avail_out = avail_out; + return cc; +} + +static inline void send_eobs(PREFIX3(streamp) strm, const struct dfltcc_param_v0 *param) { + deflate_state *state = (deflate_state *)strm->state; + + send_bits(state, PREFIX(bi_reverse)(param->eobs >> (15 - param->eobl), param->eobl), param->eobl, state->bi_buf, state->bi_valid); + PREFIX(flush_pending)(strm); + if (state->pending != 0) { + /* The remaining data is located in pending_out[0:pending]. If someone + * calls put_byte() - this might happen in deflate() - the byte will be + * placed into pending_buf[pending], which is incorrect. Move the + * remaining data to the beginning of pending_buf so that put_byte() is + * usable again. + */ + memmove(state->pending_buf, state->pending_out, state->pending); + state->pending_out = state->pending_buf; + } +#ifdef ZLIB_DEBUG + state->compressed_len += param->eobl; +#endif +} + +int Z_INTERNAL PREFIX(dfltcc_deflate)(PREFIX3(streamp) strm, int flush, block_state *result) { + deflate_state *state = (deflate_state *)strm->state; + arch_deflate_state *dfltcc_state = &state->arch; + struct dfltcc_param_v0 *param = &dfltcc_state->common.param; + uInt masked_avail_in; + dfltcc_cc cc; + int need_empty_block; + int soft_bcc; + int no_flush; + + if (!PREFIX(dfltcc_can_deflate)(strm)) { + /* Clear history. */ + if (flush == Z_FULL_FLUSH) + param->hl = 0; + return 0; + } + +again: + masked_avail_in = 0; + soft_bcc = 0; + no_flush = flush == Z_NO_FLUSH; + + /* No input data. Return, except when Continuation Flag is set, which means + * that DFLTCC has buffered some output in the parameter block and needs to + * be called again in order to flush it. + */ + if (strm->avail_in == 0 && !param->cf) { + /* A block is still open, and the hardware does not support closing + * blocks without adding data. Thus, close it manually. + */ + if (!no_flush && param->bcf) { + send_eobs(strm, param); + param->bcf = 0; + } + /* Let one of deflate_* functions write a trailing empty block. */ + if (flush == Z_FINISH) + return 0; + /* Clear history. */ + if (flush == Z_FULL_FLUSH) + param->hl = 0; + /* Trigger block post-processing if necessary. */ + *result = no_flush ? need_more : block_done; + return 1; + } + + /* There is an open non-BFINAL block, we are not going to close it just + * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see + * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new + * DHT in order to adapt to a possibly changed input data distribution. + */ + if (param->bcf && no_flush && + strm->total_in > dfltcc_state->block_threshold && + strm->avail_in >= dfltcc_state->dht_threshold) { + if (param->cf) { + /* We need to flush the DFLTCC buffer before writing the + * End-of-block Symbol. Mask the input data and proceed as usual. + */ + masked_avail_in += strm->avail_in; + strm->avail_in = 0; + no_flush = 0; + } else { + /* DFLTCC buffer is empty, so we can manually write the + * End-of-block Symbol right away. + */ + send_eobs(strm, param); + param->bcf = 0; + dfltcc_state->block_threshold = strm->total_in + dfltcc_state->block_size; + } + } + + /* No space for compressed data. If we proceed, dfltcc_cmpr() will return + * DFLTCC_CC_OP1_TOO_SHORT without buffering header bits, but we will still + * set BCF=1, which is wrong. Avoid complications and return early. + */ + if (strm->avail_out == 0) { + *result = need_more; + return 1; + } + + /* The caller gave us too much data. Pass only one block worth of + * uncompressed data to DFLTCC and mask the rest, so that on the next + * iteration we start a new block. + */ + if (no_flush && strm->avail_in > dfltcc_state->block_size) { + masked_avail_in += (strm->avail_in - dfltcc_state->block_size); + strm->avail_in = dfltcc_state->block_size; + } + + /* When we have an open non-BFINAL deflate block and caller indicates that + * the stream is ending, we need to close an open deflate block and open a + * BFINAL one. + */ + need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf; + + /* Translate stream to parameter block */ + param->cvt = state->wrap == 2 ? CVT_CRC32 : CVT_ADLER32; + if (!no_flush) + /* We need to close a block. Always do this in software - when there is + * no input data, the hardware will not honor BCC. */ + soft_bcc = 1; + if (flush == Z_FINISH && !param->bcf) + /* We are about to open a BFINAL block, set Block Header Final bit + * until the stream ends. + */ + param->bhf = 1; + /* DFLTCC-CMPR will write to next_out, so make sure that buffers with + * higher precedence are empty. + */ + Assert(state->pending == 0, "There must be no pending bytes"); + Assert(state->bi_valid < 8, "There must be less than 8 pending bits"); + param->sbb = (unsigned int)state->bi_valid; + if (param->sbb > 0) + *strm->next_out = (unsigned char)state->bi_buf; + /* Honor history and check value */ + param->nt = 0; + if (state->wrap == 1) + param->cv = strm->adler; + else if (state->wrap == 2) + param->cv = ZSWAP32(state->crc_fold.value); + + /* When opening a block, choose a Huffman-Table Type */ + if (!param->bcf) { + if (state->strategy == Z_FIXED || (strm->total_in == 0 && dfltcc_state->block_threshold > 0)) + param->htt = HTT_FIXED; + else { + param->htt = HTT_DYNAMIC; + dfltcc_gdht(strm); + } + } + + /* Deflate */ + do { + cc = dfltcc_cmpr(strm); + if (strm->avail_in < 4096 && masked_avail_in > 0) + /* We are about to call DFLTCC with a small input buffer, which is + * inefficient. Since there is masked data, there will be at least + * one more DFLTCC call, so skip the current one and make the next + * one handle more data. + */ + break; + } while (cc == DFLTCC_CC_AGAIN); + + /* Translate parameter block to stream */ + strm->msg = oesc_msg(dfltcc_state->common.msg, param->oesc); + state->bi_valid = param->sbb; + if (state->bi_valid == 0) + state->bi_buf = 0; /* Avoid accessing next_out */ + else + state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1); + if (state->wrap == 1) + strm->adler = param->cv; + else if (state->wrap == 2) + state->crc_fold.value = ZSWAP32(param->cv); + + /* Unmask the input data */ + strm->avail_in += masked_avail_in; + masked_avail_in = 0; + + /* If we encounter an error, it means there is a bug in DFLTCC call */ + Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG"); + + /* Update Block-Continuation Flag. It will be used to check whether to call + * GDHT the next time. + */ + if (cc == DFLTCC_CC_OK) { + if (soft_bcc) { + send_eobs(strm, param); + param->bcf = 0; + dfltcc_state->block_threshold = strm->total_in + dfltcc_state->block_size; + } else + param->bcf = 1; + if (flush == Z_FINISH) { + if (need_empty_block) + /* Make the current deflate() call also close the stream */ + return 0; + else { + bi_windup(state); + *result = finish_done; + } + } else { + if (flush == Z_FULL_FLUSH) + param->hl = 0; /* Clear history */ + *result = flush == Z_NO_FLUSH ? need_more : block_done; + } + } else { + param->bcf = 1; + *result = need_more; + } + if (strm->avail_in != 0 && strm->avail_out != 0) + goto again; /* deflate() must use all input or all output */ + return 1; +} + +/* + Switching between hardware and software compression. + + DFLTCC does not support all zlib settings, e.g. generation of non-compressed + blocks or alternative window sizes. When such settings are applied on the + fly with deflateParams, we need to convert between hardware and software + window formats. +*/ +static int dfltcc_was_deflate_used(PREFIX3(streamp) strm) { + deflate_state *state = (deflate_state *)strm->state; + struct dfltcc_param_v0 *param = &state->arch.common.param; + + return strm->total_in > 0 || param->nt == 0 || param->hl > 0; +} + +int Z_INTERNAL PREFIX(dfltcc_deflate_params)(PREFIX3(streamp) strm, int level, int strategy, int *flush) { + deflate_state *state = (deflate_state *)strm->state; + int could_deflate = PREFIX(dfltcc_can_deflate)(strm); + int can_deflate = dfltcc_can_deflate_with_params(strm, level, state->w_bits, strategy, state->reproducible); + + if (can_deflate == could_deflate) + /* We continue to work in the same mode - no changes needed */ + return Z_OK; + + if (!dfltcc_was_deflate_used(strm)) + /* DFLTCC was not used yet - no changes needed */ + return Z_OK; + + /* For now, do not convert between window formats - simply get rid of the old data instead */ + *flush = Z_FULL_FLUSH; + return Z_OK; +} + +int Z_INTERNAL PREFIX(dfltcc_deflate_done)(PREFIX3(streamp) strm, int flush) { + deflate_state *state = (deflate_state *)strm->state; + struct dfltcc_param_v0 *param = &state->arch.common.param; + + /* When deflate(Z_FULL_FLUSH) is called with small avail_out, it might + * close the block without resetting the compression state. Detect this + * situation and return that deflation is not done. + */ + if (flush == Z_FULL_FLUSH && strm->avail_out == 0) + return 0; + + /* Return that deflation is not done if DFLTCC is used and either it + * buffered some data (Continuation Flag is set), or has not written EOBS + * yet (Block-Continuation Flag is set). + */ + return !PREFIX(dfltcc_can_deflate)(strm) || (!param->cf && !param->bcf); +} + +int Z_INTERNAL PREFIX(dfltcc_can_set_reproducible)(PREFIX3(streamp) strm, int reproducible) { + deflate_state *state = (deflate_state *)strm->state; + + return reproducible != state->reproducible && !dfltcc_was_deflate_used(strm); +} + +/* + Preloading history. +*/ +int Z_INTERNAL PREFIX(dfltcc_deflate_set_dictionary)(PREFIX3(streamp) strm, + const unsigned char *dictionary, uInt dict_length) { + deflate_state *state = (deflate_state *)strm->state; + struct dfltcc_param_v0 *param = &state->arch.common.param; + + append_history(param, state->window, dictionary, dict_length); + state->strstart = 1; /* Add FDICT to zlib header */ + state->block_start = state->strstart; /* Make deflate_stored happy */ + return Z_OK; +} + +int Z_INTERNAL PREFIX(dfltcc_deflate_get_dictionary)(PREFIX3(streamp) strm, unsigned char *dictionary, uInt *dict_length) { + deflate_state *state = (deflate_state *)strm->state; + struct dfltcc_param_v0 *param = &state->arch.common.param; + + if (dictionary) + get_history(param, state->window, dictionary); + if (dict_length) + *dict_length = param->hl; + return Z_OK; +} diff --git a/arch/s390/dfltcc_deflate.h b/arch/s390/dfltcc_deflate.h new file mode 100644 index 0000000000..35e2fd3f62 --- /dev/null +++ b/arch/s390/dfltcc_deflate.h @@ -0,0 +1,58 @@ +#ifndef DFLTCC_DEFLATE_H +#define DFLTCC_DEFLATE_H + +#include "deflate.h" +#include "dfltcc_common.h" + +void Z_INTERNAL PREFIX(dfltcc_reset_deflate_state)(PREFIX3(streamp)); +int Z_INTERNAL PREFIX(dfltcc_can_deflate)(PREFIX3(streamp) strm); +int Z_INTERNAL PREFIX(dfltcc_deflate)(PREFIX3(streamp) strm, int flush, block_state *result); +int Z_INTERNAL PREFIX(dfltcc_deflate_params)(PREFIX3(streamp) strm, int level, int strategy, int *flush); +int Z_INTERNAL PREFIX(dfltcc_deflate_done)(PREFIX3(streamp) strm, int flush); +int Z_INTERNAL PREFIX(dfltcc_can_set_reproducible)(PREFIX3(streamp) strm, int reproducible); +int Z_INTERNAL PREFIX(dfltcc_deflate_set_dictionary)(PREFIX3(streamp) strm, + const unsigned char *dictionary, uInt dict_length); +int Z_INTERNAL PREFIX(dfltcc_deflate_get_dictionary)(PREFIX3(streamp) strm, unsigned char *dictionary, uInt* dict_length); + +#define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) \ + do { \ + if (PREFIX(dfltcc_can_deflate)((strm))) \ + return PREFIX(dfltcc_deflate_set_dictionary)((strm), (dict), (dict_len)); \ + } while (0) + +#define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) \ + do { \ + if (PREFIX(dfltcc_can_deflate)((strm))) \ + return PREFIX(dfltcc_deflate_get_dictionary)((strm), (dict), (dict_len)); \ + } while (0) + +#define DEFLATE_RESET_KEEP_HOOK PREFIX(dfltcc_reset_deflate_state) + +#define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) \ + do { \ + int err; \ +\ + err = PREFIX(dfltcc_deflate_params)((strm), (level), (strategy), (hook_flush)); \ + if (err == Z_STREAM_ERROR) \ + return err; \ + } while (0) + +#define DEFLATE_DONE PREFIX(dfltcc_deflate_done) + +#define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, source_len) \ + do { \ + if (deflateStateCheck((strm)) || PREFIX(dfltcc_can_deflate)((strm))) \ + (complen) = DEFLATE_BOUND_COMPLEN(source_len); \ + } while (0) + +#define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) (PREFIX(dfltcc_can_deflate)((strm))) + +#define DEFLATE_HOOK PREFIX(dfltcc_deflate) + +#define DEFLATE_NEED_CHECKSUM(strm) (!PREFIX(dfltcc_can_deflate)((strm))) + +#define DEFLATE_CAN_SET_REPRODUCIBLE PREFIX(dfltcc_can_set_reproducible) + +#define DEFLATE_ADJUST_WINDOW_SIZE(n) MAX(n, HB_SIZE) + +#endif diff --git a/arch/s390/dfltcc_detail.h b/arch/s390/dfltcc_detail.h new file mode 100644 index 0000000000..ae6001ba38 --- /dev/null +++ b/arch/s390/dfltcc_detail.h @@ -0,0 +1,275 @@ +#include "zbuild.h" +#include + +#ifdef HAVE_SYS_SDT_H +#include +#endif + +/* + Tuning parameters. + */ +#ifndef DFLTCC_LEVEL_MASK +#define DFLTCC_LEVEL_MASK 0x2 +#endif +#ifndef DFLTCC_BLOCK_SIZE +#define DFLTCC_BLOCK_SIZE 1048576 +#endif +#ifndef DFLTCC_FIRST_FHT_BLOCK_SIZE +#define DFLTCC_FIRST_FHT_BLOCK_SIZE 4096 +#endif +#ifndef DFLTCC_DHT_MIN_SAMPLE_SIZE +#define DFLTCC_DHT_MIN_SAMPLE_SIZE 4096 +#endif +#ifndef DFLTCC_RIBM +#define DFLTCC_RIBM 0 +#endif + +#define static_assert(c, msg) __attribute__((unused)) static char static_assert_failed_ ## msg[c ? 1 : -1] + +#define DFLTCC_SIZEOF_QAF 32 +static_assert(sizeof(struct dfltcc_qaf_param) == DFLTCC_SIZEOF_QAF, qaf); + +static inline int is_bit_set(const char *bits, int n) { + return bits[n / 8] & (1 << (7 - (n % 8))); +} + +static inline void clear_bit(char *bits, int n) { + bits[n / 8] &= ~(1 << (7 - (n % 8))); +} + +#define DFLTCC_FACILITY 151 + +static inline int is_dfltcc_enabled(void) { + uint64_t facilities[(DFLTCC_FACILITY / 64) + 1]; + Z_REGISTER uint8_t r0 __asm__("r0"); + + memset(facilities, 0, sizeof(facilities)); + r0 = sizeof(facilities) / sizeof(facilities[0]) - 1; + /* STFLE is supported since z9-109 and only in z/Architecture mode. When + * compiling with -m31, gcc defaults to ESA mode, however, since the kernel + * is 64-bit, it's always z/Architecture mode at runtime. + */ + __asm__ volatile( +#ifndef __clang__ + ".machinemode push\n" + ".machinemode zarch\n" +#endif + "stfle %[facilities]\n" +#ifndef __clang__ + ".machinemode pop\n" +#endif + : [facilities] "=Q" (facilities), [r0] "+r" (r0) :: "cc"); + return is_bit_set((const char *)facilities, DFLTCC_FACILITY); +} + +#define DFLTCC_FMT0 0 + +#define CVT_CRC32 0 +#define CVT_ADLER32 1 +#define HTT_FIXED 0 +#define HTT_DYNAMIC 1 + +#define DFLTCC_SIZEOF_GDHT_V0 384 +#define DFLTCC_SIZEOF_CMPR_XPND_V0 1536 +static_assert(offsetof(struct dfltcc_param_v0, csb) == DFLTCC_SIZEOF_GDHT_V0, gdht_v0); +static_assert(sizeof(struct dfltcc_param_v0) == DFLTCC_SIZEOF_CMPR_XPND_V0, cmpr_xpnd_v0); + +static inline z_const char *oesc_msg(char *buf, int oesc) { + if (oesc == 0x00) + return NULL; /* Successful completion */ + else { + sprintf(buf, "Operation-Ending-Supplemental Code is 0x%.2X", oesc); + return buf; + } +} + +/* + C wrapper for the DEFLATE CONVERSION CALL instruction. + */ +typedef enum { + DFLTCC_CC_OK = 0, + DFLTCC_CC_OP1_TOO_SHORT = 1, + DFLTCC_CC_OP2_TOO_SHORT = 2, + DFLTCC_CC_OP2_CORRUPT = 2, + DFLTCC_CC_AGAIN = 3, +} dfltcc_cc; + +#define DFLTCC_QAF 0 +#define DFLTCC_GDHT 1 +#define DFLTCC_CMPR 2 +#define DFLTCC_XPND 4 +#define HBT_CIRCULAR (1 << 7) +#define DFLTCC_FN_MASK ((1 << 7) - 1) + +/* Return lengths of high (starting at param->ho) and low (starting at 0) fragments of the circular history buffer. */ +static inline void get_history_lengths(struct dfltcc_param_v0 *param, size_t *hl_high, size_t *hl_low) { + *hl_high = MIN(param->hl, HB_SIZE - param->ho); + *hl_low = param->hl - *hl_high; +} + +/* Notify instrumentation about an upcoming read/write access to the circular history buffer. */ +static inline void instrument_read_write_hist(struct dfltcc_param_v0 *param, void *hist) { + size_t hl_high, hl_low; + + get_history_lengths(param, &hl_high, &hl_low); + instrument_read_write(hist + param->ho, hl_high); + instrument_read_write(hist, hl_low); +} + +/* Notify MSan about a completed write to the circular history buffer. */ +static inline void msan_unpoison_hist(struct dfltcc_param_v0 *param, void *hist) { + size_t hl_high, hl_low; + + get_history_lengths(param, &hl_high, &hl_low); + __msan_unpoison(hist + param->ho, hl_high); + __msan_unpoison(hist, hl_low); +} + +static inline dfltcc_cc dfltcc(int fn, void *param, + unsigned char **op1, size_t *len1, + z_const unsigned char **op2, size_t *len2, void *hist) { + unsigned char *t2 = op1 ? *op1 : NULL; + unsigned char *orig_t2 = t2; + size_t t3 = len1 ? *len1 : 0; + z_const unsigned char *t4 = op2 ? *op2 : NULL; + size_t t5 = len2 ? *len2 : 0; + Z_REGISTER int r0 __asm__("r0"); + Z_REGISTER void *r1 __asm__("r1"); + Z_REGISTER unsigned char *r2 __asm__("r2"); + Z_REGISTER size_t r3 __asm__("r3"); + Z_REGISTER z_const unsigned char *r4 __asm__("r4"); + Z_REGISTER size_t r5 __asm__("r5"); + int cc; + + /* Insert pre-instrumentation for DFLTCC. */ + switch (fn & DFLTCC_FN_MASK) { + case DFLTCC_QAF: + instrument_write(param, DFLTCC_SIZEOF_QAF); + break; + case DFLTCC_GDHT: + instrument_read_write(param, DFLTCC_SIZEOF_GDHT_V0); + instrument_read(t4, t5); + break; + case DFLTCC_CMPR: + case DFLTCC_XPND: + instrument_read_write(param, DFLTCC_SIZEOF_CMPR_XPND_V0); + instrument_read(t4, t5); + instrument_write(t2, t3); + instrument_read_write_hist(param, hist); + break; + } + + r0 = fn; r1 = param; r2 = t2; r3 = t3; r4 = t4; r5 = t5; + __asm__ volatile( +#ifdef HAVE_SYS_SDT_H + STAP_PROBE_ASM(zlib, dfltcc_entry, STAP_PROBE_ASM_TEMPLATE(5)) +#endif + ".insn rrf,0xb9390000,%[r2],%[r4],%[hist],0\n" +#ifdef HAVE_SYS_SDT_H + STAP_PROBE_ASM(zlib, dfltcc_exit, STAP_PROBE_ASM_TEMPLATE(5)) +#endif + "ipm %[cc]\n" + : [r2] "+r" (r2) + , [r3] "+r" (r3) + , [r4] "+r" (r4) + , [r5] "+r" (r5) + , [cc] "=r" (cc) + : [r0] "r" (r0) + , [r1] "r" (r1) + , [hist] "r" (hist) +#ifdef HAVE_SYS_SDT_H + , STAP_PROBE_ASM_OPERANDS(5, r2, r3, r4, r5, hist) +#endif + : "cc", "memory"); + t2 = r2; t3 = r3; t4 = r4; t5 = r5; + + /* Insert post-instrumentation for DFLTCC. */ + switch (fn & DFLTCC_FN_MASK) { + case DFLTCC_QAF: + __msan_unpoison(param, DFLTCC_SIZEOF_QAF); + break; + case DFLTCC_GDHT: + __msan_unpoison(param, DFLTCC_SIZEOF_GDHT_V0); + break; + case DFLTCC_CMPR: + __msan_unpoison(param, DFLTCC_SIZEOF_CMPR_XPND_V0); + __msan_unpoison(orig_t2, t2 - orig_t2 + (((struct dfltcc_param_v0 *)param)->sbb == 0 ? 0 : 1)); + msan_unpoison_hist(param, hist); + break; + case DFLTCC_XPND: + __msan_unpoison(param, DFLTCC_SIZEOF_CMPR_XPND_V0); + __msan_unpoison(orig_t2, t2 - orig_t2); + msan_unpoison_hist(param, hist); + break; + } + + if (op1) + *op1 = t2; + if (len1) + *len1 = t3; + if (op2) + *op2 = t4; + if (len2) + *len2 = t5; + return (cc >> 28) & 3; +} + +#define ALIGN_UP(p, size) (__typeof__(p))(((uintptr_t)(p) + ((size) - 1)) & ~((size) - 1)) + +static inline void dfltcc_reset_state(struct dfltcc_state *dfltcc_state) { + /* Initialize available functions */ + if (is_dfltcc_enabled()) { + dfltcc(DFLTCC_QAF, &dfltcc_state->param, NULL, NULL, NULL, NULL, NULL); + memmove(&dfltcc_state->af, &dfltcc_state->param, sizeof(dfltcc_state->af)); + } else + memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af)); + + /* Initialize parameter block */ + memset(&dfltcc_state->param, 0, sizeof(dfltcc_state->param)); + dfltcc_state->param.nt = 1; + dfltcc_state->param.ribm = DFLTCC_RIBM; +} + +static inline void dfltcc_copy_state(void *dst, const void *src, uInt size, uInt extension_size) { + memcpy(dst, src, ALIGN_UP(size, 8) + extension_size); +} + +static inline void append_history(struct dfltcc_param_v0 *param, unsigned char *history, + const unsigned char *buf, uInt count) { + size_t offset; + size_t n; + + /* Do not use more than 32K */ + if (count > HB_SIZE) { + buf += count - HB_SIZE; + count = HB_SIZE; + } + offset = (param->ho + param->hl) % HB_SIZE; + if (offset + count <= HB_SIZE) + /* Circular history buffer does not wrap - copy one chunk */ + memcpy(history + offset, buf, count); + else { + /* Circular history buffer wraps - copy two chunks */ + n = HB_SIZE - offset; + memcpy(history + offset, buf, n); + memcpy(history, buf + n, count - n); + } + n = param->hl + count; + if (n <= HB_SIZE) + /* All history fits into buffer - no need to discard anything */ + param->hl = n; + else { + /* History does not fit into buffer - discard extra bytes */ + param->ho = (param->ho + (n - HB_SIZE)) % HB_SIZE; + param->hl = HB_SIZE; + } +} + +static inline void get_history(struct dfltcc_param_v0 *param, const unsigned char *history, + unsigned char *buf) { + size_t hl_high, hl_low; + + get_history_lengths(param, &hl_high, &hl_low); + memcpy(buf, history + param->ho, hl_high); + memcpy(buf + hl_high, history, hl_low); +} diff --git a/arch/s390/dfltcc_inflate.c b/arch/s390/dfltcc_inflate.c new file mode 100644 index 0000000000..cc3cb39781 --- /dev/null +++ b/arch/s390/dfltcc_inflate.c @@ -0,0 +1,191 @@ +/* dfltcc_inflate.c - IBM Z DEFLATE CONVERSION CALL decompression support. */ + +/* + Use the following commands to build zlib-ng with DFLTCC decompression support: + + $ ./configure --with-dfltcc-inflate + or + + $ cmake -DWITH_DFLTCC_INFLATE=1 . + + and then + + $ make +*/ + +#include "zbuild.h" +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "dfltcc_inflate.h" +#include "dfltcc_detail.h" + +void Z_INTERNAL PREFIX(dfltcc_reset_inflate_state)(PREFIX3(streamp) strm) { + struct inflate_state *state = (struct inflate_state *)strm->state; + + dfltcc_reset_state(&state->arch.common); +} + +int Z_INTERNAL PREFIX(dfltcc_can_inflate)(PREFIX3(streamp) strm) { + struct inflate_state *state = (struct inflate_state *)strm->state; + struct dfltcc_state *dfltcc_state = &state->arch.common; + + /* Unsupported hardware */ + return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) && is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0); +} + +static inline dfltcc_cc dfltcc_xpnd(PREFIX3(streamp) strm) { + struct inflate_state *state = (struct inflate_state *)strm->state; + struct dfltcc_param_v0 *param = &state->arch.common.param; + size_t avail_in = strm->avail_in; + size_t avail_out = strm->avail_out; + dfltcc_cc cc; + + cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR, + param, &strm->next_out, &avail_out, + &strm->next_in, &avail_in, state->window); + strm->avail_in = avail_in; + strm->avail_out = avail_out; + return cc; +} + +dfltcc_inflate_action Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, int flush, int *ret) { + struct inflate_state *state = (struct inflate_state *)strm->state; + struct dfltcc_state *dfltcc_state = &state->arch.common; + struct dfltcc_param_v0 *param = &dfltcc_state->param; + dfltcc_cc cc; + + if (flush == Z_BLOCK || flush == Z_TREES) { + /* DFLTCC does not support stopping on block boundaries */ + if (PREFIX(dfltcc_inflate_disable)(strm)) { + *ret = Z_STREAM_ERROR; + return DFLTCC_INFLATE_BREAK; + } else + return DFLTCC_INFLATE_SOFTWARE; + } + + if (state->last) { + if (state->bits != 0) { + strm->next_in++; + strm->avail_in--; + state->bits = 0; + } + state->mode = CHECK; + return DFLTCC_INFLATE_CONTINUE; + } + + if (strm->avail_in == 0 && !param->cf) + return DFLTCC_INFLATE_BREAK; + + /* if window not in use yet, initialize */ + if (state->wsize == 0) + state->wsize = 1U << state->wbits; + + /* Translate stream to parameter block */ + param->cvt = ((state->wrap & 4) && state->flags) ? CVT_CRC32 : CVT_ADLER32; + param->sbb = state->bits; + if (param->hl) + param->nt = 0; /* Honor history for the first block */ + if (state->wrap & 4) + param->cv = state->flags ? ZSWAP32(state->check) : state->check; + + /* Inflate */ + do { + cc = dfltcc_xpnd(strm); + } while (cc == DFLTCC_CC_AGAIN); + + /* Translate parameter block to stream */ + strm->msg = oesc_msg(dfltcc_state->msg, param->oesc); + state->last = cc == DFLTCC_CC_OK; + state->bits = param->sbb; + if (state->wrap & 4) + strm->adler = state->check = state->flags ? ZSWAP32(param->cv) : param->cv; + if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) { + /* Report an error if stream is corrupted */ + state->mode = BAD; + return DFLTCC_INFLATE_CONTINUE; + } + state->mode = TYPEDO; + /* Break if operands are exhausted, otherwise continue looping */ + return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ? + DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE; +} + +int Z_INTERNAL PREFIX(dfltcc_was_inflate_used)(PREFIX3(streamp) strm) { + struct inflate_state *state = (struct inflate_state *)strm->state; + + return !state->arch.common.param.nt; +} + +/* + Rotates a circular buffer. + The implementation is based on https://cplusplus.com/reference/algorithm/rotate/ + */ +static void rotate(unsigned char *start, unsigned char *pivot, unsigned char *end) { + unsigned char *p = pivot; + unsigned char tmp; + + while (p != start) { + tmp = *start; + *start = *p; + *p = tmp; + + start++; + p++; + + if (p == end) + p = pivot; + else if (start == pivot) + pivot = p; + } +} + +int Z_INTERNAL PREFIX(dfltcc_inflate_disable)(PREFIX3(streamp) strm) { + struct inflate_state *state = (struct inflate_state *)strm->state; + struct dfltcc_state *dfltcc_state = &state->arch.common; + struct dfltcc_param_v0 *param = &dfltcc_state->param; + + if (!PREFIX(dfltcc_can_inflate)(strm)) + return 0; + if (PREFIX(dfltcc_was_inflate_used)(strm)) + /* DFLTCC has already decompressed some data. Since there is not + * enough information to resume decompression in software, the call + * must fail. + */ + return 1; + /* DFLTCC was not used yet - decompress in software */ + memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af)); + /* Convert the window from the hardware to the software format */ + rotate(state->window, state->window + param->ho, state->window + HB_SIZE); + state->whave = state->wnext = MIN(param->hl, state->wsize); + return 0; +} + +/* + Preloading history. +*/ +int Z_INTERNAL PREFIX(dfltcc_inflate_set_dictionary)(PREFIX3(streamp) strm, + const unsigned char *dictionary, uInt dict_length) { + struct inflate_state *state = (struct inflate_state *)strm->state; + struct dfltcc_param_v0 *param = &state->arch.common.param; + + /* if window not in use yet, initialize */ + if (state->wsize == 0) + state->wsize = 1U << state->wbits; + + append_history(param, state->window, dictionary, dict_length); + state->havedict = 1; + return Z_OK; +} + +int Z_INTERNAL PREFIX(dfltcc_inflate_get_dictionary)(PREFIX3(streamp) strm, + unsigned char *dictionary, uInt *dict_length) { + struct inflate_state *state = (struct inflate_state *)strm->state; + struct dfltcc_param_v0 *param = &state->arch.common.param; + + if (dictionary && state->window) + get_history(param, state->window, dictionary); + if (dict_length) + *dict_length = param->hl; + return Z_OK; +} diff --git a/arch/s390/dfltcc_inflate.h b/arch/s390/dfltcc_inflate.h new file mode 100644 index 0000000000..3623f8ed7f --- /dev/null +++ b/arch/s390/dfltcc_inflate.h @@ -0,0 +1,67 @@ +#ifndef DFLTCC_INFLATE_H +#define DFLTCC_INFLATE_H + +#include "dfltcc_common.h" + +void Z_INTERNAL PREFIX(dfltcc_reset_inflate_state)(PREFIX3(streamp) strm); +int Z_INTERNAL PREFIX(dfltcc_can_inflate)(PREFIX3(streamp) strm); +typedef enum { + DFLTCC_INFLATE_CONTINUE, + DFLTCC_INFLATE_BREAK, + DFLTCC_INFLATE_SOFTWARE, +} dfltcc_inflate_action; +dfltcc_inflate_action Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, int flush, int *ret); +int Z_INTERNAL PREFIX(dfltcc_was_inflate_used)(PREFIX3(streamp) strm); +int Z_INTERNAL PREFIX(dfltcc_inflate_disable)(PREFIX3(streamp) strm); +int Z_INTERNAL PREFIX(dfltcc_inflate_set_dictionary)(PREFIX3(streamp) strm, + const unsigned char *dictionary, uInt dict_length); +int Z_INTERNAL PREFIX(dfltcc_inflate_get_dictionary)(PREFIX3(streamp) strm, + unsigned char *dictionary, uInt* dict_length); + +#define INFLATE_RESET_KEEP_HOOK PREFIX(dfltcc_reset_inflate_state) + +#define INFLATE_PRIME_HOOK(strm, bits, value) \ + do { if (PREFIX(dfltcc_inflate_disable)((strm))) return Z_STREAM_ERROR; } while (0) + +#define INFLATE_TYPEDO_HOOK(strm, flush) \ + if (PREFIX(dfltcc_can_inflate)((strm))) { \ + dfltcc_inflate_action action; \ +\ + RESTORE(); \ + action = PREFIX(dfltcc_inflate)((strm), (flush), &ret); \ + LOAD(); \ + if (action == DFLTCC_INFLATE_CONTINUE) \ + break; \ + else if (action == DFLTCC_INFLATE_BREAK) \ + goto inf_leave; \ + } + +#define INFLATE_NEED_CHECKSUM(strm) (!PREFIX(dfltcc_can_inflate)((strm))) + +#define INFLATE_NEED_UPDATEWINDOW(strm) (!PREFIX(dfltcc_can_inflate)((strm))) + +#define INFLATE_MARK_HOOK(strm) \ + do { \ + if (PREFIX(dfltcc_was_inflate_used)((strm))) return -(1L << 16); \ + } while (0) + +#define INFLATE_SYNC_POINT_HOOK(strm) \ + do { \ + if (PREFIX(dfltcc_was_inflate_used)((strm))) return Z_STREAM_ERROR; \ + } while (0) + +#define INFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) \ + do { \ + if (PREFIX(dfltcc_can_inflate)((strm))) \ + return PREFIX(dfltcc_inflate_set_dictionary)((strm), (dict), (dict_len)); \ + } while (0) + +#define INFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) \ + do { \ + if (PREFIX(dfltcc_can_inflate)((strm))) \ + return PREFIX(dfltcc_inflate_get_dictionary)((strm), (dict), (dict_len)); \ + } while (0) + +#define INFLATE_ADJUST_WINDOW_SIZE(n) MAX(n, HB_SIZE) + +#endif diff --git a/arch/s390/s390_features.c b/arch/s390/s390_features.c new file mode 100644 index 0000000000..1f90a926c0 --- /dev/null +++ b/arch/s390/s390_features.c @@ -0,0 +1,14 @@ +#include "zbuild.h" +#include "s390_features.h" + +#ifdef HAVE_SYS_AUXV_H +# include +#endif + +#ifndef HWCAP_S390_VXRS +#define HWCAP_S390_VXRS (1 << 11) +#endif + +void Z_INTERNAL s390_check_features(struct s390_cpu_features *features) { + features->has_vx = getauxval(AT_HWCAP) & HWCAP_S390_VXRS; +} diff --git a/arch/s390/s390_features.h b/arch/s390/s390_features.h new file mode 100644 index 0000000000..fb2ac14b26 --- /dev/null +++ b/arch/s390/s390_features.h @@ -0,0 +1,14 @@ +/* s390_features.h -- check for s390 features. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef S390_FEATURES_H_ +#define S390_FEATURES_H_ + +struct s390_cpu_features { + int has_vx; +}; + +void Z_INTERNAL s390_check_features(struct s390_cpu_features *features); + +#endif diff --git a/arch/s390/s390_functions.h b/arch/s390/s390_functions.h new file mode 100644 index 0000000000..e6855cd701 --- /dev/null +++ b/arch/s390/s390_functions.h @@ -0,0 +1,27 @@ +/* s390_functions.h -- s390 implementations for arch-specific functions. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef S390_FUNCTIONS_H_ +#define S390_FUNCTIONS_H_ + +#ifdef S390_CRC32_VX +uint32_t crc32_s390_vx(uint32_t crc, const uint8_t *buf, size_t len); + +#ifdef __clang__ +# if ((__clang_major__ == 18) || (__clang_major__ == 19 && (__clang_minor__ < 1 || (__clang_minor__ == 1 && __clang_patchlevel__ < 2)))) +# error CRC32-VX optimizations are broken due to compiler bug in Clang versions: 18.0.0 <= clang_version < 19.1.2. \ + Either disable the zlib-ng CRC32-VX optimization, or switch to another compiler/compiler version. +# endif +#endif + +#endif + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +# if defined(S390_CRC32_VX) && defined(__zarch__) && __ARCH__ >= 11 && defined(__VX__) +# undef native_crc32 +# define native_crc32 = crc32_s390_vx +# endif +#endif + +#endif diff --git a/arch/s390/self-hosted-builder/actions-runner b/arch/s390/self-hosted-builder/actions-runner new file mode 100644 index 0000000000..8d194bac3f --- /dev/null +++ b/arch/s390/self-hosted-builder/actions-runner @@ -0,0 +1,59 @@ +#!/bin/bash + +# +# Ephemeral runner startup script. +# +# Expects the following environment variables: +# +# - REPO= +# - PAT_TOKEN= +# + +set -e -u + +# Validate required environment variables +if [ -z "${REPO:-}" ] || [ -z "${PAT_TOKEN:-}" ]; then + echo "Error: REPO and/or PAT_TOKEN environment variables not found" + exit 1 +fi + +# Check the cached registration token. +TOKEN_FILE=registration-token.json +if [ -f $TOKEN_FILE ]; then + set +e + EXPIRES=$(jq --raw-output .EXPIRES "$TOKEN_FILE" 2>/dev/null) + STATUS=$? + set -e +else + STATUS=1 +fi +if [[ $STATUS -ne 0 || $(date +%s) -ge $(date -d "$EXPIRES" +%s) ]]; then + # Refresh the cached registration token. + curl \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $PAT_TOKEN" \ + "https://api.github.com/repos/$REPO/actions/runners/registration-token" \ + -o "$TOKEN_FILE" +fi + +REG_TOKEN=$(jq --raw-output .token "$TOKEN_FILE") +if [ $REG_TOKEN = "null" ]; then + echo "Failed to get registration token" + exit 1 +fi + +# (Re-)register the runner. +./config.sh remove --token "$REG_TOKEN" || true +set -x +./config.sh \ + --url "https://github.com/$REPO" \ + --token "$REG_TOKEN" \ + --unattended \ + --disableupdate \ + --replace \ + --labels z15 \ + --ephemeral + +# Run one job. +./run.sh diff --git a/arch/s390/self-hosted-builder/actions-runner-rebuild.sh b/arch/s390/self-hosted-builder/actions-runner-rebuild.sh new file mode 100644 index 0000000000..703448fca0 --- /dev/null +++ b/arch/s390/self-hosted-builder/actions-runner-rebuild.sh @@ -0,0 +1,54 @@ +#!/usr/bin/bash +set -ex + +TMPDIR="$(mktemp -d)" + +if [ -f actions-runner.Dockerfile ]; then + MODE=1 + cp actions-runner.Dockerfile actions-runner entrypoint $TMPDIR + cd $TMPDIR +else + MODE=2 + cd $TMPDIR + wget https://raw.githubusercontent.com/zlib-ng/zlib-ng/refs/heads/develop/arch/s390/self-hosted-builder/actions-runner.Dockerfile + wget https://raw.githubusercontent.com/zlib-ng/zlib-ng/refs/heads/develop/arch/s390/self-hosted-builder/actions-runner + wget https://raw.githubusercontent.com/zlib-ng/zlib-ng/refs/heads/develop/arch/s390/self-hosted-builder/entrypoint +fi + +# Copy rpms needed to workaround VX compiler bug, ref #1852 +mkdir clang +cp /clang-19/*.rpm clang/ + +# Stop service +systemctl stop actions-runner || true + +# Delete old container +podman container rm gaplib-actions-runner || true + +# Delete old image +podman image rm localhost/zlib-ng/actions-runner || true + +# Build new image +podman build --squash -f actions-runner.Dockerfile --tag zlib-ng/actions-runner . 2>&1 | tee /var/log/actions-runner-build.log + +# Create new container +podman create --replace --name=gaplib-actions-runner --env-file=/etc/actions-runner --init \ + --volume=actions-runner-temp:/home/actions-runner zlib-ng/actions-runner 2>&1 | tee -a /var/log/actions-runner-build.log + +# Start service +systemctl start actions-runner || true + +# Cleanup +podman image prune -af || true + +# Clean up tempfile +if [ "$MODE" == "2" ] ; then + cd $TMPDIR + rm actions-runner.Dockerfile + rm actions-runner + rm entrypoint + rm -rf clang + cd .. + rmdir $TMPDIR + echo "Deleted tempfiles." +fi diff --git a/arch/s390/self-hosted-builder/actions-runner.Dockerfile b/arch/s390/self-hosted-builder/actions-runner.Dockerfile new file mode 100644 index 0000000000..f43ab85f03 --- /dev/null +++ b/arch/s390/self-hosted-builder/actions-runner.Dockerfile @@ -0,0 +1,54 @@ +# Self-Hosted IBM Z Github Actions Runner. + +FROM almalinux:9 + +RUN dnf update -y -q && \ + dnf install -y -q --enablerepo=crb wget git which sudo jq sed \ + cmake make automake autoconf m4 libtool ninja-build python3-pip \ + gcc gcc-c++ clang llvm-toolset glibc-all-langpacks langpacks-en \ + glibc-static libstdc++-static libstdc++-devel libxslt-devel libxml2-devel + +RUN dnf install -y -q dotnet-sdk-8.0 && \ + echo "Using SDK - `dotnet --version`" + +RUN cd /tmp && \ + git clone -q https://github.com/actions/runner && \ + cd runner && \ + git checkout $(git describe --tags $(git rev-list --tags --max-count=1)) -b build && \ + wget https://github.com/anup-kodlekere/gaplib/raw/refs/heads/main/build-files/runner-sdk-8.patch && \ + git apply runner-sdk-8.patch && \ + sed -i'' -e /version/s/8......\"$/$8.0.100\"/ src/global.json + +RUN cd /tmp/runner/src && \ + ./dev.sh layout && \ + ./dev.sh package && \ + rm -rf /root/.dotnet /root/.nuget + +RUN useradd -c "Action Runner" -m actions-runner && \ + usermod -L actions-runner + +RUN tar -xf /tmp/runner/_package/*.tar.gz -C /home/actions-runner && \ + chown -R actions-runner:actions-runner /home/actions-runner + +#VOLUME /home/actions-runner + +# Workaround: Install custom clang version to avoid compiler bug, ref #1852 +RUN mkdir /tmp/clang + +COPY clang/*.rpm /tmp/clang + +RUN dnf -y upgrade /tmp/clang/*.rpm && \ + rm -rf /tmp/clang + +# Cleanup +RUN rm -rf /tmp/runner /var/cache/dnf/* /tmp/runner.patch /tmp/global.json && \ + dnf clean all + +USER actions-runner + +# Scripts. +COPY --chmod=555 entrypoint /usr/bin/ +COPY --chmod=555 actions-runner /usr/bin/ +WORKDIR /home/actions-runner +ENTRYPOINT ["/usr/bin/entrypoint"] +CMD ["/usr/bin/actions-runner"] diff --git a/arch/s390/self-hosted-builder/actions-runner.service b/arch/s390/self-hosted-builder/actions-runner.service new file mode 100644 index 0000000000..79560cde18 --- /dev/null +++ b/arch/s390/self-hosted-builder/actions-runner.service @@ -0,0 +1,18 @@ +[Unit] +Description=Podman container: Gaplib Github Actions Runner +Wants=network-online.target +After=network-online.target +StartLimitIntervalSec=1 +RequiresMountsFor=/run/user/1001/containers + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=always +TimeoutStopSec=61 +ExecStart=/usr/bin/podman start gaplib-actions-runner +ExecStop=/usr/bin/podman stop -t 30 gaplib-actions-runner +ExecStopPost=/usr/bin/podman stop -t 10 gaplib-actions-runner +Type=forking + +[Install] +WantedBy=default.target diff --git a/arch/s390/self-hosted-builder/entrypoint b/arch/s390/self-hosted-builder/entrypoint new file mode 100644 index 0000000000..eb8772becf --- /dev/null +++ b/arch/s390/self-hosted-builder/entrypoint @@ -0,0 +1,30 @@ +#!/bin/bash + +# +# Container entrypoint that waits for all spawned processes. +# + +set -e -u + +# Create a FIFO and start reading from its read end. +tempdir=$(mktemp -d "/tmp/done.XXXXXXXXXX") +trap 'rm -r "$tempdir"' EXIT +done="$tempdir/pipe" +mkfifo "$done" +cat "$done" & waiter=$! + +# Start the workload. Its descendants will inherit the FIFO's write end. +status=0 +if [ "$#" -eq 0 ]; then + bash 9>"$done" || status=$? +else + "$@" 9>"$done" || status=$? +fi + +# When the workload and all of its descendants exit, the FIFO's write end will +# be closed and `cat "$done"` will exit. Wait until it happens. This is needed +# in order to handle SelfUpdater, which the workload may start in background +# before exiting. +wait "$waiter" + +exit "$status" diff --git a/arch/x86/Makefile.in b/arch/x86/Makefile.in new file mode 100644 index 0000000000..a797517df3 --- /dev/null +++ b/arch/x86/Makefile.in @@ -0,0 +1,147 @@ +# Makefile for zlib +# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler +# For conditions of distribution and use, see copyright notice in zlib.h + +CC= +CFLAGS= +SFLAGS= +INCLUDES= +SUFFIX= + +AVX512FLAG=-mavx512f -mavx512dq -mavx512vl -mavx512bw -mbmi2 +AVX512VNNIFLAG=-mavx512vnni -mbmi2 +AVX2FLAG=-mavx2 -mbmi2 +SSE2FLAG=-msse2 +SSSE3FLAG=-mssse3 +SSE42FLAG=-msse4.2 +PCLMULFLAG=-mpclmul +VPCLMULFLAG=-mvpclmulqdq +XSAVEFLAG=-mxsave +NOLTOFLAG= + +SRCDIR=. +SRCTOP=../.. +TOPDIR=$(SRCTOP) + +all: \ + x86_features.o x86_features.lo \ + adler32_avx2.o adler32_avx2.lo \ + adler32_avx512.o adler32_avx512.lo \ + adler32_avx512_vnni.o adler32_avx512_vnni.lo \ + adler32_sse42.o adler32_sse42.lo \ + adler32_ssse3.o adler32_ssse3.lo \ + chunkset_avx2.o chunkset_avx2.lo \ + chunkset_avx512.o chunkset_avx512.lo \ + chunkset_sse2.o chunkset_sse2.lo \ + chunkset_ssse3.o chunkset_ssse3.lo \ + compare256_avx2.o compare256_avx2.lo \ + compare256_sse2.o compare256_sse2.lo \ + crc32_pclmulqdq.o crc32_pclmulqdq.lo \ + crc32_vpclmulqdq.o crc32_vpclmulqdq.lo \ + slide_hash_avx2.o slide_hash_avx2.lo \ + slide_hash_sse2.o slide_hash_sse2.lo + +x86_features.o: + $(CC) $(CFLAGS) $(XSAVEFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/x86_features.c + +x86_features.lo: + $(CC) $(SFLAGS) $(XSAVEFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/x86_features.c + +chunkset_avx2.o: + $(CC) $(CFLAGS) $(AVX2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_avx2.c + +chunkset_avx2.lo: + $(CC) $(SFLAGS) $(AVX2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_avx2.c + +chunkset_avx512.o: + $(CC) $(CFLAGS) $(AVX512FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_avx512.c + +chunkset_avx512.lo: + $(CC) $(SFLAGS) $(AVX512FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_avx512.c + +chunkset_sse2.o: + $(CC) $(CFLAGS) $(SSE2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_sse2.c + +chunkset_sse2.lo: + $(CC) $(SFLAGS) $(SSE2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_sse2.c + +chunkset_ssse3.o: + $(CC) $(CFLAGS) $(SSSE3FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_ssse3.c + +chunkset_ssse3.lo: + $(CC) $(SFLAGS) $(SSSE3FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_ssse3.c + +compare256_avx2.o: + $(CC) $(CFLAGS) $(AVX2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_avx2.c + +compare256_avx2.lo: + $(CC) $(SFLAGS) $(AVX2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_avx2.c + +compare256_sse2.o: + $(CC) $(CFLAGS) $(SSE2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_sse2.c + +compare256_sse2.lo: + $(CC) $(SFLAGS) $(SSE2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_sse2.c + +crc32_pclmulqdq.o: + $(CC) $(CFLAGS) $(PCLMULFLAG) $(SSE42FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_pclmulqdq.c + +crc32_pclmulqdq.lo: + $(CC) $(SFLAGS) $(PCLMULFLAG) $(SSE42FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_pclmulqdq.c + +crc32_vpclmulqdq.o: + $(CC) $(CFLAGS) $(PCLMULFLAG) $(VPCLMULFLAG) $(AVX512FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_vpclmulqdq.c + +crc32_vpclmulqdq.lo: + $(CC) $(SFLAGS) $(PCLMULFLAG) $(VPCLMULFLAG) $(AVX512FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_vpclmulqdq.c + +slide_hash_avx2.o: + $(CC) $(CFLAGS) $(AVX2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_avx2.c + +slide_hash_avx2.lo: + $(CC) $(SFLAGS) $(AVX2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_avx2.c + +slide_hash_sse2.o: + $(CC) $(CFLAGS) $(SSE2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_sse2.c + +slide_hash_sse2.lo: + $(CC) $(SFLAGS) $(SSE2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_sse2.c + +adler32_avx2.o: $(SRCDIR)/adler32_avx2.c + $(CC) $(CFLAGS) $(AVX2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx2.c + +adler32_avx2.lo: $(SRCDIR)/adler32_avx2.c + $(CC) $(SFLAGS) $(AVX2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx2.c + +adler32_avx512.o: $(SRCDIR)/adler32_avx512.c + $(CC) $(CFLAGS) $(AVX512FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx512.c + +adler32_avx512.lo: $(SRCDIR)/adler32_avx512.c + $(CC) $(SFLAGS) $(AVX512FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx512.c + +adler32_avx512_vnni.o: $(SRCDIR)/adler32_avx512_vnni.c + $(CC) $(CFLAGS) $(AVX512VNNIFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx512_vnni.c + +adler32_avx512_vnni.lo: $(SRCDIR)/adler32_avx512_vnni.c + $(CC) $(SFLAGS) $(AVX512VNNIFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx512_vnni.c + +adler32_ssse3.o: $(SRCDIR)/adler32_ssse3.c + $(CC) $(CFLAGS) $(SSSE3FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_ssse3.c + +adler32_ssse3.lo: $(SRCDIR)/adler32_ssse3.c + $(CC) $(SFLAGS) $(SSSE3FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_ssse3.c + +adler32_sse42.o: $(SRCDIR)/adler32_sse42.c + $(CC) $(CFLAGS) $(SSE42FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_sse42.c + +adler32_sse42.lo: $(SRCDIR)/adler32_sse42.c + $(CC) $(SFLAGS) $(SSE42FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_sse42.c + +mostlyclean: clean +clean: + rm -f *.o *.lo *~ + rm -rf objs + rm -f *.gcda *.gcno *.gcov + +distclean: clean + rm -f Makefile diff --git a/arch/x86/adler32_avx2.c b/arch/x86/adler32_avx2.c new file mode 100644 index 0000000000..38e7f068e3 --- /dev/null +++ b/arch/x86/adler32_avx2.c @@ -0,0 +1,145 @@ +/* adler32_avx2.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011 Mark Adler + * Copyright (C) 2022 Adam Stylinski + * Authors: + * Brian Bockelman + * Adam Stylinski + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef X86_AVX2 + +#include "zbuild.h" +#include +#include "adler32_p.h" +#include "adler32_avx2_p.h" +#include "x86_intrins.h" + +extern uint32_t adler32_fold_copy_sse42(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); +extern uint32_t adler32_ssse3(uint32_t adler, const uint8_t *src, size_t len); + +static inline uint32_t adler32_fold_copy_impl(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len, const int COPY) { + if (src == NULL) return 1L; + if (len == 0) return adler; + + uint32_t adler0, adler1; + adler1 = (adler >> 16) & 0xffff; + adler0 = adler & 0xffff; + +rem_peel: + if (len < 16) { + if (COPY) { + return adler32_copy_len_16(adler0, src, dst, len, adler1); + } else { + return adler32_len_16(adler0, src, len, adler1); + } + } else if (len < 32) { + if (COPY) { + return adler32_fold_copy_sse42(adler, dst, src, len); + } else { + return adler32_ssse3(adler, src, len); + } + } + + __m256i vs1, vs2; + + const __m256i dot2v = _mm256_setr_epi8(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, + 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + const __m256i dot3v = _mm256_set1_epi16(1); + const __m256i zero = _mm256_setzero_si256(); + + while (len >= 32) { + vs1 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler0)); + vs2 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler1)); + __m256i vs1_0 = vs1; + __m256i vs3 = _mm256_setzero_si256(); + + size_t k = MIN(len, NMAX); + k -= k % 32; + len -= k; + + while (k >= 32) { + /* + vs1 = adler + sum(c[i]) + vs2 = sum2 + 32 vs1 + sum( (32-i+1) c[i] ) + */ + __m256i vbuf = _mm256_loadu_si256((__m256i*)src); + src += 32; + k -= 32; + + __m256i vs1_sad = _mm256_sad_epu8(vbuf, zero); // Sum of abs diff, resulting in 2 x int32's + + if (COPY) { + _mm256_storeu_si256((__m256i*)dst, vbuf); + dst += 32; + } + + vs1 = _mm256_add_epi32(vs1, vs1_sad); + vs3 = _mm256_add_epi32(vs3, vs1_0); + __m256i v_short_sum2 = _mm256_maddubs_epi16(vbuf, dot2v); // sum 32 uint8s to 16 shorts + __m256i vsum2 = _mm256_madd_epi16(v_short_sum2, dot3v); // sum 16 shorts to 8 uint32s + vs2 = _mm256_add_epi32(vsum2, vs2); + vs1_0 = vs1; + } + + /* Defer the multiplication with 32 to outside of the loop */ + vs3 = _mm256_slli_epi32(vs3, 5); + vs2 = _mm256_add_epi32(vs2, vs3); + + /* The compiler is generating the following sequence for this integer modulus + * when done the scalar way, in GPRs: + + adler = (s1_unpack[0] % BASE) + (s1_unpack[1] % BASE) + (s1_unpack[2] % BASE) + (s1_unpack[3] % BASE) + + (s1_unpack[4] % BASE) + (s1_unpack[5] % BASE) + (s1_unpack[6] % BASE) + (s1_unpack[7] % BASE); + + mov $0x80078071,%edi // move magic constant into 32 bit register %edi + ... + vmovd %xmm1,%esi // move vector lane 0 to 32 bit register %esi + mov %rsi,%rax // zero-extend this value to 64 bit precision in %rax + imul %rdi,%rsi // do a signed multiplication with magic constant and vector element + shr $0x2f,%rsi // shift right by 47 + imul $0xfff1,%esi,%esi // do a signed multiplication with value truncated to 32 bits with 0xfff1 + sub %esi,%eax // subtract lower 32 bits of original vector value from modified one above + ... + // repeats for each element with vpextract instructions + + This is tricky with AVX2 for a number of reasons: + 1.) There's no 64 bit multiplication instruction, but there is a sequence to get there + 2.) There's ways to extend vectors to 64 bit precision, but no simple way to truncate + back down to 32 bit precision later (there is in AVX512) + 3.) Full width integer multiplications aren't cheap + + We can, however, do a relatively cheap sequence for horizontal sums. + Then, we simply do the integer modulus on the resulting 64 bit GPR, on a scalar value. It was + previously thought that casting to 64 bit precision was needed prior to the horizontal sum, but + that is simply not the case, as NMAX is defined as the maximum number of scalar sums that can be + performed on the maximum possible inputs before overflow + */ + + + /* In AVX2-land, this trip through GPRs will probably be unavoidable, as there's no cheap and easy + * conversion from 64 bit integer to 32 bit (needed for the inexpensive modulus with a constant). + * This casting to 32 bit is cheap through GPRs (just register aliasing). See above for exactly + * what the compiler is doing to avoid integer divisions. */ + adler0 = partial_hsum256(vs1) % BASE; + adler1 = hsum256(vs2) % BASE; + } + + adler = adler0 | (adler1 << 16); + + if (len) { + goto rem_peel; + } + + return adler; +} + +Z_INTERNAL uint32_t adler32_avx2(uint32_t adler, const uint8_t *src, size_t len) { + return adler32_fold_copy_impl(adler, NULL, src, len, 0); +} + +Z_INTERNAL uint32_t adler32_fold_copy_avx2(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { + return adler32_fold_copy_impl(adler, dst, src, len, 1); +} + +#endif diff --git a/arch/x86/adler32_avx2_p.h b/arch/x86/adler32_avx2_p.h new file mode 100644 index 0000000000..f0f8a4a887 --- /dev/null +++ b/arch/x86/adler32_avx2_p.h @@ -0,0 +1,32 @@ +/* adler32_avx2_p.h -- adler32 avx2 utility functions + * Copyright (C) 2022 Adam Stylinski + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef ADLER32_AVX2_P_H_ +#define ADLER32_AVX2_P_H_ + +#if defined(X86_AVX2) || defined(X86_AVX512VNNI) + +/* 32 bit horizontal sum, adapted from Agner Fog's vector library. */ +static inline uint32_t hsum256(__m256i x) { + __m128i sum1 = _mm_add_epi32(_mm256_extracti128_si256(x, 1), + _mm256_castsi256_si128(x)); + __m128i sum2 = _mm_add_epi32(sum1, _mm_unpackhi_epi64(sum1, sum1)); + __m128i sum3 = _mm_add_epi32(sum2, _mm_shuffle_epi32(sum2, 1)); + return (uint32_t)_mm_cvtsi128_si32(sum3); +} + +static inline uint32_t partial_hsum256(__m256i x) { + /* We need a permutation vector to extract every other integer. The + * rest are going to be zeros */ + const __m256i perm_vec = _mm256_setr_epi32(0, 2, 4, 6, 1, 1, 1, 1); + __m256i non_zero = _mm256_permutevar8x32_epi32(x, perm_vec); + __m128i non_zero_sse = _mm256_castsi256_si128(non_zero); + __m128i sum2 = _mm_add_epi32(non_zero_sse,_mm_unpackhi_epi64(non_zero_sse, non_zero_sse)); + __m128i sum3 = _mm_add_epi32(sum2, _mm_shuffle_epi32(sum2, 1)); + return (uint32_t)_mm_cvtsi128_si32(sum3); +} +#endif + +#endif diff --git a/arch/x86/adler32_avx512.c b/arch/x86/adler32_avx512.c new file mode 100644 index 0000000000..626c4807f8 --- /dev/null +++ b/arch/x86/adler32_avx512.c @@ -0,0 +1,108 @@ +/* adler32_avx512.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011 Mark Adler + * Authors: + * Adam Stylinski + * Brian Bockelman + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef X86_AVX512 + +#include "zbuild.h" +#include "adler32_p.h" +#include "arch_functions.h" +#include +#include "x86_intrins.h" +#include "adler32_avx512_p.h" + +static inline uint32_t adler32_fold_copy_impl(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len, const int COPY) { + if (src == NULL) return 1L; + if (len == 0) return adler; + + uint32_t adler0, adler1; + adler1 = (adler >> 16) & 0xffff; + adler0 = adler & 0xffff; + +rem_peel: + if (len < 64) { + /* This handles the remaining copies, just call normal adler checksum after this */ + if (COPY) { + __mmask64 storemask = (0xFFFFFFFFFFFFFFFFUL >> (64 - len)); + __m512i copy_vec = _mm512_maskz_loadu_epi8(storemask, src); + _mm512_mask_storeu_epi8(dst, storemask, copy_vec); + } + + return adler32_avx2(adler, src, len); + } + + __m512i vbuf, vs1_0, vs3; + + const __m512i dot2v = _mm512_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64); + const __m512i dot3v = _mm512_set1_epi16(1); + const __m512i zero = _mm512_setzero_si512(); + size_t k; + + while (len >= 64) { + __m512i vs1 = _mm512_zextsi128_si512(_mm_cvtsi32_si128(adler0)); + __m512i vs2 = _mm512_zextsi128_si512(_mm_cvtsi32_si128(adler1)); + vs1_0 = vs1; + vs3 = _mm512_setzero_si512(); + + k = MIN(len, NMAX); + k -= k % 64; + len -= k; + + while (k >= 64) { + /* + vs1 = adler + sum(c[i]) + vs2 = sum2 + 64 vs1 + sum( (64-i+1) c[i] ) + */ + vbuf = _mm512_loadu_si512(src); + + if (COPY) { + _mm512_storeu_si512(dst, vbuf); + dst += 64; + } + + src += 64; + k -= 64; + + __m512i vs1_sad = _mm512_sad_epu8(vbuf, zero); + __m512i v_short_sum2 = _mm512_maddubs_epi16(vbuf, dot2v); + vs1 = _mm512_add_epi32(vs1_sad, vs1); + vs3 = _mm512_add_epi32(vs3, vs1_0); + __m512i vsum2 = _mm512_madd_epi16(v_short_sum2, dot3v); + vs2 = _mm512_add_epi32(vsum2, vs2); + vs1_0 = vs1; + } + + vs3 = _mm512_slli_epi32(vs3, 6); + vs2 = _mm512_add_epi32(vs2, vs3); + + adler0 = partial_hsum(vs1) % BASE; + adler1 = _mm512_reduce_add_epu32(vs2) % BASE; + } + + adler = adler0 | (adler1 << 16); + + /* Process tail (len < 64). */ + if (len) { + goto rem_peel; + } + + return adler; +} + +Z_INTERNAL uint32_t adler32_fold_copy_avx512(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { + return adler32_fold_copy_impl(adler, dst, src, len, 1); +} + +Z_INTERNAL uint32_t adler32_avx512(uint32_t adler, const uint8_t *src, size_t len) { + return adler32_fold_copy_impl(adler, NULL, src, len, 0); +} + +#endif + diff --git a/arch/x86/adler32_avx512_p.h b/arch/x86/adler32_avx512_p.h new file mode 100644 index 0000000000..742269053c --- /dev/null +++ b/arch/x86/adler32_avx512_p.h @@ -0,0 +1,57 @@ +#ifndef AVX512_FUNCS_H +#define AVX512_FUNCS_H + +#include +#include + +/* Written because Visual C++ toolchains before v142 have constant overflow in AVX512 intrinsic macros */ +#if defined(_MSC_VER) && !defined(_MM_K0_REG8) +# undef _mm512_extracti64x4_epi64 +# define _mm512_extracti64x4_epi64(v1, e1) _mm512_maskz_extracti64x4_epi64(UINT8_MAX, v1, e1) +# undef _mm512_set1_epi16 +# define _mm512_set1_epi16(e1) _mm512_maskz_set1_epi16(UINT32_MAX, e1) +# undef _mm512_maddubs_epi16 +# define _mm512_maddubs_epi16(v1, v2) _mm512_maskz_maddubs_epi16(UINT32_MAX, v1, v2) +#endif + +/* Written because *_add_epi32(a) sets off ubsan */ +static inline uint32_t _mm512_reduce_add_epu32(__m512i x) { + __m256i a = _mm512_extracti64x4_epi64(x, 1); + __m256i b = _mm512_extracti64x4_epi64(x, 0); + + __m256i a_plus_b = _mm256_add_epi32(a, b); + __m128i c = _mm256_extracti128_si256(a_plus_b, 1); + __m128i d = _mm256_extracti128_si256(a_plus_b, 0); + __m128i c_plus_d = _mm_add_epi32(c, d); + + __m128i sum1 = _mm_unpackhi_epi64(c_plus_d, c_plus_d); + __m128i sum2 = _mm_add_epi32(sum1, c_plus_d); + __m128i sum3 = _mm_shuffle_epi32(sum2, 0x01); + __m128i sum4 = _mm_add_epi32(sum2, sum3); + + return _mm_cvtsi128_si32(sum4); +} + +static inline uint32_t partial_hsum(__m512i x) { + /* We need a permutation vector to extract every other integer. The + * rest are going to be zeros. Marking this const so the compiler stands + * a better chance of keeping this resident in a register through entire + * loop execution. We certainly have enough zmm registers (32) */ + const __m512i perm_vec = _mm512_setr_epi32(0, 2, 4, 6, 8, 10, 12, 14, + 1, 1, 1, 1, 1, 1, 1, 1); + + __m512i non_zero = _mm512_permutexvar_epi32(perm_vec, x); + + /* From here, it's a simple 256 bit wide reduction sum */ + __m256i non_zero_avx = _mm512_castsi512_si256(non_zero); + + /* See Agner Fog's vectorclass for a decent reference. Essentially, phadd is + * pretty slow, much slower than the longer instruction sequence below */ + __m128i sum1 = _mm_add_epi32(_mm256_extracti128_si256(non_zero_avx, 1), + _mm256_castsi256_si128(non_zero_avx)); + __m128i sum2 = _mm_add_epi32(sum1,_mm_unpackhi_epi64(sum1, sum1)); + __m128i sum3 = _mm_add_epi32(sum2,_mm_shuffle_epi32(sum2, 1)); + return (uint32_t)_mm_cvtsi128_si32(sum3); +} + +#endif diff --git a/arch/x86/adler32_avx512_vnni.c b/arch/x86/adler32_avx512_vnni.c new file mode 100644 index 0000000000..4c5cfc1cad --- /dev/null +++ b/arch/x86/adler32_avx512_vnni.c @@ -0,0 +1,210 @@ +/* adler32_avx512_vnni.c -- compute the Adler-32 checksum of a data stream + * Based on Brian Bockelman's AVX2 version + * Copyright (C) 1995-2011 Mark Adler + * Authors: + * Adam Stylinski + * Brian Bockelman + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef X86_AVX512VNNI + +#include "zbuild.h" +#include "adler32_p.h" +#include "arch_functions.h" +#include +#include "x86_intrins.h" +#include "adler32_avx512_p.h" +#include "adler32_avx2_p.h" + +Z_INTERNAL uint32_t adler32_avx512_vnni(uint32_t adler, const uint8_t *src, size_t len) { + if (src == NULL) return 1L; + if (len == 0) return adler; + + uint32_t adler0, adler1; + adler1 = (adler >> 16) & 0xffff; + adler0 = adler & 0xffff; + +rem_peel: + if (len < 32) + return adler32_ssse3(adler, src, len); + + if (len < 64) + return adler32_avx2(adler, src, len); + + const __m512i dot2v = _mm512_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64); + + const __m512i zero = _mm512_setzero_si512(); + __m512i vs1, vs2; + + while (len >= 64) { + vs1 = _mm512_zextsi128_si512(_mm_cvtsi32_si128(adler0)); + vs2 = _mm512_zextsi128_si512(_mm_cvtsi32_si128(adler1)); + size_t k = MIN(len, NMAX); + k -= k % 64; + len -= k; + __m512i vs1_0 = vs1; + __m512i vs3 = _mm512_setzero_si512(); + /* We might get a tad bit more ILP here if we sum to a second register in the loop */ + __m512i vs2_1 = _mm512_setzero_si512(); + __m512i vbuf0, vbuf1; + + /* Remainder peeling */ + if (k % 128) { + vbuf1 = _mm512_loadu_si512((__m512i*)src); + + src += 64; + k -= 64; + + __m512i vs1_sad = _mm512_sad_epu8(vbuf1, zero); + vs1 = _mm512_add_epi32(vs1, vs1_sad); + vs3 = _mm512_add_epi32(vs3, vs1_0); + vs2 = _mm512_dpbusd_epi32(vs2, vbuf1, dot2v); + vs1_0 = vs1; + } + + /* Manually unrolled this loop by 2 for an decent amount of ILP */ + while (k >= 128) { + /* + vs1 = adler + sum(c[i]) + vs2 = sum2 + 64 vs1 + sum( (64-i+1) c[i] ) + */ + vbuf0 = _mm512_loadu_si512((__m512i*)src); + vbuf1 = _mm512_loadu_si512((__m512i*)(src + 64)); + src += 128; + k -= 128; + + __m512i vs1_sad = _mm512_sad_epu8(vbuf0, zero); + vs1 = _mm512_add_epi32(vs1, vs1_sad); + vs3 = _mm512_add_epi32(vs3, vs1_0); + /* multiply-add, resulting in 16 ints. Fuse with sum stage from prior versions, as we now have the dp + * instructions to eliminate them */ + vs2 = _mm512_dpbusd_epi32(vs2, vbuf0, dot2v); + + vs3 = _mm512_add_epi32(vs3, vs1); + vs1_sad = _mm512_sad_epu8(vbuf1, zero); + vs1 = _mm512_add_epi32(vs1, vs1_sad); + vs2_1 = _mm512_dpbusd_epi32(vs2_1, vbuf1, dot2v); + vs1_0 = vs1; + } + + vs3 = _mm512_slli_epi32(vs3, 6); + vs2 = _mm512_add_epi32(vs2, vs3); + vs2 = _mm512_add_epi32(vs2, vs2_1); + + adler0 = partial_hsum(vs1) % BASE; + adler1 = _mm512_reduce_add_epu32(vs2) % BASE; + } + + adler = adler0 | (adler1 << 16); + + /* Process tail (len < 64). */ + if (len) { + goto rem_peel; + } + + return adler; +} + +Z_INTERNAL uint32_t adler32_fold_copy_avx512_vnni(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { + if (src == NULL) return 1L; + if (len == 0) return adler; + + uint32_t adler0, adler1; + adler1 = (adler >> 16) & 0xffff; + adler0 = adler & 0xffff; + +rem_peel_copy: + if (len < 32) { + /* This handles the remaining copies, just call normal adler checksum after this */ + __mmask32 storemask = (0xFFFFFFFFUL >> (32 - len)); + __m256i copy_vec = _mm256_maskz_loadu_epi8(storemask, src); + _mm256_mask_storeu_epi8(dst, storemask, copy_vec); + + return adler32_ssse3(adler, src, len); + } + + const __m256i dot2v = _mm256_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + + const __m256i zero = _mm256_setzero_si256(); + __m256i vs1, vs2; + + while (len >= 32) { + vs1 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler0)); + vs2 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler1)); + size_t k = MIN(len, NMAX); + k -= k % 32; + len -= k; + __m256i vs1_0 = vs1; + __m256i vs3 = _mm256_setzero_si256(); + /* We might get a tad bit more ILP here if we sum to a second register in the loop */ + __m256i vs2_1 = _mm256_setzero_si256(); + __m256i vbuf0, vbuf1; + + /* Remainder peeling */ + if (k % 64) { + vbuf1 = _mm256_loadu_si256((__m256i*)src); + _mm256_storeu_si256((__m256i*)dst, vbuf1); + dst += 32; + + src += 32; + k -= 32; + + __m256i vs1_sad = _mm256_sad_epu8(vbuf1, zero); + vs1 = _mm256_add_epi32(vs1, vs1_sad); + vs3 = _mm256_add_epi32(vs3, vs1_0); + vs2 = _mm256_dpbusd_epi32(vs2, vbuf1, dot2v); + vs1_0 = vs1; + } + + /* Manually unrolled this loop by 2 for an decent amount of ILP */ + while (k >= 64) { + /* + vs1 = adler + sum(c[i]) + vs2 = sum2 + 64 vs1 + sum( (64-i+1) c[i] ) + */ + vbuf0 = _mm256_loadu_si256((__m256i*)src); + vbuf1 = _mm256_loadu_si256((__m256i*)(src + 32)); + _mm256_storeu_si256((__m256i*)dst, vbuf0); + _mm256_storeu_si256((__m256i*)(dst + 32), vbuf1); + dst += 64; + src += 64; + k -= 64; + + __m256i vs1_sad = _mm256_sad_epu8(vbuf0, zero); + vs1 = _mm256_add_epi32(vs1, vs1_sad); + vs3 = _mm256_add_epi32(vs3, vs1_0); + /* multiply-add, resulting in 16 ints. Fuse with sum stage from prior versions, as we now have the dp + * instructions to eliminate them */ + vs2 = _mm256_dpbusd_epi32(vs2, vbuf0, dot2v); + + vs3 = _mm256_add_epi32(vs3, vs1); + vs1_sad = _mm256_sad_epu8(vbuf1, zero); + vs1 = _mm256_add_epi32(vs1, vs1_sad); + vs2_1 = _mm256_dpbusd_epi32(vs2_1, vbuf1, dot2v); + vs1_0 = vs1; + } + + vs3 = _mm256_slli_epi32(vs3, 5); + vs2 = _mm256_add_epi32(vs2, vs3); + vs2 = _mm256_add_epi32(vs2, vs2_1); + + adler0 = partial_hsum256(vs1) % BASE; + adler1 = hsum256(vs2) % BASE; + } + + adler = adler0 | (adler1 << 16); + + /* Process tail (len < 64). */ + if (len) { + goto rem_peel_copy; + } + + return adler; +} + +#endif diff --git a/arch/x86/adler32_sse42.c b/arch/x86/adler32_sse42.c new file mode 100644 index 0000000000..df0739d165 --- /dev/null +++ b/arch/x86/adler32_sse42.c @@ -0,0 +1,120 @@ +/* adler32_sse42.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011 Mark Adler + * Authors: + * Adam Stylinski + * Brian Bockelman + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "adler32_p.h" +#include "adler32_ssse3_p.h" +#include + +#ifdef X86_SSE42 + +Z_INTERNAL uint32_t adler32_fold_copy_sse42(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { + uint32_t adler0, adler1; + adler1 = (adler >> 16) & 0xffff; + adler0 = adler & 0xffff; + +rem_peel: + if (len < 16) { + return adler32_copy_len_16(adler0, src, dst, len, adler1); + } + + __m128i vbuf, vbuf_0; + __m128i vs1_0, vs3, vs1, vs2, vs2_0, v_sad_sum1, v_short_sum2, v_short_sum2_0, + v_sad_sum2, vsum2, vsum2_0; + __m128i zero = _mm_setzero_si128(); + const __m128i dot2v = _mm_setr_epi8(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17); + const __m128i dot2v_0 = _mm_setr_epi8(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + const __m128i dot3v = _mm_set1_epi16(1); + size_t k; + + while (len >= 16) { + + k = MIN(len, NMAX); + k -= k % 16; + len -= k; + + vs1 = _mm_cvtsi32_si128(adler0); + vs2 = _mm_cvtsi32_si128(adler1); + + vs3 = _mm_setzero_si128(); + vs2_0 = _mm_setzero_si128(); + vs1_0 = vs1; + + while (k >= 32) { + /* + vs1 = adler + sum(c[i]) + vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] ) + */ + vbuf = _mm_loadu_si128((__m128i*)src); + vbuf_0 = _mm_loadu_si128((__m128i*)(src + 16)); + src += 32; + k -= 32; + + v_sad_sum1 = _mm_sad_epu8(vbuf, zero); + v_sad_sum2 = _mm_sad_epu8(vbuf_0, zero); + _mm_storeu_si128((__m128i*)dst, vbuf); + _mm_storeu_si128((__m128i*)(dst + 16), vbuf_0); + dst += 32; + + v_short_sum2 = _mm_maddubs_epi16(vbuf, dot2v); + v_short_sum2_0 = _mm_maddubs_epi16(vbuf_0, dot2v_0); + + vs1 = _mm_add_epi32(v_sad_sum1, vs1); + vs3 = _mm_add_epi32(vs1_0, vs3); + + vsum2 = _mm_madd_epi16(v_short_sum2, dot3v); + vsum2_0 = _mm_madd_epi16(v_short_sum2_0, dot3v); + vs1 = _mm_add_epi32(v_sad_sum2, vs1); + vs2 = _mm_add_epi32(vsum2, vs2); + vs2_0 = _mm_add_epi32(vsum2_0, vs2_0); + vs1_0 = vs1; + } + + vs2 = _mm_add_epi32(vs2_0, vs2); + vs3 = _mm_slli_epi32(vs3, 5); + vs2 = _mm_add_epi32(vs3, vs2); + vs3 = _mm_setzero_si128(); + + while (k >= 16) { + /* + vs1 = adler + sum(c[i]) + vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] ) + */ + vbuf = _mm_loadu_si128((__m128i*)src); + src += 16; + k -= 16; + + v_sad_sum1 = _mm_sad_epu8(vbuf, zero); + v_short_sum2 = _mm_maddubs_epi16(vbuf, dot2v_0); + + vs1 = _mm_add_epi32(v_sad_sum1, vs1); + vs3 = _mm_add_epi32(vs1_0, vs3); + vsum2 = _mm_madd_epi16(v_short_sum2, dot3v); + vs2 = _mm_add_epi32(vsum2, vs2); + vs1_0 = vs1; + + _mm_storeu_si128((__m128i*)dst, vbuf); + dst += 16; + } + + vs3 = _mm_slli_epi32(vs3, 4); + vs2 = _mm_add_epi32(vs2, vs3); + + adler0 = partial_hsum(vs1) % BASE; + adler1 = hsum(vs2) % BASE; + } + + /* If this is true, there's fewer than 16 elements remaining */ + if (len) { + goto rem_peel; + } + + return adler0 | (adler1 << 16); +} + +#endif diff --git a/arch/x86/adler32_ssse3.c b/arch/x86/adler32_ssse3.c new file mode 100644 index 0000000000..15e2f78ba3 --- /dev/null +++ b/arch/x86/adler32_ssse3.c @@ -0,0 +1,156 @@ +/* adler32_ssse3.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011 Mark Adler + * Authors: + * Adam Stylinski + * Brian Bockelman + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "adler32_p.h" +#include "adler32_ssse3_p.h" + +#ifdef X86_SSSE3 + +#include + +Z_INTERNAL uint32_t adler32_ssse3(uint32_t adler, const uint8_t *buf, size_t len) { + uint32_t sum2; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (UNLIKELY(len == 1)) + return adler32_len_1(adler, buf, sum2); + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (UNLIKELY(buf == NULL)) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (UNLIKELY(len < 16)) + return adler32_len_16(adler, buf, len, sum2); + + const __m128i dot2v = _mm_setr_epi8(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17); + const __m128i dot2v_0 = _mm_setr_epi8(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + const __m128i dot3v = _mm_set1_epi16(1); + const __m128i zero = _mm_setzero_si128(); + + __m128i vbuf, vs1_0, vs3, vs1, vs2, vs2_0, v_sad_sum1, v_short_sum2, v_short_sum2_0, + vbuf_0, v_sad_sum2, vsum2, vsum2_0; + + /* If our buffer is unaligned (likely), make the determination whether + * or not there's enough of a buffer to consume to make the scalar, aligning + * additions worthwhile or if it's worth it to just eat the cost of an unaligned + * load. This is a pretty simple test, just test if 16 - the remainder + len is + * < 16 */ + size_t max_iters = NMAX; + size_t rem = (uintptr_t)buf & 15; + size_t align_offset = 16 - rem; + size_t k = 0; + if (rem) { + if (len < 16 + align_offset) { + /* Let's eat the cost of this one unaligned load so that + * we don't completely skip over the vectorization. Doing + * 16 bytes at a time unaligned is better than 16 + <= 15 + * sums */ + vbuf = _mm_loadu_si128((__m128i*)buf); + len -= 16; + buf += 16; + vs1 = _mm_cvtsi32_si128(adler); + vs2 = _mm_cvtsi32_si128(sum2); + vs3 = _mm_setzero_si128(); + vs1_0 = vs1; + goto unaligned_jmp; + } + + for (size_t i = 0; i < align_offset; ++i) { + adler += *(buf++); + sum2 += adler; + } + + /* lop off the max number of sums based on the scalar sums done + * above */ + len -= align_offset; + max_iters -= align_offset; + } + + + while (len >= 16) { + vs1 = _mm_cvtsi32_si128(adler); + vs2 = _mm_cvtsi32_si128(sum2); + vs3 = _mm_setzero_si128(); + vs2_0 = _mm_setzero_si128(); + vs1_0 = vs1; + + k = (len < max_iters ? len : max_iters); + k -= k % 16; + len -= k; + + while (k >= 32) { + /* + vs1 = adler + sum(c[i]) + vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] ) + */ + vbuf = _mm_load_si128((__m128i*)buf); + vbuf_0 = _mm_load_si128((__m128i*)(buf + 16)); + buf += 32; + k -= 32; + + v_sad_sum1 = _mm_sad_epu8(vbuf, zero); + v_sad_sum2 = _mm_sad_epu8(vbuf_0, zero); + vs1 = _mm_add_epi32(v_sad_sum1, vs1); + vs3 = _mm_add_epi32(vs1_0, vs3); + + vs1 = _mm_add_epi32(v_sad_sum2, vs1); + v_short_sum2 = _mm_maddubs_epi16(vbuf, dot2v); + vsum2 = _mm_madd_epi16(v_short_sum2, dot3v); + v_short_sum2_0 = _mm_maddubs_epi16(vbuf_0, dot2v_0); + vs2 = _mm_add_epi32(vsum2, vs2); + vsum2_0 = _mm_madd_epi16(v_short_sum2_0, dot3v); + vs2_0 = _mm_add_epi32(vsum2_0, vs2_0); + vs1_0 = vs1; + } + + vs2 = _mm_add_epi32(vs2_0, vs2); + vs3 = _mm_slli_epi32(vs3, 5); + vs2 = _mm_add_epi32(vs3, vs2); + vs3 = _mm_setzero_si128(); + + while (k >= 16) { + /* + vs1 = adler + sum(c[i]) + vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] ) + */ + vbuf = _mm_load_si128((__m128i*)buf); + buf += 16; + k -= 16; + +unaligned_jmp: + v_sad_sum1 = _mm_sad_epu8(vbuf, zero); + vs1 = _mm_add_epi32(v_sad_sum1, vs1); + vs3 = _mm_add_epi32(vs1_0, vs3); + v_short_sum2 = _mm_maddubs_epi16(vbuf, dot2v_0); + vsum2 = _mm_madd_epi16(v_short_sum2, dot3v); + vs2 = _mm_add_epi32(vsum2, vs2); + vs1_0 = vs1; + } + + vs3 = _mm_slli_epi32(vs3, 4); + vs2 = _mm_add_epi32(vs2, vs3); + + /* We don't actually need to do a full horizontal sum, since psadbw is actually doing + * a partial reduction sum implicitly and only summing to integers in vector positions + * 0 and 2. This saves us some contention on the shuffle port(s) */ + adler = partial_hsum(vs1) % BASE; + sum2 = hsum(vs2) % BASE; + max_iters = NMAX; + } + + /* Process tail (len < 16). */ + return adler32_len_16(adler, buf, len, sum2); +} + +#endif diff --git a/arch/x86/adler32_ssse3_p.h b/arch/x86/adler32_ssse3_p.h new file mode 100644 index 0000000000..d7ec3fe0d5 --- /dev/null +++ b/arch/x86/adler32_ssse3_p.h @@ -0,0 +1,29 @@ +/* adler32_ssse3_p.h -- adler32 ssse3 utility functions + * Copyright (C) 2022 Adam Stylinski + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef ADLER32_SSSE3_P_H_ +#define ADLER32_SSSE3_P_H_ + +#ifdef X86_SSSE3 + +#include +#include + +static inline uint32_t partial_hsum(__m128i x) { + __m128i second_int = _mm_srli_si128(x, 8); + __m128i sum = _mm_add_epi32(x, second_int); + return _mm_cvtsi128_si32(sum); +} + +static inline uint32_t hsum(__m128i x) { + __m128i sum1 = _mm_unpackhi_epi64(x, x); + __m128i sum2 = _mm_add_epi32(x, sum1); + __m128i sum3 = _mm_shuffle_epi32(sum2, 0x01); + __m128i sum4 = _mm_add_epi32(sum2, sum3); + return _mm_cvtsi128_si32(sum4); +} +#endif + +#endif diff --git a/arch/x86/avx2_tables.h b/arch/x86/avx2_tables.h new file mode 100644 index 0000000000..50759993b9 --- /dev/null +++ b/arch/x86/avx2_tables.h @@ -0,0 +1,44 @@ +#ifndef _AVX2_TABLES_H +#define _AVX2_TABLES_H + +#include "../generic/chunk_permute_table.h" + +/* Populate don't cares so that this is a direct lookup (with some indirection into the permute table), because dist can + * never be 0 - 2, we'll start with an offset, subtracting 3 from the input */ +static const lut_rem_pair perm_idx_lut[29] = { + { 0, 2}, /* 3 */ + { 0, 0}, /* don't care */ + { 1 * 32, 2}, /* 5 */ + { 2 * 32, 2}, /* 6 */ + { 3 * 32, 4}, /* 7 */ + { 0 * 32, 0}, /* don't care */ + { 4 * 32, 5}, /* 9 */ + { 5 * 32, 22}, /* 10 */ + { 6 * 32, 21}, /* 11 */ + { 7 * 32, 20}, /* 12 */ + { 8 * 32, 6}, /* 13 */ + { 9 * 32, 4}, /* 14 */ + {10 * 32, 2}, /* 15 */ + { 0 * 32, 0}, /* don't care */ + {11 * 32, 15}, /* 17 */ + {11 * 32 + 16, 14}, /* 18 */ + {11 * 32 + 16 * 2, 13}, /* 19 */ + {11 * 32 + 16 * 3, 12}, /* 20 */ + {11 * 32 + 16 * 4, 11}, /* 21 */ + {11 * 32 + 16 * 5, 10}, /* 22 */ + {11 * 32 + 16 * 6, 9}, /* 23 */ + {11 * 32 + 16 * 7, 8}, /* 24 */ + {11 * 32 + 16 * 8, 7}, /* 25 */ + {11 * 32 + 16 * 9, 6}, /* 26 */ + {11 * 32 + 16 * 10, 5}, /* 27 */ + {11 * 32 + 16 * 11, 4}, /* 28 */ + {11 * 32 + 16 * 12, 3}, /* 29 */ + {11 * 32 + 16 * 13, 2}, /* 30 */ + {11 * 32 + 16 * 14, 1} /* 31 */ +}; + +static const uint16_t half_rem_vals[13] = { + 1, 0, 1, 4, 2, 0, 7, 6, 5, 4, 3, 2, 1 +}; + +#endif diff --git a/arch/x86/chunkset_avx2.c b/arch/x86/chunkset_avx2.c new file mode 100644 index 0000000000..c7f336fde7 --- /dev/null +++ b/arch/x86/chunkset_avx2.c @@ -0,0 +1,130 @@ +/* chunkset_avx2.c -- AVX2 inline functions to copy small data chunks. + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#include "zbuild.h" +#include "zmemory.h" + +#ifdef X86_AVX2 +#include "avx2_tables.h" +#include +#include "x86_intrins.h" + +typedef __m256i chunk_t; +typedef __m128i halfchunk_t; + +#define HAVE_CHUNKMEMSET_2 +#define HAVE_CHUNKMEMSET_4 +#define HAVE_CHUNKMEMSET_8 +#define HAVE_CHUNKMEMSET_16 +#define HAVE_CHUNK_MAG +#define HAVE_HALF_CHUNK + +static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { + *chunk = _mm256_set1_epi16(zng_memread_2(from)); +} + +static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { + *chunk = _mm256_set1_epi32(zng_memread_4(from)); +} + +static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { + *chunk = _mm256_set1_epi64x(zng_memread_8(from)); +} + +static inline void chunkmemset_16(uint8_t *from, chunk_t *chunk) { + /* See explanation in chunkset_avx512.c */ +#if defined(_MSC_VER) && _MSC_VER <= 1900 + halfchunk_t half = _mm_loadu_si128((__m128i*)from); + *chunk = _mm256_inserti128_si256(_mm256_castsi128_si256(half), half, 1); +#else + *chunk = _mm256_broadcastsi128_si256(_mm_loadu_si128((__m128i*)from)); +#endif +} + +static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { + *chunk = _mm256_loadu_si256((__m256i *)s); +} + +static inline void storechunk(uint8_t *out, chunk_t *chunk) { + _mm256_storeu_si256((__m256i *)out, *chunk); +} + +static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, uint32_t *chunk_rem, uint32_t dist) { + lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; + __m256i ret_vec; + /* While technically we only need to read 4 or 8 bytes into this vector register for a lot of cases, GCC is + * compiling this to a shared load for all branches, preferring the simpler code. Given that the buf value isn't in + * GPRs to begin with the 256 bit load is _probably_ just as inexpensive */ + *chunk_rem = lut_rem.remval; + + /* See note in chunkset_ssse3.c for why this is ok */ + __msan_unpoison(buf + dist, 32 - dist); + + if (dist < 16) { + /* This simpler case still requires us to shuffle in 128 bit lanes, so we must apply a static offset after + * broadcasting the first vector register to both halves. This is _marginally_ faster than doing two separate + * shuffles and combining the halves later */ + const __m256i permute_xform = + _mm256_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16); + __m256i perm_vec = _mm256_load_si256((__m256i*)(permute_table+lut_rem.idx)); + __m128i ret_vec0 = _mm_loadu_si128((__m128i*)buf); + perm_vec = _mm256_add_epi8(perm_vec, permute_xform); + ret_vec = _mm256_inserti128_si256(_mm256_castsi128_si256(ret_vec0), ret_vec0, 1); + ret_vec = _mm256_shuffle_epi8(ret_vec, perm_vec); + } else { + __m128i ret_vec0 = _mm_loadu_si128((__m128i*)buf); + __m128i ret_vec1 = _mm_loadu_si128((__m128i*)(buf + 16)); + /* Take advantage of the fact that only the latter half of the 256 bit vector will actually differ */ + __m128i perm_vec1 = _mm_load_si128((__m128i*)(permute_table + lut_rem.idx)); + __m128i xlane_permutes = _mm_cmpgt_epi8(_mm_set1_epi8(16), perm_vec1); + __m128i xlane_res = _mm_shuffle_epi8(ret_vec0, perm_vec1); + /* Since we can't wrap twice, we can simply keep the later half exactly how it is instead of having to _also_ + * shuffle those values */ + __m128i latter_half = _mm_blendv_epi8(ret_vec1, xlane_res, xlane_permutes); + ret_vec = _mm256_inserti128_si256(_mm256_castsi128_si256(ret_vec0), latter_half, 1); + } + + return ret_vec; +} + +static inline void loadhalfchunk(uint8_t const *s, halfchunk_t *chunk) { + *chunk = _mm_loadu_si128((__m128i *)s); +} + +static inline void storehalfchunk(uint8_t *out, halfchunk_t *chunk) { + _mm_storeu_si128((__m128i *)out, *chunk); +} + +static inline chunk_t halfchunk2whole(halfchunk_t *chunk) { + /* We zero extend mostly to appease some memory sanitizers. These bytes are ultimately + * unlikely to be actually written or read from */ + return _mm256_zextsi128_si256(*chunk); +} + +static inline halfchunk_t GET_HALFCHUNK_MAG(uint8_t *buf, uint32_t *chunk_rem, uint32_t dist) { + lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; + __m128i perm_vec, ret_vec; + __msan_unpoison(buf + dist, 16 - dist); + ret_vec = _mm_loadu_si128((__m128i*)buf); + *chunk_rem = half_rem_vals[dist - 3]; + + perm_vec = _mm_load_si128((__m128i*)(permute_table + lut_rem.idx)); + ret_vec = _mm_shuffle_epi8(ret_vec, perm_vec); + + return ret_vec; +} + +#define CHUNKSIZE chunksize_avx2 +#define CHUNKCOPY chunkcopy_avx2 +#define CHUNKUNROLL chunkunroll_avx2 +#define CHUNKMEMSET chunkmemset_avx2 +#define CHUNKMEMSET_SAFE chunkmemset_safe_avx2 + +#include "chunkset_tpl.h" + +#define INFLATE_FAST inflate_fast_avx2 + +#include "inffast_tpl.h" + +#endif diff --git a/arch/x86/chunkset_avx512.c b/arch/x86/chunkset_avx512.c new file mode 100644 index 0000000000..9d28d33d5e --- /dev/null +++ b/arch/x86/chunkset_avx512.c @@ -0,0 +1,182 @@ +/* chunkset_avx512.c -- AVX512 inline functions to copy small data chunks. + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#include "zbuild.h" +#include "zmemory.h" + +#ifdef X86_AVX512 + +#include "avx2_tables.h" +#include +#include "x86_intrins.h" + +typedef __m256i chunk_t; +typedef __m128i halfchunk_t; +typedef __mmask32 mask_t; +typedef __mmask16 halfmask_t; + +#define HAVE_CHUNKMEMSET_2 +#define HAVE_CHUNKMEMSET_4 +#define HAVE_CHUNKMEMSET_8 +#define HAVE_CHUNKMEMSET_16 +#define HAVE_CHUNK_MAG +#define HAVE_HALF_CHUNK +#define HAVE_MASKED_READWRITE +#define HAVE_CHUNKCOPY +#define HAVE_HALFCHUNKCOPY + +static inline halfmask_t gen_half_mask(unsigned len) { + return (halfmask_t)_bzhi_u32(0xFFFF, len); +} + +static inline mask_t gen_mask(unsigned len) { + return (mask_t)_bzhi_u32(0xFFFFFFFF, len); +} + +static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { + *chunk = _mm256_set1_epi16(zng_memread_2(from)); +} + +static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { + *chunk = _mm256_set1_epi32(zng_memread_4(from)); +} + +static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { + *chunk = _mm256_set1_epi64x(zng_memread_8(from)); +} + +static inline void chunkmemset_16(uint8_t *from, chunk_t *chunk) { + /* Unfortunately there seems to be a compiler bug in Visual Studio 2015 where + * the load is dumped to the stack with an aligned move for this memory-register + * broadcast. The vbroadcasti128 instruction is 2 fewer cycles and this dump to + * stack doesn't exist if compiled with optimizations. For the sake of working + * properly in a debugger, let's take the 2 cycle penalty */ +#if defined(_MSC_VER) && _MSC_VER <= 1900 + halfchunk_t half = _mm_loadu_si128((__m128i*)from); + *chunk = _mm256_inserti128_si256(_mm256_castsi128_si256(half), half, 1); +#else + *chunk = _mm256_broadcastsi128_si256(_mm_loadu_si128((__m128i*)from)); +#endif +} + +static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { + *chunk = _mm256_loadu_si256((__m256i *)s); +} + +static inline void storechunk(uint8_t *out, chunk_t *chunk) { + _mm256_storeu_si256((__m256i *)out, *chunk); +} + +static inline uint8_t* CHUNKCOPY(uint8_t *out, uint8_t const *from, unsigned len) { + Assert(len > 0, "chunkcopy should never have a length 0"); + + chunk_t chunk; + uint32_t rem = len % sizeof(chunk_t); + + if (len < sizeof(chunk_t)) { + mask_t rem_mask = gen_mask(rem); + chunk = _mm256_maskz_loadu_epi8(rem_mask, from); + _mm256_mask_storeu_epi8(out, rem_mask, chunk); + return out + rem; + } + + loadchunk(from, &chunk); + rem = (rem == 0) ? sizeof(chunk_t) : rem; + storechunk(out, &chunk); + out += rem; + from += rem; + len -= rem; + + while (len > 0) { + loadchunk(from, &chunk); + storechunk(out, &chunk); + out += sizeof(chunk_t); + from += sizeof(chunk_t); + len -= sizeof(chunk_t); + } + + return out; +} + +static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, uint32_t *chunk_rem, uint32_t dist) { + lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; + __m256i ret_vec; + *chunk_rem = lut_rem.remval; + + /* See the AVX2 implementation for more detailed comments. This is that + some masked + * loads to avoid an out of bounds read on the heap */ + + if (dist < 16) { + const __m256i permute_xform = + _mm256_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16); + __m256i perm_vec = _mm256_load_si256((__m256i*)(permute_table+lut_rem.idx)); + halfmask_t load_mask = gen_half_mask(dist); + __m128i ret_vec0 = _mm_maskz_loadu_epi8(load_mask, buf); + perm_vec = _mm256_add_epi8(perm_vec, permute_xform); + ret_vec = _mm256_inserti128_si256(_mm256_castsi128_si256(ret_vec0), ret_vec0, 1); + ret_vec = _mm256_shuffle_epi8(ret_vec, perm_vec); + } else { + halfmask_t load_mask = gen_half_mask(dist - 16); + __m128i ret_vec0 = _mm_loadu_si128((__m128i*)buf); + __m128i ret_vec1 = _mm_maskz_loadu_epi8(load_mask, (__m128i*)(buf + 16)); + __m128i perm_vec1 = _mm_load_si128((__m128i*)(permute_table + lut_rem.idx)); + halfmask_t xlane_mask = _mm_cmp_epi8_mask(perm_vec1, _mm_set1_epi8(15), _MM_CMPINT_LE); + __m128i latter_half = _mm_mask_shuffle_epi8(ret_vec1, xlane_mask, ret_vec0, perm_vec1); + ret_vec = _mm256_inserti128_si256(_mm256_castsi128_si256(ret_vec0), latter_half, 1); + } + + return ret_vec; +} + +static inline void storehalfchunk(uint8_t *out, halfchunk_t *chunk) { + _mm_storeu_si128((__m128i *)out, *chunk); +} + +static inline chunk_t halfchunk2whole(halfchunk_t *chunk) { + /* We zero extend mostly to appease some memory sanitizers. These bytes are ultimately + * unlikely to be actually written or read from */ + return _mm256_zextsi128_si256(*chunk); +} + +static inline halfchunk_t GET_HALFCHUNK_MAG(uint8_t *buf, uint32_t *chunk_rem, uint32_t dist) { + lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; + __m128i perm_vec, ret_vec; + halfmask_t load_mask = gen_half_mask(dist); + ret_vec = _mm_maskz_loadu_epi8(load_mask, buf); + *chunk_rem = half_rem_vals[dist - 3]; + + perm_vec = _mm_load_si128((__m128i*)(permute_table + lut_rem.idx)); + ret_vec = _mm_shuffle_epi8(ret_vec, perm_vec); + + return ret_vec; +} + +static inline uint8_t* HALFCHUNKCOPY(uint8_t *out, uint8_t const *from, unsigned len) { + Assert(len > 0, "chunkcopy should never have a length 0"); + halfchunk_t chunk; + + uint32_t rem = len % sizeof(halfchunk_t); + if (rem == 0) { + rem = sizeof(halfchunk_t); + } + + halfmask_t rem_mask = gen_half_mask(rem); + chunk = _mm_maskz_loadu_epi8(rem_mask, from); + _mm_mask_storeu_epi8(out, rem_mask, chunk); + + return out + rem; +} + +#define CHUNKSIZE chunksize_avx512 +#define CHUNKUNROLL chunkunroll_avx512 +#define CHUNKMEMSET chunkmemset_avx512 +#define CHUNKMEMSET_SAFE chunkmemset_safe_avx512 + +#include "chunkset_tpl.h" + +#define INFLATE_FAST inflate_fast_avx512 + +#include "inffast_tpl.h" + +#endif diff --git a/arch/x86/chunkset_sse2.c b/arch/x86/chunkset_sse2.c new file mode 100644 index 0000000000..dcfe2c70d2 --- /dev/null +++ b/arch/x86/chunkset_sse2.c @@ -0,0 +1,49 @@ +/* chunkset_sse2.c -- SSE2 inline functions to copy small data chunks. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zmemory.h" + +#ifdef X86_SSE2 +#include + +typedef __m128i chunk_t; + +#define HAVE_CHUNKMEMSET_2 +#define HAVE_CHUNKMEMSET_4 +#define HAVE_CHUNKMEMSET_8 + +static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { + *chunk = _mm_set1_epi16(zng_memread_2(from)); +} + +static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { + *chunk = _mm_set1_epi32(zng_memread_4(from)); +} + +static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { + *chunk = _mm_set1_epi64x(zng_memread_8(from)); +} + +static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { + *chunk = _mm_loadu_si128((__m128i *)s); +} + +static inline void storechunk(uint8_t *out, chunk_t *chunk) { + _mm_storeu_si128((__m128i *)out, *chunk); +} + +#define CHUNKSIZE chunksize_sse2 +#define CHUNKCOPY chunkcopy_sse2 +#define CHUNKUNROLL chunkunroll_sse2 +#define CHUNKMEMSET chunkmemset_sse2 +#define CHUNKMEMSET_SAFE chunkmemset_safe_sse2 + +#include "chunkset_tpl.h" + +#define INFLATE_FAST inflate_fast_sse2 + +#include "inffast_tpl.h" + +#endif diff --git a/arch/x86/chunkset_ssse3.c b/arch/x86/chunkset_ssse3.c new file mode 100644 index 0000000000..75b698c61b --- /dev/null +++ b/arch/x86/chunkset_ssse3.c @@ -0,0 +1,86 @@ +/* chunkset_ssse3.c -- SSSE3 inline functions to copy small data chunks. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zmemory.h" + +#if defined(X86_SSSE3) +#include +#include "../generic/chunk_permute_table.h" + +typedef __m128i chunk_t; + +#define HAVE_CHUNKMEMSET_2 +#define HAVE_CHUNKMEMSET_4 +#define HAVE_CHUNKMEMSET_8 +#define HAVE_CHUNK_MAG + +static const lut_rem_pair perm_idx_lut[13] = { + {0, 1}, /* 3 */ + {0, 0}, /* don't care */ + {1 * 32, 1}, /* 5 */ + {2 * 32, 4}, /* 6 */ + {3 * 32, 2}, /* 7 */ + {0 * 32, 0}, /* don't care */ + {4 * 32, 7}, /* 9 */ + {5 * 32, 6}, /* 10 */ + {6 * 32, 5}, /* 11 */ + {7 * 32, 4}, /* 12 */ + {8 * 32, 3}, /* 13 */ + {9 * 32, 2}, /* 14 */ + {10 * 32, 1},/* 15 */ +}; + + +static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { + *chunk = _mm_set1_epi16(zng_memread_2(from)); +} + +static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { + *chunk = _mm_set1_epi32(zng_memread_4(from)); +} + +static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { + *chunk = _mm_set1_epi64x(zng_memread_8(from)); +} + +static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { + *chunk = _mm_loadu_si128((__m128i *)s); +} + +static inline void storechunk(uint8_t *out, chunk_t *chunk) { + _mm_storeu_si128((__m128i *)out, *chunk); +} + +static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, uint32_t *chunk_rem, uint32_t dist) { + lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; + __m128i perm_vec, ret_vec; + /* Important to note: + * This is _not_ to subvert the memory sanitizer but to instead unpoison some + * bytes we willingly and purposefully load uninitialized that we swizzle over + * in a vector register, anyway. If what we assume is wrong about what is used, + * the memory sanitizer will still usefully flag it */ + __msan_unpoison(buf + dist, 16 - dist); + ret_vec = _mm_loadu_si128((__m128i*)buf); + *chunk_rem = lut_rem.remval; + + perm_vec = _mm_load_si128((__m128i*)(permute_table + lut_rem.idx)); + ret_vec = _mm_shuffle_epi8(ret_vec, perm_vec); + + return ret_vec; +} + +#define CHUNKSIZE chunksize_ssse3 +#define CHUNKMEMSET chunkmemset_ssse3 +#define CHUNKMEMSET_SAFE chunkmemset_safe_ssse3 +#define CHUNKCOPY chunkcopy_ssse3 +#define CHUNKUNROLL chunkunroll_ssse3 + +#include "chunkset_tpl.h" + +#define INFLATE_FAST inflate_fast_ssse3 + +#include "inffast_tpl.h" + +#endif diff --git a/arch/x86/compare256_avx2.c b/arch/x86/compare256_avx2.c new file mode 100644 index 0000000000..8a0213c3a6 --- /dev/null +++ b/arch/x86/compare256_avx2.c @@ -0,0 +1,64 @@ +/* compare256_avx2.c -- AVX2 version of compare256 + * Copyright Mika T. Lindqvist + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zmemory.h" +#include "deflate.h" +#include "fallback_builtins.h" + +#if defined(X86_AVX2) && defined(HAVE_BUILTIN_CTZ) + +#include +#ifdef _MSC_VER +# include +#endif + +static inline uint32_t compare256_avx2_static(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0; + + do { + __m256i ymm_src0, ymm_src1, ymm_cmp; + ymm_src0 = _mm256_loadu_si256((__m256i*)src0); + ymm_src1 = _mm256_loadu_si256((__m256i*)src1); + ymm_cmp = _mm256_cmpeq_epi8(ymm_src0, ymm_src1); /* non-identical bytes = 00, identical bytes = FF */ + unsigned mask = (unsigned)_mm256_movemask_epi8(ymm_cmp); + if (mask != 0xFFFFFFFF) { + uint32_t match_byte = (uint32_t)__builtin_ctz(~mask); /* Invert bits so identical = 0 */ + return len + match_byte; + } + + src0 += 32, src1 += 32, len += 32; + + ymm_src0 = _mm256_loadu_si256((__m256i*)src0); + ymm_src1 = _mm256_loadu_si256((__m256i*)src1); + ymm_cmp = _mm256_cmpeq_epi8(ymm_src0, ymm_src1); + mask = (unsigned)_mm256_movemask_epi8(ymm_cmp); + if (mask != 0xFFFFFFFF) { + uint32_t match_byte = (uint32_t)__builtin_ctz(~mask); + return len + match_byte; + } + + src0 += 32, src1 += 32, len += 32; + } while (len < 256); + + return 256; +} + +Z_INTERNAL uint32_t compare256_avx2(const uint8_t *src0, const uint8_t *src1) { + return compare256_avx2_static(src0, src1); +} + +#define LONGEST_MATCH longest_match_avx2 +#define COMPARE256 compare256_avx2_static + +#include "match_tpl.h" + +#define LONGEST_MATCH_SLOW +#define LONGEST_MATCH longest_match_slow_avx2 +#define COMPARE256 compare256_avx2_static + +#include "match_tpl.h" + +#endif diff --git a/arch/x86/compare256_sse2.c b/arch/x86/compare256_sse2.c new file mode 100644 index 0000000000..25b65316a8 --- /dev/null +++ b/arch/x86/compare256_sse2.c @@ -0,0 +1,97 @@ +/* compare256_sse2.c -- SSE2 version of compare256 + * Copyright Adam Stylinski + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zmemory.h" +#include "deflate.h" +#include "fallback_builtins.h" + +#if defined(X86_SSE2) && defined(HAVE_BUILTIN_CTZ) + +#include + +static inline uint32_t compare256_sse2_static(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0; + int align_offset = ((uintptr_t)src0) & 15; + const uint8_t *end0 = src0 + 256; + const uint8_t *end1 = src1 + 256; + __m128i xmm_src0, xmm_src1, xmm_cmp; + + /* Do the first load unaligned, than all subsequent ones we have at least + * one aligned load. Sadly aligning both loads is probably unrealistic */ + xmm_src0 = _mm_loadu_si128((__m128i*)src0); + xmm_src1 = _mm_loadu_si128((__m128i*)src1); + xmm_cmp = _mm_cmpeq_epi8(xmm_src0, xmm_src1); + + unsigned mask = (unsigned)_mm_movemask_epi8(xmm_cmp); + + /* Compiler _may_ turn this branch into a ptest + movemask, + * since a lot of those uops are shared and fused */ + if (mask != 0xFFFF) { + uint32_t match_byte = (uint32_t)__builtin_ctz(~mask); + return len + match_byte; + } + + int align_adv = 16 - align_offset; + len += align_adv; + src0 += align_adv; + src1 += align_adv; + + /* Do a flooring division (should just be a shift right) */ + int num_iter = (256 - len) / 16; + + for (int i = 0; i < num_iter; ++i) { + xmm_src0 = _mm_load_si128((__m128i*)src0); + xmm_src1 = _mm_loadu_si128((__m128i*)src1); + xmm_cmp = _mm_cmpeq_epi8(xmm_src0, xmm_src1); + + mask = (unsigned)_mm_movemask_epi8(xmm_cmp); + + /* Compiler _may_ turn this branch into a ptest + movemask, + * since a lot of those uops are shared and fused */ + if (mask != 0xFFFF) { + uint32_t match_byte = (uint32_t)__builtin_ctz(~mask); + return len + match_byte; + } + + len += 16, src0 += 16, src1 += 16; + } + + if (align_offset) { + src0 = end0 - 16; + src1 = end1 - 16; + len = 256 - 16; + + xmm_src0 = _mm_loadu_si128((__m128i*)src0); + xmm_src1 = _mm_loadu_si128((__m128i*)src1); + xmm_cmp = _mm_cmpeq_epi8(xmm_src0, xmm_src1); + + mask = (unsigned)_mm_movemask_epi8(xmm_cmp); + + if (mask != 0xFFFF) { + uint32_t match_byte = (uint32_t)__builtin_ctz(~mask); + return len + match_byte; + } + } + + return 256; +} + +Z_INTERNAL uint32_t compare256_sse2(const uint8_t *src0, const uint8_t *src1) { + return compare256_sse2_static(src0, src1); +} + +#define LONGEST_MATCH longest_match_sse2 +#define COMPARE256 compare256_sse2_static + +#include "match_tpl.h" + +#define LONGEST_MATCH_SLOW +#define LONGEST_MATCH longest_match_slow_sse2 +#define COMPARE256 compare256_sse2_static + +#include "match_tpl.h" + +#endif diff --git a/arch/x86/crc32_fold_pclmulqdq_tpl.h b/arch/x86/crc32_fold_pclmulqdq_tpl.h new file mode 100644 index 0000000000..1ffe201dda --- /dev/null +++ b/arch/x86/crc32_fold_pclmulqdq_tpl.h @@ -0,0 +1,199 @@ +/* + * Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ + * instruction. + * + * A white paper describing this algorithm can be found at: + * doc/crc-pclmulqdq.pdf + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * Copyright (C) 2016 Marian Beermann (support for initial value) + * Authors: + * Wajdi Feghali + * Jim Guilford + * Vinodh Gopal + * Erdinc Ozturk + * Jim Kukunas + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef COPY +Z_INTERNAL void CRC32_FOLD_COPY(crc32_fold *crc, uint8_t *dst, const uint8_t *src, size_t len) { +#else +Z_INTERNAL void CRC32_FOLD(crc32_fold *crc, const uint8_t *src, size_t len, uint32_t init_crc) { +#endif + unsigned long algn_diff; + __m128i xmm_t0, xmm_t1, xmm_t2, xmm_t3; + __m128i xmm_crc0, xmm_crc1, xmm_crc2, xmm_crc3; + __m128i xmm_crc_part = _mm_setzero_si128(); + char ALIGNED_(16) partial_buf[16] = { 0 }; +#ifndef COPY + __m128i xmm_initial = _mm_cvtsi32_si128(init_crc); + int32_t first = init_crc != 0; + + /* The CRC functions don't call this for input < 16, as a minimum of 16 bytes of input is needed + * for the aligning load that occurs. If there's an initial CRC, to carry it forward through + * the folded CRC there must be 16 - src % 16 + 16 bytes available, which by definition can be + * up to 15 bytes + one full vector load. */ + assert(len >= 16 || first == 0); +#endif + crc32_fold_load((__m128i *)crc->fold, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + + if (len < 16) { + if (len == 0) + return; + + memcpy(partial_buf, src, len); + xmm_crc_part = _mm_load_si128((const __m128i *)partial_buf); +#ifdef COPY + memcpy(dst, partial_buf, len); +#endif + goto partial; + } + + algn_diff = ((uintptr_t)16 - ((uintptr_t)src & 0xF)) & 0xF; + if (algn_diff) { + xmm_crc_part = _mm_loadu_si128((__m128i *)src); +#ifdef COPY + _mm_storeu_si128((__m128i *)dst, xmm_crc_part); + dst += algn_diff; +#else + XOR_INITIAL128(xmm_crc_part); + + if (algn_diff < 4 && init_crc != 0) { + xmm_t0 = xmm_crc_part; + if (len >= 32) { + xmm_crc_part = _mm_loadu_si128((__m128i*)src + 1); + fold_1(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t0); + } else { + memcpy(partial_buf, src + 16, len - 16); + xmm_crc_part = _mm_load_si128((__m128i*)partial_buf); + fold_1(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t0); + src += 16; + len -= 16; +#ifdef COPY + dst -= algn_diff; +#endif + goto partial; + } + + src += 16; + len -= 16; + } +#endif + + partial_fold(algn_diff, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, &xmm_crc_part); + + src += algn_diff; + len -= algn_diff; + } + +#ifdef X86_VPCLMULQDQ + if (len >= 256) { +#ifdef COPY + size_t n = fold_16_vpclmulqdq_copy(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, dst, src, len); + dst += n; +#else + size_t n = fold_16_vpclmulqdq(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, src, len, + xmm_initial, first); + first = 0; +#endif + len -= n; + src += n; + } +#endif + + while (len >= 64) { + len -= 64; + xmm_t0 = _mm_load_si128((__m128i *)src); + xmm_t1 = _mm_load_si128((__m128i *)src + 1); + xmm_t2 = _mm_load_si128((__m128i *)src + 2); + xmm_t3 = _mm_load_si128((__m128i *)src + 3); + src += 64; + + fold_4(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); +#ifdef COPY + _mm_storeu_si128((__m128i *)dst, xmm_t0); + _mm_storeu_si128((__m128i *)dst + 1, xmm_t1); + _mm_storeu_si128((__m128i *)dst + 2, xmm_t2); + _mm_storeu_si128((__m128i *)dst + 3, xmm_t3); + dst += 64; +#else + XOR_INITIAL128(xmm_t0); +#endif + + xmm_crc0 = _mm_xor_si128(xmm_crc0, xmm_t0); + xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_t1); + xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t2); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t3); + } + + /* + * len = num bytes left - 64 + */ + if (len >= 48) { + len -= 48; + + xmm_t0 = _mm_load_si128((__m128i *)src); + xmm_t1 = _mm_load_si128((__m128i *)src + 1); + xmm_t2 = _mm_load_si128((__m128i *)src + 2); + src += 48; +#ifdef COPY + _mm_storeu_si128((__m128i *)dst, xmm_t0); + _mm_storeu_si128((__m128i *)dst + 1, xmm_t1); + _mm_storeu_si128((__m128i *)dst + 2, xmm_t2); + dst += 48; +#else + XOR_INITIAL128(xmm_t0); +#endif + fold_3(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + + xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_t0); + xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t1); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t2); + } else if (len >= 32) { + len -= 32; + + xmm_t0 = _mm_load_si128((__m128i *)src); + xmm_t1 = _mm_load_si128((__m128i *)src + 1); + src += 32; +#ifdef COPY + _mm_storeu_si128((__m128i *)dst, xmm_t0); + _mm_storeu_si128((__m128i *)dst + 1, xmm_t1); + dst += 32; +#else + XOR_INITIAL128(xmm_t0); +#endif + fold_2(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + + xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t0); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t1); + } else if (len >= 16) { + len -= 16; + xmm_t0 = _mm_load_si128((__m128i *)src); + src += 16; +#ifdef COPY + _mm_storeu_si128((__m128i *)dst, xmm_t0); + dst += 16; +#else + XOR_INITIAL128(xmm_t0); +#endif + fold_1(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t0); + } + +partial: + if (len) { + memcpy(&xmm_crc_part, src, len); +#ifdef COPY + _mm_storeu_si128((__m128i *)partial_buf, xmm_crc_part); + memcpy(dst, partial_buf, len); +#endif + partial_fold(len, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, &xmm_crc_part); + } + + crc32_fold_save((__m128i *)crc->fold, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); +} diff --git a/arch/x86/crc32_fold_vpclmulqdq_tpl.h b/arch/x86/crc32_fold_vpclmulqdq_tpl.h new file mode 100644 index 0000000000..3ea5c33055 --- /dev/null +++ b/arch/x86/crc32_fold_vpclmulqdq_tpl.h @@ -0,0 +1,107 @@ +/* crc32_fold_vpclmulqdq_tpl.h -- VPCMULQDQ-based CRC32 folding template. + * Copyright Wangyang Guo (wangyang.guo@intel.com) + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef COPY +static size_t fold_16_vpclmulqdq_copy(__m128i *xmm_crc0, __m128i *xmm_crc1, + __m128i *xmm_crc2, __m128i *xmm_crc3, uint8_t *dst, const uint8_t *src, size_t len) { +#else +static size_t fold_16_vpclmulqdq(__m128i *xmm_crc0, __m128i *xmm_crc1, + __m128i *xmm_crc2, __m128i *xmm_crc3, const uint8_t *src, size_t len, + __m128i init_crc, int32_t first) { + __m512i zmm_initial = _mm512_zextsi128_si512(init_crc); +#endif + __m512i zmm_t0, zmm_t1, zmm_t2, zmm_t3; + __m512i zmm_crc0, zmm_crc1, zmm_crc2, zmm_crc3; + __m512i z0, z1, z2, z3; + size_t len_tmp = len; + const __m512i zmm_fold4 = _mm512_set4_epi32( + 0x00000001, 0x54442bd4, 0x00000001, 0xc6e41596); + const __m512i zmm_fold16 = _mm512_set4_epi32( + 0x00000001, 0x1542778a, 0x00000001, 0x322d1430); + + // zmm register init + zmm_crc0 = _mm512_setzero_si512(); + zmm_t0 = _mm512_loadu_si512((__m512i *)src); +#ifndef COPY + XOR_INITIAL512(zmm_t0); +#endif + zmm_crc1 = _mm512_loadu_si512((__m512i *)src + 1); + zmm_crc2 = _mm512_loadu_si512((__m512i *)src + 2); + zmm_crc3 = _mm512_loadu_si512((__m512i *)src + 3); + + /* already have intermediate CRC in xmm registers + * fold4 with 4 xmm_crc to get zmm_crc0 + */ + zmm_crc0 = _mm512_inserti32x4(zmm_crc0, *xmm_crc0, 0); + zmm_crc0 = _mm512_inserti32x4(zmm_crc0, *xmm_crc1, 1); + zmm_crc0 = _mm512_inserti32x4(zmm_crc0, *xmm_crc2, 2); + zmm_crc0 = _mm512_inserti32x4(zmm_crc0, *xmm_crc3, 3); + z0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x01); + zmm_crc0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x10); + zmm_crc0 = _mm512_ternarylogic_epi32(zmm_crc0, z0, zmm_t0, 0x96); + +#ifdef COPY + _mm512_storeu_si512((__m512i *)dst, zmm_t0); + _mm512_storeu_si512((__m512i *)dst + 1, zmm_crc1); + _mm512_storeu_si512((__m512i *)dst + 2, zmm_crc2); + _mm512_storeu_si512((__m512i *)dst + 3, zmm_crc3); + dst += 256; +#endif + len -= 256; + src += 256; + + // fold-16 loops + while (len >= 256) { + zmm_t0 = _mm512_loadu_si512((__m512i *)src); + zmm_t1 = _mm512_loadu_si512((__m512i *)src + 1); + zmm_t2 = _mm512_loadu_si512((__m512i *)src + 2); + zmm_t3 = _mm512_loadu_si512((__m512i *)src + 3); + + z0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold16, 0x01); + z1 = _mm512_clmulepi64_epi128(zmm_crc1, zmm_fold16, 0x01); + z2 = _mm512_clmulepi64_epi128(zmm_crc2, zmm_fold16, 0x01); + z3 = _mm512_clmulepi64_epi128(zmm_crc3, zmm_fold16, 0x01); + + zmm_crc0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold16, 0x10); + zmm_crc1 = _mm512_clmulepi64_epi128(zmm_crc1, zmm_fold16, 0x10); + zmm_crc2 = _mm512_clmulepi64_epi128(zmm_crc2, zmm_fold16, 0x10); + zmm_crc3 = _mm512_clmulepi64_epi128(zmm_crc3, zmm_fold16, 0x10); + + zmm_crc0 = _mm512_ternarylogic_epi32(zmm_crc0, z0, zmm_t0, 0x96); + zmm_crc1 = _mm512_ternarylogic_epi32(zmm_crc1, z1, zmm_t1, 0x96); + zmm_crc2 = _mm512_ternarylogic_epi32(zmm_crc2, z2, zmm_t2, 0x96); + zmm_crc3 = _mm512_ternarylogic_epi32(zmm_crc3, z3, zmm_t3, 0x96); + +#ifdef COPY + _mm512_storeu_si512((__m512i *)dst, zmm_t0); + _mm512_storeu_si512((__m512i *)dst + 1, zmm_t1); + _mm512_storeu_si512((__m512i *)dst + 2, zmm_t2); + _mm512_storeu_si512((__m512i *)dst + 3, zmm_t3); + dst += 256; +#endif + len -= 256; + src += 256; + } + // zmm_crc[0,1,2,3] -> zmm_crc0 + z0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x01); + zmm_crc0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x10); + zmm_crc0 = _mm512_ternarylogic_epi32(zmm_crc0, z0, zmm_crc1, 0x96); + + z0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x01); + zmm_crc0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x10); + zmm_crc0 = _mm512_ternarylogic_epi32(zmm_crc0, z0, zmm_crc2, 0x96); + + z0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x01); + zmm_crc0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x10); + zmm_crc0 = _mm512_ternarylogic_epi32(zmm_crc0, z0, zmm_crc3, 0x96); + + // zmm_crc0 -> xmm_crc[0, 1, 2, 3] + *xmm_crc0 = _mm512_extracti32x4_epi32(zmm_crc0, 0); + *xmm_crc1 = _mm512_extracti32x4_epi32(zmm_crc0, 1); + *xmm_crc2 = _mm512_extracti32x4_epi32(zmm_crc0, 2); + *xmm_crc3 = _mm512_extracti32x4_epi32(zmm_crc0, 3); + + return (len_tmp - len); // return n bytes processed +} diff --git a/arch/x86/crc32_pclmulqdq.c b/arch/x86/crc32_pclmulqdq.c new file mode 100644 index 0000000000..9383b7a2ba --- /dev/null +++ b/arch/x86/crc32_pclmulqdq.c @@ -0,0 +1,30 @@ +/* + * Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ + * instruction. + * + * A white paper describing this algorithm can be found at: + * doc/crc-pclmulqdq.pdf + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * Copyright (C) 2016 Marian Beermann (support for initial value) + * Authors: + * Wajdi Feghali + * Jim Guilford + * Vinodh Gopal + * Erdinc Ozturk + * Jim Kukunas + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef X86_PCLMULQDQ_CRC + +#define CRC32_FOLD_COPY crc32_fold_pclmulqdq_copy +#define CRC32_FOLD crc32_fold_pclmulqdq +#define CRC32_FOLD_RESET crc32_fold_pclmulqdq_reset +#define CRC32_FOLD_FINAL crc32_fold_pclmulqdq_final +#define CRC32 crc32_pclmulqdq + +#include "crc32_pclmulqdq_tpl.h" + +#endif diff --git a/arch/x86/crc32_pclmulqdq_tpl.h b/arch/x86/crc32_pclmulqdq_tpl.h new file mode 100644 index 0000000000..3a4f6af5af --- /dev/null +++ b/arch/x86/crc32_pclmulqdq_tpl.h @@ -0,0 +1,375 @@ +/* + * Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ + * instruction. + * + * A white paper describing this algorithm can be found at: + * doc/crc-pclmulqdq.pdf + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * Copyright (C) 2016 Marian Beermann (support for initial value) + * Authors: + * Wajdi Feghali + * Jim Guilford + * Vinodh Gopal + * Erdinc Ozturk + * Jim Kukunas + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" + +#include +#include +#include // _mm_extract_epi32 +#ifdef X86_VPCLMULQDQ +# include +#endif + +#include "crc32.h" +#include "crc32_braid_p.h" +#include "crc32_braid_tbl.h" +#include "x86_intrins.h" +#include + +#ifdef X86_VPCLMULQDQ +static size_t fold_16_vpclmulqdq(__m128i *xmm_crc0, __m128i *xmm_crc1, + __m128i *xmm_crc2, __m128i *xmm_crc3, const uint8_t *src, size_t len, __m128i init_crc, + int32_t first); +static size_t fold_16_vpclmulqdq_copy(__m128i *xmm_crc0, __m128i *xmm_crc1, + __m128i *xmm_crc2, __m128i *xmm_crc3, uint8_t *dst, const uint8_t *src, size_t len); +#endif + +static void fold_1(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3) { + const __m128i xmm_fold4 = _mm_set_epi32( 0x00000001, 0x54442bd4, + 0x00000001, 0xc6e41596); + __m128i x_tmp3; + __m128 ps_crc0, ps_crc3, ps_res; + + x_tmp3 = *xmm_crc3; + + *xmm_crc3 = *xmm_crc0; + *xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); + *xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10); + ps_crc0 = _mm_castsi128_ps(*xmm_crc0); + ps_crc3 = _mm_castsi128_ps(*xmm_crc3); + ps_res = _mm_xor_ps(ps_crc0, ps_crc3); + + *xmm_crc0 = *xmm_crc1; + *xmm_crc1 = *xmm_crc2; + *xmm_crc2 = x_tmp3; + *xmm_crc3 = _mm_castps_si128(ps_res); +} + +static void fold_2(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3) { + const __m128i xmm_fold4 = _mm_set_epi32( 0x00000001, 0x54442bd4, + 0x00000001, 0xc6e41596); + __m128i x_tmp3, x_tmp2; + __m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3, ps_res31, ps_res20; + + x_tmp3 = *xmm_crc3; + x_tmp2 = *xmm_crc2; + + *xmm_crc3 = *xmm_crc1; + *xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01); + *xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10); + ps_crc3 = _mm_castsi128_ps(*xmm_crc3); + ps_crc1 = _mm_castsi128_ps(*xmm_crc1); + ps_res31 = _mm_xor_ps(ps_crc3, ps_crc1); + + *xmm_crc2 = *xmm_crc0; + *xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); + *xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x10); + ps_crc0 = _mm_castsi128_ps(*xmm_crc0); + ps_crc2 = _mm_castsi128_ps(*xmm_crc2); + ps_res20 = _mm_xor_ps(ps_crc0, ps_crc2); + + *xmm_crc0 = x_tmp2; + *xmm_crc1 = x_tmp3; + *xmm_crc2 = _mm_castps_si128(ps_res20); + *xmm_crc3 = _mm_castps_si128(ps_res31); +} + +static void fold_3(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3) { + const __m128i xmm_fold4 = _mm_set_epi32( 0x00000001, 0x54442bd4, + 0x00000001, 0xc6e41596); + __m128i x_tmp3; + __m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3, ps_res32, ps_res21, ps_res10; + + x_tmp3 = *xmm_crc3; + + *xmm_crc3 = *xmm_crc2; + *xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x01); + *xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10); + ps_crc2 = _mm_castsi128_ps(*xmm_crc2); + ps_crc3 = _mm_castsi128_ps(*xmm_crc3); + ps_res32 = _mm_xor_ps(ps_crc2, ps_crc3); + + *xmm_crc2 = *xmm_crc1; + *xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01); + *xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x10); + ps_crc1 = _mm_castsi128_ps(*xmm_crc1); + ps_crc2 = _mm_castsi128_ps(*xmm_crc2); + ps_res21 = _mm_xor_ps(ps_crc1, ps_crc2); + + *xmm_crc1 = *xmm_crc0; + *xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); + *xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x10); + ps_crc0 = _mm_castsi128_ps(*xmm_crc0); + ps_crc1 = _mm_castsi128_ps(*xmm_crc1); + ps_res10 = _mm_xor_ps(ps_crc0, ps_crc1); + + *xmm_crc0 = x_tmp3; + *xmm_crc1 = _mm_castps_si128(ps_res10); + *xmm_crc2 = _mm_castps_si128(ps_res21); + *xmm_crc3 = _mm_castps_si128(ps_res32); +} + +static void fold_4(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3) { + const __m128i xmm_fold4 = _mm_set_epi32( 0x00000001, 0x54442bd4, + 0x00000001, 0xc6e41596); + __m128i x_tmp0, x_tmp1, x_tmp2, x_tmp3; + __m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3; + __m128 ps_t0, ps_t1, ps_t2, ps_t3; + __m128 ps_res0, ps_res1, ps_res2, ps_res3; + + x_tmp0 = *xmm_crc0; + x_tmp1 = *xmm_crc1; + x_tmp2 = *xmm_crc2; + x_tmp3 = *xmm_crc3; + + *xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); + x_tmp0 = _mm_clmulepi64_si128(x_tmp0, xmm_fold4, 0x10); + ps_crc0 = _mm_castsi128_ps(*xmm_crc0); + ps_t0 = _mm_castsi128_ps(x_tmp0); + ps_res0 = _mm_xor_ps(ps_crc0, ps_t0); + + *xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01); + x_tmp1 = _mm_clmulepi64_si128(x_tmp1, xmm_fold4, 0x10); + ps_crc1 = _mm_castsi128_ps(*xmm_crc1); + ps_t1 = _mm_castsi128_ps(x_tmp1); + ps_res1 = _mm_xor_ps(ps_crc1, ps_t1); + + *xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x01); + x_tmp2 = _mm_clmulepi64_si128(x_tmp2, xmm_fold4, 0x10); + ps_crc2 = _mm_castsi128_ps(*xmm_crc2); + ps_t2 = _mm_castsi128_ps(x_tmp2); + ps_res2 = _mm_xor_ps(ps_crc2, ps_t2); + + *xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x01); + x_tmp3 = _mm_clmulepi64_si128(x_tmp3, xmm_fold4, 0x10); + ps_crc3 = _mm_castsi128_ps(*xmm_crc3); + ps_t3 = _mm_castsi128_ps(x_tmp3); + ps_res3 = _mm_xor_ps(ps_crc3, ps_t3); + + *xmm_crc0 = _mm_castps_si128(ps_res0); + *xmm_crc1 = _mm_castps_si128(ps_res1); + *xmm_crc2 = _mm_castps_si128(ps_res2); + *xmm_crc3 = _mm_castps_si128(ps_res3); +} + +static const unsigned ALIGNED_(32) pshufb_shf_table[60] = { + 0x84838281, 0x88878685, 0x8c8b8a89, 0x008f8e8d, /* shl 15 (16 - 1)/shr1 */ + 0x85848382, 0x89888786, 0x8d8c8b8a, 0x01008f8e, /* shl 14 (16 - 3)/shr2 */ + 0x86858483, 0x8a898887, 0x8e8d8c8b, 0x0201008f, /* shl 13 (16 - 4)/shr3 */ + 0x87868584, 0x8b8a8988, 0x8f8e8d8c, 0x03020100, /* shl 12 (16 - 4)/shr4 */ + 0x88878685, 0x8c8b8a89, 0x008f8e8d, 0x04030201, /* shl 11 (16 - 5)/shr5 */ + 0x89888786, 0x8d8c8b8a, 0x01008f8e, 0x05040302, /* shl 10 (16 - 6)/shr6 */ + 0x8a898887, 0x8e8d8c8b, 0x0201008f, 0x06050403, /* shl 9 (16 - 7)/shr7 */ + 0x8b8a8988, 0x8f8e8d8c, 0x03020100, 0x07060504, /* shl 8 (16 - 8)/shr8 */ + 0x8c8b8a89, 0x008f8e8d, 0x04030201, 0x08070605, /* shl 7 (16 - 9)/shr9 */ + 0x8d8c8b8a, 0x01008f8e, 0x05040302, 0x09080706, /* shl 6 (16 -10)/shr10*/ + 0x8e8d8c8b, 0x0201008f, 0x06050403, 0x0a090807, /* shl 5 (16 -11)/shr11*/ + 0x8f8e8d8c, 0x03020100, 0x07060504, 0x0b0a0908, /* shl 4 (16 -12)/shr12*/ + 0x008f8e8d, 0x04030201, 0x08070605, 0x0c0b0a09, /* shl 3 (16 -13)/shr13*/ + 0x01008f8e, 0x05040302, 0x09080706, 0x0d0c0b0a, /* shl 2 (16 -14)/shr14*/ + 0x0201008f, 0x06050403, 0x0a090807, 0x0e0d0c0b /* shl 1 (16 -15)/shr15*/ +}; + +static void partial_fold(const size_t len, __m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, + __m128i *xmm_crc3, __m128i *xmm_crc_part) { + const __m128i xmm_fold4 = _mm_set_epi32( 0x00000001, 0x54442bd4, + 0x00000001, 0xc6e41596); + const __m128i xmm_mask3 = _mm_set1_epi32((int32_t)0x80808080); + + __m128i xmm_shl, xmm_shr, xmm_tmp1, xmm_tmp2, xmm_tmp3; + __m128i xmm_a0_0, xmm_a0_1; + __m128 ps_crc3, psa0_0, psa0_1, ps_res; + + xmm_shl = _mm_load_si128((__m128i *)(pshufb_shf_table + (4 * (len - 1)))); + xmm_shr = xmm_shl; + xmm_shr = _mm_xor_si128(xmm_shr, xmm_mask3); + + xmm_a0_0 = _mm_shuffle_epi8(*xmm_crc0, xmm_shl); + + *xmm_crc0 = _mm_shuffle_epi8(*xmm_crc0, xmm_shr); + xmm_tmp1 = _mm_shuffle_epi8(*xmm_crc1, xmm_shl); + *xmm_crc0 = _mm_or_si128(*xmm_crc0, xmm_tmp1); + + *xmm_crc1 = _mm_shuffle_epi8(*xmm_crc1, xmm_shr); + xmm_tmp2 = _mm_shuffle_epi8(*xmm_crc2, xmm_shl); + *xmm_crc1 = _mm_or_si128(*xmm_crc1, xmm_tmp2); + + *xmm_crc2 = _mm_shuffle_epi8(*xmm_crc2, xmm_shr); + xmm_tmp3 = _mm_shuffle_epi8(*xmm_crc3, xmm_shl); + *xmm_crc2 = _mm_or_si128(*xmm_crc2, xmm_tmp3); + + *xmm_crc3 = _mm_shuffle_epi8(*xmm_crc3, xmm_shr); + *xmm_crc_part = _mm_shuffle_epi8(*xmm_crc_part, xmm_shl); + *xmm_crc3 = _mm_or_si128(*xmm_crc3, *xmm_crc_part); + + xmm_a0_1 = _mm_clmulepi64_si128(xmm_a0_0, xmm_fold4, 0x10); + xmm_a0_0 = _mm_clmulepi64_si128(xmm_a0_0, xmm_fold4, 0x01); + + ps_crc3 = _mm_castsi128_ps(*xmm_crc3); + psa0_0 = _mm_castsi128_ps(xmm_a0_0); + psa0_1 = _mm_castsi128_ps(xmm_a0_1); + + ps_res = _mm_xor_ps(ps_crc3, psa0_0); + ps_res = _mm_xor_ps(ps_res, psa0_1); + + *xmm_crc3 = _mm_castps_si128(ps_res); +} + +static inline void crc32_fold_load(__m128i *fold, __m128i *fold0, __m128i *fold1, __m128i *fold2, __m128i *fold3) { + *fold0 = _mm_load_si128(fold + 0); + *fold1 = _mm_load_si128(fold + 1); + *fold2 = _mm_load_si128(fold + 2); + *fold3 = _mm_load_si128(fold + 3); +} + +static inline void crc32_fold_save(__m128i *fold, const __m128i *fold0, const __m128i *fold1, + const __m128i *fold2, const __m128i *fold3) { + _mm_storeu_si128(fold + 0, *fold0); + _mm_storeu_si128(fold + 1, *fold1); + _mm_storeu_si128(fold + 2, *fold2); + _mm_storeu_si128(fold + 3, *fold3); +} + +Z_INTERNAL uint32_t CRC32_FOLD_RESET(crc32_fold *crc) { + __m128i xmm_crc0 = _mm_cvtsi32_si128(0x9db42487); + __m128i xmm_zero = _mm_setzero_si128(); + crc32_fold_save((__m128i *)crc->fold, &xmm_crc0, &xmm_zero, &xmm_zero, &xmm_zero); + return 0; +} + +#define ONCE(op) if (first) { first = 0; op; } +#define XOR_INITIAL128(where) ONCE(where = _mm_xor_si128(where, xmm_initial)) +#ifdef X86_VPCLMULQDQ +# define XOR_INITIAL512(where) ONCE(where = _mm512_xor_si512(where, zmm_initial)) +#endif + +#ifdef X86_VPCLMULQDQ +# include "crc32_fold_vpclmulqdq_tpl.h" +#endif +#include "crc32_fold_pclmulqdq_tpl.h" +#define COPY +#ifdef X86_VPCLMULQDQ +# include "crc32_fold_vpclmulqdq_tpl.h" +#endif +#include "crc32_fold_pclmulqdq_tpl.h" + +static const unsigned ALIGNED_(16) crc_k[] = { + 0xccaa009e, 0x00000000, /* rk1 */ + 0x751997d0, 0x00000001, /* rk2 */ + 0xccaa009e, 0x00000000, /* rk5 */ + 0x63cd6124, 0x00000001, /* rk6 */ + 0xf7011640, 0x00000001, /* rk7 */ + 0xdb710640, 0x00000001 /* rk8 */ +}; + +static const unsigned ALIGNED_(16) crc_mask[4] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 +}; + +static const unsigned ALIGNED_(16) crc_mask2[4] = { + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +}; + +Z_INTERNAL uint32_t CRC32_FOLD_FINAL(crc32_fold *crc) { + const __m128i xmm_mask = _mm_load_si128((__m128i *)crc_mask); + const __m128i xmm_mask2 = _mm_load_si128((__m128i *)crc_mask2); + __m128i xmm_crc0, xmm_crc1, xmm_crc2, xmm_crc3; + __m128i x_tmp0, x_tmp1, x_tmp2, crc_fold; + + crc32_fold_load((__m128i *)crc->fold, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + + /* + * k1 + */ + crc_fold = _mm_load_si128((__m128i *)crc_k); + + x_tmp0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x10); + xmm_crc0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x01); + xmm_crc1 = _mm_xor_si128(xmm_crc1, x_tmp0); + xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_crc0); + + x_tmp1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x10); + xmm_crc1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x01); + xmm_crc2 = _mm_xor_si128(xmm_crc2, x_tmp1); + xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_crc1); + + x_tmp2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x10); + xmm_crc2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x01); + xmm_crc3 = _mm_xor_si128(xmm_crc3, x_tmp2); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2); + + /* + * k5 + */ + crc_fold = _mm_load_si128((__m128i *)(crc_k + 4)); + + xmm_crc0 = xmm_crc3; + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0); + xmm_crc0 = _mm_srli_si128(xmm_crc0, 8); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0); + + xmm_crc0 = xmm_crc3; + xmm_crc3 = _mm_slli_si128(xmm_crc3, 4); + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0); + xmm_crc3 = _mm_and_si128(xmm_crc3, xmm_mask2); + + /* + * k7 + */ + xmm_crc1 = xmm_crc3; + xmm_crc2 = xmm_crc3; + crc_fold = _mm_load_si128((__m128i *)(crc_k + 8)); + + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2); + xmm_crc3 = _mm_and_si128(xmm_crc3, xmm_mask); + + xmm_crc2 = xmm_crc3; + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc1); + + crc->value = ~((uint32_t)_mm_extract_epi32(xmm_crc3, 2)); + + return crc->value; +} + +static inline uint32_t crc32_small(uint32_t crc, const uint8_t *buf, size_t len) { + uint32_t c = (~crc) & 0xffffffff; + + while (len) { + len--; + DO1; + } + + return c ^ 0xffffffff; +} + +Z_INTERNAL uint32_t CRC32(uint32_t crc32, const uint8_t *buf, size_t len) { + /* For lens smaller than ~12, crc32_small method is faster. + * But there are also minimum requirements for the pclmul functions due to alignment */ + if (len < 16) + return crc32_small(crc32, buf, len); + + crc32_fold ALIGNED_(16) crc_state; + CRC32_FOLD_RESET(&crc_state); + CRC32_FOLD(&crc_state, buf, len, crc32); + return CRC32_FOLD_FINAL(&crc_state); +} diff --git a/arch/x86/crc32_vpclmulqdq.c b/arch/x86/crc32_vpclmulqdq.c new file mode 100644 index 0000000000..cad35b14ee --- /dev/null +++ b/arch/x86/crc32_vpclmulqdq.c @@ -0,0 +1,17 @@ +/* crc32_vpclmulqdq.c -- VPCMULQDQ-based CRC32 folding implementation. + * Copyright Wangyang Guo (wangyang.guo@intel.com) + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef X86_VPCLMULQDQ_CRC + +#define X86_VPCLMULQDQ +#define CRC32_FOLD_COPY crc32_fold_vpclmulqdq_copy +#define CRC32_FOLD crc32_fold_vpclmulqdq +#define CRC32_FOLD_RESET crc32_fold_vpclmulqdq_reset +#define CRC32_FOLD_FINAL crc32_fold_vpclmulqdq_final +#define CRC32 crc32_vpclmulqdq + +#include "crc32_pclmulqdq_tpl.h" + +#endif diff --git a/arch/x86/slide_hash_avx2.c b/arch/x86/slide_hash_avx2.c new file mode 100644 index 0000000000..8533473234 --- /dev/null +++ b/arch/x86/slide_hash_avx2.c @@ -0,0 +1,40 @@ +/* + * AVX2 optimized hash slide, based on Intel's slide_sse implementation + * + * Copyright (C) 2017 Intel Corporation + * Authors: + * Arjan van de Ven + * Jim Kukunas + * Mika T. Lindqvist + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#include "zbuild.h" +#include "deflate.h" + +#include + +static inline void slide_hash_chain(Pos *table, uint32_t entries, const __m256i wsize) { + table += entries; + table -= 16; + + do { + __m256i value, result; + + value = _mm256_loadu_si256((__m256i *)table); + result = _mm256_subs_epu16(value, wsize); + _mm256_storeu_si256((__m256i *)table, result); + + table -= 16; + entries -= 16; + } while (entries > 0); +} + +Z_INTERNAL void slide_hash_avx2(deflate_state *s) { + Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + uint16_t wsize = (uint16_t)s->w_size; + const __m256i ymm_wsize = _mm256_set1_epi16((short)wsize); + + slide_hash_chain(s->head, HASH_SIZE, ymm_wsize); + slide_hash_chain(s->prev, wsize, ymm_wsize); +} diff --git a/arch/x86/slide_hash_sse2.c b/arch/x86/slide_hash_sse2.c new file mode 100644 index 0000000000..6900a59d15 --- /dev/null +++ b/arch/x86/slide_hash_sse2.c @@ -0,0 +1,63 @@ +/* + * SSE optimized hash slide + * + * Copyright (C) 2017 Intel Corporation + * Authors: + * Arjan van de Ven + * Jim Kukunas + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#include "zbuild.h" +#include "deflate.h" + +#include +#include + +static inline void slide_hash_chain(Pos *table0, Pos *table1, uint32_t entries0, + uint32_t entries1, const __m128i wsize) { + uint32_t entries; + Pos *table; + __m128i value0, value1, result0, result1; + + int on_chain = 0; + +next_chain: + table = (on_chain) ? table1 : table0; + entries = (on_chain) ? entries1 : entries0; + + table += entries; + table -= 16; + + /* ZALLOC allocates this pointer unless the user chose a custom allocator. + * Our alloc function is aligned to 64 byte boundaries */ + do { + value0 = _mm_load_si128((__m128i *)table); + value1 = _mm_load_si128((__m128i *)(table + 8)); + result0 = _mm_subs_epu16(value0, wsize); + result1 = _mm_subs_epu16(value1, wsize); + _mm_store_si128((__m128i *)table, result0); + _mm_store_si128((__m128i *)(table + 8), result1); + + table -= 16; + entries -= 16; + } while (entries > 0); + + ++on_chain; + if (on_chain > 1) { + return; + } else { + goto next_chain; + } +} + +Z_INTERNAL void slide_hash_sse2(deflate_state *s) { + Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + uint16_t wsize = (uint16_t)s->w_size; + const __m128i xmm_wsize = _mm_set1_epi16((short)wsize); + + assert(((uintptr_t)s->head & 15) == 0); + assert(((uintptr_t)s->prev & 15) == 0); + + slide_hash_chain(s->head, s->prev, HASH_SIZE, wsize, xmm_wsize); +} diff --git a/arch/x86/x86_features.c b/arch/x86/x86_features.c new file mode 100644 index 0000000000..9491a00730 --- /dev/null +++ b/arch/x86/x86_features.c @@ -0,0 +1,117 @@ +/* x86_features.c - x86 feature check + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * Author: + * Jim Kukunas + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "x86_features.h" + +#ifdef _MSC_VER +# include +#else +// Newer versions of GCC and clang come with cpuid.h +# include +# ifdef X86_HAVE_XSAVE_INTRIN +# if __GNUC__ == 8 +# include +# else +# include +# endif +# endif +#endif + +#include + +static inline void cpuid(int info, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx) { +#ifdef _MSC_VER + unsigned int registers[4]; + __cpuid((int *)registers, info); + + *eax = registers[0]; + *ebx = registers[1]; + *ecx = registers[2]; + *edx = registers[3]; +#else + *eax = *ebx = *ecx = *edx = 0; + __cpuid(info, *eax, *ebx, *ecx, *edx); +#endif +} + +static inline void cpuidex(int info, int subinfo, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx) { +#ifdef _MSC_VER + unsigned int registers[4]; + __cpuidex((int *)registers, info, subinfo); + + *eax = registers[0]; + *ebx = registers[1]; + *ecx = registers[2]; + *edx = registers[3]; +#else + *eax = *ebx = *ecx = *edx = 0; + __cpuid_count(info, subinfo, *eax, *ebx, *ecx, *edx); +#endif +} + +static inline uint64_t xgetbv(unsigned int xcr) { +#if defined(_MSC_VER) || defined(X86_HAVE_XSAVE_INTRIN) + return _xgetbv(xcr); +#else + uint32_t eax, edx; + __asm__ ( ".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(xcr)); + return (uint64_t)(edx) << 32 | eax; +#endif +} + +void Z_INTERNAL x86_check_features(struct x86_cpu_features *features) { + unsigned eax, ebx, ecx, edx; + unsigned maxbasic; + + cpuid(0, &maxbasic, &ebx, &ecx, &edx); + cpuid(1 /*CPU_PROCINFO_AND_FEATUREBITS*/, &eax, &ebx, &ecx, &edx); + + features->has_sse2 = edx & 0x4000000; + features->has_ssse3 = ecx & 0x200; + features->has_sse42 = ecx & 0x100000; + features->has_pclmulqdq = ecx & 0x2; + + if (ecx & 0x08000000) { + uint64_t xfeature = xgetbv(0); + + features->has_os_save_ymm = ((xfeature & 0x06) == 0x06); + features->has_os_save_zmm = ((xfeature & 0xe6) == 0xe6); + } + + if (maxbasic >= 7) { + cpuidex(7, 0, &eax, &ebx, &ecx, &edx); + + // check BMI1 bit + // Reference: https://software.intel.com/sites/default/files/article/405250/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family.pdf + features->has_vpclmulqdq = ecx & 0x400; + + // check AVX2 bit if the OS supports saving YMM registers + if (features->has_os_save_ymm) { + features->has_avx2 = ebx & 0x20; + } + + features->has_bmi2 = ebx & 0x8; + + // check AVX512 bits if the OS supports saving ZMM registers + if (features->has_os_save_zmm) { + features->has_avx512f = ebx & 0x00010000; + if (features->has_avx512f) { + // According to the Intel Software Developer's Manual, AVX512F must be enabled too in order to enable + // AVX512(DQ,BW,VL). + features->has_avx512dq = ebx & 0x00020000; + features->has_avx512bw = ebx & 0x40000000; + features->has_avx512vl = ebx & 0x80000000; + } + features->has_avx512_common = features->has_avx512f && features->has_avx512dq && features->has_avx512bw \ + && features->has_avx512vl && features->has_bmi2; + features->has_avx512vnni = ecx & 0x800; + } + } +} diff --git a/arch/x86/x86_features.h b/arch/x86/x86_features.h new file mode 100644 index 0000000000..3901ad75be --- /dev/null +++ b/arch/x86/x86_features.h @@ -0,0 +1,29 @@ +/* x86_features.h -- check for CPU features + * Copyright (C) 2013 Intel Corporation Jim Kukunas + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef X86_FEATURES_H_ +#define X86_FEATURES_H_ + +struct x86_cpu_features { + int has_avx2; + int has_avx512f; + int has_avx512dq; + int has_avx512bw; + int has_avx512vl; + int has_avx512_common; // Enabled when AVX512(F,DQ,BW,VL) are all enabled. + int has_avx512vnni; + int has_bmi2; + int has_sse2; + int has_ssse3; + int has_sse42; + int has_pclmulqdq; + int has_vpclmulqdq; + int has_os_save_ymm; + int has_os_save_zmm; +}; + +void Z_INTERNAL x86_check_features(struct x86_cpu_features *features); + +#endif /* X86_FEATURES_H_ */ diff --git a/arch/x86/x86_functions.h b/arch/x86/x86_functions.h new file mode 100644 index 0000000000..fc62daeae1 --- /dev/null +++ b/arch/x86/x86_functions.h @@ -0,0 +1,181 @@ +/* x86_functions.h -- x86 implementations for arch-specific functions. + * Copyright (C) 2013 Intel Corporation Jim Kukunas + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef X86_FUNCTIONS_H_ +#define X86_FUNCTIONS_H_ + +#ifdef X86_SSE2 +uint32_t chunksize_sse2(void); +uint8_t* chunkmemset_safe_sse2(uint8_t *out, uint8_t *from, unsigned len, unsigned left); + +# ifdef HAVE_BUILTIN_CTZ + uint32_t compare256_sse2(const uint8_t *src0, const uint8_t *src1); + uint32_t longest_match_sse2(deflate_state *const s, Pos cur_match); + uint32_t longest_match_slow_sse2(deflate_state *const s, Pos cur_match); + void slide_hash_sse2(deflate_state *s); +# endif + void inflate_fast_sse2(PREFIX3(stream)* strm, uint32_t start); +#endif + +#ifdef X86_SSSE3 +uint32_t adler32_ssse3(uint32_t adler, const uint8_t *buf, size_t len); +uint8_t* chunkmemset_safe_ssse3(uint8_t *out, uint8_t *from, unsigned len, unsigned left); +void inflate_fast_ssse3(PREFIX3(stream) *strm, uint32_t start); +#endif + +#ifdef X86_SSE42 +uint32_t adler32_fold_copy_sse42(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); +#endif + +#ifdef X86_AVX2 +uint32_t adler32_avx2(uint32_t adler, const uint8_t *buf, size_t len); +uint32_t adler32_fold_copy_avx2(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); +uint32_t chunksize_avx2(void); +uint8_t* chunkmemset_safe_avx2(uint8_t *out, uint8_t *from, unsigned len, unsigned left); + +# ifdef HAVE_BUILTIN_CTZ + uint32_t compare256_avx2(const uint8_t *src0, const uint8_t *src1); + uint32_t longest_match_avx2(deflate_state *const s, Pos cur_match); + uint32_t longest_match_slow_avx2(deflate_state *const s, Pos cur_match); + void slide_hash_avx2(deflate_state *s); +# endif + void inflate_fast_avx2(PREFIX3(stream)* strm, uint32_t start); +#endif +#ifdef X86_AVX512 +uint32_t adler32_avx512(uint32_t adler, const uint8_t *buf, size_t len); +uint32_t adler32_fold_copy_avx512(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); +uint32_t chunksize_avx512(void); +uint8_t* chunkmemset_safe_avx512(uint8_t *out, uint8_t *from, unsigned len, unsigned left); +void inflate_fast_avx512(PREFIX3(stream)* strm, uint32_t start); +#endif +#ifdef X86_AVX512VNNI +uint32_t adler32_avx512_vnni(uint32_t adler, const uint8_t *buf, size_t len); +uint32_t adler32_fold_copy_avx512_vnni(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); +#endif + +#ifdef X86_PCLMULQDQ_CRC +uint32_t crc32_fold_pclmulqdq_reset(crc32_fold *crc); +void crc32_fold_pclmulqdq_copy(crc32_fold *crc, uint8_t *dst, const uint8_t *src, size_t len); +void crc32_fold_pclmulqdq(crc32_fold *crc, const uint8_t *src, size_t len, uint32_t init_crc); +uint32_t crc32_fold_pclmulqdq_final(crc32_fold *crc); +uint32_t crc32_pclmulqdq(uint32_t crc32, const uint8_t *buf, size_t len); +#endif +#ifdef X86_VPCLMULQDQ_CRC +uint32_t crc32_fold_vpclmulqdq_reset(crc32_fold *crc); +void crc32_fold_vpclmulqdq_copy(crc32_fold *crc, uint8_t *dst, const uint8_t *src, size_t len); +void crc32_fold_vpclmulqdq(crc32_fold *crc, const uint8_t *src, size_t len, uint32_t init_crc); +uint32_t crc32_fold_vpclmulqdq_final(crc32_fold *crc); +uint32_t crc32_vpclmulqdq(uint32_t crc32, const uint8_t *buf, size_t len); +#endif + + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +// X86 - SSE2 +# if (defined(X86_SSE2) && defined(__SSE2__)) || defined(__x86_64__) || defined(_M_X64) || defined(X86_NOCHECK_SSE2) +# undef native_chunkmemset_safe +# define native_chunkmemset_safe chunkmemset_safe_sse2 +# undef native_chunksize +# define native_chunksize chunksize_sse2 +# undef native_inflate_fast +# define native_inflate_fast inflate_fast_sse2 +# undef native_slide_hash +# define native_slide_hash slide_hash_sse2 +# ifdef HAVE_BUILTIN_CTZ +# undef native_compare256 +# define native_compare256 compare256_sse2 +# undef native_longest_match +# define native_longest_match longest_match_sse2 +# undef native_longest_match_slow +# define native_longest_match_slow longest_match_slow_sse2 +# endif +#endif +// X86 - SSSE3 +# if defined(X86_SSSE3) && defined(__SSSE3__) +# undef native_adler32 +# define native_adler32 adler32_ssse3 +# undef native_chunkmemset_safe +# define native_chunkmemset_safe chunkmemset_safe_ssse3 +# undef native_inflate_fast +# define native_inflate_fast inflate_fast_ssse3 +# endif +// X86 - SSE4.2 +# if defined(X86_SSE42) && defined(__SSE4_2__) +# undef native_adler32_fold_copy +# define native_adler32_fold_copy adler32_fold_copy_sse42 +# endif + +// X86 - PCLMUL +#if defined(X86_PCLMULQDQ_CRC) && defined(__PCLMUL__) +# undef native_crc32 +# define native_crc32 crc32_pclmulqdq +# undef native_crc32_fold +# define native_crc32_fold crc32_fold_pclmulqdq +# undef native_crc32_fold_copy +# define native_crc32_fold_copy crc32_fold_pclmulqdq_copy +# undef native_crc32_fold_final +# define native_crc32_fold_final crc32_fold_pclmulqdq_final +# undef native_crc32_fold_reset +# define native_crc32_fold_reset crc32_fold_pclmulqdq_reset +#endif +// X86 - AVX +# if defined(X86_AVX2) && defined(__AVX2__) +# undef native_adler32 +# define native_adler32 adler32_avx2 +# undef native_adler32_fold_copy +# define native_adler32_fold_copy adler32_fold_copy_avx2 +# undef native_chunkmemset_safe +# define native_chunkmemset_safe chunkmemset_safe_avx2 +# undef native_chunksize +# define native_chunksize chunksize_avx2 +# undef native_inflate_fast +# define native_inflate_fast inflate_fast_avx2 +# undef native_slide_hash +# define native_slide_hash slide_hash_avx2 +# ifdef HAVE_BUILTIN_CTZ +# undef native_compare256 +# define native_compare256 compare256_avx2 +# undef native_longest_match +# define native_longest_match longest_match_avx2 +# undef native_longest_match_slow +# define native_longest_match_slow longest_match_slow_avx2 +# endif +# endif + +// X86 - AVX512 (F,DQ,BW,Vl) +# if defined(X86_AVX512) && defined(__AVX512F__) && defined(__AVX512DQ__) && defined(__AVX512BW__) && defined(__AVX512VL__) +# undef native_adler32 +# define native_adler32 adler32_avx512 +# undef native_adler32_fold_copy +# define native_adler32_fold_copy adler32_fold_copy_avx512 +# undef native_chunkmemset_safe +# define native_chunkmemset_safe chunkmemset_safe_avx512 +# undef native_chunksize +# define native_chunksize chunksize_avx512 +# undef native_inflate_fast +# define native_inflate_fast inflate_fast_avx512 +// X86 - AVX512 (VNNI) +# if defined(X86_AVX512VNNI) && defined(__AVX512VNNI__) +# undef native_adler32 +# define native_adler32 adler32_avx512_vnni +# undef native_adler32_fold_copy +# define native_adler32_fold_copy adler32_fold_copy_avx512_vnni +# endif +// X86 - VPCLMULQDQ +# if defined(__PCLMUL__) && defined(__AVX512F__) && defined(__VPCLMULQDQ__) +# undef native_crc32 +# define native_crc32 crc32_vpclmulqdq +# undef native_crc32_fold +# define native_crc32_fold crc32_fold_vpclmulqdq +# undef native_crc32_fold_copy +# define native_crc32_fold_copy crc32_fold_vpclmulqdq_copy +# undef native_crc32_fold_final +# define native_crc32_fold_final crc32_fold_vpclmulqdq_final +# undef native_crc32_fold_reset +# define native_crc32_fold_reset crc32_fold_vpclmulqdq_reset +# endif +# endif +#endif + +#endif /* X86_FUNCTIONS_H_ */ diff --git a/arch/x86/x86_intrins.h b/arch/x86/x86_intrins.h new file mode 100644 index 0000000000..a2ec0027c3 --- /dev/null +++ b/arch/x86/x86_intrins.h @@ -0,0 +1,92 @@ +#ifndef X86_INTRINS_H +#define X86_INTRINS_H + +/* Unfortunately GCC didn't support these things until version 10. + * Similarly, AppleClang didn't support them in Xcode 9.2 but did in 9.3. + */ +#ifdef __AVX2__ +#include + +#if (!defined(__clang__) && !defined(__NVCOMPILER) && defined(__GNUC__) && __GNUC__ < 10) \ + || (defined(__apple_build_version__) && __apple_build_version__ < 9020039) +static inline __m256i _mm256_zextsi128_si256(__m128i a) { + __m128i r; + __asm__ volatile ("vmovdqa %1,%0" : "=x" (r) : "x" (a)); + return _mm256_castsi128_si256(r); +} + +#ifdef __AVX512F__ +static inline __m512i _mm512_zextsi128_si512(__m128i a) { + __m128i r; + __asm__ volatile ("vmovdqa %1,%0" : "=x" (r) : "x" (a)); + return _mm512_castsi128_si512(r); +} +#endif // __AVX512F__ +#endif // gcc/AppleClang version test + +#endif // __AVX2__ + +/* GCC <9 is missing some AVX512 intrinsics. + */ +#ifdef __AVX512F__ +#if (!defined(__clang__) && !defined(__NVCOMPILER) && defined(__GNUC__) && __GNUC__ < 9) +#include + +#define PACK(c0, c1, c2, c3) (((int)(unsigned char)(c0) << 24) | ((int)(unsigned char)(c1) << 16) | \ + ((int)(unsigned char)(c2) << 8) | ((int)(unsigned char)(c3))) + +static inline __m512i _mm512_set_epi8(char __q63, char __q62, char __q61, char __q60, + char __q59, char __q58, char __q57, char __q56, + char __q55, char __q54, char __q53, char __q52, + char __q51, char __q50, char __q49, char __q48, + char __q47, char __q46, char __q45, char __q44, + char __q43, char __q42, char __q41, char __q40, + char __q39, char __q38, char __q37, char __q36, + char __q35, char __q34, char __q33, char __q32, + char __q31, char __q30, char __q29, char __q28, + char __q27, char __q26, char __q25, char __q24, + char __q23, char __q22, char __q21, char __q20, + char __q19, char __q18, char __q17, char __q16, + char __q15, char __q14, char __q13, char __q12, + char __q11, char __q10, char __q09, char __q08, + char __q07, char __q06, char __q05, char __q04, + char __q03, char __q02, char __q01, char __q00) { + return _mm512_set_epi32(PACK(__q63, __q62, __q61, __q60), PACK(__q59, __q58, __q57, __q56), + PACK(__q55, __q54, __q53, __q52), PACK(__q51, __q50, __q49, __q48), + PACK(__q47, __q46, __q45, __q44), PACK(__q43, __q42, __q41, __q40), + PACK(__q39, __q38, __q37, __q36), PACK(__q35, __q34, __q33, __q32), + PACK(__q31, __q30, __q29, __q28), PACK(__q27, __q26, __q25, __q24), + PACK(__q23, __q22, __q21, __q20), PACK(__q19, __q18, __q17, __q16), + PACK(__q15, __q14, __q13, __q12), PACK(__q11, __q10, __q09, __q08), + PACK(__q07, __q06, __q05, __q04), PACK(__q03, __q02, __q01, __q00)); +} + +#undef PACK + +#endif // gcc version test +#endif // __AVX512F__ + +/* Missing zero-extension AVX and AVX512 intrinsics. + * Fixed in Microsoft Visual Studio 2017 version 15.7 + * https://developercommunity.visualstudio.com/t/missing-zero-extension-avx-and-avx512-intrinsics/175737 + */ +#if defined(_MSC_VER) && _MSC_VER < 1914 +#ifdef __AVX2__ +static inline __m256i _mm256_zextsi128_si256(__m128i a) { + return _mm256_inserti128_si256(_mm256_setzero_si256(), a, 0); +} +#endif // __AVX2__ + +#ifdef __AVX512F__ +static inline __m512i _mm512_zextsi128_si512(__m128i a) { + return _mm512_inserti32x4(_mm512_setzero_si512(), a, 0); +} +#endif // __AVX512F__ +#endif // defined(_MSC_VER) && _MSC_VER < 1914 + +/* Visual C++ toolchains before v142 have constant overflow in AVX512 intrinsics */ +#if defined(_MSC_VER) && defined(__AVX512F__) && !defined(_MM_K0_REG8) +# undef _mm512_extracti32x4_epi32 +# define _mm512_extracti32x4_epi32(v1, e1) _mm512_maskz_extracti32x4_epi32(UINT8_MAX, v1, e1) +#endif +#endif // include guard X86_INTRINS_H diff --git a/arch_functions.h b/arch_functions.h new file mode 100644 index 0000000000..9a7f8d9379 --- /dev/null +++ b/arch_functions.h @@ -0,0 +1,29 @@ +/* arch_functions.h -- Arch-specific function prototypes. + * Copyright (C) 2017 Hans Kristian Rosbach + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef CPU_FUNCTIONS_H_ +#define CPU_FUNCTIONS_H_ + +#include "zbuild.h" +#include "zutil.h" +#include "crc32.h" +#include "deflate.h" +#include "fallback_builtins.h" + +#include "arch/generic/generic_functions.h" + +#if defined(X86_FEATURES) +# include "arch/x86/x86_functions.h" +#elif defined(ARM_FEATURES) +# include "arch/arm/arm_functions.h" +#elif defined(PPC_FEATURES) || defined(POWER_FEATURES) +# include "arch/power/power_functions.h" +#elif defined(S390_FEATURES) +# include "arch/s390/s390_functions.h" +#elif defined(RISCV_FEATURES) +# include "arch/riscv/riscv_functions.h" +#endif + +#endif diff --git a/chunkset_tpl.h b/chunkset_tpl.h new file mode 100644 index 0000000000..383b4d8f84 --- /dev/null +++ b/chunkset_tpl.h @@ -0,0 +1,283 @@ +/* chunkset_tpl.h -- inline functions to copy small data chunks. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include + +/* Returns the chunk size */ +Z_INTERNAL uint32_t CHUNKSIZE(void) { + return sizeof(chunk_t); +} + +/* Behave like memcpy, but assume that it's OK to overwrite at least + chunk_t bytes of output even if the length is shorter than this, + that the length is non-zero, and that `from` lags `out` by at least + sizeof chunk_t bytes (or that they don't overlap at all or simply that + the distance is less than the length of the copy). + + Aside from better memory bus utilisation, this means that short copies + (chunk_t bytes or fewer) will fall straight through the loop + without iteration, which will hopefully make the branch prediction more + reliable. */ +#ifndef HAVE_CHUNKCOPY +static inline uint8_t* CHUNKCOPY(uint8_t *out, uint8_t const *from, unsigned len) { + Assert(len > 0, "chunkcopy should never have a length 0"); + chunk_t chunk; + int32_t align = ((len - 1) % sizeof(chunk_t)) + 1; + loadchunk(from, &chunk); + storechunk(out, &chunk); + out += align; + from += align; + len -= align; + while (len > 0) { + loadchunk(from, &chunk); + storechunk(out, &chunk); + out += sizeof(chunk_t); + from += sizeof(chunk_t); + len -= sizeof(chunk_t); + } + return out; +} +#endif + +/* Perform short copies until distance can be rewritten as being at least + sizeof chunk_t. + + This assumes that it's OK to overwrite at least the first + 2*sizeof(chunk_t) bytes of output even if the copy is shorter than this. + This assumption holds because inflate_fast() starts every iteration with at + least 258 bytes of output space available (258 being the maximum length + output from a single token; see inflate_fast()'s assumptions below). */ +#ifndef HAVE_CHUNKUNROLL +static inline uint8_t* CHUNKUNROLL(uint8_t *out, unsigned *dist, unsigned *len) { + unsigned char const *from = out - *dist; + chunk_t chunk; + while (*dist < *len && *dist < sizeof(chunk_t)) { + loadchunk(from, &chunk); + storechunk(out, &chunk); + out += *dist; + *len -= *dist; + *dist += *dist; + } + return out; +} +#endif + +#ifndef HAVE_CHUNK_MAG +/* Loads a magazine to feed into memory of the pattern */ +static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, uint32_t *chunk_rem, uint32_t dist) { + /* This code takes string of length dist from "from" and repeats + * it for as many times as can fit in a chunk_t (vector register) */ + uint64_t cpy_dist; + uint64_t bytes_remaining = sizeof(chunk_t); + chunk_t chunk_load; + uint8_t *cur_chunk = (uint8_t *)&chunk_load; + while (bytes_remaining) { + cpy_dist = MIN(dist, bytes_remaining); + memcpy(cur_chunk, buf, (size_t)cpy_dist); + bytes_remaining -= cpy_dist; + cur_chunk += cpy_dist; + /* This allows us to bypass an expensive integer division since we're effectively + * counting in this loop, anyway */ + *chunk_rem = (uint32_t)cpy_dist; + } + + return chunk_load; +} +#endif + +#if defined(HAVE_HALF_CHUNK) && !defined(HAVE_HALFCHUNKCOPY) +static inline uint8_t* HALFCHUNKCOPY(uint8_t *out, uint8_t const *from, unsigned len) { + halfchunk_t chunk; + int32_t align = ((len - 1) % sizeof(halfchunk_t)) + 1; + loadhalfchunk(from, &chunk); + storehalfchunk(out, &chunk); + out += align; + from += align; + len -= align; + while (len > 0) { + loadhalfchunk(from, &chunk); + storehalfchunk(out, &chunk); + out += sizeof(halfchunk_t); + from += sizeof(halfchunk_t); + len -= sizeof(halfchunk_t); + } + return out; +} +#endif + +/* Copy DIST bytes from OUT - DIST into OUT + DIST * k, for 0 <= k < LEN/DIST. + Return OUT + LEN. */ +static inline uint8_t* CHUNKMEMSET(uint8_t *out, uint8_t *from, unsigned len) { + /* Debug performance related issues when len < sizeof(uint64_t): + Assert(len >= sizeof(uint64_t), "chunkmemset should be called on larger chunks"); */ + Assert(from != out, "chunkmemset cannot have a distance 0"); + + chunk_t chunk_load; + uint32_t chunk_mod = 0; + uint32_t adv_amount; + int64_t sdist = out - from; + uint64_t dist = llabs(sdist); + + /* We are supporting the case for when we are reading bytes from ahead in the buffer. + * We now have to handle this, though it wasn't _quite_ clear if this rare circumstance + * always needed to be handled here or if we're just now seeing it because we are + * dispatching to this function, more */ + if (sdist < 0 && dist < len) { +#ifdef HAVE_MASKED_READWRITE + /* We can still handle this case if we can mitigate over writing _and_ we + * fit the entirety of the copy length with one load */ + if (len <= sizeof(chunk_t)) { + /* Tempting to add a goto to the block below but hopefully most compilers + * collapse these identical code segments as one label to jump to */ + return CHUNKCOPY(out, from, len); + } +#endif + /* Here the memmove semantics match perfectly, as when this happens we are + * effectively sliding down the contents of memory by dist bytes */ + memmove(out, from, len); + return out + len; + } + + if (dist == 1) { + memset(out, *from, len); + return out + len; + } else if (dist >= sizeof(chunk_t)) { + return CHUNKCOPY(out, from, len); + } + + /* Only AVX2+ as there's 128 bit vectors and 256 bit. We allow for shorter vector + * lengths because they serve to allow more cases to fall into chunkcopy, as the + * distance of the shorter length is still deemed a safe distance. We rewrite this + * here rather than calling the ssse3 variant directly now because doing so required + * dispatching to another function and broke inlining for this function entirely. We + * also can merge an assert and some remainder peeling behavior into the same code blocks, + * making the code a little smaller. */ +#ifdef HAVE_HALF_CHUNK + if (len <= sizeof(halfchunk_t)) { + if (dist >= sizeof(halfchunk_t)) + return HALFCHUNKCOPY(out, from, len); + + if ((dist % 2) != 0 || dist == 6) { + halfchunk_t halfchunk_load = GET_HALFCHUNK_MAG(from, &chunk_mod, (unsigned)dist); + + if (len == sizeof(halfchunk_t)) { + storehalfchunk(out, &halfchunk_load); + len -= sizeof(halfchunk_t); + out += sizeof(halfchunk_t); + } + + chunk_load = halfchunk2whole(&halfchunk_load); + goto rem_bytes; + } + } +#endif + +#ifdef HAVE_CHUNKMEMSET_2 + if (dist == 2) { + chunkmemset_2(from, &chunk_load); + } else +#endif +#ifdef HAVE_CHUNKMEMSET_4 + if (dist == 4) { + chunkmemset_4(from, &chunk_load); + } else +#endif +#ifdef HAVE_CHUNKMEMSET_8 + if (dist == 8) { + chunkmemset_8(from, &chunk_load); + } else +#endif +#ifdef HAVE_CHUNKMEMSET_16 + if (dist == 16) { + chunkmemset_16(from, &chunk_load); + } else +#endif + chunk_load = GET_CHUNK_MAG(from, &chunk_mod, (unsigned)dist); + + adv_amount = sizeof(chunk_t) - chunk_mod; + + while (len >= (2 * sizeof(chunk_t))) { + storechunk(out, &chunk_load); + storechunk(out + adv_amount, &chunk_load); + out += 2 * adv_amount; + len -= 2 * adv_amount; + } + + /* If we don't have a "dist" length that divides evenly into a vector + * register, we can write the whole vector register but we need only + * advance by the amount of the whole string that fits in our chunk_t. + * If we do divide evenly into the vector length, adv_amount = chunk_t size*/ + while (len >= sizeof(chunk_t)) { + storechunk(out, &chunk_load); + len -= adv_amount; + out += adv_amount; + } + +#ifdef HAVE_HALF_CHUNK +rem_bytes: +#endif + if (len) { + memcpy(out, &chunk_load, len); + out += len; + } + + return out; +} + +Z_INTERNAL uint8_t* CHUNKMEMSET_SAFE(uint8_t *out, uint8_t *from, unsigned len, unsigned left) { +#if OPTIMAL_CMP < 32 + static const uint32_t align_mask = 7; +#elif OPTIMAL_CMP == 32 + static const uint32_t align_mask = 3; +#endif + + len = MIN(len, left); + +#if OPTIMAL_CMP < 64 + while (((uintptr_t)out & align_mask) && (len > 0)) { + *out++ = *from++; + --len; + --left; + } +#endif + +#ifndef HAVE_MASKED_READWRITE + if (UNLIKELY(left < sizeof(chunk_t))) { + while (len > 0) { + *out++ = *from++; + --len; + } + + return out; + } +#endif + + if (len) + out = CHUNKMEMSET(out, from, len); + + return out; +} + +static inline uint8_t *CHUNKCOPY_SAFE(uint8_t *out, uint8_t *from, uint64_t len, uint8_t *safe) +{ + if (out == from) + return out + len; + + uint64_t safelen = (safe - out); + len = MIN(len, safelen); + +#ifndef HAVE_MASKED_READWRITE + uint64_t from_dist = (uint64_t)llabs(safe - from); + if (UNLIKELY(from_dist < sizeof(chunk_t) || safelen < sizeof(chunk_t))) { + while (len--) { + *out++ = *from++; + } + + return out; + } +#endif + + return CHUNKMEMSET(out, from, (unsigned)len); +} diff --git a/cmake/detect-arch.c b/cmake/detect-arch.c new file mode 100644 index 0000000000..b78b4af2a9 --- /dev/null +++ b/cmake/detect-arch.c @@ -0,0 +1,115 @@ +// archdetect.c -- Detect compiler architecture and raise preprocessor error +// containing a simple arch identifier. +// Copyright (C) 2019 Hans Kristian Rosbach +// Licensed under the Zlib license, see LICENSE.md for details + +// x86_64 +#if defined(__x86_64__) || defined(_M_X64) + #error archfound x86_64 + +// x86 +#elif defined(__i386) || defined(_M_IX86) + #error archfound i686 + +// ARM +#elif defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC) + #error archfound aarch64 +#elif defined(__arm__) || defined(__arm) || defined(_M_ARM) || defined(__TARGET_ARCH_ARM) + #if defined(__ARM64_ARCH_8__) || defined(__ARMv8__) || defined(__ARMv8_A__) + #error archfound armv8 + #elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) + #error archfound armv7 + #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6M__) + #error archfound armv6 + #elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__) + #error archfound armv5 + #elif defined(__ARM_ARCH_4T__) || defined(__TARGET_ARCH_5E__) + #error archfound armv4 + #elif defined(__ARM_ARCH_3__) || defined(__TARGET_ARCH_3M__) + #error archfound armv3 + #elif defined(__ARM_ARCH_2__) + #error archfound armv2 + #endif + +// PowerPC +#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) + #if defined(__64BIT__) || defined(__powerpc64__) || defined(__ppc64__) + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #error archfound powerpc64le + #else + #error archfound powerpc64 + #endif + #else + #error archfound powerpc + #endif + +// --------------- Less common architectures alphabetically below --------------- + +// ALPHA +#elif defined(__alpha__) || defined(__alpha) + #error archfound alpha + +// Blackfin +#elif defined(__BFIN__) + #error archfound blackfin + +// Itanium +#elif defined(__ia64) || defined(_M_IA64) + #error archfound ia64 + +// MIPS +#elif defined(__mips__) || defined(__mips) + #error archfound mips + +// Motorola 68000-series +#elif defined(__m68k__) + #error archfound m68k + +// SuperH +#elif defined(__sh__) + #error archfound sh + +// SPARC +#elif defined(__sparc__) || defined(__sparc) + #if defined(__sparcv9) || defined(__sparc_v9__) + #error archfound sparc9 + #elif defined(__sparcv8) || defined(__sparc_v8__) + #error archfound sparc8 + #endif + +// SystemZ +#elif defined(__370__) + #error archfound s370 +#elif defined(__s390__) + #error archfound s390 +#elif defined(__s390x) || defined(__zarch__) + #error archfound s390x + +// PARISC +#elif defined(__hppa__) + #error archfound parisc + +// RS-6000 +#elif defined(__THW_RS6000) + #error archfound rs6000 + +// RISC-V +#elif defined(__riscv) + #if __riscv_xlen == 64 + #error archfound riscv64 + #elif __riscv_xlen == 32 + #error archfound riscv32 + #endif + +// LOONGARCH +#elif defined(__loongarch_lp64) + #error archfound loongarch64 + +// Emscripten (WebAssembly) +#elif defined(__EMSCRIPTEN__) + #error archfound wasm32 + +// return 'unrecognized' if we do not know what architecture this is +#else + #error archfound unrecognized +#endif diff --git a/cmake/detect-arch.cmake b/cmake/detect-arch.cmake new file mode 100644 index 0000000000..dfdc6013ce --- /dev/null +++ b/cmake/detect-arch.cmake @@ -0,0 +1,104 @@ +# detect-arch.cmake -- Detect compiler architecture and set ARCH and BASEARCH +# Copyright (C) 2019 Hans Kristian Rosbach +# Licensed under the Zlib license, see LICENSE.md for details +set(ARCHDETECT_FOUND TRUE) + +if(CMAKE_OSX_ARCHITECTURES) + # If multiple architectures are requested (universal build), pick only the first + list(GET CMAKE_OSX_ARCHITECTURES 0 ARCH) +elseif(MSVC) + if("${MSVC_C_ARCHITECTURE_ID}" STREQUAL "X86") + set(ARCH "i686") + elseif("${MSVC_C_ARCHITECTURE_ID}" STREQUAL "x64") + set(ARCH "x86_64") + elseif("${MSVC_C_ARCHITECTURE_ID}" STREQUAL "ARM" OR "${MSVC_C_ARCHITECTURE_ID}" STREQUAL "ARMV7") + set(ARCH "arm") + elseif ("${MSVC_C_ARCHITECTURE_ID}" STREQUAL "ARM64" OR "${MSVC_C_ARCHITECTURE_ID}" STREQUAL "ARM64EC") + set(ARCH "aarch64") + endif() +elseif(EMSCRIPTEN) + set(ARCH "wasm32") +elseif(CMAKE_CROSSCOMPILING) + set(ARCH ${CMAKE_C_COMPILER_TARGET}) +else() + # Let preprocessor parse archdetect.c and raise an error containing the arch identifier + enable_language(C) + try_run( + run_result_unused + compile_result_unused + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_LIST_DIR}/detect-arch.c + COMPILE_OUTPUT_VARIABLE RAWOUTPUT + CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} + ) + + # Find basearch tag, and extract the arch word into BASEARCH variable + string(REGEX REPLACE ".*archfound ([a-zA-Z0-9_]+).*" "\\1" ARCH "${RAWOUTPUT}") + if(NOT ARCH) + set(ARCH unknown) + endif() +endif() + +# Make sure we have ARCH set +if(NOT ARCH OR ARCH STREQUAL "unknown") + set(ARCH ${CMAKE_SYSTEM_PROCESSOR}) + message(STATUS "Arch not recognized, falling back to cmake arch: '${ARCH}'") +else() + message(STATUS "Arch detected: '${ARCH}'") +endif() + +# Base arch detection +if("${ARCH}" MATCHES "(x86_64|AMD64|i[3-6]86)") + set(BASEARCH "x86") + set(BASEARCH_X86_FOUND TRUE) +elseif("${ARCH}" MATCHES "(arm(v[0-9])?|aarch64|cortex)") + set(BASEARCH "arm") + set(BASEARCH_ARM_FOUND TRUE) +elseif("${ARCH}" MATCHES "ppc(64(le)?)?|powerpc(64(le)?)?") + set(BASEARCH "ppc") + set(BASEARCH_PPC_FOUND TRUE) +elseif("${ARCH}" MATCHES "alpha") + set(BASEARCH "alpha") + set(BASEARCH_ALPHA_FOUND TRUE) +elseif("${ARCH}" MATCHES "blackfin") + set(BASEARCH "blackfin") + set(BASEARCH_BLACKFIN_FOUND TRUE) +elseif("${ARCH}" MATCHES "ia64") + set(BASEARCH "ia64") + set(BASEARCH_IA64_FOUND TRUE) +elseif("${ARCH}" MATCHES "mips") + set(BASEARCH "mips") + set(BASEARCH_MIPS_FOUND TRUE) +elseif("${ARCH}" MATCHES "m68k") + set(BASEARCH "m68k") + set(BASEARCH_M68K_FOUND TRUE) +elseif("${ARCH}" MATCHES "sh") + set(BASEARCH "sh") + set(BASEARCH_SH_FOUND TRUE) +elseif("${ARCH}" MATCHES "sparc[89]?") + set(BASEARCH "sparc") + set(BASEARCH_SPARC_FOUND TRUE) +elseif("${ARCH}" MATCHES "s3[679]0x?") + set(BASEARCH "s360") + set(BASEARCH_S360_FOUND TRUE) +elseif("${ARCH}" MATCHES "parisc") + set(BASEARCH "parisc") + set(BASEARCH_PARISC_FOUND TRUE) +elseif("${ARCH}" MATCHES "rs6000") + set(BASEARCH "rs6000") + set(BASEARCH_RS6000_FOUND TRUE) +elseif("${ARCH}" MATCHES "riscv(32|64)") + set(BASEARCH "riscv") + set(BASEARCH_RISCV_FOUND TRUE) +elseif("${ARCH}" MATCHES "loongarch64") + set(BASEARCH "loongarch") + set(BASEARCH_LOONGARCH_FOUND TRUE) +elseif("${ARCH}" MATCHES "wasm32") + set(BASEARCH "wasm32") + set(BASEARCH_WASM32_FOUND TRUE) +else() + set(BASEARCH "x86") + set(BASEARCH_X86_FOUND TRUE) + message(STATUS "Basearch '${ARCH}' not recognized, defaulting to 'x86'.") +endif() +message(STATUS "Basearch of '${ARCH}' has been detected as: '${BASEARCH}'") diff --git a/cmake/detect-coverage.cmake b/cmake/detect-coverage.cmake new file mode 100644 index 0000000000..8e67a085cd --- /dev/null +++ b/cmake/detect-coverage.cmake @@ -0,0 +1,46 @@ +# detect-coverage.cmake -- Detect supported compiler coverage flags +# Licensed under the Zlib license, see LICENSE.md for details + +macro(add_code_coverage) + # Check for -coverage flag support for Clang/GCC + if(CMAKE_VERSION VERSION_LESS 3.14) + set(CMAKE_REQUIRED_LIBRARIES -lgcov) + else() + set(CMAKE_REQUIRED_LINK_OPTIONS -coverage) + endif() + check_c_compiler_flag(-coverage HAVE_COVERAGE) + set(CMAKE_REQUIRED_LIBRARIES) + set(CMAKE_REQUIRED_LINK_OPTIONS) + + if(HAVE_COVERAGE) + add_compile_options(-coverage) + add_link_options(-coverage) + message(STATUS "Code coverage enabled using: -coverage") + else() + # Some versions of GCC don't support -coverage shorthand + if(CMAKE_VERSION VERSION_LESS 3.14) + set(CMAKE_REQUIRED_LIBRARIES -lgcov) + else() + set(CMAKE_REQUIRED_LINK_OPTIONS -lgcov -fprofile-arcs) + endif() + check_c_compiler_flag("-ftest-coverage -fprofile-arcs -fprofile-values" HAVE_TEST_COVERAGE) + set(CMAKE_REQUIRED_LIBRARIES) + set(CMAKE_REQUIRED_LINK_OPTIONS) + + if(HAVE_TEST_COVERAGE) + add_compile_options(-ftest-coverage -fprofile-arcs -fprofile-values) + add_link_options(-lgcov -fprofile-arcs) + message(STATUS "Code coverage enabled using: -ftest-coverage") + else() + message(WARNING "Compiler does not support code coverage") + set(WITH_CODE_COVERAGE OFF) + endif() + endif() + + # Set optimization level to zero for code coverage builds + if (WITH_CODE_COVERAGE) + # Use CMake compiler flag variables due to add_compile_options failure on Windows GCC + set(CMAKE_C_FLAGS "-O0 ${CMAKE_C_FLAGS}") + set(CMAKE_CXX_FLAGS "-O0 ${CMAKE_CXX_FLAGS}") + endif() +endmacro() diff --git a/cmake/detect-install-dirs.cmake b/cmake/detect-install-dirs.cmake new file mode 100644 index 0000000000..a7c774f474 --- /dev/null +++ b/cmake/detect-install-dirs.cmake @@ -0,0 +1,43 @@ +# detect-install-dirs.cmake -- Detect install directory parameters +# Copyright (C) 2021 Hans Kristian Rosbach +# Licensed under the Zlib license, see LICENSE.md for details + +# Determine installation directory for executables +if (DEFINED BIN_INSTALL_DIR) + set(BIN_INSTALL_DIR "${BIN_INSTALL_DIR}" CACHE PATH "Installation directory for executables (Deprecated)" FORCE) + set(CMAKE_INSTALL_BINDIR "${BIN_INSTALL_DIR}") +elseif (DEFINED INSTALL_BIN_DIR) + set(CMAKE_INSTALL_BINDIR "${INSTALL_BIN_DIR}") +endif() + +# Determine installation directory for libraries +if (DEFINED LIB_INSTALL_DIR) + set(LIB_INSTALL_DIR "${LIB_INSTALL_DIR}" CACHE PATH "Installation directory for libraries (Deprecated)" FORCE) + set(CMAKE_INSTALL_LIBDIR "${LIB_INSTALL_DIR}") +elseif (DEFINED INSTALL_LIB_DIR) + set(CMAKE_INSTALL_LIBDIR "${INSTALL_LIB_DIR}") +endif() + +# Determine installation directory for include files +if (DEFINED INC_INSTALL_DIR) + set(INC_INSTALL_DIR "${INC_INSTALL_DIR}" CACHE PATH "Installation directory for headers (Deprecated)" FORCE) + set(CMAKE_INSTALL_INCLUDEDIR "${INC_INSTALL_DIR}") +elseif (DEFINED INSTALL_INC_DIR) + set(CMAKE_INSTALL_INCLUDEDIR "${INSTALL_INC_DIR}") +endif() + +# Define GNU standard installation directories +include(GNUInstallDirs) + +# Determine installation directory for pkgconfig files +if (DEFINED PKGCONFIG_INSTALL_DIR) + set(PKGCONFIG_INSTALL_DIR "${PKGCONFIG_INSTALL_DIR}" CACHE PATH "Installation directory for pkgconfig (.pc) files" FORCE) +elseif (DEFINED INSTALL_PKGCONFIG_DIR) + set(PKGCONFIG_INSTALL_DIR "${INSTALL_PKGCONFIG_DIR}" CACHE PATH "Installation directory for pkgconfig (.pc) files" FORCE) +elseif (DEFINED CMAKE_INSTALL_PKGCONFIGDIR) + set(PKGCONFIG_INSTALL_DIR "${CMAKE_INSTALL_PKGCONFIGDIR}" CACHE PATH "Installation directory for pkgconfig (.pc) files" FORCE) +elseif (DEFINED CMAKE_INSTALL_FULL_PKGCONFIGDIR) + set(PKGCONFIG_INSTALL_DIR "${CMAKE_INSTALL_FULL_PKGCONFIGDIR}" CACHE PATH "Installation directory for pkgconfig (.pc) files" FORCE) +else() + set(PKGCONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") +endif() diff --git a/cmake/detect-intrinsics.cmake b/cmake/detect-intrinsics.cmake new file mode 100644 index 0000000000..b96ac0a442 --- /dev/null +++ b/cmake/detect-intrinsics.cmake @@ -0,0 +1,604 @@ +# detect-intrinsics.cmake -- Detect compiler intrinsics support +# Licensed under the Zlib license, see LICENSE.md for details + +macro(check_acle_compiler_flag) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + check_c_compiler_flag("-march=armv8-a+crc" HAVE_MARCH_ARMV8_CRC) + if(HAVE_MARCH_ARMV8_CRC) + set(ACLEFLAG "-march=armv8-a+crc" CACHE INTERNAL "Compiler option to enable ACLE support") + else() + check_c_compiler_flag("-march=armv8-a+crc+simd" HAVE_MARCH_ARMV8_CRC_SIMD) + if(HAVE_MARCH_ARMV8_CRC_SIMD) + set(ACLEFLAG "-march=armv8-a+crc+simd" CACHE INTERNAL "Compiler option to enable ACLE support") + endif() + endif() + endif() + endif() + # Check whether compiler supports ARMv8 CRC intrinsics + set(CMAKE_REQUIRED_FLAGS "${ACLEFLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#if defined(_MSC_VER) + #include + #else + #include + #endif + unsigned int f(unsigned int a, unsigned int b) { + return __crc32w(a, b); + } + int main(void) { return 0; }" + HAVE_ACLE_FLAG + ) + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_armv6_compiler_flag) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + check_c_compiler_flag("-march=armv6" HAVE_MARCH_ARMV6) + if(HAVE_MARCH_ARMV6) + set(ARMV6FLAG "-march=armv6" CACHE INTERNAL "Compiler option to enable ARMv6 support") + endif() + endif() + endif() + # Check whether compiler supports ARMv6 inline asm + set(CMAKE_REQUIRED_FLAGS "${ARMV6FLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "unsigned int f(unsigned int a, unsigned int b) { + unsigned int c; + __asm__ __volatile__ ( \"uqsub16 %0, %1, %2\" : \"=r\" (c) : \"r\" (a), \"r\" (b) ); + return (int)c; + } + int main(void) { return f(1,2); }" + HAVE_ARMV6_INLINE_ASM + ) + # Check whether compiler supports ARMv6 intrinsics + check_c_source_compiles( + "#if defined(_MSC_VER) + #include + #else + #include + #endif + unsigned int f(unsigned int a, unsigned int b) { + #if defined(_MSC_VER) + return _arm_uqsub16(a, b); + #else + return __uqsub16(a, b); + #endif + } + int main(void) { return f(1,2); }" + HAVE_ARMV6_INTRIN + ) + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_avx512_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "Intel") + if(CMAKE_HOST_UNIX OR APPLE) + set(AVX512FLAG "-mavx512f -mavx512dq -mavx512bw -mavx512vl -mbmi2") + else() + set(AVX512FLAG "/arch:AVX512") + endif() + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + # For CPUs that can benefit from AVX512, it seems GCC generates suboptimal + # instruction scheduling unless you specify a reasonable -mtune= target + set(AVX512FLAG "-mavx512f -mavx512dq -mavx512bw -mavx512vl -mbmi2") + if(NOT MSVC) + check_c_compiler_flag("-mtune=cascadelake" HAVE_CASCADE_LAKE) + if(HAVE_CASCADE_LAKE) + set(AVX512FLAG "${AVX512FLAG} -mtune=cascadelake") + else() + set(AVX512FLAG "${AVX512FLAG} -mtune=skylake-avx512") + endif() + unset(HAVE_CASCADE_LAKE) + endif() + elseif(MSVC) + set(AVX512FLAG "/arch:AVX512") + endif() + endif() + # Check whether compiler supports AVX512 intrinsics + set(CMAKE_REQUIRED_FLAGS "${AVX512FLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + __m512i f(__m512i y) { + __m512i x = _mm512_set1_epi8(2); + return _mm512_sub_epi8(x, y); + } + int main(void) { return 0; }" + HAVE_AVX512_INTRIN + ) +endmacro() + +macro(check_avx512vnni_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "Intel") + if(CMAKE_HOST_UNIX OR APPLE OR CMAKE_C_COMPILER_ID MATCHES "IntelLLVM") + set(AVX512VNNIFLAG "-mavx512f -mavx512dq -mavx512bw -mavx512vl -mavx512vnni -mbmi2") + else() + set(AVX512VNNIFLAG "/arch:AVX512") + endif() + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + set(AVX512VNNIFLAG "-mavx512f -mavx512dq -mavx512bw -mavx512vl -mavx512vnni -mbmi2") + if(NOT MSVC) + check_c_compiler_flag("-mtune=cascadelake" HAVE_CASCADE_LAKE) + if(HAVE_CASCADE_LAKE) + set(AVX512VNNIFLAG "${AVX512VNNIFLAG} -mtune=cascadelake") + else() + set(AVX512VNNIFLAG "${AVX512VNNIFLAG} -mtune=skylake-avx512") + endif() + unset(HAVE_CASCADE_LAKE) + endif() + elseif(MSVC) + set(AVX512VNNIFLAG "/arch:AVX512") + endif() + endif() + # Check whether compiler supports AVX512vnni intrinsics + set(CMAKE_REQUIRED_FLAGS "${AVX512VNNIFLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + __m512i f(__m512i x, __m512i y) { + __m512i z = _mm512_setzero_epi32(); + return _mm512_dpbusd_epi32(z, x, y); + } + int main(void) { return 0; }" + HAVE_AVX512VNNI_INTRIN + ) + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_avx2_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "Intel") + if(CMAKE_HOST_UNIX OR APPLE) + set(AVX2FLAG "-mavx2 -mbmi2") + else() + set(AVX2FLAG "/arch:AVX2") + endif() + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + set(AVX2FLAG "-mavx2 -mbmi2") + elseif(MSVC) + set(AVX2FLAG "/arch:AVX2") + endif() + endif() + # Check whether compiler supports AVX2 intrinics + set(CMAKE_REQUIRED_FLAGS "${AVX2FLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + __m256i f(__m256i x) { + const __m256i y = _mm256_set1_epi16(1); + return _mm256_subs_epu16(x, y); + } + int main(void) { return 0; }" + HAVE_AVX2_INTRIN + ) + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_neon_compiler_flag) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + if("${ARCH}" MATCHES "aarch64") + set(NEONFLAG "-march=armv8-a+simd") + else() + set(NEONFLAG "-mfpu=neon") + endif() + endif() + endif() + # Check whether compiler supports NEON flag + set(CMAKE_REQUIRED_FLAGS "${NEONFLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#if defined(_M_ARM64) || defined(_M_ARM64EC) + # include + #else + # include + #endif + int main() { return 0; }" + NEON_AVAILABLE FAIL_REGEX "not supported") + # Check whether compiler native flag is enough for NEON support + # Some GCC versions don't enable FPU (vector unit) when using -march=native + if(NEON_AVAILABLE AND NATIVEFLAG AND (NOT "${ARCH}" MATCHES "aarch64")) + check_c_source_compiles( + "#include + uint8x16_t f(uint8x16_t x, uint8x16_t y) { + return vaddq_u8(x, y); + } + int main(int argc, char* argv[]) { + uint8x16_t a = vdupq_n_u8(argc); + uint8x16_t b = vdupq_n_u8(argc); + uint8x16_t result = f(a, b); + return result[0]; + }" + ARM_NEON_SUPPORT_NATIVE + ) + if(NOT ARM_NEON_SUPPORT_NATIVE) + set(CMAKE_REQUIRED_FLAGS "${NATIVEFLAG} -mfpu=neon ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + uint8x16_t f(uint8x16_t x, uint8x16_t y) { + return vaddq_u8(x, y); + } + int main(int argc, char* argv[]) { + uint8x16_t a = vdupq_n_u8(argc); + uint8x16_t b = vdupq_n_u8(argc); + uint8x16_t result = f(a, b); + return result[0]; + }" + ARM_NEON_SUPPORT_NATIVE_MFPU + ) + if(ARM_NEON_SUPPORT_NATIVE_MFPU) + set(NEONFLAG "-mfpu=neon") + else() + # Remove local NEON_AVAILABLE variable and overwrite the cache + unset(NEON_AVAILABLE) + set(NEON_AVAILABLE "" CACHE INTERNAL "NEON support available" FORCE) + endif() + endif() + endif() + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_neon_ld4_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + if("${ARCH}" MATCHES "aarch64") + set(NEONFLAG "-march=armv8-a+simd") + else() + set(NEONFLAG "-mfpu=neon") + endif() + endif() + endif() + # Check whether compiler supports loading 4 neon vecs into a register range + set(CMAKE_REQUIRED_FLAGS "${NEONFLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC)) + # include + #else + # include + #endif + int32x4x4_t f(int var[16]) { return vld1q_s32_x4(var); } + int main(void) { return 0; }" + NEON_HAS_LD4) + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_pclmulqdq_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "IntelLLVM") + set(PCLMULFLAG "-mpclmul") + endif() + endif() + # Check whether compiler supports PCLMULQDQ intrinsics + if(NOT (APPLE AND "${ARCH}" MATCHES "i386")) + # The pclmul code currently crashes on Mac in 32bit mode. Avoid for now. + set(CMAKE_REQUIRED_FLAGS "${PCLMULFLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + #include + __m128i f(__m128i a, __m128i b) { return _mm_clmulepi64_si128(a, b, 0x10); } + int main(void) { return 0; }" + HAVE_PCLMULQDQ_INTRIN + ) + set(CMAKE_REQUIRED_FLAGS) + else() + set(HAVE_PCLMULQDQ_INTRIN OFF) + endif() +endmacro() + +macro(check_vpclmulqdq_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "IntelLLVM") + set(VPCLMULFLAG "-mvpclmulqdq -mavx512f") + endif() + endif() + # Check whether compiler supports VPCLMULQDQ intrinsics + if(NOT (APPLE AND "${ARCH}" MATCHES "i386")) + set(CMAKE_REQUIRED_FLAGS "${VPCLMULFLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + #include + __m512i f(__m512i a) { + __m512i b = _mm512_setzero_si512(); + return _mm512_clmulepi64_epi128(a, b, 0x10); + } + int main(void) { return 0; }" + HAVE_VPCLMULQDQ_INTRIN + ) + set(CMAKE_REQUIRED_FLAGS) + else() + set(HAVE_VPCLMULQDQ_INTRIN OFF) + endif() +endmacro() + +macro(check_ppc_intrinsics) + # Check if compiler supports AltiVec + set(CMAKE_REQUIRED_FLAGS "-maltivec ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + int main(void) + { + vector int a = vec_splats(0); + vector int b = vec_splats(0); + a = vec_add(a, b); + return 0; + }" + HAVE_ALTIVEC + ) + set(CMAKE_REQUIRED_FLAGS) + + if(HAVE_ALTIVEC) + set(PPCFLAGS "-maltivec") + endif() + + set(CMAKE_REQUIRED_FLAGS "-maltivec -mno-vsx ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + int main(void) + { + vector int a = vec_splats(0); + vector int b = vec_splats(0); + a = vec_add(a, b); + return 0; + }" + HAVE_NOVSX + ) + set(CMAKE_REQUIRED_FLAGS) + + if(HAVE_NOVSX) + set(PPCFLAGS "${PPCFLAGS} -mno-vsx") + endif() + + # Check if we have what we need for AltiVec optimizations + set(CMAKE_REQUIRED_FLAGS "${PPCFLAGS} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + #ifdef __FreeBSD__ + #include + #endif + int main() { + #ifdef __FreeBSD__ + unsigned long hwcap; + elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); + return (hwcap & PPC_FEATURE_HAS_ALTIVEC); + #else + return (getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC); + #endif + }" + HAVE_VMX + ) + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_power8_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + set(POWER8FLAG "-mcpu=power8") + endif() + endif() + # Check if we have what we need for POWER8 optimizations + set(CMAKE_REQUIRED_FLAGS "${POWER8FLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + #ifdef __FreeBSD__ + #include + #endif + int main() { + #ifdef __FreeBSD__ + unsigned long hwcap; + elf_aux_info(AT_HWCAP2, &hwcap, sizeof(hwcap)); + return (hwcap & PPC_FEATURE2_ARCH_2_07); + #else + return (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07); + #endif + }" + HAVE_POWER8_INTRIN + ) + if(NOT HAVE_POWER8_INTRIN AND HAVE_LINUX_AUXVEC_H) + check_c_source_compiles( + "#include + #include + int main() { + return (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07); + }" + HAVE_POWER8_INTRIN2 + ) + if(HAVE_POWER8_INTRIN2) + set(POWER8_NEED_AUXVEC_H 1) + set(HAVE_POWER8_INTRIN ${HAVE_POWER8_INTRIN2} CACHE INTERNAL "Have POWER8 intrinsics" FORCE) + unset(HAVE_POWER8_INTRIN2 CACHE) + endif() + endif() + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_rvv_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + set(RISCVFLAG "-march=rv64gcv") + endif() + endif() + # Check whether compiler supports RVV + set(CMAKE_REQUIRED_FLAGS "${RISCVFLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + int main() { + return 0; + }" + HAVE_RVV_INTRIN + ) + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_s390_intrinsics) + check_c_source_compiles( + "#include + #ifndef HWCAP_S390_VXRS + #define HWCAP_S390_VXRS (1 << 11) + #endif + int main() { + return (getauxval(AT_HWCAP) & HWCAP_S390_VXRS); + }" + HAVE_S390_INTRIN + ) +endmacro() + +macro(check_power9_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + set(POWER9FLAG "-mcpu=power9") + endif() + endif() + # Check if we have what we need for POWER9 optimizations + set(CMAKE_REQUIRED_FLAGS "${POWER9FLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + #ifdef __FreeBSD__ + #include + #endif + int main() { + #ifdef __FreeBSD__ + unsigned long hwcap; + elf_aux_info(AT_HWCAP2, &hwcap, sizeof(hwcap)); + return (hwcap & PPC_FEATURE2_ARCH_3_00); + #else + return (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00); + #endif + }" + HAVE_POWER9_INTRIN + ) + if(NOT HAVE_POWER9_INTRIN AND HAVE_LINUX_AUXVEC_H) + check_c_source_compiles( + "#include + #include + int main() { + return (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00); + }" + HAVE_POWER9_INTRIN2 + ) + if(HAVE_POWER9_INTRIN2) + set(POWER9_NEED_AUXVEC_H 1) + set(HAVE_POWER9_INTRIN ${HAVE_POWER9_INTRIN2} CACHE INTERNAL "Have POWER9 intrinsics" FORCE) + unset(HAVE_POWER9_INTRIN2 CACHE) + endif() + endif() + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_sse2_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "Intel") + if(CMAKE_HOST_UNIX OR APPLE) + set(SSE2FLAG "-msse2") + else() + set(SSE2FLAG "/arch:SSE2") + endif() + elseif(MSVC) + if(NOT "${ARCH}" MATCHES "x86_64") + set(SSE2FLAG "/arch:SSE2") + endif() + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + set(SSE2FLAG "-msse2") + endif() + endif() + # Check whether compiler supports SSE2 intrinsics + set(CMAKE_REQUIRED_FLAGS "${SSE2FLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + __m128i f(__m128i x, __m128i y) { return _mm_sad_epu8(x, y); } + int main(void) { return 0; }" + HAVE_SSE2_INTRIN + ) + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_ssse3_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "Intel") + if(CMAKE_HOST_UNIX OR APPLE) + set(SSSE3FLAG "-mssse3") + else() + set(SSSE3FLAG "/arch:SSSE3") + endif() + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + set(SSSE3FLAG "-mssse3") + endif() + endif() + # Check whether compiler supports SSSE3 intrinsics + set(CMAKE_REQUIRED_FLAGS "${SSSE3FLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + __m128i f(__m128i u) { + __m128i v = _mm_set1_epi32(1); + return _mm_hadd_epi32(u, v); + } + int main(void) { return 0; }" + HAVE_SSSE3_INTRIN + ) +endmacro() + +macro(check_sse42_intrinsics) + if(NOT NATIVEFLAG) + if(CMAKE_C_COMPILER_ID MATCHES "Intel") + if(CMAKE_HOST_UNIX OR APPLE) + set(SSE42FLAG "-msse4.2") + else() + set(SSE42FLAG "/arch:SSE4.2") + endif() + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + set(SSE42FLAG "-msse4.2") + endif() + endif() + # Check whether compiler supports SSE4.2 intrinsics + set(CMAKE_REQUIRED_FLAGS "${SSE42FLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + unsigned int f(unsigned int a, unsigned int b) { return _mm_crc32_u32(a, b); } + int main(void) { return 0; }" + HAVE_SSE42_INTRIN + ) + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_vgfma_intrinsics) + if(NOT NATIVEFLAG) + set(VGFMAFLAG "-march=z13") + if(CMAKE_C_COMPILER_ID MATCHES "GNU") + set(VGFMAFLAG "${VGFMAFLAG} -mzarch") + endif() + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(VGFMAFLAG "${VGFMAFLAG} -fzvector") + endif() + endif() + # Check whether compiler supports "VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE" intrinsic + set(CMAKE_REQUIRED_FLAGS "${VGFMAFLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#include + int main(void) { + unsigned long long a __attribute__((vector_size(16))) = { 0 }; + unsigned long long b __attribute__((vector_size(16))) = { 0 }; + unsigned char c __attribute__((vector_size(16))) = { 0 }; + c = vec_gfmsum_accum_128(a, b, c); + return c[0]; + }" + HAVE_VGFMA_INTRIN FAIL_REGEX "not supported") + set(CMAKE_REQUIRED_FLAGS) +endmacro() + +macro(check_xsave_intrinsics) + if(NOT NATIVEFLAG AND NOT MSVC AND NOT CMAKE_C_COMPILER_ID MATCHES "Intel") + set(XSAVEFLAG "-mxsave") + endif() + set(CMAKE_REQUIRED_FLAGS "${XSAVEFLAG} ${NATIVEFLAG} ${ZNOLTOFLAG}") + check_c_source_compiles( + "#ifdef _MSC_VER + # include + #elif __GNUC__ == 8 && __GNUC_MINOR__ > 1 + # include + #else + # include + #endif + unsigned int f(unsigned int a) { return (int) _xgetbv(a); } + int main(void) { return 0; }" + HAVE_XSAVE_INTRIN FAIL_REGEX "not supported") + set(CMAKE_REQUIRED_FLAGS) +endmacro() diff --git a/cmake/detect-sanitizer.cmake b/cmake/detect-sanitizer.cmake new file mode 100644 index 0000000000..b71c1a37f3 --- /dev/null +++ b/cmake/detect-sanitizer.cmake @@ -0,0 +1,157 @@ +# detect-sanitizer.cmake -- Detect supported compiler sanitizer flags +# Licensed under the Zlib license, see LICENSE.md for details + +macro(add_common_sanitizer_flags) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + add_compile_options(-g3) + endif() + check_c_compiler_flag(-fno-omit-frame-pointer HAVE_NO_OMIT_FRAME_POINTER) + if(HAVE_NO_OMIT_FRAME_POINTER) + add_compile_options(-fno-omit-frame-pointer) + add_link_options(-fno-omit-frame-pointer) + endif() + check_c_compiler_flag(-fno-optimize-sibling-calls HAVE_NO_OPTIMIZE_SIBLING_CALLS) + if(HAVE_NO_OPTIMIZE_SIBLING_CALLS) + add_compile_options(-fno-optimize-sibling-calls) + add_link_options(-fno-optimize-sibling-calls) + endif() +endmacro() + +macro(check_sanitizer_support known_checks supported_checks) + set(available_checks "") + + # Build list of supported sanitizer flags by incrementally trying compilation with + # known sanitizer checks + + foreach(check ${known_checks}) + if(available_checks STREQUAL "") + set(compile_checks "${check}") + else() + set(compile_checks "${available_checks},${check}") + endif() + + set(CMAKE_REQUIRED_FLAGS -fsanitize=${compile_checks}) + + check_c_source_compiles("int main() { return 0; }" HAVE_SANITIZER_${check} + FAIL_REGEX "not supported|unrecognized command|unknown option") + + set(CMAKE_REQUIRED_FLAGS) + + if(HAVE_SANITIZER_${check}) + set(available_checks ${compile_checks}) + endif() + endforeach() + + set(${supported_checks} ${available_checks}) +endmacro() + +macro(add_address_sanitizer) + set(known_checks + address + pointer-compare + pointer-subtract + ) + + check_sanitizer_support("${known_checks}" supported_checks) + if(NOT ${supported_checks} STREQUAL "") + message(STATUS "Address sanitizer is enabled: ${supported_checks}") + add_compile_options(-fsanitize=${supported_checks}) + add_link_options(-fsanitize=${supported_checks}) + add_common_sanitizer_flags() + else() + message(STATUS "Address sanitizer is not supported") + endif() + + if(CMAKE_CROSSCOMPILING_EMULATOR) + # Only check for leak sanitizer if not cross-compiling due to qemu crash + message(WARNING "Leak sanitizer is not supported when cross compiling") + else() + # Leak sanitizer requires address sanitizer + check_sanitizer_support("leak" supported_checks) + if(NOT ${supported_checks} STREQUAL "") + message(STATUS "Leak sanitizer is enabled: ${supported_checks}") + add_compile_options(-fsanitize=${supported_checks}) + add_link_options(-fsanitize=${supported_checks}) + add_common_sanitizer_flags() + else() + message(STATUS "Leak sanitizer is not supported") + endif() + endif() +endmacro() + +macro(add_memory_sanitizer) + check_sanitizer_support("memory" supported_checks) + if(NOT ${supported_checks} STREQUAL "") + message(STATUS "Memory sanitizer is enabled: ${supported_checks}") + add_compile_options(-fsanitize=${supported_checks}) + add_link_options(-fsanitize=${supported_checks}) + add_common_sanitizer_flags() + + check_c_compiler_flag(-fsanitize-memory-track-origins HAVE_MEMORY_TRACK_ORIGINS) + if(HAVE_MEMORY_TRACK_ORIGINS) + add_compile_options(-fsanitize-memory-track-origins) + add_link_options(-fsanitize-memory-track-origins) + endif() + else() + message(STATUS "Memory sanitizer is not supported") + endif() +endmacro() + +macro(add_thread_sanitizer) + check_sanitizer_support("thread" supported_checks) + if(NOT ${supported_checks} STREQUAL "") + message(STATUS "Thread sanitizer is enabled: ${supported_checks}") + add_compile_options(-fsanitize=${supported_checks}) + add_link_options(-fsanitize=${supported_checks}) + add_common_sanitizer_flags() + else() + message(STATUS "Thread sanitizer is not supported") + endif() +endmacro() + +macro(add_undefined_sanitizer) + set(known_checks + alignment + array-bounds + bool + bounds + builtin + enum + float-cast-overflow + float-divide-by-zero + function + integer-divide-by-zero + local-bounds + null + nonnull-attribute + pointer-overflow + return + returns-nonnull-attribute + shift + shift-base + shift-exponent + signed-integer-overflow + undefined + unsigned-integer-overflow + unsigned-shift-base + vla-bound + vptr + ) + + # Object size sanitizer has no effect at -O0 and produces compiler warning if enabled + if(NOT CMAKE_C_FLAGS MATCHES "-O0") + list(APPEND known_checks object-size) + endif() + + check_sanitizer_support("${known_checks}" supported_checks) + + if(NOT ${supported_checks} STREQUAL "") + message(STATUS "Undefined behavior sanitizer is enabled: ${supported_checks}") + add_compile_options(-fsanitize=${supported_checks}) + add_link_options(-fsanitize=${supported_checks}) + + add_common_sanitizer_flags() + else() + message(STATUS "Undefined behavior sanitizer is not supported") + endif() +endmacro() diff --git a/cmake/fallback-macros.cmake b/cmake/fallback-macros.cmake new file mode 100644 index 0000000000..8bc6cf25be --- /dev/null +++ b/cmake/fallback-macros.cmake @@ -0,0 +1,19 @@ +# fallback-macros.cmake -- CMake fallback macros +# Copyright (C) 2022 Nathan Moinvaziri +# Licensed under the Zlib license, see LICENSE.md for details + +# CMake less than version 3.5.2 +if(NOT COMMAND add_compile_options) + macro(add_compile_options options) + string(APPEND CMAKE_C_FLAGS ${options}) + string(APPEND CMAKE_CXX_FLAGS ${options}) + endmacro() +endif() + +# CMake less than version 3.14 +if(NOT COMMAND add_link_options) + macro(add_link_options options) + string(APPEND CMAKE_EXE_LINKER_FLAGS ${options}) + string(APPEND CMAKE_SHARED_LINKER_FLAGS ${options}) + endmacro() +endif() diff --git a/cmake/toolchain-aarch64.cmake b/cmake/toolchain-aarch64.cmake new file mode 100644 index 0000000000..1e24731077 --- /dev/null +++ b/cmake/toolchain-aarch64.cmake @@ -0,0 +1,24 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR aarch64) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER_TARGET "aarch64-linux-gnu") +set(CMAKE_CXX_COMPILER_TARGET "aarch64-linux-gnu") + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-aarch64 -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-arm.cmake b/cmake/toolchain-arm.cmake new file mode 100644 index 0000000000..1bdd8d2cc1 --- /dev/null +++ b/cmake/toolchain-arm.cmake @@ -0,0 +1,29 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) +set(CMAKE_SYSTEM_VERSION 1) + +if(NOT DEFINED CMAKE_C_COMPILER_TARGET) + set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabi) +endif() +if(NOT DEFINED CMAKE_CXX_COMPILER_TARGET) + set(CMAKE_CXX_COMPILER_TARGET arm-linux-gnueabi) +endif() + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-arm -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-armhf.cmake b/cmake/toolchain-armhf.cmake new file mode 100644 index 0000000000..007859caf6 --- /dev/null +++ b/cmake/toolchain-armhf.cmake @@ -0,0 +1,25 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf) +set(CMAKE_CXX_COMPILER_TARGET arm-linux-gnueabihf) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-arm -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-llvm-mingw-aarch64.cmake b/cmake/toolchain-llvm-mingw-aarch64.cmake new file mode 100644 index 0000000000..4da1e2c796 --- /dev/null +++ b/cmake/toolchain-llvm-mingw-aarch64.cmake @@ -0,0 +1,41 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_C_COMPILER_FRONTEND_VARIANT GNU) +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR wine) + +set(CMAKE_C_COMPILER_TARGET aarch64-w64-mingw32) +set(CMAKE_CXX_COMPILER_TARGET aarch64-w64-mingw32) +set(CMAKE_RC_COMPILER_TARGET aarch64-w64-mingw32) +set(CMAKE_SYSTEM_PROCESSOR aarch64) + +# Required to propagate 'LLVM_MINGW_ROOT' variables to C compiler feature test. +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES LLVM_MINGW_ROOT) + +if(NOT LLVM_MINGW_ROOT) + set(LLVM_MINGW_ROOT $ENV{LLVM_MINGW_ROOT}) +endif() +cmake_path(CONVERT "${LLVM_MINGW_ROOT}" TO_CMAKE_PATH_LIST LLVM_MINGW_ROOT) + +set(CMAKE_FIND_ROOT_PATH ${LLVM_MINGW_ROOT} ${LLVM_MINGW_ROOT}/aarch64-w64-mingw32) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +find_program(C_COMPILER_FULL_PATH ${CMAKE_C_COMPILER_TARGET}-clang HINTS ${LLVM_MINGW_ROOT}/bin) +if(NOT C_COMPILER_FULL_PATH) +message(FATAL_ERROR "Compiler for ${CMAKE_C_COMPILER_TARGET} not found. Try setting llvm-mingw root path to LLVM_MINGW_ROOT variable!") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH ${CMAKE_CXX_COMPILER_TARGET}-clang++ HINTS ${LLVM_MINGW_ROOT}/bin) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() + +find_program(RC_COMPILER_FULL_PATH ${CMAKE_RC_COMPILER_TARGET}-windres HINTS ${LLVM_MINGW_ROOT}/bin) +if(RC_COMPILER_FULL_PATH) + set(CMAKE_RC_COMPILER ${RC_COMPILER_FULL_PATH}) +endif() + +add_compile_options($<$:-gcodeview>) +add_link_options(-Wl,-pdb=) diff --git a/cmake/toolchain-llvm-mingw-armv7.cmake b/cmake/toolchain-llvm-mingw-armv7.cmake new file mode 100644 index 0000000000..d077309b86 --- /dev/null +++ b/cmake/toolchain-llvm-mingw-armv7.cmake @@ -0,0 +1,41 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_C_COMPILER_FRONTEND_VARIANT GNU) +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR wine) + +set(CMAKE_C_COMPILER_TARGET armv7-w64-mingw32) +set(CMAKE_CXX_COMPILER_TARGET armv7-w64-mingw32) +set(CMAKE_RC_COMPILER_TARGET armv7-w64-mingw32) +set(CMAKE_SYSTEM_PROCESSOR armv7) + +# Required to propagate 'LLVM_MINGW_ROOT' variables to C compiler feature test. +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES LLVM_MINGW_ROOT) + +if(NOT LLVM_MINGW_ROOT) + set(LLVM_MINGW_ROOT $ENV{LLVM_MINGW_ROOT}) +endif() +cmake_path(CONVERT "${LLVM_MINGW_ROOT}" TO_CMAKE_PATH_LIST LLVM_MINGW_ROOT) + +set(CMAKE_FIND_ROOT_PATH ${LLVM_MINGW_ROOT} ${LLVM_MINGW_ROOT}/armv7-w64-mingw32) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +find_program(C_COMPILER_FULL_PATH ${CMAKE_C_COMPILER_TARGET}-clang HINTS ${LLVM_MINGW_ROOT}/bin) +if(NOT C_COMPILER_FULL_PATH) +message(FATAL_ERROR "Compiler for ${CMAKE_C_COMPILER_TARGET} not found. Try setting llvm-mingw root path to LLVM_MINGW_ROOT variable!") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH ${CMAKE_CXX_COMPILER_TARGET}-clang++ HINTS ${LLVM_MINGW_ROOT}/bin) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() + +find_program(RC_COMPILER_FULL_PATH ${CMAKE_RC_COMPILER_TARGET}-windres HINTS ${LLVM_MINGW_ROOT}/bin) +if(RC_COMPILER_FULL_PATH) + set(CMAKE_RC_COMPILER ${RC_COMPILER_FULL_PATH}) +endif() + +add_compile_options($<$:-gcodeview>) +add_link_options(-Wl,-pdb=) diff --git a/cmake/toolchain-llvm-mingw-i686.cmake b/cmake/toolchain-llvm-mingw-i686.cmake new file mode 100644 index 0000000000..17a0aa7909 --- /dev/null +++ b/cmake/toolchain-llvm-mingw-i686.cmake @@ -0,0 +1,41 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_C_COMPILER_FRONTEND_VARIANT GNU) +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR wine) + +set(CMAKE_C_COMPILER_TARGET i686-w64-mingw32) +set(CMAKE_CXX_COMPILER_TARGET i686-w64-mingw32) +set(CMAKE_RC_COMPILER_TARGET i686-w64-mingw32) +set(CMAKE_SYSTEM_PROCESSOR i686) + +# Required to propagate 'LLVM_MINGW_ROOT' variables to C compiler feature test. +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES LLVM_MINGW_ROOT) + +if(NOT LLVM_MINGW_ROOT) + set(LLVM_MINGW_ROOT $ENV{LLVM_MINGW_ROOT}) +endif() +cmake_path(CONVERT "${LLVM_MINGW_ROOT}" TO_CMAKE_PATH_LIST LLVM_MINGW_ROOT) + +set(CMAKE_FIND_ROOT_PATH ${LLVM_MINGW_ROOT} ${LLVM_MINGW_ROOT}/i686-w64-mingw32) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +find_program(C_COMPILER_FULL_PATH ${CMAKE_C_COMPILER_TARGET}-clang HINTS ${LLVM_MINGW_ROOT}/bin) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Compiler for ${CMAKE_C_COMPILER_TARGET} not found. Try setting llvm-mingw root path to LLVM_MINGW_ROOT variable!") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH ${CMAKE_CXX_COMPILER_TARGET}-clang++ HINTS ${LLVM_MINGW_ROOT}/bin) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() + +find_program(RC_COMPILER_FULL_PATH ${CMAKE_RC_COMPILER_TARGET}-windres HINTS ${LLVM_MINGW_ROOT}/bin) +if(RC_COMPILER_FULL_PATH) + set(CMAKE_RC_COMPILER ${RC_COMPILER_FULL_PATH}) +endif() + +add_compile_options($<$:-gcodeview>) +add_link_options(-Wl,-pdb=) diff --git a/cmake/toolchain-llvm-mingw-x86_64.cmake b/cmake/toolchain-llvm-mingw-x86_64.cmake new file mode 100644 index 0000000000..e519562418 --- /dev/null +++ b/cmake/toolchain-llvm-mingw-x86_64.cmake @@ -0,0 +1,41 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_C_COMPILER_FRONTEND_VARIANT GNU) +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR wine) + +set(CMAKE_C_COMPILER_TARGET x86_64-w64-mingw32) +set(CMAKE_CXX_COMPILER_TARGET x86_64-w64-mingw32) +set(CMAKE_RC_COMPILER_TARGET x86_64-w64-mingw32) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +# Required to propagate 'LLVM_MINGW_ROOT' variables to C compiler feature test. +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES LLVM_MINGW_ROOT) + +if(NOT LLVM_MINGW_ROOT) + set(LLVM_MINGW_ROOT $ENV{LLVM_MINGW_ROOT}) +endif() +cmake_path(CONVERT "${LLVM_MINGW_ROOT}" TO_CMAKE_PATH_LIST LLVM_MINGW_ROOT) + +set(CMAKE_FIND_ROOT_PATH ${LLVM_MINGW_ROOT} ${LLVM_MINGW_ROOT}/x86_64-w64-mingw32) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +find_program(C_COMPILER_FULL_PATH ${CMAKE_C_COMPILER_TARGET}-clang HINTS ${LLVM_MINGW_ROOT}/bin) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Compiler for ${CMAKE_C_COMPILER_TARGET} not found. Try setting llvm-mingw root path to LLVM_MINGW_ROOT variable!") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH ${CMAKE_CXX_COMPILER_TARGET}-clang++ HINTS ${LLVM_MINGW_ROOT}/bin) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() + +find_program(RC_COMPILER_FULL_PATH ${CMAKE_RC_COMPILER_TARGET}-windres HINTS ${LLVM_MINGW_ROOT}/bin) +if(RC_COMPILER_FULL_PATH) + set(CMAKE_RC_COMPILER ${RC_COMPILER_FULL_PATH}) +endif() + +add_compile_options($<$:-gcodeview>) +add_link_options(-Wl,-pdb=) diff --git a/cmake/toolchain-mingw-i686.cmake b/cmake/toolchain-mingw-i686.cmake new file mode 100644 index 0000000000..b95e63f50c --- /dev/null +++ b/cmake/toolchain-mingw-i686.cmake @@ -0,0 +1,35 @@ +set(CMAKE_SYSTEM_NAME Windows) + +set(CMAKE_C_COMPILER_TARGET i686-w64-mingw32) +set(CMAKE_CXX_COMPILER_TARGET i686-w64-mingw32) +set(CMAKE_RC_COMPILER_TARGET i686-w64-mingw32) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR wine) + +set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +# Prefer posix gcc variant for gtest pthread support +find_program(C_COMPILER_FULL_PATH NAMES + ${CMAKE_C_COMPILER_TARGET}-gcc-posix + ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES + ${CMAKE_CXX_COMPILER_TARGET}-g++-posix + ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() + +find_program(RC_COMPILER_FULL_PATH NAMES + ${CMAKE_RC_COMPILER_TARGET}-windres) +if(RC_COMPILER_FULL_PATH) + set(CMAKE_RC_COMPILER ${RC_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-mingw-x86_64.cmake b/cmake/toolchain-mingw-x86_64.cmake new file mode 100644 index 0000000000..8c660b0b1e --- /dev/null +++ b/cmake/toolchain-mingw-x86_64.cmake @@ -0,0 +1,34 @@ +set(CMAKE_SYSTEM_NAME Windows) + +set(CMAKE_C_COMPILER_TARGET x86_64-w64-mingw32) +set(CMAKE_CXX_COMPILER_TARGET x86_64-w64-mingw32) +set(CMAKE_RC_COMPILER_TARGET x86_64-w64-mingw32) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR wine) + +set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +# Prefer posix gcc variant for gtest pthread support +find_program(C_COMPILER_FULL_PATH NAMES + ${CMAKE_C_COMPILER_TARGET}-gcc-posix + ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES + ${CMAKE_CXX_COMPILER_TARGET}-g++-posix + ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() + +find_program(RC_COMPILER_FULL_PATH NAMES ${CMAKE_RC_COMPILER_TARGET}-windres) +if(RC_COMPILER_FULL_PATH) + set(CMAKE_RC_COMPILER ${RC_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-mips.cmake b/cmake/toolchain-mips.cmake new file mode 100644 index 0000000000..69a1025e34 --- /dev/null +++ b/cmake/toolchain-mips.cmake @@ -0,0 +1,29 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR mips) +set(CMAKE_SYSTEM_VERSION 1) + +if(NOT DEFINED CMAKE_C_COMPILER_TARGET) + set(CMAKE_C_COMPILER_TARGET mips-linux-gnu) +endif() +if(NOT DEFINED CMAKE_CXX_COMPILER_TARGET) + set(CMAKE_CXX_COMPILER_TARGET mips-linux-gnu) +endif() + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-mips -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-mips64.cmake b/cmake/toolchain-mips64.cmake new file mode 100644 index 0000000000..8ef3b6b009 --- /dev/null +++ b/cmake/toolchain-mips64.cmake @@ -0,0 +1,29 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR mips64) +set(CMAKE_SYSTEM_VERSION 1) + +if(NOT DEFINED CMAKE_C_COMPILER_TARGET) + set(CMAKE_C_COMPILER_TARGET mips64-linux-gnuabi64) +endif() +if(NOT DEFINED CMAKE_CXX_COMPILER_TARGET) + set(CMAKE_CXX_COMPILER_TARGET mips64-linux-gnuabi64) +endif() + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-mips64 -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-powerpc.cmake b/cmake/toolchain-powerpc.cmake new file mode 100644 index 0000000000..f09713370d --- /dev/null +++ b/cmake/toolchain-powerpc.cmake @@ -0,0 +1,25 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR powerpc) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER_TARGET powerpc-linux-gnu) +set(CMAKE_CXX_COMPILER_TARGET powerpc-linux-gnu) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-ppc -cpu 7400 -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-powerpc64-clang.cmake b/cmake/toolchain-powerpc64-clang.cmake new file mode 100644 index 0000000000..f986796f6b --- /dev/null +++ b/cmake/toolchain-powerpc64-clang.cmake @@ -0,0 +1,16 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR ppc64) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER clang) +set(CMAKE_C_COMPILER_TARGET powerpc64-linux-gnu) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_CXX_COMPILER_TARGET powerpc64-linux-gnu) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-ppc64 -cpu power9 -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/cmake/toolchain-powerpc64-power9.cmake b/cmake/toolchain-powerpc64-power9.cmake new file mode 100644 index 0000000000..2ea190a4d1 --- /dev/null +++ b/cmake/toolchain-powerpc64-power9.cmake @@ -0,0 +1,25 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR ppc64) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER_TARGET powerpc64-linux-gnu) +set(CMAKE_CXX_COMPILER_TARGET powerpc64-linux-gnu) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-ppc64 -cpu power9 -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-powerpc64.cmake b/cmake/toolchain-powerpc64.cmake new file mode 100644 index 0000000000..80d8b904e7 --- /dev/null +++ b/cmake/toolchain-powerpc64.cmake @@ -0,0 +1,25 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR ppc64) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER_TARGET powerpc64-linux-gnu) +set(CMAKE_CXX_COMPILER_TARGET powerpc64-linux-gnu) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-ppc64 -cpu power8 -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-powerpc64le-clang.cmake b/cmake/toolchain-powerpc64le-clang.cmake new file mode 100644 index 0000000000..b3423c590d --- /dev/null +++ b/cmake/toolchain-powerpc64le-clang.cmake @@ -0,0 +1,16 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR ppc64le) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER clang) +set(CMAKE_C_COMPILER_TARGET powerpc64le-linux-gnu) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_CXX_COMPILER_TARGET powerpc64le-linux-gnu) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-ppc64le -cpu power9 -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/cmake/toolchain-powerpc64le-power9.cmake b/cmake/toolchain-powerpc64le-power9.cmake new file mode 100644 index 0000000000..5ac8c7a9c1 --- /dev/null +++ b/cmake/toolchain-powerpc64le-power9.cmake @@ -0,0 +1,25 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR ppc64le) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER_TARGET powerpc64le-linux-gnu) +set(CMAKE_CXX_COMPILER_TARGET powerpc64le-linux-gnu) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-ppc64le -cpu power9 -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-powerpc64le.cmake b/cmake/toolchain-powerpc64le.cmake new file mode 100644 index 0000000000..68381de120 --- /dev/null +++ b/cmake/toolchain-powerpc64le.cmake @@ -0,0 +1,25 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR ppc64le) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER_TARGET powerpc64le-linux-gnu) +set(CMAKE_CXX_COMPILER_TARGET powerpc64le-linux-gnu) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-ppc64le -cpu power8 -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-riscv.cmake b/cmake/toolchain-riscv.cmake new file mode 100644 index 0000000000..9cf8fdb7fe --- /dev/null +++ b/cmake/toolchain-riscv.cmake @@ -0,0 +1,28 @@ +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_SYSTEM_NAME "Linux") +set(CMAKE_SYSTEM_PROCESSOR "riscv64") + +# Avoid to use system path for cross-compile +set(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH FALSE) + +set(TOOLCHAIN_PATH "" CACHE STRING "The toolchain path.") +if(NOT TOOLCHAIN_PATH) + set(TOOLCHAIN_PATH ${CMAKE_SOURCE_DIR}/prebuilt-riscv-toolchain-qemu/riscv-clang) +endif() + +set(TOOLCHAIN_PREFIX "riscv64-unknown-linux-gnu-" CACHE STRING "The toolchain prefix.") +set(QEMU_PATH "" CACHE STRING "The qemu path.") +if(NOT QEMU_PATH) + set(QEMU_PATH ${CMAKE_SOURCE_DIR}/prebuilt-riscv-toolchain-qemu/riscv-qemu/bin/qemu-riscv64) +endif() + +# toolchain setting +set(CMAKE_C_COMPILER "${TOOLCHAIN_PATH}/bin/${TOOLCHAIN_PREFIX}clang") +set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PATH}/bin/${TOOLCHAIN_PREFIX}clang++") + +# disable auto-vectorizer +add_compile_options(-fno-vectorize -fno-slp-vectorize) + +# emulator setting +set(QEMU_CPU_OPTION "rv64,zba=true,zbb=true,zbc=true,zbs=true,v=true,vlen=512,elen=64,vext_spec=v1.0") +set(CMAKE_CROSSCOMPILING_EMULATOR ${QEMU_PATH} -cpu ${QEMU_CPU_OPTION} -L ${TOOLCHAIN_PATH}/sysroot/) diff --git a/cmake/toolchain-s390x.cmake b/cmake/toolchain-s390x.cmake new file mode 100644 index 0000000000..9455a2bedb --- /dev/null +++ b/cmake/toolchain-s390x.cmake @@ -0,0 +1,25 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR s390x) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER_TARGET s390x-linux-gnu) +set(CMAKE_CXX_COMPILER_TARGET s390x-linux-gnu) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-s390x -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/cmake/toolchain-sparc64.cmake b/cmake/toolchain-sparc64.cmake new file mode 100644 index 0000000000..16161a78c0 --- /dev/null +++ b/cmake/toolchain-sparc64.cmake @@ -0,0 +1,25 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR sparc64) +set(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER_TARGET sparc64-linux-gnu) +set(CMAKE_CXX_COMPILER_TARGET sparc64-linux-gnu) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_CROSSCOMPILING_EMULATOR qemu-sparc64 -L /usr/${CMAKE_C_COMPILER_TARGET}/) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +find_program(C_COMPILER_FULL_PATH NAMES ${CMAKE_C_COMPILER_TARGET}-gcc) +if(NOT C_COMPILER_FULL_PATH) + message(FATAL_ERROR "Cross-compiler for ${CMAKE_C_COMPILER_TARGET} not found") +endif() +set(CMAKE_C_COMPILER ${C_COMPILER_FULL_PATH}) + +find_program(CXX_COMPILER_FULL_PATH NAMES g++-${CMAKE_CXX_COMPILER_TARGET} ${CMAKE_CXX_COMPILER_TARGET}-g++) +if(CXX_COMPILER_FULL_PATH) + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_FULL_PATH}) +endif() diff --git a/compare256_rle.h b/compare256_rle.h new file mode 100644 index 0000000000..5edfd734a0 --- /dev/null +++ b/compare256_rle.h @@ -0,0 +1,133 @@ +/* compare256_rle.h -- 256 byte run-length encoding comparison + * Copyright (C) 2022 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zmemory.h" +#include "fallback_builtins.h" + +typedef uint32_t (*compare256_rle_func)(const uint8_t* src0, const uint8_t* src1); + +/* 8-bit integer comparison */ +static inline uint32_t compare256_rle_8(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0; + + do { + if (*src0 != *src1) + return len; + src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src1 += 1, len += 1; + if (*src0 != *src1) + return len; + src1 += 1, len += 1; + } while (len < 256); + + return 256; +} + +/* 16-bit integer comparison */ +static inline uint32_t compare256_rle_16(const uint8_t *src0, const uint8_t *src1) { + uint32_t len = 0; + uint16_t src0_cmp; + + src0_cmp = zng_memread_2(src0); + + do { + if (src0_cmp != zng_memread_2(src1)) + return len + (*src0 == *src1); + src1 += 2, len += 2; + if (src0_cmp != zng_memread_2(src1)) + return len + (*src0 == *src1); + src1 += 2, len += 2; + if (src0_cmp != zng_memread_2(src1)) + return len + (*src0 == *src1); + src1 += 2, len += 2; + if (src0_cmp != zng_memread_2(src1)) + return len + (*src0 == *src1); + src1 += 2, len += 2; + } while (len < 256); + + return 256; +} + +#ifdef HAVE_BUILTIN_CTZ +/* 32-bit integer comparison */ +static inline uint32_t compare256_rle_32(const uint8_t *src0, const uint8_t *src1) { + uint32_t sv, len = 0; + uint16_t src0_cmp; + + src0_cmp = zng_memread_2(src0); + sv = ((uint32_t)src0_cmp << 16) | src0_cmp; + + do { + uint32_t mv, diff; + + mv = zng_memread_4(src1); + + diff = sv ^ mv; + if (diff) { +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t match_byte = __builtin_ctz(diff) / 8; +#else + uint32_t match_byte = __builtin_clz(diff) / 8; +#endif + return len + match_byte; + } + + src1 += 4, len += 4; + } while (len < 256); + + return 256; +} +#endif + +#ifdef HAVE_BUILTIN_CTZLL +/* 64-bit integer comparison */ +static inline uint32_t compare256_rle_64(const uint8_t *src0, const uint8_t *src1) { + uint32_t src0_cmp32, len = 0; + uint16_t src0_cmp; + uint64_t sv; + + src0_cmp = zng_memread_2(src0); + src0_cmp32 = ((uint32_t)src0_cmp << 16) | src0_cmp; + sv = ((uint64_t)src0_cmp32 << 32) | src0_cmp32; + + do { + uint64_t mv, diff; + + mv = zng_memread_8(src1); + + diff = sv ^ mv; + if (diff) { +#if BYTE_ORDER == LITTLE_ENDIAN + uint64_t match_byte = __builtin_ctzll(diff) / 8; +#else + uint64_t match_byte = __builtin_clzll(diff) / 8; +#endif + return len + (uint32_t)match_byte; + } + + src1 += 8, len += 8; + } while (len < 256); + + return 256; +} +#endif diff --git a/compress.c b/compress.c new file mode 100644 index 0000000000..66118e4f4b --- /dev/null +++ b/compress.c @@ -0,0 +1,98 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zutil.h" + +/* =========================================================================== + * Architecture-specific hooks. + */ +#ifdef S390_DFLTCC_DEFLATE +# include "arch/s390/dfltcc_common.h" +#else +/* Returns the upper bound on compressed data length based on uncompressed data length, assuming default settings. + * Zero means that arch-specific deflation code behaves identically to the regular zlib-ng algorithms. */ +# define DEFLATE_BOUND_COMPLEN(source_len) 0 +#endif + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int Z_EXPORT PREFIX(compress2)(unsigned char *dest, z_uintmax_t *destLen, const unsigned char *source, + z_uintmax_t sourceLen, int level) { + PREFIX3(stream) stream; + int err; + const unsigned int max = (unsigned int)-1; + z_size_t left; + + left = *destLen; + *destLen = 0; + + stream.zalloc = NULL; + stream.zfree = NULL; + stream.opaque = NULL; + + err = PREFIX(deflateInit)(&stream, level); + if (err != Z_OK) + return err; + + stream.next_out = dest; + stream.avail_out = 0; + stream.next_in = (z_const unsigned char *)source; + stream.avail_in = 0; + + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (unsigned long)max ? max : (unsigned int)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = sourceLen > (unsigned long)max ? max : (unsigned int)sourceLen; + sourceLen -= stream.avail_in; + } + err = PREFIX(deflate)(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); + } while (err == Z_OK); + + *destLen = stream.total_out; + PREFIX(deflateEnd)(&stream); + return err == Z_STREAM_END ? Z_OK : err; +} + +/* =========================================================================== + */ +int Z_EXPORT PREFIX(compress)(unsigned char *dest, z_uintmax_t *destLen, const unsigned char *source, z_uintmax_t sourceLen) { + return PREFIX(compress2)(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +z_uintmax_t Z_EXPORT PREFIX(compressBound)(z_uintmax_t sourceLen) { + z_uintmax_t complen = DEFLATE_BOUND_COMPLEN(sourceLen); + + if (complen > 0) + /* Architecture-specific code provided an upper bound. */ + return complen + ZLIB_WRAPLEN; + +#ifndef NO_QUICK_STRATEGY + return sourceLen /* The source size itself */ + + (sourceLen == 0 ? 1 : 0) /* Always at least one byte for any input */ + + (sourceLen < 9 ? 1 : 0) /* One extra byte for lengths less than 9 */ + + DEFLATE_QUICK_OVERHEAD(sourceLen) /* Source encoding overhead, padded to next full byte */ + + DEFLATE_BLOCK_OVERHEAD /* Deflate block overhead bytes */ + + ZLIB_WRAPLEN; /* zlib wrapper */ +#else + return sourceLen + (sourceLen >> 4) + 7 + ZLIB_WRAPLEN; +#endif +} diff --git a/configure b/configure new file mode 100644 index 0000000000..3487d092bc --- /dev/null +++ b/configure @@ -0,0 +1,2218 @@ +#!/bin/sh +# configure script for zlib. +# +# Normally configure builds both a static and a shared library. +# If you want to build just a static library, use: ./configure --static +# +# To impose specific compiler or flags or install directory, use for example: +# prefix=$HOME CC=cc CFLAGS="-O4" ./configure +# or for csh/tcsh users: +# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure) + +# Incorrect settings of CC or CFLAGS may prevent creating a shared library. +# If you have problems, try without defining CC and CFLAGS before reporting +# an error. + +# start off configure.log +echo -------------------- >> configure.log +echo $0 $* >> configure.log +date >> configure.log + +SRCDIR=$(cd $(dirname $0); pwd) +BUILDDIR=$(pwd) + +# set command prefix for cross-compilation +if [ -n "${CHOST}" ]; then + # normalize the chost before parsing it + NORM_CHOST=$(sh "$SRCDIR"/tools/config.sub $CHOST) + uname="$(echo "${NORM_CHOST}" | sed -e 's/^[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)-.*$/\1/')" + CROSS_PREFIX="${CHOST}-" + ARCH="$(echo "${NORM_CHOST}" | sed -e 's/-.*//')" +else + ARCH="$(uname -m)" +fi + +case "${ARCH}" in + x86_64) + case "${CFLAGS}" in + *-m32*) + ARCH=i686 + ;; + esac + ;; + i386 | i486 | i586 | i686) + case "${CFLAGS}" in + *-m64*) + ARCH=x86_64 + ;; + esac + ;; +esac + +# destination name for windows import library +IMPORTLIB= + +# establish commands for library building +if "${CROSS_PREFIX}ar" --version >/dev/null 2>/dev/null || test $? -lt 126; then + AR=${AR-"${CROSS_PREFIX}ar"} + test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log +else + AR=${AR-"ar"} + test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log +fi +ARFLAGS=${ARFLAGS-"rc"} +if "${CROSS_PREFIX}ranlib" --version >/dev/null 2>/dev/null || test $? -lt 126; then + RANLIB=${RANLIB-"${CROSS_PREFIX}ranlib"} + test -n "${CROSS_PREFIX}" && echo Using ${RANLIB} | tee -a configure.log +else + RANLIB=${RANLIB-"ranlib"} +fi + +# set defaults before processing command line options +LDCONFIG=${LDCONFIG-"ldconfig"} +DEFFILE= +RC= +RCFLAGS= +RCOBJS= +STRIP= +ARCHS= +PC_CFLAGS= +prefix=${prefix-/usr/local} +exec_prefix=${exec_prefix-'${prefix}'} +bindir=${bindir-'${exec_prefix}/bin'} +libdir=${libdir-'${exec_prefix}/lib'} +sharedlibdir=${sharedlibdir-'${libdir}'} +includedir=${includedir-'${prefix}/include'} +mandir=${mandir-'${prefix}/share/man'} +shared_ext='.so' +shared=1 +gzfileops=1 +compat=0 +cover=0 +build32=0 +build64=0 +buildvpclmulqdq=1 +buildacle=1 +buildarmv6=1 +buildaltivec=1 +buildpower8=1 +buildpower9=1 +buildneon=1 +builddfltccdeflate=0 +builddfltccinflate=0 +buildcrc32vx=1 +floatabi= +forcesse2=0 +# For CPUs that can benefit from AVX512, it seems GCC generates suboptimal +# instruction scheduling unless you specify a reasonable -mtune= target +avx512flag="-mavx512f -mavx512dq -mavx512bw -mavx512vl -mbmi2" +avx512vnniflag="${avx512flag} -mavx512vnni" +avx2flag="-mavx2 -mbmi2" +sse2flag="-msse2" +ssse3flag="-mssse3" +sse42flag="-msse4.2" +pclmulflag="-mpclmul" +vpclmulflag="-mvpclmulqdq -mavx512f" +xsaveflag="-mxsave" +acleflag= +neonflag= +armv6flag= +noltoflag="-fno-lto" +vgfmaflag="-march=z13" +vmxflag="-maltivec" +symbol_prefix="" +without_optimizations=0 +without_new_strategies=0 +reducedmem=0 +gcc=0 +warn=0 +debug=0 +visibility=1 +old_cc="$CC" +old_cflags="$CFLAGS" +OBJC='$(OBJZ)' +PIC_OBJC='$(PIC_OBJZ)' +INSTALLTARGETS="install-shared install-static" +UNINSTALLTARGETS="uninstall-shared uninstall-static" + +TEST="teststatic" + +# leave this script, optionally in a bad way +leave() +{ + if test "$*" != "0"; then + echo "** $0 aborting." | tee -a configure.log + fi + rm -f $test.[co] $test $test$shared_ext $test.gcno ./--version + echo -------------------- >> configure.log + echo >> configure.log + echo >> configure.log + exit $1 +} + +# process command line options +while test $# -ge 1 +do +case "$1" in + -h* | --help) + echo 'usage:' | tee -a configure.log + echo ' configure [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log + echo ' [--static] [--32] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log + echo ' [--includedir=INCLUDEDIR] [--mandir=MANDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log + echo ' [--sprefix=SYMBOL_PREFIX] Adds a prefix to all exported symbols' | tee -a configure.log + echo ' [--warn] Enables extra compiler warnings' | tee -a configure.log + echo ' [--debug] Enables extra debug prints during operation' | tee -a configure.log + echo ' [--zlib-compat] Compiles for zlib-compatible API instead of zlib-ng API' | tee -a configure.log + echo ' [--without-gzfileops] Compiles without the gzfile parts of the API enabled' | tee -a configure.log + echo ' [--without-optimizations] Compiles without support for optional instruction sets' | tee -a configure.log + echo ' [--without-new-strategies] Compiles without using new additional deflate strategies' | tee -a configure.log + echo ' [--without-acle] Compiles without ARM C Language Extensions' | tee -a configure.log + echo ' [--without-neon] Compiles without ARM Neon SIMD instruction set' | tee -a configure.log + echo ' [--without-armv6] Compiles without ARMv6 SIMD instruction set' | tee -a configure.log + echo ' [--without-altivec] Compiles without PPC AltiVec support' | tee -a configure.log + echo ' [--without-power8] Compiles without Power8 instruction set' | tee -a configure.log + echo ' [--with-dfltcc-deflate] Use DEFLATE CONVERSION CALL instruction for compression on IBM Z' | tee -a configure.log + echo ' [--with-dfltcc-inflate] Use DEFLATE CONVERSION CALL instruction for decompression on IBM Z' | tee -a configure.log + echo ' [--without-crc32-vx] Build without vectorized CRC32 on IBM Z' | tee -a configure.log + echo ' [--with-reduced-mem] Reduced memory usage for special cases (reduces performance)' | tee -a configure.log + echo ' [--force-sse2] Assume SSE2 instructions are always available (disabled by default on x86, enabled on x86_64)' | tee -a configure.log + exit 0 ;; + -p*=* | --prefix=*) prefix=$(echo $1 | sed 's/.*=//'); shift ;; + -e*=* | --eprefix=*) exec_prefix=$(echo $1 | sed 's/.*=//'); shift ;; + -m*=* | --sprefix=*) symbol_prefix=$(echo $1 | sed 's/.*=//'); shift ;; + -l*=* | --libdir=*) libdir=$(echo $1 | sed 's/.*=//'); shift ;; + --sharedlibdir=*) sharedlibdir=$(echo $1 | sed 's/.*=//'); shift ;; + -i*=* | --includedir=*) includedir=$(echo $1 | sed 's/.*=//');shift ;; + --mandir=*) mandir=$(echo $1 | sed 's/.*=//');shift ;; + -u*=* | --uname=*) uname=$(echo $1 | sed 's/.*=//');shift ;; + -p* | --prefix) prefix="$2"; shift; shift ;; + -e* | --eprefix) exec_prefix="$2"; shift; shift ;; + -m* | --sprefix) symbol_prefix="$2"; shift; shift ;; + -l* | --libdir) libdir="$2"; shift; shift ;; + -i* | --includedir) includedir="$2"; shift; shift ;; + -s* | --shared | --enable-shared) shared=1; shift ;; + -t | --static) shared=0; shift ;; + --zlib-compat) compat=1; shift ;; + --without-gzfileops) gzfileops=0; shift ;; + --cover) cover=1; shift ;; + -3* | --32) build32=1; shift ;; + -6* | --64) build64=1; shift ;; + --without-vpclmulqdq) buildvpclmulqdq=0; shift ;; + --without-acle) buildacle=0; shift ;; + --without-neon) buildneon=0; shift ;; + --without-armv6) buildarmv6=0; shift ;; + --without-altivec) buildaltivec=0 ; shift ;; + --without-power8) buildpower8=0 ; shift ;; + --without-power9) buildpower9=0 ; shift ;; + --with-dfltcc-deflate) builddfltccdeflate=1; shift ;; + --with-dfltcc-inflate) builddfltccinflate=1; shift ;; + --without-crc32-vx) buildcrc32vx=0; shift ;; + --with-reduced-mem) reducedmem=1; shift ;; + --force-sse2) forcesse2=1; shift ;; + -a*=* | --archs=*) ARCHS=$(echo $1 | sed 's/.*=//'); shift ;; + --sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;; + --localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;; + -noopt | --without-optimizations) without_optimizations=1; shift;; + -oldstrat | --without-new-strategies) without_new_strategies=1; shift;; + -w* | --warn) warn=1; shift ;; + -d* | --debug) debug=1; shift ;; + + *) + echo "unknown option: $1" | tee -a configure.log + echo "$0 --help for help" | tee -a configure.log + leave 1;; + esac +done + +# temporary file name +test=ztest$$ + +# put arguments in log, also put test file in log if used in arguments +show() +{ + case "$@" in + *$test.c*) + echo "=== $test.c ===" >> configure.log + cat $test.c >> configure.log + echo "===" >> configure.log;; + esac + echo "$@" >> configure.log +} + +# check for gcc vs. cc and set compile and link flags based on the system identified by uname +cat > $test.c <&1) in + *gcc*) gcc=1 ;; + *clang*) gcc=1 ;; +esac + +if test $build32 -eq 1; then + CFLAGS="${CFLAGS} -m32" + SFLAGS="${SFLAGS} -m32" + LDFLAGS="${LDFLAGS} -m32" +fi +if test $build64 -eq 1; then + CFLAGS="${CFLAGS} -m64" + SFLAGS="${SFLAGS} -m64" + LDFLAGS="${LDFLAGS} -m64" +fi + +# Set library name depending on zlib-compat option +if test $compat -eq 0; then + LIBNAME=libz-ng + LIBNAME2=zlib-ng + SUFFIX=-ng +else + LIBNAME=libz + LIBNAME2=zlib + SUFFIX="" +fi + +STATICLIB=${LIBNAME}.a +MAPNAME=${LIBNAME2}.map + +# extract zlib version numbers from zlib.h +if test $compat -eq 0; then + VER=$(sed -n -e '/ZLIBNG_VERSION "/s/.*"\(.*\)".*/\1/p' < ${SRCDIR}/zlib-ng.h.in) + VER3=$(sed -n -e '/ZLIBNG_VERSION "/s/.*"\([0-9]*\.[0-9]*\.[0-9]*\).*/\1/p' < ${SRCDIR}/zlib-ng.h.in) + VER2=$(sed -n -e '/ZLIBNG_VERSION "/s/.*"\([0-9]*\.[0-9]*\)\..*/\1/p' < ${SRCDIR}/zlib-ng.h.in) + VER1=$(sed -n -e '/ZLIBNG_VERSION "/s/.*"\([0-9]*\)\..*/\1/p' < ${SRCDIR}/zlib-ng.h.in) +else + VER=$(sed -n -e '/ZLIB_VERSION "/s/.*"\(.*\)".*/\1/p' < ${SRCDIR}/zlib.h.in) + VER3=$(sed -n -e '/ZLIB_VERSION "/s/.*"\([0-9]*\.[0-9]*\.[0-9]*\).*/\1/p' < ${SRCDIR}/zlib.h.in) + VER2=$(sed -n -e '/ZLIB_VERSION "/s/.*"\([0-9]*\.[0-9]*\)\..*/\1/p' < ${SRCDIR}/zlib.h.in) + VER1=$(sed -n -e '/ZLIB_VERSION "/s/.*"\([0-9]*\)\..*/\1/p' < ${SRCDIR}/zlib.h.in) +fi + +show $cc -c $test.c +if test "$gcc" -eq 1 && ($cc $CFLAGS -c $test.c) >> configure.log 2>&1; then + echo "$cc" | tee -a configure.log + CC="$cc" + if test "${CFLAGS#*"-std="}" = "$CFLAGS" ; then + CFLAGS="${CFLAGS} -std=c11" + fi + + # Re-check ARCH if the compiler is a cross-compiler. + if $CC -print-multiarch 1> /dev/null 2>&1 && test -n "$($CC -print-multiarch)" 1> /dev/null 2>&1; then + CC_ARCH=$($CC $CFLAGS -print-multiarch | sed 's/-.*//g') + else + CC_ARCH=$($CC $CFLAGS -dumpmachine | sed 's/-.*//g') + fi + case $CC_ARCH in + i386 | i486 | i586 | i686) + # Honor user choice if gcc is multilib and 64-bit is requested + if test $build64 -eq 1; then + ARCH=x86_64 + else + ARCH=$CC_ARCH + fi ;; + x86_64) + # Honor user choice if gcc is multilib and 32-bit is requested + if test $build32 -ne 1; then + ARCH=$CC_ARCH + fi ;; + arm | armeb) + ARCH=arm + if test "${uname}" = "eabi"; then + uname=arm + fi ;; + armv8l) + ARCH=armv8-a ;; + aarch64 | aarch64_be | arm64) + if test "${uname}" = "elf"; then + uname=aarch64 + fi + ARCH=aarch64 ;; + powerpc | ppc) + ARCH=powerpc ;; + powerpc64 | ppc64) + ARCH=powerpc64 ;; + powerpc64le | ppc64le) + ARCH=powerpc64le ;; + esac + CFLAGS="-O2 ${CFLAGS}" + if test -n "${ARCHS}"; then + CFLAGS="${CFLAGS} ${ARCHS}" + LDFLAGS="${LDFLAGS} ${ARCHS}" + fi + CFLAGS="${CFLAGS} -Wall" + SFLAGS="${CFLAGS} -fPIC" + if test "$warn" -eq 1; then + CFLAGS="${CFLAGS} -Wextra" + fi + if test $debug -eq 1; then + CFLAGS="${CFLAGS} -DZLIB_DEBUG" + SFLAGS="${SFLAGS} -DZLIB_DEBUG" + else + CFLAGS="${CFLAGS} -DNDEBUG" + SFLAGS="${SFLAGS} -DNDEBUG" + fi + if test -z "$uname"; then + uname=$( (uname -s || echo unknown) 2>/dev/null) + fi + case "$uname" in + Linux* | linux* | GNU | GNU/* | solaris* | Haiku) + LDSHARED=${LDSHARED-"$cc"} + LDSHAREDFLAGS="-shared -Wl,-soname,${LIBNAME}.so.${VER1}" ;; + *BSD | *bsd* | DragonFly) + LDSHARED=${LDSHARED-"$cc"} + LDSHAREDFLAGS="-shared -Wl,-soname,${LIBNAME}.so.${VER1}" + LDCONFIG="ldconfig -m" ;; + CYGWIN* | Cygwin* | cygwin*) + visibility=0 + ARFLAGS="rcs" + SFLAGS="${CFLAGS}" + shared_ext='.dll' + sharedlibdir='${bindir}' + if test $compat -eq 0; then + SHAREDLIB=cygz-ng$shared_ext + else + SHAREDLIB=cygz$shared_ext + fi + SHAREDLIBM='' + SHAREDLIBV='' + SHAREDTARGET=$SHAREDLIB + IMPORTLIB="${LIBNAME}.dll.a" + LDSHARED=${LDSHARED-"$cc"} + LDSHAREDFLAGS="-shared -Wl,--out-implib,${IMPORTLIB}" + LDSHAREDLIBC="" + if test $gzfileops -eq 0; then + DEFFILE='win32/${LIBNAME2}.def' + fi + RC="${CROSS_PREFIX}windres" + RCFLAGS="-I ${BUILDDIR}" + RCOBJS='zlibrc.o' + STRIP="${CROSS_PREFIX}strip" + EXE='.exe' ;; + MSYS* | msys*) + visibility=0 + ARFLAGS="rcs" + SFLAGS="${CFLAGS}" + shared_ext='.dll' + sharedlibdir='${bindir}' + if test $compat -eq 0; then + SHAREDLIB=msys-z-ng$shared_ext + else + SHAREDLIB=msys-z$shared_ext + fi + SHAREDLIBM='' + SHAREDLIBV='' + SHAREDTARGET=$SHAREDLIB + IMPORTLIB="${LIBNAME}.dll.a" + LDSHARED=${LDSHARED-"$cc"} + LDSHAREDFLAGS="-shared -Wl,--out-implib,${IMPORTLIB}" + LDSHAREDLIBC="" + if test $gzfileops -eq 0; then + DEFFILE='win32/${LIBNAME2}.def' + fi + RC="${CROSS_PREFIX}windres" + RCFLAGS="-I ${BUILDDIR}" + RCOBJS='zlibrc.o' + STRIP="${CROSS_PREFIX}strip" + EXE='.exe' ;; + MINGW* | mingw*) + visibility=0 + ARFLAGS="rcs" + CFLAGS="${CFLAGS} -D_POSIX_C_SOURCE=200809L -D_GNU_SOURCE=1 -Wno-pedantic-ms-format" + SFLAGS="${CFLAGS}" + shared_ext='.dll' + sharedlibdir='${bindir}' + SHAREDLIB=${LIBNAME}-$VER1$shared_ext + SHAREDLIBM='' + SHAREDLIBV='' + SHAREDTARGET=$SHAREDLIB + IMPORTLIB="${LIBNAME}.dll.a" + LDSHARED=${LDSHARED-"$cc"} + LDSHAREDFLAGS="-shared -Wl,--out-implib=${IMPORTLIB}" + LDSHAREDLIBC="" + if test $gzfileops -eq 0; then + DEFFILE='win32/${LIBNAME2}.def' + fi + RC="${CROSS_PREFIX}windres" + RCFLAGS="-I ${BUILDDIR}" + if [ "$CC" = "mingw32-gcc" ]; then + case $ARCH in + i386 | i486 | i586 | i686) RCFLAGS="${RCFLAGS} -F pe-i386";; + esac; + fi + RCOBJS='zlibrc.o' + STRIP="${CROSS_PREFIX}strip" + EXE='.exe' ;; + QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4 + # (alain.bonnefoy@icbt.com) + LDSHARED=${LDSHARED-"$cc"} + LDSHAREDFLAGS="-shared -Wl,-h${LIBNAME}.so.${VER1}" ;; + HP-UX*) + LDSHARED=${LDSHARED-"$cc"} + LDSHAREDFLAGS="-shared" + case $( (uname -m || echo unknown) 2>/dev/null) in + ia64) + shared_ext='.so' + SHAREDLIB='${LIBNAME}.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='${LIBNAME}.sl' ;; + esac ;; + Darwin* | darwin*) + shared_ext='.dylib' + SHAREDLIB=${LIBNAME}$shared_ext + SHAREDLIBV=${LIBNAME}.$VER$shared_ext + SHAREDLIBM=${LIBNAME}.$VER1$shared_ext + SHAREDTARGET=$SHAREDLIBV + LDSHARED=${LDSHARED-"$cc"} + LDSHAREDFLAGS="-dynamiclib -install_name @rpath/${SHAREDLIBM} -compatibility_version ${VER1} -current_version ${VER3}" + if "${CROSS_PREFIX}libtool" -V 2>&1 | grep Apple > /dev/null; then + AR="${CROSS_PREFIX}libtool" + elif libtool -V 2>&1 | grep Apple > /dev/null; then + AR="libtool" + else + AR="/usr/bin/libtool" + fi + ARFLAGS="-o" ;; + aarch64) + LDSHARED=${LDSHARED-"$cc"} + LDSHAREDFLAGS="-shared -Wl,-soname,${LIBNAME}.so.${VER1}" + LDSHAREDLIBC="-Wl,--start-group -lc -lrdimon -Wl,--end-group" ;; + *) + LDSHARED=${LDSHARED-"$cc"} + LDSHAREDFLAGS="-shared" ;; + esac +else + # find system name and corresponding cc options + CC=${CC-cc} + gcc=0 + echo "$CC" | tee -a configure.log + if test -z "$uname"; then + uname=$( (uname -sr || echo unknown) 2>/dev/null) + fi + case "$uname" in + HP-UX*) SFLAGS=${CFLAGS-"-O +z"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"ld"} + LDSHAREDFLAGS="-b" + case $( (uname -m || echo unknown) 2>/dev/null) in + ia64) + shared_ext='.so' + SHAREDLIB='${LIBNAME}.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='${LIBNAME}.sl' ;; + esac ;; + AIX*) # Courtesy of dbakker@arrayasolutions.com + SFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + CFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + LDSHARED=${LDSHARED-"xlc"} + LDSHAREDFLAGS="-G" ;; + # send working options for other systems to zlib@gzip.org + *) SFLAGS=${CFLAGS-"-O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc"} + LDSHAREDFLAGS="-shared" ;; + esac +fi + +# Symbol versioning +case "$uname" in + CYGWIN* | Cygwin* | cygwin* | MINGW* | mingw* | MSYS* | msys* | Darwin* | darwin*) + echo "Checking for Symbol versioning... No." + ;; + *) + if test $shared -eq 1; then + echo "Checking for Symbol versioning... Yes." + CFLAGS="${CFLAGS} -DHAVE_SYMVER" + SFLAGS="${SFLAGS} -DHAVE_SYMVER" + else + echo "Checking for Symbol versioning... No." + fi + ;; +esac + +# Simplify some later conditionals +case "$uname" in +Linux* | linux*) + LINUX=1 ;; +*) + LINUX=0 ;; +esac + +# destination names for shared library if not defined above +SHAREDLIB=${SHAREDLIB-"${LIBNAME}$shared_ext"} +SHAREDLIBV=${SHAREDLIBV-"${LIBNAME}$shared_ext.$VER"} +SHAREDLIBM=${SHAREDLIBM-"${LIBNAME}$shared_ext.$VER1"} +SHAREDTARGET=${SHAREDTARGET-"${LIBNAME}$shared_ext.$VER"} + +echo >> configure.log + +# define functions for testing compiler and library characteristics and logging the results + +cat > $test.c </dev/null; then + try() + { + show "$@" + test "$( ("$@") 2>&1 | tee -a configure.log)" = "" + } + echo - using any output from compiler to indicate an error >> configure.log +else + try() + { + show "$@" + ( "$@" ) >> configure.log 2>&1 + ret=$? + if test $ret -ne 0; then + echo "(exit code $ret)" >> configure.log + fi + return $ret + } +fi + +cat > $test.c << EOF +int foo() { return 0; } +EOF +echo "Checking for obsessive-compulsive compiler options..." >> configure.log +if try $CC -c $CFLAGS $test.c; then + : +else + echo "Compiler error reporting is too harsh for $0 (perhaps remove -Werror)." | tee -a configure.log + leave 1 +fi + +echo >> configure.log + +# see if shared library build supported +cat > $test.c <> configure.log + +# check for version script support +cat > $test.c < $test.map <> configure.log + +# check for large file support, and if none, check for fseeko() +cat > $test.c < +off64_t dummy = 0; +EOF +if try $CC -c $CFLAGS -D_LARGEFILE64_SOURCE=1 $test.c; then + CFLAGS="${CFLAGS} -D_LARGEFILE64_SOURCE=1" + SFLAGS="${SFLAGS} -D_LARGEFILE64_SOURCE=1" + echo "Checking for off64_t... Yes." | tee -a configure.log + echo "Checking for fseeko... Yes." | tee -a configure.log +else + echo "Checking for off64_t... No." | tee -a configure.log + echo >> configure.log + cat > $test.c < +int main() { + _off64_t dummy = 0; + return 0; +} +EOF + if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then + echo "Checking for _off64_t... Yes." | tee -a configure.log + else + echo "Checking for _off64_t... No." | tee -a configure.log + fi + echo >> configure.log + cat > $test.c < +int main(void) { + fseeko(NULL, 0, 0); + return 0; +} +EOF + if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then + echo "Checking for fseeko... Yes." | tee -a configure.log + else + CFLAGS="${CFLAGS} -DNO_FSEEKO" + SFLAGS="${SFLAGS} -DNO_FSEEKO" + echo "Checking for fseeko... No." | tee -a configure.log + fi +fi +echo >> configure.log + +cat > $test.c < +int main(void) { + void *ptr = 0; + int ret = posix_memalign(&ptr, 64, 10); + if (ptr) + free(ptr); + return ret; +} +EOF +if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then + echo "Checking for posix_memalign... Yes." | tee -a configure.log + CFLAGS="${CFLAGS} -DHAVE_POSIX_MEMALIGN" + SFLAGS="${SFLAGS} -DHAVE_POSIX_MEMALIGN" +else + echo "Checking for posix_memalign... No." | tee -a configure.log +fi +echo >> configure.log + +cat > $test.c < +int main(void) { + void *ptr = aligned_alloc(64, 10); + if (ptr) + free(ptr); + return 0; +} +EOF +if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then + echo "Checking for aligned_alloc... Yes." | tee -a configure.log + CFLAGS="${CFLAGS} -DHAVE_ALIGNED_ALLOC" + SFLAGS="${SFLAGS} -DHAVE_ALIGNED_ALLOC" +else + echo "Checking for aligned_alloc... No." | tee -a configure.log +fi +echo >> configure.log + +# check for strerror() for use by gz* functions +cat > $test.c < +#include +int main() { return strlen(strerror(errno)); } +EOF +if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then + echo "Checking for strerror... Yes." | tee -a configure.log +else + CFLAGS="${CFLAGS} -DNO_STRERROR" + SFLAGS="${SFLAGS} -DNO_STRERROR" + echo "Checking for strerror... No." | tee -a configure.log +fi + +# check for getauxval() or elf_aux_info() for architecture feature detection at run-time +cat > $test.c < +int main() { +#ifdef __FreeBSD__ + int test; + return elf_aux_info(AT_PAGESZ, &test, sizeof(test)); +#else + return getauxval(0); +#endif +} +EOF +if try $CC $CFLAGS -o $test $test.c $LDSHAREDLIBC; then + echo "Checking for getauxval() or elf_aux_info() in sys/auxv.h... Yes." | tee -a configure.log + CFLAGS="${CFLAGS} -DHAVE_SYS_AUXV_H" + SFLAGS="${SFLAGS} -DHAVE_SYS_AUXV_H" +else + echo "Checking for getauxval() in sys/auxv.h... No." | tee -a configure.log +fi + +# We need to remove consigured files (zconf.h etc) from source directory if building outside of it +if [ "$SRCDIR" != "$BUILDDIR" ]; then + rm -f $SRCDIR/zconf${SUFFIX}.h + rm -f $SRCDIR/zlib${SUFFIX}.h + rm -f $SRCDIR/zlib_name_mangling${SUFFIX}.h +fi + +# Rename @ZLIB_SYMBOL_PREFIX@ to $symbol_prefix in gzread.c, zlib.h and zlib_name_mangling.h +sed < $SRCDIR/gzread.c.in "s/@ZLIB_SYMBOL_PREFIX@/$symbol_prefix/g" > gzread.c +sed < $SRCDIR/zlib${SUFFIX}.h.in "s/@ZLIB_SYMBOL_PREFIX@/$symbol_prefix/g" > zlib${SUFFIX}.h +if [ ! -z "$symbol_prefix" ]; then + sed < $SRCDIR/zlib_name_mangling${SUFFIX}.h.in "s/@ZLIB_SYMBOL_PREFIX@/$symbol_prefix/g" > zlib_name_mangling${SUFFIX}.h +else + # symbol_prefix is not set, copy the empty mangling header + cp -p $SRCDIR/zlib_name_mangling.h.empty zlib_name_mangling${SUFFIX}.h +fi + +# copy clean zconf.h for subsequent edits +cp -p $SRCDIR/zconf${SUFFIX}.h.in zconf${SUFFIX}.h + +echo >> configure.log + +# check for unistd.h and save result in zconf.h +cat > $test.c < +int main() { return 0; } +EOF +if try $CC -c $CFLAGS $test.c; then + sed < zconf${SUFFIX}.h "/^#ifdef HAVE_UNISTD_H.* may be/s/def HAVE_UNISTD_H\(.*\) may be/ 1\1 was/" > zconf${SUFFIX}.temp.h + mv zconf${SUFFIX}.temp.h zconf${SUFFIX}.h + echo "Checking for unistd.h... Yes." | tee -a configure.log +else + sed < zconf${SUFFIX}.h "/^#ifdef HAVE_UNISTD_H.* may be/s/def HAVE_UNISTD_H\(.*\) may be set to #if 1/ 0\1 was set to #if 0/" > zconf${SUFFIX}.temp.h + mv zconf${SUFFIX}.temp.h zconf${SUFFIX}.h + echo "Checking for unistd.h... No." | tee -a configure.log +fi + +echo >> configure.log + +# check for ptrdiff_t and save result in zconf.h +printf "Checking for ptrdiff_t... " | tee -a configure.log +cat > $test.c < +int fun(ptrdiff_t *a) { (void)a; return 0; } +EOF +if try $CC -c $CFLAGS $test.c; then + echo "Yes." | tee -a configure.log +else + echo "No." | tee -a configure.log + sed < zconf${SUFFIX}.h "/^#ifdef NEED_PTRDIFF_T.* may be/s/def NEED_PTRDIFF_T\(.*\) may be/ 1\1 was/" > zconf${SUFFIX}.temp.h + mv zconf${SUFFIX}.temp.h zconf${SUFFIX}.h + + printf "Checking for sizeof(void *)... " | tee -a configure.log + cat > $test.c < +#define COMPILE_TIME_ASSERT(pred) struct s { int x: (pred) ? 1 : -1; } +COMPILE_TIME_ASSERT(sizeof(int32_t) == sizeof(void *)); +EOF + if try $CC -c $CFLAGS $test.c; then + echo "sizeof(int32_t)." | tee -a configure.log + sed < zconf${SUFFIX}.h "s/^typedef PTRDIFF_TYPE ptrdiff_t;/typedef int32_t ptrdiff_t;/g" > zconf${SUFFIX}.temp.h + mv zconf${SUFFIX}.temp.h zconf${SUFFIX}.h + else + cat > $test.c < +#define COMPILE_TIME_ASSERT(pred) struct s { int x: (pred) ? 1 : -1; } +COMPILE_TIME_ASSERT(sizeof(int64_t) == sizeof(void *)); +EOF + if try $CC -c $CFLAGS $test.c; then + echo "sizeof(int64_t)." | tee -a configure.log + sed < zconf${SUFFIX}.h "s/^typedef PTRDIFF_TYPE ptrdiff_t;/typedef int64_t ptrdiff_t;/g" > zconf${SUFFIX}.temp.h + mv zconf${SUFFIX}.temp.h zconf${SUFFIX}.h + else + echo "unknown." | tee -a configure.log + exit 1 + fi + fi +fi + +# if --zlib-compat was requested +if test $compat -eq 1; then + gzfileops=1 + CFLAGS="${CFLAGS} -DZLIB_COMPAT" + SFLAGS="${SFLAGS} -DZLIB_COMPAT" + case "$uname" in + CYGWIN* | Cygwin* | cygwin* | MSYS* | msys* | MINGW* | mingw*) + DEFFILE="win32/zlibcompat.def" ;; + esac +fi + +if [ ! -z "$DEFFILE" ]; then + mkdir -p win32 + sed < $SRCDIR/$DEFFILE.in "s/@ZLIB_SYMBOL_PREFIX@/$symbol_prefix/g" > $DEFFILE +fi + +# if --gzfileops was requested +if test $gzfileops -eq 1; then + CFLAGS="${CFLAGS} -DWITH_GZFILEOP" + SFLAGS="${SFLAGS} -DWITH_GZFILEOP" + OBJC="${OBJC} \$(OBJG)" + PIC_OBJC="${PIC_OBJC} \$(PIC_OBJG)" +else + TESTOBJG="\$(OBJG)" + PIC_TESTOBJG="\$(OBJG)" +fi + +# enable reduced memory configuration +if test $reducedmem -eq 1; then + echo "Configuring for reduced memory environment." | tee -a configure.log + CFLAGS="${CFLAGS} -DHASH_SIZE=32768u -DGZBUFSIZE=8192 -DNO_LIT_MEM" +fi + +# if code coverage testing was requested, use older gcc if defined, e.g. "gcc-4.2" on Mac OS X +if test $cover -eq 1; then + CFLAGS="${CFLAGS} -fprofile-arcs -ftest-coverage" + LDFLAGS="${LDFLAGS} -fprofile-arcs -ftest-coverage" + if test -n "$GCC_CLASSIC"; then + CC=$GCC_CLASSIC + fi +fi + +echo >> configure.log + +# Check for ANSI C compliant compiler +cat > $test.c < +#include +#include +#include "zconf${SUFFIX}.h" +int main() { +#ifdef STDC + return 0; +#endif + return 1; +} +EOF +if try $CC -c $CFLAGS $test.c; then + echo "Checking for ANSI C compliant compiler... Yes." | tee -a configure.log + : +else + echo "Checking for ANSI C compliant compiler... No." | tee -a configure.log + echo "Error: ANSI C compatible compiler needed, cannot continue." | tee -a configure.log + leave 1 +fi + +# Check for -fno-semantic-interposition compiler support +echo "" > test.c + cat > $test.c <> configure.log 2>&1; then + echo "Checking for -fno-semantic-interposition... Yes." | tee -a configure.log + SFLAGS="$SFLAGS -fno-semantic-interposition" +else + echo "Checking for -fno-semantic-interposition... No." | tee -a configure.log +fi + +# Check for -fno-lto compiler support +if test $gcc -eq 1 -a $without_optimizations -eq 0; then + cat > $test.c <> configure.log 2>&1; then + echo "Checking for -fno-lto... Yes." | tee -a configure.log + else + echo "Checking for -fno-lto... No." | tee -a configure.log + noltoflag="" + fi +fi + +# see if we can hide zlib internal symbols that are linked between separate source files using hidden +if test "$gcc" -eq 1 && test "$visibility" -eq 1; then + echo >> configure.log + cat > $test.c <> configure.log + echo "Checking for attribute(visibility(hidden)) support... Yes." | tee -a configure.log + else + echo >> configure.log + echo "Checking for attribute(visibility(hidden)) support... No." | tee -a configure.log + fi +fi + +# see if we can hide zlib internal symbols that are linked between separate source files using internal +if test "$gcc" -eq 1 && test "$visibility" -eq 1; then + echo >> configure.log + cat > $test.c <> configure.log + echo "Checking for attribute(visibility(internal)) support... Yes." | tee -a configure.log + else + echo >> configure.log + echo "Checking for attribute(visibility(internal)) support... No." | tee -a configure.log + fi +fi + +# Check for attribute(aligned) support in compiler +cat > $test.c << EOF +int main(void) { + __attribute__((aligned(8))) int test = 0; + (void)test; + return 0; +} +EOF +if try ${CC} ${CFLAGS} $test.c $LDSHAREDLIBC; then + echo "Checking for attribute(aligned) ... Yes." | tee -a configure.log + CFLAGS="$CFLAGS -DHAVE_ATTRIBUTE_ALIGNED" + SFLAGS="$SFLAGS -DHAVE_ATTRIBUTE_ALIGNED" +else + echo "Checking for attribute(aligned) ... No." | tee -a configure.log +fi + +# Check for __builtin_assume_aligned(x,n) support in compiler +cat > $test.c << EOF +char *test(char *buffer) { + char *abuffer = __builtin_assume_aligned(buffer,64); + return abuffer; +} +int main() { + return 0; +} +EOF +if try ${CC} ${CFLAGS} $test.c $LDSHAREDLIBC; then + echo "Checking for __builtin_assume_aligned() ... Yes." | tee -a configure.log + CFLAGS="$CFLAGS -DHAVE_BUILTIN_ASSUME_ALIGNED" + SFLAGS="$SFLAGS -DHAVE_BUILTIN_ASSUME_ALIGNED" +else + echo "Checking for __builtin_assume_aligned() ... No." | tee -a configure.log +fi + +# Check for __builtin_ctz() support in compiler +cat > $test.c << EOF +long f(unsigned int x) { return __builtin_ctz(x); } +int main(void) { return 0; } +EOF +if try ${CC} ${CFLAGS} $test.c $LDSHAREDLIBC; then + echo "Checking for __builtin_ctz ... Yes." | tee -a configure.log + CFLAGS="$CFLAGS -DHAVE_BUILTIN_CTZ" + SFLAGS="$SFLAGS -DHAVE_BUILTIN_CTZ" +else + echo "Checking for __builtin_ctz ... No." | tee -a configure.log +fi + +# Check for __builtin_ctzll() support in compiler +cat > $test.c << EOF +long f(unsigned long long x) { return __builtin_ctzll(x); } +int main(void) { return 0; } +EOF +if try ${CC} ${CFLAGS} $test.c $LDSHAREDLIBC; then + echo "Checking for __builtin_ctzll ... Yes." | tee -a configure.log + CFLAGS="$CFLAGS -DHAVE_BUILTIN_CTZLL" + SFLAGS="$SFLAGS -DHAVE_BUILTIN_CTZLL" +else + echo "Checking for __builtin_ctzll ... No." | tee -a configure.log +fi + +check_avx2_intrinsics() { + # Check whether compiler supports AVX2 intrinsics + cat > $test.c << EOF +#include +__m256i f(__m256i x) { + const __m256i y = _mm256_set1_epi16(1); + return _mm256_subs_epu16(x, y); +} +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${avx2flag} $test.c; then + echo "Checking for AVX2 intrinsics ... Yes." | tee -a configure.log + HAVE_AVX2_INTRIN=1 + else + echo "Checking for AVX2 intrinsics ... No." | tee -a configure.log + HAVE_AVX2_INTRIN=0 + fi +} + +check_avx512_intrinsics() { + # Check whether compiler supports AVX512 intrinsics + cat > $test.c << EOF +#include +__m512i f(__m512i y) { + __m512i x = _mm512_set1_epi8(2); + return _mm512_sub_epi8(x, y); +} +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${avx512flag} $test.c; then + echo "Checking for AVX512 intrinsics ... Yes." | tee -a configure.log + HAVE_AVX512_INTRIN=1 + else + echo "Checking for AVX512 intrinsics ... No." | tee -a configure.log + HAVE_AVX512_INTRIN=0 + fi +} + +check_mtune_skylake_avx512_compiler_flag() { + # Check whether -mtune=skylake-avx512 works correctly + cat > $test.c << EOF +int main() { return 0; } +EOF + if try $CC -c $CFLAGS -mtune=skylake-avx512 $test.c; then + MTUNE_SKYLAKE_AVX512_AVAILABLE=1 + echo "Check whether -mtune=skylake-avx512 works ... Yes." | tee -a configure.log + else + echo "Check whether -mtune=skylake-avx512 works ... No." | tee -a configure.log + MTUNE_SKYLAKE_AVX512_AVAILABLE=0 + fi +} + +check_mtune_cascadelake_compiler_flag() { + # Check whether -mtune=cascadelake works correctly + cat > $test.c << EOF +int main() { return 0; } +EOF + if try $CC -c $CFLAGS -mtune=cascadelake $test.c; then + MTUNE_CASCADELAKE_AVAILABLE=1 + echo "Check whether -mtune=cascadelake works ... Yes." | tee -a configure.log + else + echo "Check whether -mtune=cascadelake works ... No." | tee -a configure.log + MTUNE_CASCADELAKE_AVAILABLE=0 + check_mtune_skylake_avx512_compiler_flag + fi +} + +check_avx512vnni_intrinsics() { + # Check whether compiler supports AVX512-VNNI intrinsics + cat > $test.c << EOF +#include +__m512i f(__m512i x, __m512i y) { + __m512i z = _mm512_setzero_epi32(); + return _mm512_dpbusd_epi32(z, x, y); +} +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${avx512vnniflag} $test.c; then + echo "Checking for AVX512VNNI intrinsics ... Yes." | tee -a configure.log + HAVE_AVX512VNNI_INTRIN=1 + else + echo "Checking for AVX512VNNI intrinsics ... No." | tee -a configure.log + HAVE_AVX512VNNI_INTRIN=0 + fi +} + +check_acle_compiler_flag() { + # Check whether -march=armv8-a+crc works correctly + cat > $test.c << EOF +int main() { return 0; } +EOF + if try $CC -c $CFLAGS -march=armv8-a+crc $test.c; then + echo "Check whether -march=armv8-a+crc works ... Yes." | tee -a configure.log + acleflag="-march=armv8-a+crc" + else + echo "Check whether -march=armv8-a+crc works ... No." | tee -a configure.log + if try $CC -c $CFLAGS -march=armv8-a+crc+simd $test.c; then + echo "Check whether -march=armv8-a+crc+simd works ... Yes." | tee -a configure.log + acleflag="-march=armv8-a+crc+simd" + else + echo "Check whether -march=armv8-a+crc+simd works ... No." | tee -a configure.log + fi + fi + + # Check whether compiler supports ARMv8 CRC intrinsics + cat > $test.c << EOF +#include +unsigned int f(unsigned int a, unsigned int b) { + return __crc32w(a, b); +} +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${acleflag} $test.c; then + echo "Checking for ARMv8 CRC intrinsics ... Yes." | tee -a configure.log + ACLE_AVAILABLE=1 + else + echo "Checking for ARMv8 CRC intrinsics ... No." | tee -a configure.log + ACLE_AVAILABLE=0 + fi +} + +check_neon_compiler_flag() { + if test "$ARCH" = "aarch64"; then + neonflag="-march=armv8-a+simd" + else + neonflag="-mfpu=neon" + fi + # Check whether neon flag is available on ARM processors. + cat > $test.c << EOF +#if defined(_M_ARM64) || defined(_M_ARM64EC) + # include + #else + # include +#endif +int main() { return 0; } +EOF + if try $CC -c $CFLAGS $neonflag $test.c; then + NEON_AVAILABLE=1 + echo "Check whether $neonflag is available ... Yes." | tee -a configure.log + else + NEON_AVAILABLE=0 + echo "Check whether $neonflag is available ... No." | tee -a configure.log + fi +} + +check_neon_ld4_intrinsics() { + cat > $test.c << EOF +#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC)) +# include +#else +# include +#endif +int32x4x4_t f(int var[16]) { return vld1q_s32_x4(var); } +int main(void) { return 0; } +EOF + if try $CC -c $CFLAGS $neonflag $test.c; then + NEON_HAS_LD4=1 + echo "check whether compiler supports 4 wide register loads ... Yes." | tee -a configure.log + else + NEON_HAS_LD4=0 + echo "check whether compiler supports 4 wide register loads ... No." | tee -a configure.log + fi +} + +check_armv6_intrinsics() { + # Check whether -march=armv6 works correctly + cat > $test.c << EOF +int main() { return 0; } +EOF + if try $CC -c $CFLAGS -march=armv6 $test.c; then + armv6flag=-march=armv6 + echo "Check whether -march=armv6 works ... Yes." | tee -a configure.log + else + echo "Check whether -march=armv6 works ... No." | tee -a configure.log + fi + + # Check whether compiler supports ARMv6 inline asm + cat > $test.c << EOF +unsigned int f(unsigned int a, unsigned int b) { + unsigned int c; + __asm__ __volatile__ ( "uqsub16 %0, %1, %2" : "=r" (c) : "r" (a), "r" (b) ); + return c; +} +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${armv6flag} $test.c; then + echo "Checking for ARMv6 inline assembly ... Yes." | tee -a configure.log + HAVE_ARMV6_INLINE_ASM=1 + else + echo "Checking for ARMv6 inline assembly ... No." | tee -a configure.log + HAVE_ARMV6_INLINE_ASM=0 + fi + + # Check whether compiler supports ARMv6 intrinsics + cat > $test.c << EOF +#include +unsigned int f(unsigned int a, unsigned int b) { + return __uqsub16(a, b); +} +int main(void) { return f(1, 2); } +EOF + if try ${CC} ${CFLAGS} ${armv6flag} $test.c; then + echo "Checking for ARMv6 intrinsics ... Yes." | tee -a configure.log + HAVE_ARMV6_INTRIN=1 + else + echo "Checking for ARMv6 intrinsics ... No." | tee -a configure.log + HAVE_ARMV6_INTRIN=0 + fi +} + +check_pclmulqdq_intrinsics() { + # Check whether compiler supports PCLMULQDQ intrinsics + cat > $test.c << EOF +#include +#include +__m128i f(__m128i a, __m128i b) { return _mm_clmulepi64_si128(a, b, 0x10); } +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${pclmulflag} $test.c; then + echo "Checking for PCLMULQDQ intrinsics ... Yes." | tee -a configure.log + HAVE_PCLMULQDQ_INTRIN=1 + else + echo "Checking for PCLMULQDQ intrinsics ... No." | tee -a configure.log + HAVE_PCLMULQDQ_INTRIN=0 + fi +} + +check_vpclmulqdq_intrinsics() { + # Check whether compiler supports VPCLMULQDQ intrinsics + cat > $test.c << EOF +#include +#include +__m512i f(__m512i a) { + __m512i b = _mm512_setzero_si512(); + return _mm512_clmulepi64_epi128(a, b, 0x10); +} +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${vpclmulflag} $test.c; then + echo "Checking for VPCLMULQDQ intrinsics ... Yes." | tee -a configure.log + HAVE_VPCLMULQDQ_INTRIN=1 + else + echo "Checking for VPCLMULQDQ intrinsics ... No." | tee -a configure.log + HAVE_VPCLMULQDQ_INTRIN=0 + fi +} + +check_xsave_intrinsics() { + # Check whether compiler supports XSAVE intrinsics + cat > $test.c << EOF +#ifdef _MSC_VER +# include +#elif __GNUC__ == 8 && __GNUC_MINOR__ > 1 +# include +#else +# include +#endif +unsigned int f(unsigned int a) { return (int) _xgetbv(a); } +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${xsaveflag} $test.c; then + echo "Checking for XSAVE intrinsics ... Yes." | tee -a configure.log + HAVE_XSAVE_INTRIN=1 + else + echo "Checking for XSAVE intrinsics ... No." | tee -a configure.log + HAVE_XSAVE_INTRIN=0 + fi +} + +check_ppc_intrinsics() { + cat > $test.c << EOF +#include +int main(void) +{ + vector int a = vec_splats(0); + vector int b = vec_splats(0); + a = vec_add(a, b); + return 0; +} +EOF + if test $buildaltivec -eq 1 && try ${CC} ${CFLAGS} -maltivec $test.c; then + echo "Checking for AltiVec intrinsics ... Yes." | tee -a configure.log + HAVE_ALTIVEC_INTRIN=1 + else + echo "Checking for AltiVec intrinsics ... No." | tee -a configure.log + HAVE_ALTIVEC_INTRIN=0 + fi + if test $buildaltivec -eq 1 && try ${CC} ${CFLAGS} -maltivec -mno-vsx $test.c; then + echo "Checking if -mno-vsx is supported ... Yes." | tee -a configure.log + vmxflag="$vmxflag -mno-vsx" + else + echo "Checking if -mno-vsx is supported ... No." | tee -a configure.log + fi + cat > $test.c << EOF +#ifdef __FreeBSD__ +#include +#endif +#include +int main() { +#ifdef __FreeBSD__ + unsigned long hwcap; + elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); + return (hwcap & PPC_FEATURE_HAS_ALTIVEC); +#else + return (getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC); +#endif +} +EOF + if try $CC -c $CFLAGS -maltivec $test.c; then + HAVE_VMX=1 + echo "Check whether VMX instructions are available ... Yes." | tee -a configure.log + else + HAVE_VMX=0 + echo "Check whether VMX instructions are available ... No." | tee -a configure.log + fi +} + +check_power8_intrinsics() { + # Check whether features needed by POWER8 optimisations are available + cat > $test.c << EOF +#ifdef __FreeBSD__ +#include +#endif +#include +int main() { +#ifdef __FreeBSD__ + unsigned long hwcap; + elf_aux_info(AT_HWCAP2, &hwcap, sizeof(hwcap)); + return (hwcap & PPC_FEATURE2_ARCH_2_07); +#else + return (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07); +#endif +} +EOF + if test $buildpower8 -eq 1 && try $CC -c $CFLAGS -mcpu=power8 $test.c; then + HAVE_POWER8_INTRIN=1 + echo "Check whether POWER8 instructions are available ... Yes." | tee -a configure.log + else + HAVE_POWER8_INTRIN=0 + echo "Check whether POWER8 instructions are available ... No." | tee -a configure.log + fi +} + +check_power9_intrinsics() { + # Check whether features needed by POWER9 optimisations are available + cat > $test.c << EOF +#ifdef __FreeBSD__ +#include +#endif +#include +int main() { +#ifdef __FreeBSD__ + unsigned long hwcap; + elf_aux_info(AT_HWCAP2, &hwcap, sizeof(hwcap)); + return (hwcap & PPC_FEATURE2_ARCH_3_00); +#else + return (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00); +#endif +} +EOF + if test $buildpower9 -eq 1 && try $CC -c $CFLAGS -mcpu=power9 $test.c; then + HAVE_POWER9_INTRIN=1 + echo "Check whether POWER9 instructions are available ... Yes." | tee -a configure.log + else + HAVE_POWER9_INTRIN=0 + echo "Check whether POWER9 instructions are available ... No." | tee -a configure.log + fi +} + +check_sse2_intrinsics() { + # Check whether compiler supports SSE2 intrinsics + cat > $test.c << EOF +#include +__m128i f(__m128i x, __m128i y) { return _mm_sad_epu8(x, y); } +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${sse2flag} $test.c; then + echo "Checking for SSE2 intrinsics ... Yes." | tee -a configure.log + HAVE_SSE2_INTRIN=1 + else + echo "Checking for SSE2 intrinsics ... No." | tee -a configure.log + HAVE_SSE2_INTRIN=0 + fi +} + +check_sse42_intrinsics() { + # Check whether compiler supports SSE4.2 intrinsics + cat > $test.c << EOF +#include +unsigned int f(unsigned int a, unsigned int b) { return _mm_crc32_u32(a, b); } +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${sse42flag} $test.c; then + echo "Checking for SSE4.2 intrinsics ... Yes." | tee -a configure.log + HAVE_SSE42_INTRIN=1 + else + echo "Checking for SSE4.2 intrinsics ... No." | tee -a configure.log + HAVE_SSE42_INTRIN=0 + fi +} + +check_ssse3_intrinsics() { + # Check whether compiler supports SSSE3 intrinsics + cat > $test.c << EOF +#include +__m128i f(__m128i u) { + __m128i v = _mm_set1_epi32(1); + return _mm_hadd_epi32(u, v); +} +int main(void) { return 0; } +EOF + if try ${CC} ${CFLAGS} ${ssse3flag} $test.c; then + echo "Checking for SSSE3 intrinsics ... Yes." | tee -a configure.log + HAVE_SSSE3_INTRIN=1 + else + echo "Checking for SSSE3 intrinsics ... No." | tee -a configure.log + HAVE_SSSE3_INTRIN=0 + fi +} + +check_vgfma_intrinsics() { + # Check whether "VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE" intrinsic is available + printf "Checking for -mzarch... " | tee -a configure.log + if try $CC -x c -c /dev/null -o /dev/null -mzarch; then + echo Yes. | tee -a configure.log + vgfmaflag="${vgfmaflag} -mzarch" + else + echo No. | tee -a configure.log + fi + printf "Checking for -fzvector... " | tee -a configure.log + if try $CC -x c -c /dev/null -o /dev/null -fzvector; then + echo Yes. | tee -a configure.log + vgfmaflag="${vgfmaflag} -fzvector" + else + echo No. | tee -a configure.log + fi + cat > $test.c << EOF +#include +int main(void) { + unsigned long long a __attribute__((vector_size(16))) = { 0 }; + unsigned long long b __attribute__((vector_size(16))) = { 0 }; + unsigned char c __attribute__((vector_size(16))) = { 0 }; + c = vec_gfmsum_accum_128(a, b, c); + return c[0]; +} +EOF + printf "Checking for VGFMA support... " | tee -a configure.log + if try $CC -c $CFLAGS $vgfmaflag $test.c; then + HAVE_VGFMA_INTRIN=1 + echo "Yes." | tee -a configure.log + else + HAVE_VGFMA_INTRIN=0 + echo "No." | tee -a configure.log + fi +} + +# Check whether to disable deflate_medium and deflate_quick +if test $without_new_strategies -eq 1; then + CFLAGS="${CFLAGS} -DNO_QUICK_STRATEGY -DNO_MEDIUM_STRATEGY" + SFLAGS="${SFLAGS} -DNO_QUICK_STRATEGY -DNO_MEDIUM_STRATEGY" +fi + +ARCHDIR='arch/generic' +ARCH_STATIC_OBJS='' +ARCH_SHARED_OBJS='' + +# Set ARCH specific FLAGS +case "${ARCH}" in + # x86/amd64 specific optimizations + i386 | i486 | i586 | i686 |x86_64) + ARCHDIR=arch/x86 + + # Enable arch-specific optimizations + if test $without_optimizations -eq 0; then + CFLAGS="${CFLAGS} -DX86_FEATURES" + SFLAGS="${SFLAGS} -DX86_FEATURES" + + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} x86_features.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} x86_features.lo" + + check_xsave_intrinsics + + if test ${HAVE_XSAVE_INTRIN} -eq 1; then + CFLAGS="${CFLAGS} -DX86_HAVE_XSAVE_INTRIN" + SFLAGS="${SFLAGS} -DX86_HAVE_XSAVE_INTRIN" + else + xsaveflag="" + fi + + check_sse2_intrinsics + + if test ${HAVE_SSE2_INTRIN} -eq 1; then + CFLAGS="${CFLAGS} -DX86_SSE2" + SFLAGS="${SFLAGS} -DX86_SSE2" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} chunkset_sse2.o compare256_sse2.o slide_hash_sse2.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} chunkset_sse2.lo compare256_sse2.lo slide_hash_sse2.lo" + + if test $forcesse2 -eq 1; then + CFLAGS="${CFLAGS} -DX86_NOCHECK_SSE2" + SFLAGS="${SFLAGS} -DX86_NOCHECK_SSE2" + fi + fi + + check_ssse3_intrinsics + + if test ${HAVE_SSSE3_INTRIN} -eq 1; then + CFLAGS="${CFLAGS} -DX86_SSSE3" + SFLAGS="${SFLAGS} -DX86_SSSE3" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} adler32_ssse3.o chunkset_ssse3.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} adler32_ssse3.lo chunkset_ssse3.lo" + fi + + check_sse42_intrinsics + + if test ${HAVE_SSE42_INTRIN} -eq 1; then + CFLAGS="${CFLAGS} -DX86_SSE42" + SFLAGS="${SFLAGS} -DX86_SSE42" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} adler32_sse42.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} adler32_sse42.lo" + fi + + check_pclmulqdq_intrinsics + + if test ${HAVE_PCLMULQDQ_INTRIN} -eq 1; then + CFLAGS="${CFLAGS} -DX86_PCLMULQDQ_CRC" + SFLAGS="${SFLAGS} -DX86_PCLMULQDQ_CRC" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} crc32_pclmulqdq.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} crc32_pclmulqdq.lo" + fi + + check_avx2_intrinsics + + if test ${HAVE_AVX2_INTRIN} -eq 1; then + CFLAGS="${CFLAGS} -DX86_AVX2" + SFLAGS="${SFLAGS} -DX86_AVX2" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} slide_hash_avx2.o chunkset_avx2.o compare256_avx2.o adler32_avx2.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} slide_hash_avx2.lo chunkset_avx2.lo compare256_avx2.lo adler32_avx2.lo" + fi + + check_avx512_intrinsics + + if test ${HAVE_AVX512_INTRIN} -eq 1; then + CFLAGS="${CFLAGS} -DX86_AVX512" + SFLAGS="${SFLAGS} -DX86_AVX512" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} adler32_avx512.o chunkset_avx512.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} adler32_avx512.lo chunkset_avx512.lo" + fi + + check_mtune_cascadelake_compiler_flag + + if test ${MTUNE_CASCADELAKE_AVAILABLE} -eq 1; then + avx512flag="${avx512flag} -mtune=cascadelake" + avx512vnniflag="${avx512vnniflag} -mtune=cascadelake" + else + if test ${MTUNE_SKYLAKE_AVX512_AVAILABLE} -eq 1; then + avx512flag="${avx512flag} -mtune=skylake-avx512" + avx512vnniflag="${avx512vnniflag} -mtune=skylake-avx512" + fi + fi + + check_avx512vnni_intrinsics + + if test ${HAVE_AVX512VNNI_INTRIN} -eq 1; then + CFLAGS="${CFLAGS} -DX86_AVX512VNNI" + SFLAGS="${SFLAGS} -DX86_AVX512VNNI" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} adler32_avx512_vnni.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} adler32_avx512_vnni.lo" + fi + + if test $buildvpclmulqdq -eq 1 && test ${HAVE_PCLMULQDQ_INTRIN} -eq 1 && test ${HAVE_AVX512_INTRIN} -eq 1; then + check_vpclmulqdq_intrinsics + + if test ${HAVE_VPCLMULQDQ_INTRIN} -eq 1; then + CFLAGS="${CFLAGS} -DX86_VPCLMULQDQ_CRC" + SFLAGS="${SFLAGS} -DX86_VPCLMULQDQ_CRC" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} crc32_vpclmulqdq.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} crc32_vpclmulqdq.lo" + fi + fi + fi + ;; + + # ARM specific optimizations + arm* | aarch64) + case "${ARCH}" in + arm*) + [ ! -z $CROSS_PREFIX ] && QEMU_ARCH=arm + ;; + aarch64) + [ ! -z $CROSS_PREFIX ] && QEMU_ARCH=aarch64 + buildarmv6=0 + ;; + esac + + ARCHDIR=arch/arm + + cat > $test.c << EOF +int main() { return 0; } +EOF + if try $CC -c $SFLAGS $test.c -mfloat-abi=softfp && + try $LDSHARED $LDSHAREDFLAGS $LDFLAGS -o $test$shared_ext $test.o $LDSHAREDLIBC; then + floatabi="-mfloat-abi=softfp" + else + if try $CC -c $SFLAGS $test.c -mfloat-abi=hard && + try $LDSHARED $LDSHAREDFLAGS $LDFLAGS -o $test$shared_ext $test.o $LDSHAREDLIBC; then + floatabi="-mfloat-abi=hard" + fi + fi + + if [ -z $floatabi ]; then + echo "ARM floating point arch not auto-detected" | tee -a configure.log + else + echo "ARM floating point arch: ${floatabi}" | tee -a configure.log + + CFLAGS="${CFLAGS} ${floatabi}" + SFLAGS="${SFLAGS} ${floatabi}" + fi + + if test $without_optimizations -eq 0; then + CFLAGS="${CFLAGS} -DARM_FEATURES" + SFLAGS="${SFLAGS} -DARM_FEATURES" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} arm_features.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} arm_features.lo" + + cat > $test.c < +EOF + if try $CC -c $CFLAGS $test.c; then + echo "Checking for arm_acle.h... Yes." | tee -a configure.log + CFLAGS="${CFLAGS} -DHAVE_ARM_ACLE_H" + SFLAGS="${SFLAGS} -DHAVE_ARM_ACLE_H" + else + echo "Checking for arm_acle.h... No." | tee -a configure.log + fi + + + if test $LINUX -eq 1; then + if test "$ARCH" = "aarch64"; then + cat > $test.c < +int main() { + return (getauxval(AT_HWCAP) & HWCAP_CRC32); +} +EOF + if try $CC -c $CFLAGS $test.c; then + CFLAGS="${CFLAGS} -DARM_AUXV_HAS_CRC32" + SFLAGS="${SFLAGS} -DARM_AUXV_HAS_CRC32" + else + echo "HWCAP_CRC32 not present in sys/auxv.h; cannot detect support at runtime." | tee -a configure.log + fi + else + cat > $test.c < +int main() { + return (getauxval(AT_HWCAP2) & HWCAP2_CRC32); +} +EOF + if try $CC -c $CFLAGS $test.c; then + CFLAGS="${CFLAGS} -DARM_AUXV_HAS_CRC32" + SFLAGS="${SFLAGS} -DARM_AUXV_HAS_CRC32" + else + cat > $test.c < +#include +int main() { + return (getauxval(AT_HWCAP2) & HWCAP2_CRC32); +} +EOF + if try $CC -c $CFLAGS $test.c; then + CFLAGS="${CFLAGS} -DARM_AUXV_HAS_CRC32 -DARM_ASM_HWCAP" + SFLAGS="${SFLAGS} -DARM_AUXV_HAS_CRC32 -DARM_ASM_HWCAP" + else + echo "HWCAP2_CRC32 not present in sys/auxv.h; cannot detect support at runtime." | tee -a configure.log + fi + fi + + cat > $test.c < +int main() { + return (getauxval(AT_HWCAP) & HWCAP_ARM_NEON); +} +EOF + if try $CC -c $CFLAGS $test.c; then + CFLAGS="${CFLAGS} -DARM_AUXV_HAS_NEON" + SFLAGS="${SFLAGS} -DARM_AUXV_HAS_NEON" + else + cat > $test.c < +int main() { + return (getauxval(AT_HWCAP) & HWCAP_NEON); +} +EOF + if try $CC -c $CFLAGS $test.c; then + CFLAGS="${CFLAGS} -DARM_AUXV_HAS_NEON" + SFLAGS="${SFLAGS} -DARM_AUXV_HAS_NEON" + else + echo "Neither HWCAP_ARM_NEON or HWCAP_NEON present in sys/auxv.h; cannot detect support at runtime." | tee -a configure.log + fi + fi + fi + fi + + if test $buildacle -eq 1; then + check_acle_compiler_flag + + if test $ACLE_AVAILABLE -eq 1; then + CFLAGS="${CFLAGS} -DARM_ACLE" + SFLAGS="${SFLAGS} -DARM_ACLE" + + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} crc32_acle.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} crc32_acle.lo" + fi + fi + + if test $buildneon -eq 1; then + check_neon_compiler_flag + + if test $NEON_AVAILABLE -eq 1; then + CFLAGS="${CFLAGS} -DARM_NEON" + SFLAGS="${SFLAGS} -DARM_NEON" + + check_neon_ld4_intrinsics + + if test $NEON_HAS_LD4 -eq 1; then + CFLAGS="${CFLAGS} -DARM_NEON_HASLD4" + SFLAGS="${SFLAGS} -DARM_NEON_HASLD4" + fi + + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} adler32_neon.o chunkset_neon.o compare256_neon.o slide_hash_neon.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} adler32_neon.lo chunkset_neon.lo compare256_neon.lo slide_hash_neon.lo" + fi + fi + + if test $buildarmv6 -eq 1; then + check_armv6_intrinsics + + if test $HAVE_ARMV6_INTRIN -eq 1 || test $HAVE_ARMV6_INLINE_ASM -eq 1; then + CFLAGS="${CFLAGS} -DARM_SIMD" + SFLAGS="${SFLAGS} -DARM_SIMD" + + if test $HAVE_ARMV6_INTRIN -eq 1; then + CFLAGS="${CFLAGS} -DARM_SIMD_INTRIN" + SFLAGS="${SFLAGS} -DARM_SIMD_INTRIN" + fi + + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} slide_hash_armv6.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} slide_hash_armv6.lo" + fi + fi + + fi + ;; + powerpc*) + case "${ARCH}" in + powerpc) + [ ! -z $CROSS_PREFIX ] && QEMU_ARCH=ppc + ;; + powerpc64) + [ ! -z $CROSS_PREFIX ] && QEMU_ARCH=ppc64 + ;; + powerpc64le) + [ ! -z $CROSS_PREFIX ] && QEMU_ARCH=ppc64le + ;; + esac + + ARCHDIR=arch/power + + if test $without_optimizations -eq 0; then + + check_ppc_intrinsics + check_power8_intrinsics + check_power9_intrinsics + + if test $HAVE_VMX -eq 1; then + CFLAGS="${CFLAGS} -DPPC_FEATURES" + SFLAGS="${SFLAGS} -DPPC_FEATURES" + fi + if test $HAVE_VMX -eq 1 -o $HAVE_POWER8_INTRIN -eq 1; then + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} power_features.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} power_features.lo" + fi + if test $HAVE_VMX -eq 1 -a $HAVE_ALTIVEC_INTRIN -eq 1; then + CFLAGS="${CFLAGS} -DPPC_VMX" + SFLAGS="${SFLAGS} -DPPC_VMX" + + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} adler32_vmx.o slide_hash_vmx.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} adler32_vmx.lo slide_hash_vmx.lo" + fi + if test $HAVE_POWER8_INTRIN -eq 1; then + CFLAGS="${CFLAGS} -DPOWER8_VSX -DPOWER_FEATURES" + SFLAGS="${SFLAGS} -DPOWER8_VSX -DPOWER_FEATURES" + + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} adler32_power8.o chunkset_power8.o slide_hash_power8.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} adler32_power8.lo chunkset_power8.lo slide_hash_power8.lo" + case "${ARCH}" in + powerpc64*) + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} crc32_power8.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} crc32_power8.lo" + CFLAGS="${CFLAGS} -DPOWER8_VSX_CRC32" + SFLAGS="${SFLAGS} -DPOWER8_VSX_CRC32" + ;; + esac + fi + if test $HAVE_POWER9_INTRIN -eq 1; then + CFLAGS="${CFLAGS} -DPOWER9 -DPOWER_FEATURES" + SFLAGS="${SFLAGS} -DPOWER9 -DPOWER_FEATURES" + + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} compare256_power9.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} compare256_power9.lo" + fi + fi + ;; + s390x) + [ ! -z $CROSS_PREFIX ] && QEMU_ARCH=s390x + ARCHDIR=arch/s390 + + if test $without_optimizations -eq 0; then + if test $buildcrc32vx -eq 1; then + CFLAGS="${CFLAGS} -DS390_FEATURES" + SFLAGS="${SFLAGS} -DS390_FEATURES" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} s390_features.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} s390_features.lo" + fi + + if test $builddfltccdeflate -eq 1; then + CFLAGS="${CFLAGS} -DS390_DFLTCC_DEFLATE" + SFLAGS="${SFLAGS} -DS390_DFLTCC_DEFLATE" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} dfltcc_deflate.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} dfltcc_deflate.lo" + ARCH="${ARCH}+dfltcc-deflate" + fi + + if test $builddfltccinflate -eq 1; then + CFLAGS="${CFLAGS} -DS390_DFLTCC_INFLATE" + SFLAGS="${SFLAGS} -DS390_DFLTCC_INFLATE" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} dfltcc_inflate.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} dfltcc_inflate.lo" + ARCH="${ARCH}+dfltcc-inflate" + fi + + if test $buildcrc32vx -eq 1; then + check_vgfma_intrinsics + if test $HAVE_VGFMA_INTRIN -eq 1; then + CFLAGS="${CFLAGS} -DS390_CRC32_VX" + SFLAGS="${SFLAGS} -DS390_CRC32_VX" + ARCH_STATIC_OBJS="${ARCH_STATIC_OBJS} crc32-vx.o" + ARCH_SHARED_OBJS="${ARCH_SHARED_OBJS} crc32-vx.lo" + ARCH="${ARCH}+crc32-vx" + fi + fi + fi + ;; + *) + [ ! -z $CROSS_PREFIX ] && QEMU_ARCH=$ARCH + ;; +esac + +echo "Uname: $uname" +echo "ARCH: ${ARCH}" +echo "Using arch directory: ${ARCHDIR}" +echo "Architecture-specific static object files:${ARCH_STATIC_OBJS}" +echo "Architecture-specific shared object files:${ARCH_SHARED_OBJS}" + +# show the results in the log +echo >> configure.log +echo ALL = $ALL >> configure.log +echo AR = $AR >> configure.log +echo ARFLAGS = $ARFLAGS >> configure.log +echo CC = $CC >> configure.log +echo CFLAGS = $CFLAGS >> configure.log +echo EXE = $EXE >> configure.log +echo LDCONFIG = $LDCONFIG >> configure.log +echo LDFLAGS = $LDFLAGS >> configure.log +echo LDSHARED = $LDSHARED >> configure.log +echo LDSHAREDFLAGS = $LDSHAREDFLAGS >> configure.log +echo LDSHAREDLIBC = $LDSHAREDLIBC >> configure.log +echo DEFFILE = $DEFFILE >> configure.log +echo RC = $RC >> configure.log +echo RCFLAGS = $RCFLAGS >> configure.log +echo RCOBJS = $RCOBJS >> configure.log +echo STRIP = $STRIP >> configure.log +echo OBJC = $OBJC >> configure.log +echo TESTOBJG = $TESTOBJG >> configure.log +echo PIC_TESTOBJG = $PIC_TESTOBJG >> configure.log +echo PIC_OBJC = $PIC_OBJC >> configure.log +echo RANLIB = $RANLIB >> configure.log +echo SFLAGS = $SFLAGS >> configure.log +echo SHAREDLIB = $SHAREDLIB >> configure.log +echo SHAREDLIBM = $SHAREDLIBM >> configure.log +echo SHAREDLIBV = $SHAREDLIBV >> configure.log +echo SHAREDTARGET = $SHAREDTARGET >> configure.log +echo IMPORTLIB = $IMPORTLIB >> configure.log +echo INSTALLTARGETS = $INSTALLTARGETS >> configure.log +echo UNINSTALLTARGETS = $UNINSTALLTARGETS >> configure.log +echo SRCDIR = $SRCDIR >> configure.log +echo BUILDDIR = $BUILDDIR >> configure.log +echo STATICLIB = $STATICLIB >> configure.log +echo TEST = $TEST >> configure.log +echo VER = $VER >> configure.log +echo exec_prefix = $exec_prefix >> configure.log +echo includedir = $includedir >> configure.log +echo bindir = $bindir >> configure.log +echo libdir = $libdir >> configure.log +echo mandir = $mandir >> configure.log +echo prefix = $prefix >> configure.log +echo symbol_prefix = $symbol_prefix >> configure.log +echo sharedlibdir = $sharedlibdir >> configure.log +echo uname = $uname >> configure.log +echo sse2flag = $sse2flag >> configure.log +echo ssse3flag = $ssse3flag >> configure.log +echo sse42flag = $sse42flag >> configure.log +echo pclmulflag = $pclmulflag >> configure.log +echo vpclmulflag = $vpclmulflag >> configure.log +echo xsaveflag = $xsaveflag >> configure.log +echo acleflag = $acleflag >> configure.log +echo neonflag = $neonflag >> configure.log +echo armv6flag = $armv6flag >> configure.log +echo ARCHDIR = ${ARCHDIR} >> configure.log +echo ARCH_STATIC_OBJS = ${ARCH_STATIC_OBJS} >> configure.log +echo ARCH_SHARED_OBJS = ${ARCH_SHARED_OBJS} >> configure.log + +# Handle sed incompatibilities when using -i +replace_in_file() { + if [ "$OS" = 'Darwin' ]; then + sed -i '.tmp' -e "$1" "$2" + else + sed -i'.tmp' -e "$1" "$2" + fi +} + +# update Makefile with the configure results + +INCLUDES="-I$SRCDIR" +if [ "$SRCDIR" != "$BUILDDIR" ]; then INCLUDES="-I$BUILDDIR ${INCLUDES}"; fi + +sed < $SRCDIR/Makefile.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^SFLAGS *=/s#=.*#=$SFLAGS# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^LDSHAREDFLAGS *=/s#=.*#=$LDSHAREDFLAGS# +/^LDVERSIONSCRIPT *=/s#=.*#=$LDVERSIONSCRIPT# +/^LIBNAME1 *=/s#=.*#=$LIBNAME# +/^LIBNAME2 *=/s#=.*#=$LIBNAME2# +/^SUFFIX *=/s#=.*#=$SUFFIX# +/^STATICLIB *=/s#=.*#=$STATICLIB# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^SHAREDTARGET *=/s#=.*#=$SHAREDTARGET# +/^IMPORTLIB *=/s#=.*#=$IMPORTLIB# +/^VER *=/s#=.*#=$VER# +/^VER1 *=/s#=.*#=$VER1# +/^AR *=/s#=.*#=$AR# +/^ARFLAGS *=/s#=.*#=$ARFLAGS# +/^RANLIB *=/s#=.*#=$RANLIB# +/^LDCONFIG *=/s#=.*#=$LDCONFIG# +/^LDSHAREDLIBC *=/s#=.*#=$LDSHAREDLIBC# +/^DEFFILE *=/s#=.*#=$DEFFILE# +/^RC *=/s#=.*#=$RC# +/^RCFLAGS *=/s#=.*#=$RCFLAGS# +/^RCOBJS *=/s#=.*#=$RCOBJS# +/^STRIP *=/s#=.*#=$STRIP# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#= $prefix# +/^exec_prefix *=/s#=.*#= $exec_prefix# +/^bindir *=/s#=.*#= $bindir# +/^symbol_prefix *=/s#=.*#= $symbol_prefix# +/^libdir *=/s#=.*#= $libdir# +/^sharedlibdir *=/s#=.*#= $sharedlibdir# +/^includedir *=/s#=.*#= $includedir# +/^mandir *=/s#=.*#= $mandir# +/^SRCDIR *=/s#=.*#=$SRCDIR# +/^INCLUDES *=/s#=.*#=$INCLUDES# +/^OBJC *=/s#=.*#= $OBJC# +/^TESTOBJG *=/s#=.*#= $TESTOBJG# +/^PIC_TESTOBJG *=/s#=.*#= $PIC_TESTOBJG# +/^PIC_OBJC *=/s#=.*#= $PIC_OBJC# +/^all: */s#:.*#: $ALL# +/^install-libs: */s#:.*#: $INSTALLTARGETS# +/^uninstall-libs: */s#:.*#: $UNINSTALLTARGETS# +/^ARCHDIR *=/s#=.*#=$ARCHDIR# +/^ARCH_STATIC_OBJS *=/s#=.*#=$ARCH_STATIC_OBJS# +/^ARCH_SHARED_OBJS *=/s#=.*#=$ARCH_SHARED_OBJS# +" > Makefile + +# Append header files dependencies. +for file in $SRCDIR/*.c $SRCDIR/test/*.c $SRCDIR/test/fuzz/*.c $SRCDIR/$ARCHDIR/*.c $SRCDIR/tools/*.c; do + if test ! -f $file; then + continue + fi + + short_name=$(echo $file | sed -e "s#$SRCDIR/##g") + incs=$(grep -h include $file | sed -n 's/# *\include *"\(.*\.h\)".*/\1/p' | sort | uniq) + includes=$(for i in $incs; do + # Check that the include file exists in the current dir, + # otherwise it may be one of the system include header. + if test -e $SRCDIR/$i; then + printf " \$(SRCDIR)/$i" + fi + # We also need to check whether the include file is in the ARCHDIR. + if test -e $SRCDIR/$ARCHDIR/$i; then + printf " \$(SRCDIR)/$ARCHDIR/$i" + fi + done) + obj=$(basename $(echo $file | sed -e 's/\.c/\.o/g' -e 's#^\./##g')) + lobj=$(basename $(echo $file | sed -e 's/\.c/\.lo/g' -e 's#^\./##g')) + + if grep -q "^$obj:" Makefile; then + # Replace the existing line with a line with all dependences. + $(replace_in_file "s#$obj:.*#$obj: \$(SRCDIR)/$short_name $includes#g" Makefile) + else + # Append at the end of Makefile a new line with the header dependences. + echo "$obj: \$(SRCDIR)/$short_name $includes" >> Makefile + + # In case this is one of the ARCHDIR files, append a dependence line + # that will force the `$(MAKE) -C $(ARCHDIR)` generic rule. Without this + # we would only execute the copy rule from ARCHDIR to SRCDIR. + if test -e $SRCDIR/$ARCHDIR/$(basename $file); then + echo "$ARCHDIR/$obj: \$(SRCDIR)/$short_name $includes" >> Makefile + fi + fi + + if grep -q "^$lobj:" Makefile; then + # Replace the existing line with a line with all dependences. + $(replace_in_file "s#$lobj:.*#$lobj: \$(SRCDIR)/$short_name $includes#g" Makefile) + else + # Append at the end of Makefile a new line with the header dependences. + echo "$lobj: \$(SRCDIR)/$short_name $includes" >> Makefile + fi +done + +# Generate Makefile in arch dir +mkdir -p $ARCHDIR + +sed < $SRCDIR/$ARCHDIR/Makefile.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^SFLAGS *=/s#=.*#=$SFLAGS# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +/^INCLUDES *=/s#=.*#=$INCLUDES# +/^SUFFIX *=/s#=.*#=$SUFFIX# +/^SRCDIR *=/s#=.*#=$SRCDIR/$ARCHDIR# +/^SRCTOP *=/s#=.*#=$SRCDIR# +/^BUILDDIR *=/s#=.*#=$BUILDDIR# +/^AVX2FLAG *=/s#=.*#=$avx2flag# +/^AVX512FLAG *=/s#=.*#=$avx512flag# +/^AVX512VNNIFLAG *=/s#=.*#=$avx512vnniflag# +/^SSE2FLAG *=/s#=.*#=$sse2flag# +/^SSSE3FLAG *=/s#=.*#=$ssse3flag# +/^SSE42FLAG *=/s#=.*#=$sse42flag# +/^PCLMULFLAG *=/s#=.*#=$pclmulflag# +/^VPCLMULFLAG *=/s#=.*#=$vpclmulflag# +/^XSAVEFLAG *=/s#=.*#=$xsaveflag# +/^ACLEFLAG *=/s#=.*#=$acleflag# +/^NEONFLAG *=/s#=.*#=$neonflag# +/^ARMV6FLAG *=/s#=.*#=$armv6flag# +/^NOLTOFLAG *=/s#=.*#=$noltoflag# +/^VGFMAFLAG *=/s#=.*#=$vgfmaflag# +/^PPCFLAGS *=/s#=.*#=$vmxflag# +" > $ARCHDIR/Makefile + +# Append header files dependencies. +for file in $SRCDIR/$ARCHDIR/*.c; do + if test ! -f $file; then + continue + fi + + incs=$(grep -h include $file | sed -n 's/# *\include *"\(.*\.h\)".*/\1/p' | sort | uniq) + includes=$(for i in $incs; do + # Check that the include file exists in the current dir, + # otherwise it may be one of the system include header. + if test -e $SRCDIR/$i; then + printf " \$(SRCTOP)/$i" + fi + # We also need to check whether the include file is in the ARCHDIR. + if test -e $SRCDIR/$ARCHDIR/$i; then + printf " \$(SRCDIR)/$i" + fi + done) + obj=$(basename $(echo $file | sed -e 's/\.c/\.o/g' -e 's#^\./##g')) + lobj=$(basename $(echo $file | sed -e 's/\.c/\.lo/g' -e 's#^\./##g')) + short_name=$(basename $file) + if grep -q "^$obj:" $ARCHDIR/Makefile; then + # Replace the existing line with a line with all dependences. + $(replace_in_file "s#$obj:.*#$obj: \$(SRCDIR)/$short_name $includes#g" $ARCHDIR/Makefile) + else + # Append at the end of Makefile a new line with the header dependences. + echo "$obj: \$(SRCDIR)/$short_name $includes" >> $ARCHDIR/Makefile + fi + + if grep -q "^$lobj:" $ARCHDIR/Makefile; then + # Replace the existing line with a line with all dependences. + $(replace_in_file "s#$lobj:.*#$lobj: \$(SRCDIR)/$short_name $includes#g" $ARCHDIR/Makefile) + else + # Append at the end of Makefile a new line with the header dependences. + echo "$lobj: \$(SRCDIR)/$short_name $includes" >> $ARCHDIR/Makefile + fi +done + +# Generate Makefile in generic arch dir +mkdir -p arch/generic + +sed < $SRCDIR/arch/generic/Makefile.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^SFLAGS *=/s#=.*#=$SFLAGS# +/^INCLUDES *=/s#=.*#=$INCLUDES# +/^SRCDIR *=/s#=.*#=$SRCDIR/arch/generic# +/^SRCTOP *=/s#=.*#=$SRCDIR# +/^BUILDDIR *=/s#=.*#=$BUILDDIR# +" > arch/generic/Makefile + +## TODO: Process header dependencies + +# Emscripten does not support large amounts of data via stdin/out +# https://github.com/emscripten-core/emscripten/issues/16755#issuecomment-1102732849 +if test "$CHOST" != "wasm32"; then + TEST="${TEST} ghtests" +fi + +# Determine emulator to use when running tests +if test -z "$EMU_RUN" && test $QEMU_ARCH; then + EMU_RUN="qemu-$QEMU_ARCH -L /usr/${CHOST}/" +fi +if test -n "$EMU_RUN"; then + echo "Using cross-compile emulator: $EMU_RUN" +fi + +if test $gzfileops -eq 1; then + PC_CFLAGS="-DWITH_GZFILEOP" +fi + +# Generate Makefile in test dir +mkdir -p test +sed < $SRCDIR/test/Makefile.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +/^EXE *=/s#=.*#=$EXE# +/^alltests: */s#:.*#: $TEST# +/^SRCDIR *=/s#=.*#=$SRCDIR/test# +/^SRCTOP *=/s#=.*#=$SRCDIR# +/^EMU_RUN *=/s#=.*#=$EMU_RUN# +/^LIBNAME *=/s#=.*#=$LIBNAME# +" > test/Makefile + +# create zlib.pc with the configure results +sed < $SRCDIR/zlib.pc.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^LDSHAREDFLAGS *=/s#=.*#=$LDSHAREDFLAGS# +/^STATICLIB *=/s#=.*#=$STATICLIB# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^IMPORTLIB *=/s#=.*#=$IMPORTLIB# +/^AR *=/s#=.*#=$AR# +/^ARFLAGS *=/s#=.*#=$ARFLAGS# +/^RANLIB *=/s#=.*#=$RANLIB# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^bindir *=/s#=.*#=$bindir# +/^symbol_prefix *=/s#=.*#=$symbol_prefix# +/^libdir *=/s#=.*#=$libdir# +/^sharedlibdir *=/s#=.*#=$sharedlibdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +" | sed -e " +s/\@VERSION\@/$VER/g; +s/\@SUFFIX\@/$SUFFIX/g; +s/\@PKG_CONFIG_CFLAGS\@/$PC_CFLAGS/g; +" > ${LIBNAME2}.pc + +# done +leave 0 diff --git a/cpu_features.c b/cpu_features.c new file mode 100644 index 0000000000..3585172e5d --- /dev/null +++ b/cpu_features.c @@ -0,0 +1,23 @@ +/* cpu_features.c -- CPU architecture feature check + * Copyright (C) 2017 Hans Kristian Rosbach + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "cpu_features.h" +#include + +Z_INTERNAL void cpu_check_features(struct cpu_features *features) { + memset(features, 0, sizeof(struct cpu_features)); +#if defined(X86_FEATURES) + x86_check_features(&features->x86); +#elif defined(ARM_FEATURES) + arm_check_features(&features->arm); +#elif defined(PPC_FEATURES) || defined(POWER_FEATURES) + power_check_features(&features->power); +#elif defined(S390_FEATURES) + s390_check_features(&features->s390); +#elif defined(RISCV_FEATURES) + riscv_check_features(&features->riscv); +#endif +} diff --git a/cpu_features.h b/cpu_features.h new file mode 100644 index 0000000000..8708724bc0 --- /dev/null +++ b/cpu_features.h @@ -0,0 +1,43 @@ +/* cpu_features.h -- CPU architecture feature check + * Copyright (C) 2017 Hans Kristian Rosbach + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef CPU_FEATURES_H_ +#define CPU_FEATURES_H_ + +#ifndef DISABLE_RUNTIME_CPU_DETECTION + +#if defined(X86_FEATURES) +# include "arch/x86/x86_features.h" +#elif defined(ARM_FEATURES) +# include "arch/arm/arm_features.h" +#elif defined(PPC_FEATURES) || defined(POWER_FEATURES) +# include "arch/power/power_features.h" +#elif defined(S390_FEATURES) +# include "arch/s390/s390_features.h" +#elif defined(RISCV_FEATURES) +# include "arch/riscv/riscv_features.h" +#endif + +struct cpu_features { +#if defined(X86_FEATURES) + struct x86_cpu_features x86; +#elif defined(ARM_FEATURES) + struct arm_cpu_features arm; +#elif defined(PPC_FEATURES) || defined(POWER_FEATURES) + struct power_cpu_features power; +#elif defined(S390_FEATURES) + struct s390_cpu_features s390; +#elif defined(RISCV_FEATURES) + struct riscv_cpu_features riscv; +#else + char empty; +#endif +}; + +void cpu_check_features(struct cpu_features *features); + +#endif + +#endif diff --git a/crc32.c b/crc32.c new file mode 100644 index 0000000000..54f6ecd420 --- /dev/null +++ b/crc32.c @@ -0,0 +1,42 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * This interleaved implementation of a CRC makes use of pipelined multiple + * arithmetic-logic units, commonly found in modern CPU cores. It is due to + * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. + */ + +#include "zbuild.h" +#include "functable.h" +#include "crc32_braid_tbl.h" + +/* ========================================================================= */ + +const uint32_t * Z_EXPORT PREFIX(get_crc_table)(void) { + return (const uint32_t *)crc_table; +} + +#ifdef ZLIB_COMPAT +unsigned long Z_EXPORT PREFIX(crc32_z)(unsigned long crc, const unsigned char *buf, size_t len) { + if (buf == NULL) return 0; + + return (unsigned long)FUNCTABLE_CALL(crc32)((uint32_t)crc, buf, len); +} +#else +uint32_t Z_EXPORT PREFIX(crc32_z)(uint32_t crc, const unsigned char *buf, size_t len) { + if (buf == NULL) return 0; + + return FUNCTABLE_CALL(crc32)(crc, buf, len); +} +#endif + +#ifdef ZLIB_COMPAT +unsigned long Z_EXPORT PREFIX(crc32)(unsigned long crc, const unsigned char *buf, unsigned int len) { + return (unsigned long)PREFIX(crc32_z)((uint32_t)crc, buf, len); +} +#else +uint32_t Z_EXPORT PREFIX(crc32)(uint32_t crc, const unsigned char *buf, uint32_t len) { + return PREFIX(crc32_z)(crc, buf, len); +} +#endif diff --git a/crc32.h b/crc32.h new file mode 100644 index 0000000000..8c3d7a8a3e --- /dev/null +++ b/crc32.h @@ -0,0 +1,16 @@ +/* crc32.h -- crc32 folding interface + * Copyright (C) 2021 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#ifndef CRC32_H_ +#define CRC32_H_ + +#define CRC32_FOLD_BUFFER_SIZE (16 * 4) +/* sizeof(__m128i) * (4 folds) */ + +typedef struct crc32_fold_s { + uint8_t fold[CRC32_FOLD_BUFFER_SIZE]; + uint32_t value; +} crc32_fold; + +#endif diff --git a/crc32_braid_comb.c b/crc32_braid_comb.c new file mode 100644 index 0000000000..f253ae10a2 --- /dev/null +++ b/crc32_braid_comb.c @@ -0,0 +1,56 @@ +/* crc32_braid_comb.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * This interleaved implementation of a CRC makes use of pipelined multiple + * arithmetic-logic units, commonly found in modern CPU cores. It is due to + * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. + */ + +#include "zutil.h" +#include "crc32_braid_p.h" +#include "crc32_braid_tbl.h" +#include "crc32_braid_comb_p.h" + +/* ========================================================================= */ +static uint32_t crc32_combine_(uint32_t crc1, uint32_t crc2, z_off64_t len2) { + return multmodp(x2nmodp(len2, 3), crc1) ^ crc2; +} +static uint32_t crc32_combine_gen_(z_off64_t len2) { + return x2nmodp(len2, 3); +} +static uint32_t crc32_combine_op_(uint32_t crc1, uint32_t crc2, const uint32_t op) { + return multmodp(op, crc1) ^ crc2; +} + +/* ========================================================================= */ + +#ifdef ZLIB_COMPAT +unsigned long Z_EXPORT PREFIX(crc32_combine)(unsigned long crc1, unsigned long crc2, z_off_t len2) { + return (unsigned long)crc32_combine_((uint32_t)crc1, (uint32_t)crc2, len2); +} +unsigned long Z_EXPORT PREFIX4(crc32_combine)(unsigned long crc1, unsigned long crc2, z_off64_t len2) { + return (unsigned long)crc32_combine_((uint32_t)crc1, (uint32_t)crc2, len2); +} +unsigned long Z_EXPORT PREFIX(crc32_combine_gen)(z_off_t len2) { + return crc32_combine_gen_(len2); +} +unsigned long Z_EXPORT PREFIX4(crc32_combine_gen)(z_off64_t len2) { + return crc32_combine_gen_(len2); +} +unsigned long Z_EXPORT PREFIX(crc32_combine_op)(unsigned long crc1, unsigned long crc2, const unsigned long op) { + return (unsigned long)crc32_combine_op_((uint32_t)crc1, (uint32_t)crc2, (uint32_t)op); +} +#else +uint32_t Z_EXPORT PREFIX4(crc32_combine)(uint32_t crc1, uint32_t crc2, z_off64_t len2) { + return crc32_combine_(crc1, crc2, len2); +} +uint32_t Z_EXPORT PREFIX(crc32_combine_gen)(z_off64_t len2) { + return crc32_combine_gen_(len2); +} +uint32_t Z_EXPORT PREFIX(crc32_combine_op)(uint32_t crc1, uint32_t crc2, const uint32_t op) { + return crc32_combine_op_(crc1, crc2, op); +} +#endif + +/* ========================================================================= */ diff --git a/crc32_braid_comb_p.h b/crc32_braid_comb_p.h new file mode 100644 index 0000000000..a269e7f5b7 --- /dev/null +++ b/crc32_braid_comb_p.h @@ -0,0 +1,42 @@ +#ifndef CRC32_BRAID_COMB_P_H_ +#define CRC32_BRAID_COMB_P_H_ + +/* + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. + */ +static uint32_t multmodp(uint32_t a, uint32_t b) { + uint32_t m, p; + + m = (uint32_t)1 << 31; + p = 0; + for (;;) { + if (a & m) { + p ^= b; + if ((a & (m - 1)) == 0) + break; + } + m >>= 1; + b = b & 1 ? (b >> 1) ^ POLY : b >> 1; + } + return p; +} + +/* + Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been + initialized. + */ +static uint32_t x2nmodp(z_off64_t n, unsigned k) { + uint32_t p; + + p = (uint32_t)1 << 31; /* x^0 == 1 */ + while (n) { + if (n & 1) + p = multmodp(x2n_table[k & 31], p); + n >>= 1; + k++; + } + return p; +} + +#endif /* CRC32_BRAID_COMB_P_H_ */ diff --git a/crc32_braid_p.h b/crc32_braid_p.h new file mode 100644 index 0000000000..003bf91920 --- /dev/null +++ b/crc32_braid_p.h @@ -0,0 +1,64 @@ +#ifndef CRC32_BRAID_P_H_ +#define CRC32_BRAID_P_H_ + +#include "zendian.h" + +/* Define N */ +#ifdef Z_TESTN +# define N Z_TESTN +#else +# define N 5 +#endif +#if N < 1 || N > 6 +# error N must be in 1..6 +#endif + +/* + Define W and the associated z_word_t type. If W is not defined, then a + braided calculation is not used, and the associated tables and code are not + compiled. + */ +#ifdef Z_TESTW +# if Z_TESTW-1 != -1 +# define W Z_TESTW +# endif +#else +# ifndef W +# if defined(__x86_64__) || defined(_M_AMD64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) +# define W 8 +# else +# define W 4 +# endif +# endif +#endif +#ifdef W +# if W == 8 + typedef uint64_t z_word_t; +# else +# undef W +# define W 4 + typedef uint32_t z_word_t; +# endif +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +# define ZSWAPWORD(word) (word) +# define BRAID_TABLE crc_braid_table +#elif BYTE_ORDER == BIG_ENDIAN +# if W == 8 +# define ZSWAPWORD(word) ZSWAP64(word) +# elif W == 4 +# define ZSWAPWORD(word) ZSWAP32(word) +# endif +# define BRAID_TABLE crc_braid_big_table +#else +# error "No endian defined" +#endif + +#define DO1 c = crc_table[(c ^ *buf++) & 0xff] ^ (c >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* CRC polynomial. */ +#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ + +#endif /* CRC32_BRAID_P_H_ */ diff --git a/crc32_braid_tbl.h b/crc32_braid_tbl.h new file mode 100644 index 0000000000..84d79a69e7 --- /dev/null +++ b/crc32_braid_tbl.h @@ -0,0 +1,9446 @@ +#ifndef CRC32_BRAID_TBL_H_ +#define CRC32_BRAID_TBL_H_ + +/* crc32_braid_tbl.h -- tables for braided CRC calculation + * Generated automatically by makecrct.c + */ + +static const uint32_t crc_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}; + +#ifdef W + +#if W == 8 + +static const z_word_t crc_big_table[] = { + 0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}; + +#else /* W == 4 */ + +static const z_word_t crc_big_table[] = { + 0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}; + +#endif + +#endif /* W */ + +#if N == 1 + +#if W == 8 + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}, + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}, + {0x0000000000000000, 0x41311b1900000000, 0x8262363200000000, + 0xc3532d2b00000000, 0x04c56c6400000000, 0x45f4777d00000000, + 0x86a75a5600000000, 0xc796414f00000000, 0x088ad9c800000000, + 0x49bbc2d100000000, 0x8ae8effa00000000, 0xcbd9f4e300000000, + 0x0c4fb5ac00000000, 0x4d7eaeb500000000, 0x8e2d839e00000000, + 0xcf1c988700000000, 0x5112c24a00000000, 0x1023d95300000000, + 0xd370f47800000000, 0x9241ef6100000000, 0x55d7ae2e00000000, + 0x14e6b53700000000, 0xd7b5981c00000000, 0x9684830500000000, + 0x59981b8200000000, 0x18a9009b00000000, 0xdbfa2db000000000, + 0x9acb36a900000000, 0x5d5d77e600000000, 0x1c6c6cff00000000, + 0xdf3f41d400000000, 0x9e0e5acd00000000, 0xa224849500000000, + 0xe3159f8c00000000, 0x2046b2a700000000, 0x6177a9be00000000, + 0xa6e1e8f100000000, 0xe7d0f3e800000000, 0x2483dec300000000, + 0x65b2c5da00000000, 0xaaae5d5d00000000, 0xeb9f464400000000, + 0x28cc6b6f00000000, 0x69fd707600000000, 0xae6b313900000000, + 0xef5a2a2000000000, 0x2c09070b00000000, 0x6d381c1200000000, + 0xf33646df00000000, 0xb2075dc600000000, 0x715470ed00000000, + 0x30656bf400000000, 0xf7f32abb00000000, 0xb6c231a200000000, + 0x75911c8900000000, 0x34a0079000000000, 0xfbbc9f1700000000, + 0xba8d840e00000000, 0x79dea92500000000, 0x38efb23c00000000, + 0xff79f37300000000, 0xbe48e86a00000000, 0x7d1bc54100000000, + 0x3c2ade5800000000, 0x054f79f000000000, 0x447e62e900000000, + 0x872d4fc200000000, 0xc61c54db00000000, 0x018a159400000000, + 0x40bb0e8d00000000, 0x83e823a600000000, 0xc2d938bf00000000, + 0x0dc5a03800000000, 0x4cf4bb2100000000, 0x8fa7960a00000000, + 0xce968d1300000000, 0x0900cc5c00000000, 0x4831d74500000000, + 0x8b62fa6e00000000, 0xca53e17700000000, 0x545dbbba00000000, + 0x156ca0a300000000, 0xd63f8d8800000000, 0x970e969100000000, + 0x5098d7de00000000, 0x11a9ccc700000000, 0xd2fae1ec00000000, + 0x93cbfaf500000000, 0x5cd7627200000000, 0x1de6796b00000000, + 0xdeb5544000000000, 0x9f844f5900000000, 0x58120e1600000000, + 0x1923150f00000000, 0xda70382400000000, 0x9b41233d00000000, + 0xa76bfd6500000000, 0xe65ae67c00000000, 0x2509cb5700000000, + 0x6438d04e00000000, 0xa3ae910100000000, 0xe29f8a1800000000, + 0x21cca73300000000, 0x60fdbc2a00000000, 0xafe124ad00000000, + 0xeed03fb400000000, 0x2d83129f00000000, 0x6cb2098600000000, + 0xab2448c900000000, 0xea1553d000000000, 0x29467efb00000000, + 0x687765e200000000, 0xf6793f2f00000000, 0xb748243600000000, + 0x741b091d00000000, 0x352a120400000000, 0xf2bc534b00000000, + 0xb38d485200000000, 0x70de657900000000, 0x31ef7e6000000000, + 0xfef3e6e700000000, 0xbfc2fdfe00000000, 0x7c91d0d500000000, + 0x3da0cbcc00000000, 0xfa368a8300000000, 0xbb07919a00000000, + 0x7854bcb100000000, 0x3965a7a800000000, 0x4b98833b00000000, + 0x0aa9982200000000, 0xc9fab50900000000, 0x88cbae1000000000, + 0x4f5def5f00000000, 0x0e6cf44600000000, 0xcd3fd96d00000000, + 0x8c0ec27400000000, 0x43125af300000000, 0x022341ea00000000, + 0xc1706cc100000000, 0x804177d800000000, 0x47d7369700000000, + 0x06e62d8e00000000, 0xc5b500a500000000, 0x84841bbc00000000, + 0x1a8a417100000000, 0x5bbb5a6800000000, 0x98e8774300000000, + 0xd9d96c5a00000000, 0x1e4f2d1500000000, 0x5f7e360c00000000, + 0x9c2d1b2700000000, 0xdd1c003e00000000, 0x120098b900000000, + 0x533183a000000000, 0x9062ae8b00000000, 0xd153b59200000000, + 0x16c5f4dd00000000, 0x57f4efc400000000, 0x94a7c2ef00000000, + 0xd596d9f600000000, 0xe9bc07ae00000000, 0xa88d1cb700000000, + 0x6bde319c00000000, 0x2aef2a8500000000, 0xed796bca00000000, + 0xac4870d300000000, 0x6f1b5df800000000, 0x2e2a46e100000000, + 0xe136de6600000000, 0xa007c57f00000000, 0x6354e85400000000, + 0x2265f34d00000000, 0xe5f3b20200000000, 0xa4c2a91b00000000, + 0x6791843000000000, 0x26a09f2900000000, 0xb8aec5e400000000, + 0xf99fdefd00000000, 0x3accf3d600000000, 0x7bfde8cf00000000, + 0xbc6ba98000000000, 0xfd5ab29900000000, 0x3e099fb200000000, + 0x7f3884ab00000000, 0xb0241c2c00000000, 0xf115073500000000, + 0x32462a1e00000000, 0x7377310700000000, 0xb4e1704800000000, + 0xf5d06b5100000000, 0x3683467a00000000, 0x77b25d6300000000, + 0x4ed7facb00000000, 0x0fe6e1d200000000, 0xccb5ccf900000000, + 0x8d84d7e000000000, 0x4a1296af00000000, 0x0b238db600000000, + 0xc870a09d00000000, 0x8941bb8400000000, 0x465d230300000000, + 0x076c381a00000000, 0xc43f153100000000, 0x850e0e2800000000, + 0x42984f6700000000, 0x03a9547e00000000, 0xc0fa795500000000, + 0x81cb624c00000000, 0x1fc5388100000000, 0x5ef4239800000000, + 0x9da70eb300000000, 0xdc9615aa00000000, 0x1b0054e500000000, + 0x5a314ffc00000000, 0x996262d700000000, 0xd85379ce00000000, + 0x174fe14900000000, 0x567efa5000000000, 0x952dd77b00000000, + 0xd41ccc6200000000, 0x138a8d2d00000000, 0x52bb963400000000, + 0x91e8bb1f00000000, 0xd0d9a00600000000, 0xecf37e5e00000000, + 0xadc2654700000000, 0x6e91486c00000000, 0x2fa0537500000000, + 0xe836123a00000000, 0xa907092300000000, 0x6a54240800000000, + 0x2b653f1100000000, 0xe479a79600000000, 0xa548bc8f00000000, + 0x661b91a400000000, 0x272a8abd00000000, 0xe0bccbf200000000, + 0xa18dd0eb00000000, 0x62defdc000000000, 0x23efe6d900000000, + 0xbde1bc1400000000, 0xfcd0a70d00000000, 0x3f838a2600000000, + 0x7eb2913f00000000, 0xb924d07000000000, 0xf815cb6900000000, + 0x3b46e64200000000, 0x7a77fd5b00000000, 0xb56b65dc00000000, + 0xf45a7ec500000000, 0x370953ee00000000, 0x763848f700000000, + 0xb1ae09b800000000, 0xf09f12a100000000, 0x33cc3f8a00000000, + 0x72fd249300000000}, + {0x0000000000000000, 0x376ac20100000000, 0x6ed4840300000000, + 0x59be460200000000, 0xdca8090700000000, 0xebc2cb0600000000, + 0xb27c8d0400000000, 0x85164f0500000000, 0xb851130e00000000, + 0x8f3bd10f00000000, 0xd685970d00000000, 0xe1ef550c00000000, + 0x64f91a0900000000, 0x5393d80800000000, 0x0a2d9e0a00000000, + 0x3d475c0b00000000, 0x70a3261c00000000, 0x47c9e41d00000000, + 0x1e77a21f00000000, 0x291d601e00000000, 0xac0b2f1b00000000, + 0x9b61ed1a00000000, 0xc2dfab1800000000, 0xf5b5691900000000, + 0xc8f2351200000000, 0xff98f71300000000, 0xa626b11100000000, + 0x914c731000000000, 0x145a3c1500000000, 0x2330fe1400000000, + 0x7a8eb81600000000, 0x4de47a1700000000, 0xe0464d3800000000, + 0xd72c8f3900000000, 0x8e92c93b00000000, 0xb9f80b3a00000000, + 0x3cee443f00000000, 0x0b84863e00000000, 0x523ac03c00000000, + 0x6550023d00000000, 0x58175e3600000000, 0x6f7d9c3700000000, + 0x36c3da3500000000, 0x01a9183400000000, 0x84bf573100000000, + 0xb3d5953000000000, 0xea6bd33200000000, 0xdd01113300000000, + 0x90e56b2400000000, 0xa78fa92500000000, 0xfe31ef2700000000, + 0xc95b2d2600000000, 0x4c4d622300000000, 0x7b27a02200000000, + 0x2299e62000000000, 0x15f3242100000000, 0x28b4782a00000000, + 0x1fdeba2b00000000, 0x4660fc2900000000, 0x710a3e2800000000, + 0xf41c712d00000000, 0xc376b32c00000000, 0x9ac8f52e00000000, + 0xada2372f00000000, 0xc08d9a7000000000, 0xf7e7587100000000, + 0xae591e7300000000, 0x9933dc7200000000, 0x1c25937700000000, + 0x2b4f517600000000, 0x72f1177400000000, 0x459bd57500000000, + 0x78dc897e00000000, 0x4fb64b7f00000000, 0x16080d7d00000000, + 0x2162cf7c00000000, 0xa474807900000000, 0x931e427800000000, + 0xcaa0047a00000000, 0xfdcac67b00000000, 0xb02ebc6c00000000, + 0x87447e6d00000000, 0xdefa386f00000000, 0xe990fa6e00000000, + 0x6c86b56b00000000, 0x5bec776a00000000, 0x0252316800000000, + 0x3538f36900000000, 0x087faf6200000000, 0x3f156d6300000000, + 0x66ab2b6100000000, 0x51c1e96000000000, 0xd4d7a66500000000, + 0xe3bd646400000000, 0xba03226600000000, 0x8d69e06700000000, + 0x20cbd74800000000, 0x17a1154900000000, 0x4e1f534b00000000, + 0x7975914a00000000, 0xfc63de4f00000000, 0xcb091c4e00000000, + 0x92b75a4c00000000, 0xa5dd984d00000000, 0x989ac44600000000, + 0xaff0064700000000, 0xf64e404500000000, 0xc124824400000000, + 0x4432cd4100000000, 0x73580f4000000000, 0x2ae6494200000000, + 0x1d8c8b4300000000, 0x5068f15400000000, 0x6702335500000000, + 0x3ebc755700000000, 0x09d6b75600000000, 0x8cc0f85300000000, + 0xbbaa3a5200000000, 0xe2147c5000000000, 0xd57ebe5100000000, + 0xe839e25a00000000, 0xdf53205b00000000, 0x86ed665900000000, + 0xb187a45800000000, 0x3491eb5d00000000, 0x03fb295c00000000, + 0x5a456f5e00000000, 0x6d2fad5f00000000, 0x801b35e100000000, + 0xb771f7e000000000, 0xeecfb1e200000000, 0xd9a573e300000000, + 0x5cb33ce600000000, 0x6bd9fee700000000, 0x3267b8e500000000, + 0x050d7ae400000000, 0x384a26ef00000000, 0x0f20e4ee00000000, + 0x569ea2ec00000000, 0x61f460ed00000000, 0xe4e22fe800000000, + 0xd388ede900000000, 0x8a36abeb00000000, 0xbd5c69ea00000000, + 0xf0b813fd00000000, 0xc7d2d1fc00000000, 0x9e6c97fe00000000, + 0xa90655ff00000000, 0x2c101afa00000000, 0x1b7ad8fb00000000, + 0x42c49ef900000000, 0x75ae5cf800000000, 0x48e900f300000000, + 0x7f83c2f200000000, 0x263d84f000000000, 0x115746f100000000, + 0x944109f400000000, 0xa32bcbf500000000, 0xfa958df700000000, + 0xcdff4ff600000000, 0x605d78d900000000, 0x5737bad800000000, + 0x0e89fcda00000000, 0x39e33edb00000000, 0xbcf571de00000000, + 0x8b9fb3df00000000, 0xd221f5dd00000000, 0xe54b37dc00000000, + 0xd80c6bd700000000, 0xef66a9d600000000, 0xb6d8efd400000000, + 0x81b22dd500000000, 0x04a462d000000000, 0x33cea0d100000000, + 0x6a70e6d300000000, 0x5d1a24d200000000, 0x10fe5ec500000000, + 0x27949cc400000000, 0x7e2adac600000000, 0x494018c700000000, + 0xcc5657c200000000, 0xfb3c95c300000000, 0xa282d3c100000000, + 0x95e811c000000000, 0xa8af4dcb00000000, 0x9fc58fca00000000, + 0xc67bc9c800000000, 0xf1110bc900000000, 0x740744cc00000000, + 0x436d86cd00000000, 0x1ad3c0cf00000000, 0x2db902ce00000000, + 0x4096af9100000000, 0x77fc6d9000000000, 0x2e422b9200000000, + 0x1928e99300000000, 0x9c3ea69600000000, 0xab54649700000000, + 0xf2ea229500000000, 0xc580e09400000000, 0xf8c7bc9f00000000, + 0xcfad7e9e00000000, 0x9613389c00000000, 0xa179fa9d00000000, + 0x246fb59800000000, 0x1305779900000000, 0x4abb319b00000000, + 0x7dd1f39a00000000, 0x3035898d00000000, 0x075f4b8c00000000, + 0x5ee10d8e00000000, 0x698bcf8f00000000, 0xec9d808a00000000, + 0xdbf7428b00000000, 0x8249048900000000, 0xb523c68800000000, + 0x88649a8300000000, 0xbf0e588200000000, 0xe6b01e8000000000, + 0xd1dadc8100000000, 0x54cc938400000000, 0x63a6518500000000, + 0x3a18178700000000, 0x0d72d58600000000, 0xa0d0e2a900000000, + 0x97ba20a800000000, 0xce0466aa00000000, 0xf96ea4ab00000000, + 0x7c78ebae00000000, 0x4b1229af00000000, 0x12ac6fad00000000, + 0x25c6adac00000000, 0x1881f1a700000000, 0x2feb33a600000000, + 0x765575a400000000, 0x413fb7a500000000, 0xc429f8a000000000, + 0xf3433aa100000000, 0xaafd7ca300000000, 0x9d97bea200000000, + 0xd073c4b500000000, 0xe71906b400000000, 0xbea740b600000000, + 0x89cd82b700000000, 0x0cdbcdb200000000, 0x3bb10fb300000000, + 0x620f49b100000000, 0x55658bb000000000, 0x6822d7bb00000000, + 0x5f4815ba00000000, 0x06f653b800000000, 0x319c91b900000000, + 0xb48adebc00000000, 0x83e01cbd00000000, 0xda5e5abf00000000, + 0xed3498be00000000}, + {0x0000000000000000, 0x6567bcb800000000, 0x8bc809aa00000000, + 0xeeafb51200000000, 0x5797628f00000000, 0x32f0de3700000000, + 0xdc5f6b2500000000, 0xb938d79d00000000, 0xef28b4c500000000, + 0x8a4f087d00000000, 0x64e0bd6f00000000, 0x018701d700000000, + 0xb8bfd64a00000000, 0xddd86af200000000, 0x3377dfe000000000, + 0x5610635800000000, 0x9f57195000000000, 0xfa30a5e800000000, + 0x149f10fa00000000, 0x71f8ac4200000000, 0xc8c07bdf00000000, + 0xada7c76700000000, 0x4308727500000000, 0x266fcecd00000000, + 0x707fad9500000000, 0x1518112d00000000, 0xfbb7a43f00000000, + 0x9ed0188700000000, 0x27e8cf1a00000000, 0x428f73a200000000, + 0xac20c6b000000000, 0xc9477a0800000000, 0x3eaf32a000000000, + 0x5bc88e1800000000, 0xb5673b0a00000000, 0xd00087b200000000, + 0x6938502f00000000, 0x0c5fec9700000000, 0xe2f0598500000000, + 0x8797e53d00000000, 0xd187866500000000, 0xb4e03add00000000, + 0x5a4f8fcf00000000, 0x3f28337700000000, 0x8610e4ea00000000, + 0xe377585200000000, 0x0dd8ed4000000000, 0x68bf51f800000000, + 0xa1f82bf000000000, 0xc49f974800000000, 0x2a30225a00000000, + 0x4f579ee200000000, 0xf66f497f00000000, 0x9308f5c700000000, + 0x7da740d500000000, 0x18c0fc6d00000000, 0x4ed09f3500000000, + 0x2bb7238d00000000, 0xc518969f00000000, 0xa07f2a2700000000, + 0x1947fdba00000000, 0x7c20410200000000, 0x928ff41000000000, + 0xf7e848a800000000, 0x3d58149b00000000, 0x583fa82300000000, + 0xb6901d3100000000, 0xd3f7a18900000000, 0x6acf761400000000, + 0x0fa8caac00000000, 0xe1077fbe00000000, 0x8460c30600000000, + 0xd270a05e00000000, 0xb7171ce600000000, 0x59b8a9f400000000, + 0x3cdf154c00000000, 0x85e7c2d100000000, 0xe0807e6900000000, + 0x0e2fcb7b00000000, 0x6b4877c300000000, 0xa20f0dcb00000000, + 0xc768b17300000000, 0x29c7046100000000, 0x4ca0b8d900000000, + 0xf5986f4400000000, 0x90ffd3fc00000000, 0x7e5066ee00000000, + 0x1b37da5600000000, 0x4d27b90e00000000, 0x284005b600000000, + 0xc6efb0a400000000, 0xa3880c1c00000000, 0x1ab0db8100000000, + 0x7fd7673900000000, 0x9178d22b00000000, 0xf41f6e9300000000, + 0x03f7263b00000000, 0x66909a8300000000, 0x883f2f9100000000, + 0xed58932900000000, 0x546044b400000000, 0x3107f80c00000000, + 0xdfa84d1e00000000, 0xbacff1a600000000, 0xecdf92fe00000000, + 0x89b82e4600000000, 0x67179b5400000000, 0x027027ec00000000, + 0xbb48f07100000000, 0xde2f4cc900000000, 0x3080f9db00000000, + 0x55e7456300000000, 0x9ca03f6b00000000, 0xf9c783d300000000, + 0x176836c100000000, 0x720f8a7900000000, 0xcb375de400000000, + 0xae50e15c00000000, 0x40ff544e00000000, 0x2598e8f600000000, + 0x73888bae00000000, 0x16ef371600000000, 0xf840820400000000, + 0x9d273ebc00000000, 0x241fe92100000000, 0x4178559900000000, + 0xafd7e08b00000000, 0xcab05c3300000000, 0x3bb659ed00000000, + 0x5ed1e55500000000, 0xb07e504700000000, 0xd519ecff00000000, + 0x6c213b6200000000, 0x094687da00000000, 0xe7e932c800000000, + 0x828e8e7000000000, 0xd49eed2800000000, 0xb1f9519000000000, + 0x5f56e48200000000, 0x3a31583a00000000, 0x83098fa700000000, + 0xe66e331f00000000, 0x08c1860d00000000, 0x6da63ab500000000, + 0xa4e140bd00000000, 0xc186fc0500000000, 0x2f29491700000000, + 0x4a4ef5af00000000, 0xf376223200000000, 0x96119e8a00000000, + 0x78be2b9800000000, 0x1dd9972000000000, 0x4bc9f47800000000, + 0x2eae48c000000000, 0xc001fdd200000000, 0xa566416a00000000, + 0x1c5e96f700000000, 0x79392a4f00000000, 0x97969f5d00000000, + 0xf2f123e500000000, 0x05196b4d00000000, 0x607ed7f500000000, + 0x8ed162e700000000, 0xebb6de5f00000000, 0x528e09c200000000, + 0x37e9b57a00000000, 0xd946006800000000, 0xbc21bcd000000000, + 0xea31df8800000000, 0x8f56633000000000, 0x61f9d62200000000, + 0x049e6a9a00000000, 0xbda6bd0700000000, 0xd8c101bf00000000, + 0x366eb4ad00000000, 0x5309081500000000, 0x9a4e721d00000000, + 0xff29cea500000000, 0x11867bb700000000, 0x74e1c70f00000000, + 0xcdd9109200000000, 0xa8beac2a00000000, 0x4611193800000000, + 0x2376a58000000000, 0x7566c6d800000000, 0x10017a6000000000, + 0xfeaecf7200000000, 0x9bc973ca00000000, 0x22f1a45700000000, + 0x479618ef00000000, 0xa939adfd00000000, 0xcc5e114500000000, + 0x06ee4d7600000000, 0x6389f1ce00000000, 0x8d2644dc00000000, + 0xe841f86400000000, 0x51792ff900000000, 0x341e934100000000, + 0xdab1265300000000, 0xbfd69aeb00000000, 0xe9c6f9b300000000, + 0x8ca1450b00000000, 0x620ef01900000000, 0x07694ca100000000, + 0xbe519b3c00000000, 0xdb36278400000000, 0x3599929600000000, + 0x50fe2e2e00000000, 0x99b9542600000000, 0xfcdee89e00000000, + 0x12715d8c00000000, 0x7716e13400000000, 0xce2e36a900000000, + 0xab498a1100000000, 0x45e63f0300000000, 0x208183bb00000000, + 0x7691e0e300000000, 0x13f65c5b00000000, 0xfd59e94900000000, + 0x983e55f100000000, 0x2106826c00000000, 0x44613ed400000000, + 0xaace8bc600000000, 0xcfa9377e00000000, 0x38417fd600000000, + 0x5d26c36e00000000, 0xb389767c00000000, 0xd6eecac400000000, + 0x6fd61d5900000000, 0x0ab1a1e100000000, 0xe41e14f300000000, + 0x8179a84b00000000, 0xd769cb1300000000, 0xb20e77ab00000000, + 0x5ca1c2b900000000, 0x39c67e0100000000, 0x80fea99c00000000, + 0xe599152400000000, 0x0b36a03600000000, 0x6e511c8e00000000, + 0xa716668600000000, 0xc271da3e00000000, 0x2cde6f2c00000000, + 0x49b9d39400000000, 0xf081040900000000, 0x95e6b8b100000000, + 0x7b490da300000000, 0x1e2eb11b00000000, 0x483ed24300000000, + 0x2d596efb00000000, 0xc3f6dbe900000000, 0xa691675100000000, + 0x1fa9b0cc00000000, 0x7ace0c7400000000, 0x9461b96600000000, + 0xf10605de00000000}, + {0x0000000000000000, 0xb029603d00000000, 0x6053c07a00000000, + 0xd07aa04700000000, 0xc0a680f500000000, 0x708fe0c800000000, + 0xa0f5408f00000000, 0x10dc20b200000000, 0xc14b703000000000, + 0x7162100d00000000, 0xa118b04a00000000, 0x1131d07700000000, + 0x01edf0c500000000, 0xb1c490f800000000, 0x61be30bf00000000, + 0xd197508200000000, 0x8297e06000000000, 0x32be805d00000000, + 0xe2c4201a00000000, 0x52ed402700000000, 0x4231609500000000, + 0xf21800a800000000, 0x2262a0ef00000000, 0x924bc0d200000000, + 0x43dc905000000000, 0xf3f5f06d00000000, 0x238f502a00000000, + 0x93a6301700000000, 0x837a10a500000000, 0x3353709800000000, + 0xe329d0df00000000, 0x5300b0e200000000, 0x042fc1c100000000, + 0xb406a1fc00000000, 0x647c01bb00000000, 0xd455618600000000, + 0xc489413400000000, 0x74a0210900000000, 0xa4da814e00000000, + 0x14f3e17300000000, 0xc564b1f100000000, 0x754dd1cc00000000, + 0xa537718b00000000, 0x151e11b600000000, 0x05c2310400000000, + 0xb5eb513900000000, 0x6591f17e00000000, 0xd5b8914300000000, + 0x86b821a100000000, 0x3691419c00000000, 0xe6ebe1db00000000, + 0x56c281e600000000, 0x461ea15400000000, 0xf637c16900000000, + 0x264d612e00000000, 0x9664011300000000, 0x47f3519100000000, + 0xf7da31ac00000000, 0x27a091eb00000000, 0x9789f1d600000000, + 0x8755d16400000000, 0x377cb15900000000, 0xe706111e00000000, + 0x572f712300000000, 0x4958f35800000000, 0xf971936500000000, + 0x290b332200000000, 0x9922531f00000000, 0x89fe73ad00000000, + 0x39d7139000000000, 0xe9adb3d700000000, 0x5984d3ea00000000, + 0x8813836800000000, 0x383ae35500000000, 0xe840431200000000, + 0x5869232f00000000, 0x48b5039d00000000, 0xf89c63a000000000, + 0x28e6c3e700000000, 0x98cfa3da00000000, 0xcbcf133800000000, + 0x7be6730500000000, 0xab9cd34200000000, 0x1bb5b37f00000000, + 0x0b6993cd00000000, 0xbb40f3f000000000, 0x6b3a53b700000000, + 0xdb13338a00000000, 0x0a84630800000000, 0xbaad033500000000, + 0x6ad7a37200000000, 0xdafec34f00000000, 0xca22e3fd00000000, + 0x7a0b83c000000000, 0xaa71238700000000, 0x1a5843ba00000000, + 0x4d77329900000000, 0xfd5e52a400000000, 0x2d24f2e300000000, + 0x9d0d92de00000000, 0x8dd1b26c00000000, 0x3df8d25100000000, + 0xed82721600000000, 0x5dab122b00000000, 0x8c3c42a900000000, + 0x3c15229400000000, 0xec6f82d300000000, 0x5c46e2ee00000000, + 0x4c9ac25c00000000, 0xfcb3a26100000000, 0x2cc9022600000000, + 0x9ce0621b00000000, 0xcfe0d2f900000000, 0x7fc9b2c400000000, + 0xafb3128300000000, 0x1f9a72be00000000, 0x0f46520c00000000, + 0xbf6f323100000000, 0x6f15927600000000, 0xdf3cf24b00000000, + 0x0eaba2c900000000, 0xbe82c2f400000000, 0x6ef862b300000000, + 0xded1028e00000000, 0xce0d223c00000000, 0x7e24420100000000, + 0xae5ee24600000000, 0x1e77827b00000000, 0x92b0e6b100000000, + 0x2299868c00000000, 0xf2e326cb00000000, 0x42ca46f600000000, + 0x5216664400000000, 0xe23f067900000000, 0x3245a63e00000000, + 0x826cc60300000000, 0x53fb968100000000, 0xe3d2f6bc00000000, + 0x33a856fb00000000, 0x838136c600000000, 0x935d167400000000, + 0x2374764900000000, 0xf30ed60e00000000, 0x4327b63300000000, + 0x102706d100000000, 0xa00e66ec00000000, 0x7074c6ab00000000, + 0xc05da69600000000, 0xd081862400000000, 0x60a8e61900000000, + 0xb0d2465e00000000, 0x00fb266300000000, 0xd16c76e100000000, + 0x614516dc00000000, 0xb13fb69b00000000, 0x0116d6a600000000, + 0x11caf61400000000, 0xa1e3962900000000, 0x7199366e00000000, + 0xc1b0565300000000, 0x969f277000000000, 0x26b6474d00000000, + 0xf6cce70a00000000, 0x46e5873700000000, 0x5639a78500000000, + 0xe610c7b800000000, 0x366a67ff00000000, 0x864307c200000000, + 0x57d4574000000000, 0xe7fd377d00000000, 0x3787973a00000000, + 0x87aef70700000000, 0x9772d7b500000000, 0x275bb78800000000, + 0xf72117cf00000000, 0x470877f200000000, 0x1408c71000000000, + 0xa421a72d00000000, 0x745b076a00000000, 0xc472675700000000, + 0xd4ae47e500000000, 0x648727d800000000, 0xb4fd879f00000000, + 0x04d4e7a200000000, 0xd543b72000000000, 0x656ad71d00000000, + 0xb510775a00000000, 0x0539176700000000, 0x15e537d500000000, + 0xa5cc57e800000000, 0x75b6f7af00000000, 0xc59f979200000000, + 0xdbe815e900000000, 0x6bc175d400000000, 0xbbbbd59300000000, + 0x0b92b5ae00000000, 0x1b4e951c00000000, 0xab67f52100000000, + 0x7b1d556600000000, 0xcb34355b00000000, 0x1aa365d900000000, + 0xaa8a05e400000000, 0x7af0a5a300000000, 0xcad9c59e00000000, + 0xda05e52c00000000, 0x6a2c851100000000, 0xba56255600000000, + 0x0a7f456b00000000, 0x597ff58900000000, 0xe95695b400000000, + 0x392c35f300000000, 0x890555ce00000000, 0x99d9757c00000000, + 0x29f0154100000000, 0xf98ab50600000000, 0x49a3d53b00000000, + 0x983485b900000000, 0x281de58400000000, 0xf86745c300000000, + 0x484e25fe00000000, 0x5892054c00000000, 0xe8bb657100000000, + 0x38c1c53600000000, 0x88e8a50b00000000, 0xdfc7d42800000000, + 0x6feeb41500000000, 0xbf94145200000000, 0x0fbd746f00000000, + 0x1f6154dd00000000, 0xaf4834e000000000, 0x7f3294a700000000, + 0xcf1bf49a00000000, 0x1e8ca41800000000, 0xaea5c42500000000, + 0x7edf646200000000, 0xcef6045f00000000, 0xde2a24ed00000000, + 0x6e0344d000000000, 0xbe79e49700000000, 0x0e5084aa00000000, + 0x5d50344800000000, 0xed79547500000000, 0x3d03f43200000000, + 0x8d2a940f00000000, 0x9df6b4bd00000000, 0x2ddfd48000000000, + 0xfda574c700000000, 0x4d8c14fa00000000, 0x9c1b447800000000, + 0x2c32244500000000, 0xfc48840200000000, 0x4c61e43f00000000, + 0x5cbdc48d00000000, 0xec94a4b000000000, 0x3cee04f700000000, + 0x8cc764ca00000000}, + {0x0000000000000000, 0xa5d35ccb00000000, 0x0ba1c84d00000000, + 0xae72948600000000, 0x1642919b00000000, 0xb391cd5000000000, + 0x1de359d600000000, 0xb830051d00000000, 0x6d8253ec00000000, + 0xc8510f2700000000, 0x66239ba100000000, 0xc3f0c76a00000000, + 0x7bc0c27700000000, 0xde139ebc00000000, 0x70610a3a00000000, + 0xd5b256f100000000, 0x9b02d60300000000, 0x3ed18ac800000000, + 0x90a31e4e00000000, 0x3570428500000000, 0x8d40479800000000, + 0x28931b5300000000, 0x86e18fd500000000, 0x2332d31e00000000, + 0xf68085ef00000000, 0x5353d92400000000, 0xfd214da200000000, + 0x58f2116900000000, 0xe0c2147400000000, 0x451148bf00000000, + 0xeb63dc3900000000, 0x4eb080f200000000, 0x3605ac0700000000, + 0x93d6f0cc00000000, 0x3da4644a00000000, 0x9877388100000000, + 0x20473d9c00000000, 0x8594615700000000, 0x2be6f5d100000000, + 0x8e35a91a00000000, 0x5b87ffeb00000000, 0xfe54a32000000000, + 0x502637a600000000, 0xf5f56b6d00000000, 0x4dc56e7000000000, + 0xe81632bb00000000, 0x4664a63d00000000, 0xe3b7faf600000000, + 0xad077a0400000000, 0x08d426cf00000000, 0xa6a6b24900000000, + 0x0375ee8200000000, 0xbb45eb9f00000000, 0x1e96b75400000000, + 0xb0e423d200000000, 0x15377f1900000000, 0xc08529e800000000, + 0x6556752300000000, 0xcb24e1a500000000, 0x6ef7bd6e00000000, + 0xd6c7b87300000000, 0x7314e4b800000000, 0xdd66703e00000000, + 0x78b52cf500000000, 0x6c0a580f00000000, 0xc9d904c400000000, + 0x67ab904200000000, 0xc278cc8900000000, 0x7a48c99400000000, + 0xdf9b955f00000000, 0x71e901d900000000, 0xd43a5d1200000000, + 0x01880be300000000, 0xa45b572800000000, 0x0a29c3ae00000000, + 0xaffa9f6500000000, 0x17ca9a7800000000, 0xb219c6b300000000, + 0x1c6b523500000000, 0xb9b80efe00000000, 0xf7088e0c00000000, + 0x52dbd2c700000000, 0xfca9464100000000, 0x597a1a8a00000000, + 0xe14a1f9700000000, 0x4499435c00000000, 0xeaebd7da00000000, + 0x4f388b1100000000, 0x9a8adde000000000, 0x3f59812b00000000, + 0x912b15ad00000000, 0x34f8496600000000, 0x8cc84c7b00000000, + 0x291b10b000000000, 0x8769843600000000, 0x22bad8fd00000000, + 0x5a0ff40800000000, 0xffdca8c300000000, 0x51ae3c4500000000, + 0xf47d608e00000000, 0x4c4d659300000000, 0xe99e395800000000, + 0x47ecadde00000000, 0xe23ff11500000000, 0x378da7e400000000, + 0x925efb2f00000000, 0x3c2c6fa900000000, 0x99ff336200000000, + 0x21cf367f00000000, 0x841c6ab400000000, 0x2a6efe3200000000, + 0x8fbda2f900000000, 0xc10d220b00000000, 0x64de7ec000000000, + 0xcaacea4600000000, 0x6f7fb68d00000000, 0xd74fb39000000000, + 0x729cef5b00000000, 0xdcee7bdd00000000, 0x793d271600000000, + 0xac8f71e700000000, 0x095c2d2c00000000, 0xa72eb9aa00000000, + 0x02fde56100000000, 0xbacde07c00000000, 0x1f1ebcb700000000, + 0xb16c283100000000, 0x14bf74fa00000000, 0xd814b01e00000000, + 0x7dc7ecd500000000, 0xd3b5785300000000, 0x7666249800000000, + 0xce56218500000000, 0x6b857d4e00000000, 0xc5f7e9c800000000, + 0x6024b50300000000, 0xb596e3f200000000, 0x1045bf3900000000, + 0xbe372bbf00000000, 0x1be4777400000000, 0xa3d4726900000000, + 0x06072ea200000000, 0xa875ba2400000000, 0x0da6e6ef00000000, + 0x4316661d00000000, 0xe6c53ad600000000, 0x48b7ae5000000000, + 0xed64f29b00000000, 0x5554f78600000000, 0xf087ab4d00000000, + 0x5ef53fcb00000000, 0xfb26630000000000, 0x2e9435f100000000, + 0x8b47693a00000000, 0x2535fdbc00000000, 0x80e6a17700000000, + 0x38d6a46a00000000, 0x9d05f8a100000000, 0x33776c2700000000, + 0x96a430ec00000000, 0xee111c1900000000, 0x4bc240d200000000, + 0xe5b0d45400000000, 0x4063889f00000000, 0xf8538d8200000000, + 0x5d80d14900000000, 0xf3f245cf00000000, 0x5621190400000000, + 0x83934ff500000000, 0x2640133e00000000, 0x883287b800000000, + 0x2de1db7300000000, 0x95d1de6e00000000, 0x300282a500000000, + 0x9e70162300000000, 0x3ba34ae800000000, 0x7513ca1a00000000, + 0xd0c096d100000000, 0x7eb2025700000000, 0xdb615e9c00000000, + 0x63515b8100000000, 0xc682074a00000000, 0x68f093cc00000000, + 0xcd23cf0700000000, 0x189199f600000000, 0xbd42c53d00000000, + 0x133051bb00000000, 0xb6e30d7000000000, 0x0ed3086d00000000, + 0xab0054a600000000, 0x0572c02000000000, 0xa0a19ceb00000000, + 0xb41ee81100000000, 0x11cdb4da00000000, 0xbfbf205c00000000, + 0x1a6c7c9700000000, 0xa25c798a00000000, 0x078f254100000000, + 0xa9fdb1c700000000, 0x0c2eed0c00000000, 0xd99cbbfd00000000, + 0x7c4fe73600000000, 0xd23d73b000000000, 0x77ee2f7b00000000, + 0xcfde2a6600000000, 0x6a0d76ad00000000, 0xc47fe22b00000000, + 0x61acbee000000000, 0x2f1c3e1200000000, 0x8acf62d900000000, + 0x24bdf65f00000000, 0x816eaa9400000000, 0x395eaf8900000000, + 0x9c8df34200000000, 0x32ff67c400000000, 0x972c3b0f00000000, + 0x429e6dfe00000000, 0xe74d313500000000, 0x493fa5b300000000, + 0xececf97800000000, 0x54dcfc6500000000, 0xf10fa0ae00000000, + 0x5f7d342800000000, 0xfaae68e300000000, 0x821b441600000000, + 0x27c818dd00000000, 0x89ba8c5b00000000, 0x2c69d09000000000, + 0x9459d58d00000000, 0x318a894600000000, 0x9ff81dc000000000, + 0x3a2b410b00000000, 0xef9917fa00000000, 0x4a4a4b3100000000, + 0xe438dfb700000000, 0x41eb837c00000000, 0xf9db866100000000, + 0x5c08daaa00000000, 0xf27a4e2c00000000, 0x57a912e700000000, + 0x1919921500000000, 0xbccacede00000000, 0x12b85a5800000000, + 0xb76b069300000000, 0x0f5b038e00000000, 0xaa885f4500000000, + 0x04facbc300000000, 0xa129970800000000, 0x749bc1f900000000, + 0xd1489d3200000000, 0x7f3a09b400000000, 0xdae9557f00000000, + 0x62d9506200000000, 0xc70a0ca900000000, 0x6978982f00000000, + 0xccabc4e400000000}, + {0x0000000000000000, 0xb40b77a600000000, 0x29119f9700000000, + 0x9d1ae83100000000, 0x13244ff400000000, 0xa72f385200000000, + 0x3a35d06300000000, 0x8e3ea7c500000000, 0x674eef3300000000, + 0xd345989500000000, 0x4e5f70a400000000, 0xfa54070200000000, + 0x746aa0c700000000, 0xc061d76100000000, 0x5d7b3f5000000000, + 0xe97048f600000000, 0xce9cde6700000000, 0x7a97a9c100000000, + 0xe78d41f000000000, 0x5386365600000000, 0xddb8919300000000, + 0x69b3e63500000000, 0xf4a90e0400000000, 0x40a279a200000000, + 0xa9d2315400000000, 0x1dd946f200000000, 0x80c3aec300000000, + 0x34c8d96500000000, 0xbaf67ea000000000, 0x0efd090600000000, + 0x93e7e13700000000, 0x27ec969100000000, 0x9c39bdcf00000000, + 0x2832ca6900000000, 0xb528225800000000, 0x012355fe00000000, + 0x8f1df23b00000000, 0x3b16859d00000000, 0xa60c6dac00000000, + 0x12071a0a00000000, 0xfb7752fc00000000, 0x4f7c255a00000000, + 0xd266cd6b00000000, 0x666dbacd00000000, 0xe8531d0800000000, + 0x5c586aae00000000, 0xc142829f00000000, 0x7549f53900000000, + 0x52a563a800000000, 0xe6ae140e00000000, 0x7bb4fc3f00000000, + 0xcfbf8b9900000000, 0x41812c5c00000000, 0xf58a5bfa00000000, + 0x6890b3cb00000000, 0xdc9bc46d00000000, 0x35eb8c9b00000000, + 0x81e0fb3d00000000, 0x1cfa130c00000000, 0xa8f164aa00000000, + 0x26cfc36f00000000, 0x92c4b4c900000000, 0x0fde5cf800000000, + 0xbbd52b5e00000000, 0x79750b4400000000, 0xcd7e7ce200000000, + 0x506494d300000000, 0xe46fe37500000000, 0x6a5144b000000000, + 0xde5a331600000000, 0x4340db2700000000, 0xf74bac8100000000, + 0x1e3be47700000000, 0xaa3093d100000000, 0x372a7be000000000, + 0x83210c4600000000, 0x0d1fab8300000000, 0xb914dc2500000000, + 0x240e341400000000, 0x900543b200000000, 0xb7e9d52300000000, + 0x03e2a28500000000, 0x9ef84ab400000000, 0x2af33d1200000000, + 0xa4cd9ad700000000, 0x10c6ed7100000000, 0x8ddc054000000000, + 0x39d772e600000000, 0xd0a73a1000000000, 0x64ac4db600000000, + 0xf9b6a58700000000, 0x4dbdd22100000000, 0xc38375e400000000, + 0x7788024200000000, 0xea92ea7300000000, 0x5e999dd500000000, + 0xe54cb68b00000000, 0x5147c12d00000000, 0xcc5d291c00000000, + 0x78565eba00000000, 0xf668f97f00000000, 0x42638ed900000000, + 0xdf7966e800000000, 0x6b72114e00000000, 0x820259b800000000, + 0x36092e1e00000000, 0xab13c62f00000000, 0x1f18b18900000000, + 0x9126164c00000000, 0x252d61ea00000000, 0xb83789db00000000, + 0x0c3cfe7d00000000, 0x2bd068ec00000000, 0x9fdb1f4a00000000, + 0x02c1f77b00000000, 0xb6ca80dd00000000, 0x38f4271800000000, + 0x8cff50be00000000, 0x11e5b88f00000000, 0xa5eecf2900000000, + 0x4c9e87df00000000, 0xf895f07900000000, 0x658f184800000000, + 0xd1846fee00000000, 0x5fbac82b00000000, 0xebb1bf8d00000000, + 0x76ab57bc00000000, 0xc2a0201a00000000, 0xf2ea168800000000, + 0x46e1612e00000000, 0xdbfb891f00000000, 0x6ff0feb900000000, + 0xe1ce597c00000000, 0x55c52eda00000000, 0xc8dfc6eb00000000, + 0x7cd4b14d00000000, 0x95a4f9bb00000000, 0x21af8e1d00000000, + 0xbcb5662c00000000, 0x08be118a00000000, 0x8680b64f00000000, + 0x328bc1e900000000, 0xaf9129d800000000, 0x1b9a5e7e00000000, + 0x3c76c8ef00000000, 0x887dbf4900000000, 0x1567577800000000, + 0xa16c20de00000000, 0x2f52871b00000000, 0x9b59f0bd00000000, + 0x0643188c00000000, 0xb2486f2a00000000, 0x5b3827dc00000000, + 0xef33507a00000000, 0x7229b84b00000000, 0xc622cfed00000000, + 0x481c682800000000, 0xfc171f8e00000000, 0x610df7bf00000000, + 0xd506801900000000, 0x6ed3ab4700000000, 0xdad8dce100000000, + 0x47c234d000000000, 0xf3c9437600000000, 0x7df7e4b300000000, + 0xc9fc931500000000, 0x54e67b2400000000, 0xe0ed0c8200000000, + 0x099d447400000000, 0xbd9633d200000000, 0x208cdbe300000000, + 0x9487ac4500000000, 0x1ab90b8000000000, 0xaeb27c2600000000, + 0x33a8941700000000, 0x87a3e3b100000000, 0xa04f752000000000, + 0x1444028600000000, 0x895eeab700000000, 0x3d559d1100000000, + 0xb36b3ad400000000, 0x07604d7200000000, 0x9a7aa54300000000, + 0x2e71d2e500000000, 0xc7019a1300000000, 0x730aedb500000000, + 0xee10058400000000, 0x5a1b722200000000, 0xd425d5e700000000, + 0x602ea24100000000, 0xfd344a7000000000, 0x493f3dd600000000, + 0x8b9f1dcc00000000, 0x3f946a6a00000000, 0xa28e825b00000000, + 0x1685f5fd00000000, 0x98bb523800000000, 0x2cb0259e00000000, + 0xb1aacdaf00000000, 0x05a1ba0900000000, 0xecd1f2ff00000000, + 0x58da855900000000, 0xc5c06d6800000000, 0x71cb1ace00000000, + 0xfff5bd0b00000000, 0x4bfecaad00000000, 0xd6e4229c00000000, + 0x62ef553a00000000, 0x4503c3ab00000000, 0xf108b40d00000000, + 0x6c125c3c00000000, 0xd8192b9a00000000, 0x56278c5f00000000, + 0xe22cfbf900000000, 0x7f3613c800000000, 0xcb3d646e00000000, + 0x224d2c9800000000, 0x96465b3e00000000, 0x0b5cb30f00000000, + 0xbf57c4a900000000, 0x3169636c00000000, 0x856214ca00000000, + 0x1878fcfb00000000, 0xac738b5d00000000, 0x17a6a00300000000, + 0xa3add7a500000000, 0x3eb73f9400000000, 0x8abc483200000000, + 0x0482eff700000000, 0xb089985100000000, 0x2d93706000000000, + 0x999807c600000000, 0x70e84f3000000000, 0xc4e3389600000000, + 0x59f9d0a700000000, 0xedf2a70100000000, 0x63cc00c400000000, + 0xd7c7776200000000, 0x4add9f5300000000, 0xfed6e8f500000000, + 0xd93a7e6400000000, 0x6d3109c200000000, 0xf02be1f300000000, + 0x4420965500000000, 0xca1e319000000000, 0x7e15463600000000, + 0xe30fae0700000000, 0x5704d9a100000000, 0xbe74915700000000, + 0x0a7fe6f100000000, 0x97650ec000000000, 0x236e796600000000, + 0xad50dea300000000, 0x195ba90500000000, 0x8441413400000000, + 0x304a369200000000}, + {0x0000000000000000, 0x9e00aacc00000000, 0x7d07254200000000, + 0xe3078f8e00000000, 0xfa0e4a8400000000, 0x640ee04800000000, + 0x87096fc600000000, 0x1909c50a00000000, 0xb51be5d300000000, + 0x2b1b4f1f00000000, 0xc81cc09100000000, 0x561c6a5d00000000, + 0x4f15af5700000000, 0xd115059b00000000, 0x32128a1500000000, + 0xac1220d900000000, 0x2b31bb7c00000000, 0xb53111b000000000, + 0x56369e3e00000000, 0xc83634f200000000, 0xd13ff1f800000000, + 0x4f3f5b3400000000, 0xac38d4ba00000000, 0x32387e7600000000, + 0x9e2a5eaf00000000, 0x002af46300000000, 0xe32d7bed00000000, + 0x7d2dd12100000000, 0x6424142b00000000, 0xfa24bee700000000, + 0x1923316900000000, 0x87239ba500000000, 0x566276f900000000, + 0xc862dc3500000000, 0x2b6553bb00000000, 0xb565f97700000000, + 0xac6c3c7d00000000, 0x326c96b100000000, 0xd16b193f00000000, + 0x4f6bb3f300000000, 0xe379932a00000000, 0x7d7939e600000000, + 0x9e7eb66800000000, 0x007e1ca400000000, 0x1977d9ae00000000, + 0x8777736200000000, 0x6470fcec00000000, 0xfa70562000000000, + 0x7d53cd8500000000, 0xe353674900000000, 0x0054e8c700000000, + 0x9e54420b00000000, 0x875d870100000000, 0x195d2dcd00000000, + 0xfa5aa24300000000, 0x645a088f00000000, 0xc848285600000000, + 0x5648829a00000000, 0xb54f0d1400000000, 0x2b4fa7d800000000, + 0x324662d200000000, 0xac46c81e00000000, 0x4f41479000000000, + 0xd141ed5c00000000, 0xedc29d2900000000, 0x73c237e500000000, + 0x90c5b86b00000000, 0x0ec512a700000000, 0x17ccd7ad00000000, + 0x89cc7d6100000000, 0x6acbf2ef00000000, 0xf4cb582300000000, + 0x58d978fa00000000, 0xc6d9d23600000000, 0x25de5db800000000, + 0xbbdef77400000000, 0xa2d7327e00000000, 0x3cd798b200000000, + 0xdfd0173c00000000, 0x41d0bdf000000000, 0xc6f3265500000000, + 0x58f38c9900000000, 0xbbf4031700000000, 0x25f4a9db00000000, + 0x3cfd6cd100000000, 0xa2fdc61d00000000, 0x41fa499300000000, + 0xdffae35f00000000, 0x73e8c38600000000, 0xede8694a00000000, + 0x0eefe6c400000000, 0x90ef4c0800000000, 0x89e6890200000000, + 0x17e623ce00000000, 0xf4e1ac4000000000, 0x6ae1068c00000000, + 0xbba0ebd000000000, 0x25a0411c00000000, 0xc6a7ce9200000000, + 0x58a7645e00000000, 0x41aea15400000000, 0xdfae0b9800000000, + 0x3ca9841600000000, 0xa2a92eda00000000, 0x0ebb0e0300000000, + 0x90bba4cf00000000, 0x73bc2b4100000000, 0xedbc818d00000000, + 0xf4b5448700000000, 0x6ab5ee4b00000000, 0x89b261c500000000, + 0x17b2cb0900000000, 0x909150ac00000000, 0x0e91fa6000000000, + 0xed9675ee00000000, 0x7396df2200000000, 0x6a9f1a2800000000, + 0xf49fb0e400000000, 0x17983f6a00000000, 0x899895a600000000, + 0x258ab57f00000000, 0xbb8a1fb300000000, 0x588d903d00000000, + 0xc68d3af100000000, 0xdf84fffb00000000, 0x4184553700000000, + 0xa283dab900000000, 0x3c83707500000000, 0xda853b5300000000, + 0x4485919f00000000, 0xa7821e1100000000, 0x3982b4dd00000000, + 0x208b71d700000000, 0xbe8bdb1b00000000, 0x5d8c549500000000, + 0xc38cfe5900000000, 0x6f9ede8000000000, 0xf19e744c00000000, + 0x1299fbc200000000, 0x8c99510e00000000, 0x9590940400000000, + 0x0b903ec800000000, 0xe897b14600000000, 0x76971b8a00000000, + 0xf1b4802f00000000, 0x6fb42ae300000000, 0x8cb3a56d00000000, + 0x12b30fa100000000, 0x0bbacaab00000000, 0x95ba606700000000, + 0x76bdefe900000000, 0xe8bd452500000000, 0x44af65fc00000000, + 0xdaafcf3000000000, 0x39a840be00000000, 0xa7a8ea7200000000, + 0xbea12f7800000000, 0x20a185b400000000, 0xc3a60a3a00000000, + 0x5da6a0f600000000, 0x8ce74daa00000000, 0x12e7e76600000000, + 0xf1e068e800000000, 0x6fe0c22400000000, 0x76e9072e00000000, + 0xe8e9ade200000000, 0x0bee226c00000000, 0x95ee88a000000000, + 0x39fca87900000000, 0xa7fc02b500000000, 0x44fb8d3b00000000, + 0xdafb27f700000000, 0xc3f2e2fd00000000, 0x5df2483100000000, + 0xbef5c7bf00000000, 0x20f56d7300000000, 0xa7d6f6d600000000, + 0x39d65c1a00000000, 0xdad1d39400000000, 0x44d1795800000000, + 0x5dd8bc5200000000, 0xc3d8169e00000000, 0x20df991000000000, + 0xbedf33dc00000000, 0x12cd130500000000, 0x8ccdb9c900000000, + 0x6fca364700000000, 0xf1ca9c8b00000000, 0xe8c3598100000000, + 0x76c3f34d00000000, 0x95c47cc300000000, 0x0bc4d60f00000000, + 0x3747a67a00000000, 0xa9470cb600000000, 0x4a40833800000000, + 0xd44029f400000000, 0xcd49ecfe00000000, 0x5349463200000000, + 0xb04ec9bc00000000, 0x2e4e637000000000, 0x825c43a900000000, + 0x1c5ce96500000000, 0xff5b66eb00000000, 0x615bcc2700000000, + 0x7852092d00000000, 0xe652a3e100000000, 0x05552c6f00000000, + 0x9b5586a300000000, 0x1c761d0600000000, 0x8276b7ca00000000, + 0x6171384400000000, 0xff71928800000000, 0xe678578200000000, + 0x7878fd4e00000000, 0x9b7f72c000000000, 0x057fd80c00000000, + 0xa96df8d500000000, 0x376d521900000000, 0xd46add9700000000, + 0x4a6a775b00000000, 0x5363b25100000000, 0xcd63189d00000000, + 0x2e64971300000000, 0xb0643ddf00000000, 0x6125d08300000000, + 0xff257a4f00000000, 0x1c22f5c100000000, 0x82225f0d00000000, + 0x9b2b9a0700000000, 0x052b30cb00000000, 0xe62cbf4500000000, + 0x782c158900000000, 0xd43e355000000000, 0x4a3e9f9c00000000, + 0xa939101200000000, 0x3739bade00000000, 0x2e307fd400000000, + 0xb030d51800000000, 0x53375a9600000000, 0xcd37f05a00000000, + 0x4a146bff00000000, 0xd414c13300000000, 0x37134ebd00000000, + 0xa913e47100000000, 0xb01a217b00000000, 0x2e1a8bb700000000, + 0xcd1d043900000000, 0x531daef500000000, 0xff0f8e2c00000000, + 0x610f24e000000000, 0x8208ab6e00000000, 0x1c0801a200000000, + 0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000, + 0xe6064b2600000000}}; + +#else /* W == 4 */ + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}, + {0x00000000, 0x41311b19, 0x82623632, 0xc3532d2b, 0x04c56c64, + 0x45f4777d, 0x86a75a56, 0xc796414f, 0x088ad9c8, 0x49bbc2d1, + 0x8ae8effa, 0xcbd9f4e3, 0x0c4fb5ac, 0x4d7eaeb5, 0x8e2d839e, + 0xcf1c9887, 0x5112c24a, 0x1023d953, 0xd370f478, 0x9241ef61, + 0x55d7ae2e, 0x14e6b537, 0xd7b5981c, 0x96848305, 0x59981b82, + 0x18a9009b, 0xdbfa2db0, 0x9acb36a9, 0x5d5d77e6, 0x1c6c6cff, + 0xdf3f41d4, 0x9e0e5acd, 0xa2248495, 0xe3159f8c, 0x2046b2a7, + 0x6177a9be, 0xa6e1e8f1, 0xe7d0f3e8, 0x2483dec3, 0x65b2c5da, + 0xaaae5d5d, 0xeb9f4644, 0x28cc6b6f, 0x69fd7076, 0xae6b3139, + 0xef5a2a20, 0x2c09070b, 0x6d381c12, 0xf33646df, 0xb2075dc6, + 0x715470ed, 0x30656bf4, 0xf7f32abb, 0xb6c231a2, 0x75911c89, + 0x34a00790, 0xfbbc9f17, 0xba8d840e, 0x79dea925, 0x38efb23c, + 0xff79f373, 0xbe48e86a, 0x7d1bc541, 0x3c2ade58, 0x054f79f0, + 0x447e62e9, 0x872d4fc2, 0xc61c54db, 0x018a1594, 0x40bb0e8d, + 0x83e823a6, 0xc2d938bf, 0x0dc5a038, 0x4cf4bb21, 0x8fa7960a, + 0xce968d13, 0x0900cc5c, 0x4831d745, 0x8b62fa6e, 0xca53e177, + 0x545dbbba, 0x156ca0a3, 0xd63f8d88, 0x970e9691, 0x5098d7de, + 0x11a9ccc7, 0xd2fae1ec, 0x93cbfaf5, 0x5cd76272, 0x1de6796b, + 0xdeb55440, 0x9f844f59, 0x58120e16, 0x1923150f, 0xda703824, + 0x9b41233d, 0xa76bfd65, 0xe65ae67c, 0x2509cb57, 0x6438d04e, + 0xa3ae9101, 0xe29f8a18, 0x21cca733, 0x60fdbc2a, 0xafe124ad, + 0xeed03fb4, 0x2d83129f, 0x6cb20986, 0xab2448c9, 0xea1553d0, + 0x29467efb, 0x687765e2, 0xf6793f2f, 0xb7482436, 0x741b091d, + 0x352a1204, 0xf2bc534b, 0xb38d4852, 0x70de6579, 0x31ef7e60, + 0xfef3e6e7, 0xbfc2fdfe, 0x7c91d0d5, 0x3da0cbcc, 0xfa368a83, + 0xbb07919a, 0x7854bcb1, 0x3965a7a8, 0x4b98833b, 0x0aa99822, + 0xc9fab509, 0x88cbae10, 0x4f5def5f, 0x0e6cf446, 0xcd3fd96d, + 0x8c0ec274, 0x43125af3, 0x022341ea, 0xc1706cc1, 0x804177d8, + 0x47d73697, 0x06e62d8e, 0xc5b500a5, 0x84841bbc, 0x1a8a4171, + 0x5bbb5a68, 0x98e87743, 0xd9d96c5a, 0x1e4f2d15, 0x5f7e360c, + 0x9c2d1b27, 0xdd1c003e, 0x120098b9, 0x533183a0, 0x9062ae8b, + 0xd153b592, 0x16c5f4dd, 0x57f4efc4, 0x94a7c2ef, 0xd596d9f6, + 0xe9bc07ae, 0xa88d1cb7, 0x6bde319c, 0x2aef2a85, 0xed796bca, + 0xac4870d3, 0x6f1b5df8, 0x2e2a46e1, 0xe136de66, 0xa007c57f, + 0x6354e854, 0x2265f34d, 0xe5f3b202, 0xa4c2a91b, 0x67918430, + 0x26a09f29, 0xb8aec5e4, 0xf99fdefd, 0x3accf3d6, 0x7bfde8cf, + 0xbc6ba980, 0xfd5ab299, 0x3e099fb2, 0x7f3884ab, 0xb0241c2c, + 0xf1150735, 0x32462a1e, 0x73773107, 0xb4e17048, 0xf5d06b51, + 0x3683467a, 0x77b25d63, 0x4ed7facb, 0x0fe6e1d2, 0xccb5ccf9, + 0x8d84d7e0, 0x4a1296af, 0x0b238db6, 0xc870a09d, 0x8941bb84, + 0x465d2303, 0x076c381a, 0xc43f1531, 0x850e0e28, 0x42984f67, + 0x03a9547e, 0xc0fa7955, 0x81cb624c, 0x1fc53881, 0x5ef42398, + 0x9da70eb3, 0xdc9615aa, 0x1b0054e5, 0x5a314ffc, 0x996262d7, + 0xd85379ce, 0x174fe149, 0x567efa50, 0x952dd77b, 0xd41ccc62, + 0x138a8d2d, 0x52bb9634, 0x91e8bb1f, 0xd0d9a006, 0xecf37e5e, + 0xadc26547, 0x6e91486c, 0x2fa05375, 0xe836123a, 0xa9070923, + 0x6a542408, 0x2b653f11, 0xe479a796, 0xa548bc8f, 0x661b91a4, + 0x272a8abd, 0xe0bccbf2, 0xa18dd0eb, 0x62defdc0, 0x23efe6d9, + 0xbde1bc14, 0xfcd0a70d, 0x3f838a26, 0x7eb2913f, 0xb924d070, + 0xf815cb69, 0x3b46e642, 0x7a77fd5b, 0xb56b65dc, 0xf45a7ec5, + 0x370953ee, 0x763848f7, 0xb1ae09b8, 0xf09f12a1, 0x33cc3f8a, + 0x72fd2493}, + {0x00000000, 0x376ac201, 0x6ed48403, 0x59be4602, 0xdca80907, + 0xebc2cb06, 0xb27c8d04, 0x85164f05, 0xb851130e, 0x8f3bd10f, + 0xd685970d, 0xe1ef550c, 0x64f91a09, 0x5393d808, 0x0a2d9e0a, + 0x3d475c0b, 0x70a3261c, 0x47c9e41d, 0x1e77a21f, 0x291d601e, + 0xac0b2f1b, 0x9b61ed1a, 0xc2dfab18, 0xf5b56919, 0xc8f23512, + 0xff98f713, 0xa626b111, 0x914c7310, 0x145a3c15, 0x2330fe14, + 0x7a8eb816, 0x4de47a17, 0xe0464d38, 0xd72c8f39, 0x8e92c93b, + 0xb9f80b3a, 0x3cee443f, 0x0b84863e, 0x523ac03c, 0x6550023d, + 0x58175e36, 0x6f7d9c37, 0x36c3da35, 0x01a91834, 0x84bf5731, + 0xb3d59530, 0xea6bd332, 0xdd011133, 0x90e56b24, 0xa78fa925, + 0xfe31ef27, 0xc95b2d26, 0x4c4d6223, 0x7b27a022, 0x2299e620, + 0x15f32421, 0x28b4782a, 0x1fdeba2b, 0x4660fc29, 0x710a3e28, + 0xf41c712d, 0xc376b32c, 0x9ac8f52e, 0xada2372f, 0xc08d9a70, + 0xf7e75871, 0xae591e73, 0x9933dc72, 0x1c259377, 0x2b4f5176, + 0x72f11774, 0x459bd575, 0x78dc897e, 0x4fb64b7f, 0x16080d7d, + 0x2162cf7c, 0xa4748079, 0x931e4278, 0xcaa0047a, 0xfdcac67b, + 0xb02ebc6c, 0x87447e6d, 0xdefa386f, 0xe990fa6e, 0x6c86b56b, + 0x5bec776a, 0x02523168, 0x3538f369, 0x087faf62, 0x3f156d63, + 0x66ab2b61, 0x51c1e960, 0xd4d7a665, 0xe3bd6464, 0xba032266, + 0x8d69e067, 0x20cbd748, 0x17a11549, 0x4e1f534b, 0x7975914a, + 0xfc63de4f, 0xcb091c4e, 0x92b75a4c, 0xa5dd984d, 0x989ac446, + 0xaff00647, 0xf64e4045, 0xc1248244, 0x4432cd41, 0x73580f40, + 0x2ae64942, 0x1d8c8b43, 0x5068f154, 0x67023355, 0x3ebc7557, + 0x09d6b756, 0x8cc0f853, 0xbbaa3a52, 0xe2147c50, 0xd57ebe51, + 0xe839e25a, 0xdf53205b, 0x86ed6659, 0xb187a458, 0x3491eb5d, + 0x03fb295c, 0x5a456f5e, 0x6d2fad5f, 0x801b35e1, 0xb771f7e0, + 0xeecfb1e2, 0xd9a573e3, 0x5cb33ce6, 0x6bd9fee7, 0x3267b8e5, + 0x050d7ae4, 0x384a26ef, 0x0f20e4ee, 0x569ea2ec, 0x61f460ed, + 0xe4e22fe8, 0xd388ede9, 0x8a36abeb, 0xbd5c69ea, 0xf0b813fd, + 0xc7d2d1fc, 0x9e6c97fe, 0xa90655ff, 0x2c101afa, 0x1b7ad8fb, + 0x42c49ef9, 0x75ae5cf8, 0x48e900f3, 0x7f83c2f2, 0x263d84f0, + 0x115746f1, 0x944109f4, 0xa32bcbf5, 0xfa958df7, 0xcdff4ff6, + 0x605d78d9, 0x5737bad8, 0x0e89fcda, 0x39e33edb, 0xbcf571de, + 0x8b9fb3df, 0xd221f5dd, 0xe54b37dc, 0xd80c6bd7, 0xef66a9d6, + 0xb6d8efd4, 0x81b22dd5, 0x04a462d0, 0x33cea0d1, 0x6a70e6d3, + 0x5d1a24d2, 0x10fe5ec5, 0x27949cc4, 0x7e2adac6, 0x494018c7, + 0xcc5657c2, 0xfb3c95c3, 0xa282d3c1, 0x95e811c0, 0xa8af4dcb, + 0x9fc58fca, 0xc67bc9c8, 0xf1110bc9, 0x740744cc, 0x436d86cd, + 0x1ad3c0cf, 0x2db902ce, 0x4096af91, 0x77fc6d90, 0x2e422b92, + 0x1928e993, 0x9c3ea696, 0xab546497, 0xf2ea2295, 0xc580e094, + 0xf8c7bc9f, 0xcfad7e9e, 0x9613389c, 0xa179fa9d, 0x246fb598, + 0x13057799, 0x4abb319b, 0x7dd1f39a, 0x3035898d, 0x075f4b8c, + 0x5ee10d8e, 0x698bcf8f, 0xec9d808a, 0xdbf7428b, 0x82490489, + 0xb523c688, 0x88649a83, 0xbf0e5882, 0xe6b01e80, 0xd1dadc81, + 0x54cc9384, 0x63a65185, 0x3a181787, 0x0d72d586, 0xa0d0e2a9, + 0x97ba20a8, 0xce0466aa, 0xf96ea4ab, 0x7c78ebae, 0x4b1229af, + 0x12ac6fad, 0x25c6adac, 0x1881f1a7, 0x2feb33a6, 0x765575a4, + 0x413fb7a5, 0xc429f8a0, 0xf3433aa1, 0xaafd7ca3, 0x9d97bea2, + 0xd073c4b5, 0xe71906b4, 0xbea740b6, 0x89cd82b7, 0x0cdbcdb2, + 0x3bb10fb3, 0x620f49b1, 0x55658bb0, 0x6822d7bb, 0x5f4815ba, + 0x06f653b8, 0x319c91b9, 0xb48adebc, 0x83e01cbd, 0xda5e5abf, + 0xed3498be}, + {0x00000000, 0x6567bcb8, 0x8bc809aa, 0xeeafb512, 0x5797628f, + 0x32f0de37, 0xdc5f6b25, 0xb938d79d, 0xef28b4c5, 0x8a4f087d, + 0x64e0bd6f, 0x018701d7, 0xb8bfd64a, 0xddd86af2, 0x3377dfe0, + 0x56106358, 0x9f571950, 0xfa30a5e8, 0x149f10fa, 0x71f8ac42, + 0xc8c07bdf, 0xada7c767, 0x43087275, 0x266fcecd, 0x707fad95, + 0x1518112d, 0xfbb7a43f, 0x9ed01887, 0x27e8cf1a, 0x428f73a2, + 0xac20c6b0, 0xc9477a08, 0x3eaf32a0, 0x5bc88e18, 0xb5673b0a, + 0xd00087b2, 0x6938502f, 0x0c5fec97, 0xe2f05985, 0x8797e53d, + 0xd1878665, 0xb4e03add, 0x5a4f8fcf, 0x3f283377, 0x8610e4ea, + 0xe3775852, 0x0dd8ed40, 0x68bf51f8, 0xa1f82bf0, 0xc49f9748, + 0x2a30225a, 0x4f579ee2, 0xf66f497f, 0x9308f5c7, 0x7da740d5, + 0x18c0fc6d, 0x4ed09f35, 0x2bb7238d, 0xc518969f, 0xa07f2a27, + 0x1947fdba, 0x7c204102, 0x928ff410, 0xf7e848a8, 0x3d58149b, + 0x583fa823, 0xb6901d31, 0xd3f7a189, 0x6acf7614, 0x0fa8caac, + 0xe1077fbe, 0x8460c306, 0xd270a05e, 0xb7171ce6, 0x59b8a9f4, + 0x3cdf154c, 0x85e7c2d1, 0xe0807e69, 0x0e2fcb7b, 0x6b4877c3, + 0xa20f0dcb, 0xc768b173, 0x29c70461, 0x4ca0b8d9, 0xf5986f44, + 0x90ffd3fc, 0x7e5066ee, 0x1b37da56, 0x4d27b90e, 0x284005b6, + 0xc6efb0a4, 0xa3880c1c, 0x1ab0db81, 0x7fd76739, 0x9178d22b, + 0xf41f6e93, 0x03f7263b, 0x66909a83, 0x883f2f91, 0xed589329, + 0x546044b4, 0x3107f80c, 0xdfa84d1e, 0xbacff1a6, 0xecdf92fe, + 0x89b82e46, 0x67179b54, 0x027027ec, 0xbb48f071, 0xde2f4cc9, + 0x3080f9db, 0x55e74563, 0x9ca03f6b, 0xf9c783d3, 0x176836c1, + 0x720f8a79, 0xcb375de4, 0xae50e15c, 0x40ff544e, 0x2598e8f6, + 0x73888bae, 0x16ef3716, 0xf8408204, 0x9d273ebc, 0x241fe921, + 0x41785599, 0xafd7e08b, 0xcab05c33, 0x3bb659ed, 0x5ed1e555, + 0xb07e5047, 0xd519ecff, 0x6c213b62, 0x094687da, 0xe7e932c8, + 0x828e8e70, 0xd49eed28, 0xb1f95190, 0x5f56e482, 0x3a31583a, + 0x83098fa7, 0xe66e331f, 0x08c1860d, 0x6da63ab5, 0xa4e140bd, + 0xc186fc05, 0x2f294917, 0x4a4ef5af, 0xf3762232, 0x96119e8a, + 0x78be2b98, 0x1dd99720, 0x4bc9f478, 0x2eae48c0, 0xc001fdd2, + 0xa566416a, 0x1c5e96f7, 0x79392a4f, 0x97969f5d, 0xf2f123e5, + 0x05196b4d, 0x607ed7f5, 0x8ed162e7, 0xebb6de5f, 0x528e09c2, + 0x37e9b57a, 0xd9460068, 0xbc21bcd0, 0xea31df88, 0x8f566330, + 0x61f9d622, 0x049e6a9a, 0xbda6bd07, 0xd8c101bf, 0x366eb4ad, + 0x53090815, 0x9a4e721d, 0xff29cea5, 0x11867bb7, 0x74e1c70f, + 0xcdd91092, 0xa8beac2a, 0x46111938, 0x2376a580, 0x7566c6d8, + 0x10017a60, 0xfeaecf72, 0x9bc973ca, 0x22f1a457, 0x479618ef, + 0xa939adfd, 0xcc5e1145, 0x06ee4d76, 0x6389f1ce, 0x8d2644dc, + 0xe841f864, 0x51792ff9, 0x341e9341, 0xdab12653, 0xbfd69aeb, + 0xe9c6f9b3, 0x8ca1450b, 0x620ef019, 0x07694ca1, 0xbe519b3c, + 0xdb362784, 0x35999296, 0x50fe2e2e, 0x99b95426, 0xfcdee89e, + 0x12715d8c, 0x7716e134, 0xce2e36a9, 0xab498a11, 0x45e63f03, + 0x208183bb, 0x7691e0e3, 0x13f65c5b, 0xfd59e949, 0x983e55f1, + 0x2106826c, 0x44613ed4, 0xaace8bc6, 0xcfa9377e, 0x38417fd6, + 0x5d26c36e, 0xb389767c, 0xd6eecac4, 0x6fd61d59, 0x0ab1a1e1, + 0xe41e14f3, 0x8179a84b, 0xd769cb13, 0xb20e77ab, 0x5ca1c2b9, + 0x39c67e01, 0x80fea99c, 0xe5991524, 0x0b36a036, 0x6e511c8e, + 0xa7166686, 0xc271da3e, 0x2cde6f2c, 0x49b9d394, 0xf0810409, + 0x95e6b8b1, 0x7b490da3, 0x1e2eb11b, 0x483ed243, 0x2d596efb, + 0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966, + 0xf10605de}}; + +#endif /* W */ + +#endif /* N == 1 */ +#if N == 2 + +#if W == 8 + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}, + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000, + 0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000, + 0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000, + 0x5bb6a3ac00000000, 0x9e8a2e9500000000, 0xdd9e558200000000, + 0x14f334e600000000, 0x57e74ff100000000, 0x92dbc2c800000000, + 0xd1cfb9df00000000, 0x7142c0ac00000000, 0x3256bbbb00000000, + 0xf76a368200000000, 0xb47e4d9500000000, 0x7d132cf100000000, + 0x3e0757e600000000, 0xfb3bdadf00000000, 0xb82fa1c800000000, + 0x69e0181700000000, 0x2af4630000000000, 0xefc8ee3900000000, + 0xacdc952e00000000, 0x65b1f44a00000000, 0x26a58f5d00000000, + 0xe399026400000000, 0xa08d797300000000, 0xa382f18200000000, + 0xe0968a9500000000, 0x25aa07ac00000000, 0x66be7cbb00000000, + 0xafd31ddf00000000, 0xecc766c800000000, 0x29fbebf100000000, + 0x6aef90e600000000, 0xbb20293900000000, 0xf834522e00000000, + 0x3d08df1700000000, 0x7e1ca40000000000, 0xb771c56400000000, + 0xf465be7300000000, 0x3159334a00000000, 0x724d485d00000000, + 0xd2c0312e00000000, 0x91d44a3900000000, 0x54e8c70000000000, + 0x17fcbc1700000000, 0xde91dd7300000000, 0x9d85a66400000000, + 0x58b92b5d00000000, 0x1bad504a00000000, 0xca62e99500000000, + 0x8976928200000000, 0x4c4a1fbb00000000, 0x0f5e64ac00000000, + 0xc63305c800000000, 0x85277edf00000000, 0x401bf3e600000000, + 0x030f88f100000000, 0x070392de00000000, 0x4417e9c900000000, + 0x812b64f000000000, 0xc23f1fe700000000, 0x0b527e8300000000, + 0x4846059400000000, 0x8d7a88ad00000000, 0xce6ef3ba00000000, + 0x1fa14a6500000000, 0x5cb5317200000000, 0x9989bc4b00000000, + 0xda9dc75c00000000, 0x13f0a63800000000, 0x50e4dd2f00000000, + 0x95d8501600000000, 0xd6cc2b0100000000, 0x7641527200000000, + 0x3555296500000000, 0xf069a45c00000000, 0xb37ddf4b00000000, + 0x7a10be2f00000000, 0x3904c53800000000, 0xfc38480100000000, + 0xbf2c331600000000, 0x6ee38ac900000000, 0x2df7f1de00000000, + 0xe8cb7ce700000000, 0xabdf07f000000000, 0x62b2669400000000, + 0x21a61d8300000000, 0xe49a90ba00000000, 0xa78eebad00000000, + 0xa481635c00000000, 0xe795184b00000000, 0x22a9957200000000, + 0x61bdee6500000000, 0xa8d08f0100000000, 0xebc4f41600000000, + 0x2ef8792f00000000, 0x6dec023800000000, 0xbc23bbe700000000, + 0xff37c0f000000000, 0x3a0b4dc900000000, 0x791f36de00000000, + 0xb07257ba00000000, 0xf3662cad00000000, 0x365aa19400000000, + 0x754eda8300000000, 0xd5c3a3f000000000, 0x96d7d8e700000000, + 0x53eb55de00000000, 0x10ff2ec900000000, 0xd9924fad00000000, + 0x9a8634ba00000000, 0x5fbab98300000000, 0x1caec29400000000, + 0xcd617b4b00000000, 0x8e75005c00000000, 0x4b498d6500000000, + 0x085df67200000000, 0xc130971600000000, 0x8224ec0100000000, + 0x4718613800000000, 0x040c1a2f00000000, 0x4f00556600000000, + 0x0c142e7100000000, 0xc928a34800000000, 0x8a3cd85f00000000, + 0x4351b93b00000000, 0x0045c22c00000000, 0xc5794f1500000000, + 0x866d340200000000, 0x57a28ddd00000000, 0x14b6f6ca00000000, + 0xd18a7bf300000000, 0x929e00e400000000, 0x5bf3618000000000, + 0x18e71a9700000000, 0xdddb97ae00000000, 0x9ecfecb900000000, + 0x3e4295ca00000000, 0x7d56eedd00000000, 0xb86a63e400000000, + 0xfb7e18f300000000, 0x3213799700000000, 0x7107028000000000, + 0xb43b8fb900000000, 0xf72ff4ae00000000, 0x26e04d7100000000, + 0x65f4366600000000, 0xa0c8bb5f00000000, 0xe3dcc04800000000, + 0x2ab1a12c00000000, 0x69a5da3b00000000, 0xac99570200000000, + 0xef8d2c1500000000, 0xec82a4e400000000, 0xaf96dff300000000, + 0x6aaa52ca00000000, 0x29be29dd00000000, 0xe0d348b900000000, + 0xa3c733ae00000000, 0x66fbbe9700000000, 0x25efc58000000000, + 0xf4207c5f00000000, 0xb734074800000000, 0x72088a7100000000, + 0x311cf16600000000, 0xf871900200000000, 0xbb65eb1500000000, + 0x7e59662c00000000, 0x3d4d1d3b00000000, 0x9dc0644800000000, + 0xded41f5f00000000, 0x1be8926600000000, 0x58fce97100000000, + 0x9191881500000000, 0xd285f30200000000, 0x17b97e3b00000000, + 0x54ad052c00000000, 0x8562bcf300000000, 0xc676c7e400000000, + 0x034a4add00000000, 0x405e31ca00000000, 0x893350ae00000000, + 0xca272bb900000000, 0x0f1ba68000000000, 0x4c0fdd9700000000, + 0x4803c7b800000000, 0x0b17bcaf00000000, 0xce2b319600000000, + 0x8d3f4a8100000000, 0x44522be500000000, 0x074650f200000000, + 0xc27addcb00000000, 0x816ea6dc00000000, 0x50a11f0300000000, + 0x13b5641400000000, 0xd689e92d00000000, 0x959d923a00000000, + 0x5cf0f35e00000000, 0x1fe4884900000000, 0xdad8057000000000, + 0x99cc7e6700000000, 0x3941071400000000, 0x7a557c0300000000, + 0xbf69f13a00000000, 0xfc7d8a2d00000000, 0x3510eb4900000000, + 0x7604905e00000000, 0xb3381d6700000000, 0xf02c667000000000, + 0x21e3dfaf00000000, 0x62f7a4b800000000, 0xa7cb298100000000, + 0xe4df529600000000, 0x2db233f200000000, 0x6ea648e500000000, + 0xab9ac5dc00000000, 0xe88ebecb00000000, 0xeb81363a00000000, + 0xa8954d2d00000000, 0x6da9c01400000000, 0x2ebdbb0300000000, + 0xe7d0da6700000000, 0xa4c4a17000000000, 0x61f82c4900000000, + 0x22ec575e00000000, 0xf323ee8100000000, 0xb037959600000000, + 0x750b18af00000000, 0x361f63b800000000, 0xff7202dc00000000, + 0xbc6679cb00000000, 0x795af4f200000000, 0x3a4e8fe500000000, + 0x9ac3f69600000000, 0xd9d78d8100000000, 0x1ceb00b800000000, + 0x5fff7baf00000000, 0x96921acb00000000, 0xd58661dc00000000, + 0x10baece500000000, 0x53ae97f200000000, 0x82612e2d00000000, + 0xc175553a00000000, 0x0449d80300000000, 0x475da31400000000, + 0x8e30c27000000000, 0xcd24b96700000000, 0x0818345e00000000, + 0x4b0c4f4900000000}, + {0x0000000000000000, 0x3e6bc2ef00000000, 0x3dd0f50400000000, + 0x03bb37eb00000000, 0x7aa0eb0900000000, 0x44cb29e600000000, + 0x47701e0d00000000, 0x791bdce200000000, 0xf440d71300000000, + 0xca2b15fc00000000, 0xc990221700000000, 0xf7fbe0f800000000, + 0x8ee03c1a00000000, 0xb08bfef500000000, 0xb330c91e00000000, + 0x8d5b0bf100000000, 0xe881ae2700000000, 0xd6ea6cc800000000, + 0xd5515b2300000000, 0xeb3a99cc00000000, 0x9221452e00000000, + 0xac4a87c100000000, 0xaff1b02a00000000, 0x919a72c500000000, + 0x1cc1793400000000, 0x22aabbdb00000000, 0x21118c3000000000, + 0x1f7a4edf00000000, 0x6661923d00000000, 0x580a50d200000000, + 0x5bb1673900000000, 0x65daa5d600000000, 0xd0035d4f00000000, + 0xee689fa000000000, 0xedd3a84b00000000, 0xd3b86aa400000000, + 0xaaa3b64600000000, 0x94c874a900000000, 0x9773434200000000, + 0xa91881ad00000000, 0x24438a5c00000000, 0x1a2848b300000000, + 0x19937f5800000000, 0x27f8bdb700000000, 0x5ee3615500000000, + 0x6088a3ba00000000, 0x6333945100000000, 0x5d5856be00000000, + 0x3882f36800000000, 0x06e9318700000000, 0x0552066c00000000, + 0x3b39c48300000000, 0x4222186100000000, 0x7c49da8e00000000, + 0x7ff2ed6500000000, 0x41992f8a00000000, 0xccc2247b00000000, + 0xf2a9e69400000000, 0xf112d17f00000000, 0xcf79139000000000, + 0xb662cf7200000000, 0x88090d9d00000000, 0x8bb23a7600000000, + 0xb5d9f89900000000, 0xa007ba9e00000000, 0x9e6c787100000000, + 0x9dd74f9a00000000, 0xa3bc8d7500000000, 0xdaa7519700000000, + 0xe4cc937800000000, 0xe777a49300000000, 0xd91c667c00000000, + 0x54476d8d00000000, 0x6a2caf6200000000, 0x6997988900000000, + 0x57fc5a6600000000, 0x2ee7868400000000, 0x108c446b00000000, + 0x1337738000000000, 0x2d5cb16f00000000, 0x488614b900000000, + 0x76edd65600000000, 0x7556e1bd00000000, 0x4b3d235200000000, + 0x3226ffb000000000, 0x0c4d3d5f00000000, 0x0ff60ab400000000, + 0x319dc85b00000000, 0xbcc6c3aa00000000, 0x82ad014500000000, + 0x811636ae00000000, 0xbf7df44100000000, 0xc66628a300000000, + 0xf80dea4c00000000, 0xfbb6dda700000000, 0xc5dd1f4800000000, + 0x7004e7d100000000, 0x4e6f253e00000000, 0x4dd412d500000000, + 0x73bfd03a00000000, 0x0aa40cd800000000, 0x34cfce3700000000, + 0x3774f9dc00000000, 0x091f3b3300000000, 0x844430c200000000, + 0xba2ff22d00000000, 0xb994c5c600000000, 0x87ff072900000000, + 0xfee4dbcb00000000, 0xc08f192400000000, 0xc3342ecf00000000, + 0xfd5fec2000000000, 0x988549f600000000, 0xa6ee8b1900000000, + 0xa555bcf200000000, 0x9b3e7e1d00000000, 0xe225a2ff00000000, + 0xdc4e601000000000, 0xdff557fb00000000, 0xe19e951400000000, + 0x6cc59ee500000000, 0x52ae5c0a00000000, 0x51156be100000000, + 0x6f7ea90e00000000, 0x166575ec00000000, 0x280eb70300000000, + 0x2bb580e800000000, 0x15de420700000000, 0x010905e600000000, + 0x3f62c70900000000, 0x3cd9f0e200000000, 0x02b2320d00000000, + 0x7ba9eeef00000000, 0x45c22c0000000000, 0x46791beb00000000, + 0x7812d90400000000, 0xf549d2f500000000, 0xcb22101a00000000, + 0xc89927f100000000, 0xf6f2e51e00000000, 0x8fe939fc00000000, + 0xb182fb1300000000, 0xb239ccf800000000, 0x8c520e1700000000, + 0xe988abc100000000, 0xd7e3692e00000000, 0xd4585ec500000000, + 0xea339c2a00000000, 0x932840c800000000, 0xad43822700000000, + 0xaef8b5cc00000000, 0x9093772300000000, 0x1dc87cd200000000, + 0x23a3be3d00000000, 0x201889d600000000, 0x1e734b3900000000, + 0x676897db00000000, 0x5903553400000000, 0x5ab862df00000000, + 0x64d3a03000000000, 0xd10a58a900000000, 0xef619a4600000000, + 0xecdaadad00000000, 0xd2b16f4200000000, 0xabaab3a000000000, + 0x95c1714f00000000, 0x967a46a400000000, 0xa811844b00000000, + 0x254a8fba00000000, 0x1b214d5500000000, 0x189a7abe00000000, + 0x26f1b85100000000, 0x5fea64b300000000, 0x6181a65c00000000, + 0x623a91b700000000, 0x5c51535800000000, 0x398bf68e00000000, + 0x07e0346100000000, 0x045b038a00000000, 0x3a30c16500000000, + 0x432b1d8700000000, 0x7d40df6800000000, 0x7efbe88300000000, + 0x40902a6c00000000, 0xcdcb219d00000000, 0xf3a0e37200000000, + 0xf01bd49900000000, 0xce70167600000000, 0xb76bca9400000000, + 0x8900087b00000000, 0x8abb3f9000000000, 0xb4d0fd7f00000000, + 0xa10ebf7800000000, 0x9f657d9700000000, 0x9cde4a7c00000000, + 0xa2b5889300000000, 0xdbae547100000000, 0xe5c5969e00000000, + 0xe67ea17500000000, 0xd815639a00000000, 0x554e686b00000000, + 0x6b25aa8400000000, 0x689e9d6f00000000, 0x56f55f8000000000, + 0x2fee836200000000, 0x1185418d00000000, 0x123e766600000000, + 0x2c55b48900000000, 0x498f115f00000000, 0x77e4d3b000000000, + 0x745fe45b00000000, 0x4a3426b400000000, 0x332ffa5600000000, + 0x0d4438b900000000, 0x0eff0f5200000000, 0x3094cdbd00000000, + 0xbdcfc64c00000000, 0x83a404a300000000, 0x801f334800000000, + 0xbe74f1a700000000, 0xc76f2d4500000000, 0xf904efaa00000000, + 0xfabfd84100000000, 0xc4d41aae00000000, 0x710de23700000000, + 0x4f6620d800000000, 0x4cdd173300000000, 0x72b6d5dc00000000, + 0x0bad093e00000000, 0x35c6cbd100000000, 0x367dfc3a00000000, + 0x08163ed500000000, 0x854d352400000000, 0xbb26f7cb00000000, + 0xb89dc02000000000, 0x86f602cf00000000, 0xffedde2d00000000, + 0xc1861cc200000000, 0xc23d2b2900000000, 0xfc56e9c600000000, + 0x998c4c1000000000, 0xa7e78eff00000000, 0xa45cb91400000000, + 0x9a377bfb00000000, 0xe32ca71900000000, 0xdd4765f600000000, + 0xdefc521d00000000, 0xe09790f200000000, 0x6dcc9b0300000000, + 0x53a759ec00000000, 0x501c6e0700000000, 0x6e77ace800000000, + 0x176c700a00000000, 0x2907b2e500000000, 0x2abc850e00000000, + 0x14d747e100000000}, + {0x0000000000000000, 0xc0df8ec100000000, 0xc1b96c5800000000, + 0x0166e29900000000, 0x8273d9b000000000, 0x42ac577100000000, + 0x43cab5e800000000, 0x83153b2900000000, 0x45e1c3ba00000000, + 0x853e4d7b00000000, 0x8458afe200000000, 0x4487212300000000, + 0xc7921a0a00000000, 0x074d94cb00000000, 0x062b765200000000, + 0xc6f4f89300000000, 0xcbc4f6ae00000000, 0x0b1b786f00000000, + 0x0a7d9af600000000, 0xcaa2143700000000, 0x49b72f1e00000000, + 0x8968a1df00000000, 0x880e434600000000, 0x48d1cd8700000000, + 0x8e25351400000000, 0x4efabbd500000000, 0x4f9c594c00000000, + 0x8f43d78d00000000, 0x0c56eca400000000, 0xcc89626500000000, + 0xcdef80fc00000000, 0x0d300e3d00000000, 0xd78f9c8600000000, + 0x1750124700000000, 0x1636f0de00000000, 0xd6e97e1f00000000, + 0x55fc453600000000, 0x9523cbf700000000, 0x9445296e00000000, + 0x549aa7af00000000, 0x926e5f3c00000000, 0x52b1d1fd00000000, + 0x53d7336400000000, 0x9308bda500000000, 0x101d868c00000000, + 0xd0c2084d00000000, 0xd1a4ead400000000, 0x117b641500000000, + 0x1c4b6a2800000000, 0xdc94e4e900000000, 0xddf2067000000000, + 0x1d2d88b100000000, 0x9e38b39800000000, 0x5ee73d5900000000, + 0x5f81dfc000000000, 0x9f5e510100000000, 0x59aaa99200000000, + 0x9975275300000000, 0x9813c5ca00000000, 0x58cc4b0b00000000, + 0xdbd9702200000000, 0x1b06fee300000000, 0x1a601c7a00000000, + 0xdabf92bb00000000, 0xef1948d600000000, 0x2fc6c61700000000, + 0x2ea0248e00000000, 0xee7faa4f00000000, 0x6d6a916600000000, + 0xadb51fa700000000, 0xacd3fd3e00000000, 0x6c0c73ff00000000, + 0xaaf88b6c00000000, 0x6a2705ad00000000, 0x6b41e73400000000, + 0xab9e69f500000000, 0x288b52dc00000000, 0xe854dc1d00000000, + 0xe9323e8400000000, 0x29edb04500000000, 0x24ddbe7800000000, + 0xe40230b900000000, 0xe564d22000000000, 0x25bb5ce100000000, + 0xa6ae67c800000000, 0x6671e90900000000, 0x67170b9000000000, + 0xa7c8855100000000, 0x613c7dc200000000, 0xa1e3f30300000000, + 0xa085119a00000000, 0x605a9f5b00000000, 0xe34fa47200000000, + 0x23902ab300000000, 0x22f6c82a00000000, 0xe22946eb00000000, + 0x3896d45000000000, 0xf8495a9100000000, 0xf92fb80800000000, + 0x39f036c900000000, 0xbae50de000000000, 0x7a3a832100000000, + 0x7b5c61b800000000, 0xbb83ef7900000000, 0x7d7717ea00000000, + 0xbda8992b00000000, 0xbcce7bb200000000, 0x7c11f57300000000, + 0xff04ce5a00000000, 0x3fdb409b00000000, 0x3ebda20200000000, + 0xfe622cc300000000, 0xf35222fe00000000, 0x338dac3f00000000, + 0x32eb4ea600000000, 0xf234c06700000000, 0x7121fb4e00000000, + 0xb1fe758f00000000, 0xb098971600000000, 0x704719d700000000, + 0xb6b3e14400000000, 0x766c6f8500000000, 0x770a8d1c00000000, + 0xb7d503dd00000000, 0x34c038f400000000, 0xf41fb63500000000, + 0xf57954ac00000000, 0x35a6da6d00000000, 0x9f35e17700000000, + 0x5fea6fb600000000, 0x5e8c8d2f00000000, 0x9e5303ee00000000, + 0x1d4638c700000000, 0xdd99b60600000000, 0xdcff549f00000000, + 0x1c20da5e00000000, 0xdad422cd00000000, 0x1a0bac0c00000000, + 0x1b6d4e9500000000, 0xdbb2c05400000000, 0x58a7fb7d00000000, + 0x987875bc00000000, 0x991e972500000000, 0x59c119e400000000, + 0x54f117d900000000, 0x942e991800000000, 0x95487b8100000000, + 0x5597f54000000000, 0xd682ce6900000000, 0x165d40a800000000, + 0x173ba23100000000, 0xd7e42cf000000000, 0x1110d46300000000, + 0xd1cf5aa200000000, 0xd0a9b83b00000000, 0x107636fa00000000, + 0x93630dd300000000, 0x53bc831200000000, 0x52da618b00000000, + 0x9205ef4a00000000, 0x48ba7df100000000, 0x8865f33000000000, + 0x890311a900000000, 0x49dc9f6800000000, 0xcac9a44100000000, + 0x0a162a8000000000, 0x0b70c81900000000, 0xcbaf46d800000000, + 0x0d5bbe4b00000000, 0xcd84308a00000000, 0xcce2d21300000000, + 0x0c3d5cd200000000, 0x8f2867fb00000000, 0x4ff7e93a00000000, + 0x4e910ba300000000, 0x8e4e856200000000, 0x837e8b5f00000000, + 0x43a1059e00000000, 0x42c7e70700000000, 0x821869c600000000, + 0x010d52ef00000000, 0xc1d2dc2e00000000, 0xc0b43eb700000000, + 0x006bb07600000000, 0xc69f48e500000000, 0x0640c62400000000, + 0x072624bd00000000, 0xc7f9aa7c00000000, 0x44ec915500000000, + 0x84331f9400000000, 0x8555fd0d00000000, 0x458a73cc00000000, + 0x702ca9a100000000, 0xb0f3276000000000, 0xb195c5f900000000, + 0x714a4b3800000000, 0xf25f701100000000, 0x3280fed000000000, + 0x33e61c4900000000, 0xf339928800000000, 0x35cd6a1b00000000, + 0xf512e4da00000000, 0xf474064300000000, 0x34ab888200000000, + 0xb7beb3ab00000000, 0x77613d6a00000000, 0x7607dff300000000, + 0xb6d8513200000000, 0xbbe85f0f00000000, 0x7b37d1ce00000000, + 0x7a51335700000000, 0xba8ebd9600000000, 0x399b86bf00000000, + 0xf944087e00000000, 0xf822eae700000000, 0x38fd642600000000, + 0xfe099cb500000000, 0x3ed6127400000000, 0x3fb0f0ed00000000, + 0xff6f7e2c00000000, 0x7c7a450500000000, 0xbca5cbc400000000, + 0xbdc3295d00000000, 0x7d1ca79c00000000, 0xa7a3352700000000, + 0x677cbbe600000000, 0x661a597f00000000, 0xa6c5d7be00000000, + 0x25d0ec9700000000, 0xe50f625600000000, 0xe46980cf00000000, + 0x24b60e0e00000000, 0xe242f69d00000000, 0x229d785c00000000, + 0x23fb9ac500000000, 0xe324140400000000, 0x60312f2d00000000, + 0xa0eea1ec00000000, 0xa188437500000000, 0x6157cdb400000000, + 0x6c67c38900000000, 0xacb84d4800000000, 0xaddeafd100000000, + 0x6d01211000000000, 0xee141a3900000000, 0x2ecb94f800000000, + 0x2fad766100000000, 0xef72f8a000000000, 0x2986003300000000, + 0xe9598ef200000000, 0xe83f6c6b00000000, 0x28e0e2aa00000000, + 0xabf5d98300000000, 0x6b2a574200000000, 0x6a4cb5db00000000, + 0xaa933b1a00000000}, + {0x0000000000000000, 0x6f4ca59b00000000, 0x9f9e3bec00000000, + 0xf0d29e7700000000, 0x7f3b060300000000, 0x1077a39800000000, + 0xe0a53def00000000, 0x8fe9987400000000, 0xfe760c0600000000, + 0x913aa99d00000000, 0x61e837ea00000000, 0x0ea4927100000000, + 0x814d0a0500000000, 0xee01af9e00000000, 0x1ed331e900000000, + 0x719f947200000000, 0xfced180c00000000, 0x93a1bd9700000000, + 0x637323e000000000, 0x0c3f867b00000000, 0x83d61e0f00000000, + 0xec9abb9400000000, 0x1c4825e300000000, 0x7304807800000000, + 0x029b140a00000000, 0x6dd7b19100000000, 0x9d052fe600000000, + 0xf2498a7d00000000, 0x7da0120900000000, 0x12ecb79200000000, + 0xe23e29e500000000, 0x8d728c7e00000000, 0xf8db311800000000, + 0x9797948300000000, 0x67450af400000000, 0x0809af6f00000000, + 0x87e0371b00000000, 0xe8ac928000000000, 0x187e0cf700000000, + 0x7732a96c00000000, 0x06ad3d1e00000000, 0x69e1988500000000, + 0x993306f200000000, 0xf67fa36900000000, 0x79963b1d00000000, + 0x16da9e8600000000, 0xe60800f100000000, 0x8944a56a00000000, + 0x0436291400000000, 0x6b7a8c8f00000000, 0x9ba812f800000000, + 0xf4e4b76300000000, 0x7b0d2f1700000000, 0x14418a8c00000000, + 0xe49314fb00000000, 0x8bdfb16000000000, 0xfa40251200000000, + 0x950c808900000000, 0x65de1efe00000000, 0x0a92bb6500000000, + 0x857b231100000000, 0xea37868a00000000, 0x1ae518fd00000000, + 0x75a9bd6600000000, 0xf0b7633000000000, 0x9ffbc6ab00000000, + 0x6f2958dc00000000, 0x0065fd4700000000, 0x8f8c653300000000, + 0xe0c0c0a800000000, 0x10125edf00000000, 0x7f5efb4400000000, + 0x0ec16f3600000000, 0x618dcaad00000000, 0x915f54da00000000, + 0xfe13f14100000000, 0x71fa693500000000, 0x1eb6ccae00000000, + 0xee6452d900000000, 0x8128f74200000000, 0x0c5a7b3c00000000, + 0x6316dea700000000, 0x93c440d000000000, 0xfc88e54b00000000, + 0x73617d3f00000000, 0x1c2dd8a400000000, 0xecff46d300000000, + 0x83b3e34800000000, 0xf22c773a00000000, 0x9d60d2a100000000, + 0x6db24cd600000000, 0x02fee94d00000000, 0x8d17713900000000, + 0xe25bd4a200000000, 0x12894ad500000000, 0x7dc5ef4e00000000, + 0x086c522800000000, 0x6720f7b300000000, 0x97f269c400000000, + 0xf8becc5f00000000, 0x7757542b00000000, 0x181bf1b000000000, + 0xe8c96fc700000000, 0x8785ca5c00000000, 0xf61a5e2e00000000, + 0x9956fbb500000000, 0x698465c200000000, 0x06c8c05900000000, + 0x8921582d00000000, 0xe66dfdb600000000, 0x16bf63c100000000, + 0x79f3c65a00000000, 0xf4814a2400000000, 0x9bcdefbf00000000, + 0x6b1f71c800000000, 0x0453d45300000000, 0x8bba4c2700000000, + 0xe4f6e9bc00000000, 0x142477cb00000000, 0x7b68d25000000000, + 0x0af7462200000000, 0x65bbe3b900000000, 0x95697dce00000000, + 0xfa25d85500000000, 0x75cc402100000000, 0x1a80e5ba00000000, + 0xea527bcd00000000, 0x851ede5600000000, 0xe06fc76000000000, + 0x8f2362fb00000000, 0x7ff1fc8c00000000, 0x10bd591700000000, + 0x9f54c16300000000, 0xf01864f800000000, 0x00cafa8f00000000, + 0x6f865f1400000000, 0x1e19cb6600000000, 0x71556efd00000000, + 0x8187f08a00000000, 0xeecb551100000000, 0x6122cd6500000000, + 0x0e6e68fe00000000, 0xfebcf68900000000, 0x91f0531200000000, + 0x1c82df6c00000000, 0x73ce7af700000000, 0x831ce48000000000, + 0xec50411b00000000, 0x63b9d96f00000000, 0x0cf57cf400000000, + 0xfc27e28300000000, 0x936b471800000000, 0xe2f4d36a00000000, + 0x8db876f100000000, 0x7d6ae88600000000, 0x12264d1d00000000, + 0x9dcfd56900000000, 0xf28370f200000000, 0x0251ee8500000000, + 0x6d1d4b1e00000000, 0x18b4f67800000000, 0x77f853e300000000, + 0x872acd9400000000, 0xe866680f00000000, 0x678ff07b00000000, + 0x08c355e000000000, 0xf811cb9700000000, 0x975d6e0c00000000, + 0xe6c2fa7e00000000, 0x898e5fe500000000, 0x795cc19200000000, + 0x1610640900000000, 0x99f9fc7d00000000, 0xf6b559e600000000, + 0x0667c79100000000, 0x692b620a00000000, 0xe459ee7400000000, + 0x8b154bef00000000, 0x7bc7d59800000000, 0x148b700300000000, + 0x9b62e87700000000, 0xf42e4dec00000000, 0x04fcd39b00000000, + 0x6bb0760000000000, 0x1a2fe27200000000, 0x756347e900000000, + 0x85b1d99e00000000, 0xeafd7c0500000000, 0x6514e47100000000, + 0x0a5841ea00000000, 0xfa8adf9d00000000, 0x95c67a0600000000, + 0x10d8a45000000000, 0x7f9401cb00000000, 0x8f469fbc00000000, + 0xe00a3a2700000000, 0x6fe3a25300000000, 0x00af07c800000000, + 0xf07d99bf00000000, 0x9f313c2400000000, 0xeeaea85600000000, + 0x81e20dcd00000000, 0x713093ba00000000, 0x1e7c362100000000, + 0x9195ae5500000000, 0xfed90bce00000000, 0x0e0b95b900000000, + 0x6147302200000000, 0xec35bc5c00000000, 0x837919c700000000, + 0x73ab87b000000000, 0x1ce7222b00000000, 0x930eba5f00000000, + 0xfc421fc400000000, 0x0c9081b300000000, 0x63dc242800000000, + 0x1243b05a00000000, 0x7d0f15c100000000, 0x8ddd8bb600000000, + 0xe2912e2d00000000, 0x6d78b65900000000, 0x023413c200000000, + 0xf2e68db500000000, 0x9daa282e00000000, 0xe803954800000000, + 0x874f30d300000000, 0x779daea400000000, 0x18d10b3f00000000, + 0x9738934b00000000, 0xf87436d000000000, 0x08a6a8a700000000, + 0x67ea0d3c00000000, 0x1675994e00000000, 0x79393cd500000000, + 0x89eba2a200000000, 0xe6a7073900000000, 0x694e9f4d00000000, + 0x06023ad600000000, 0xf6d0a4a100000000, 0x999c013a00000000, + 0x14ee8d4400000000, 0x7ba228df00000000, 0x8b70b6a800000000, + 0xe43c133300000000, 0x6bd58b4700000000, 0x04992edc00000000, + 0xf44bb0ab00000000, 0x9b07153000000000, 0xea98814200000000, + 0x85d424d900000000, 0x7506baae00000000, 0x1a4a1f3500000000, + 0x95a3874100000000, 0xfaef22da00000000, 0x0a3dbcad00000000, + 0x6571193600000000}, + {0x0000000000000000, 0x85d996dd00000000, 0x4bb55c6000000000, + 0xce6ccabd00000000, 0x966ab9c000000000, 0x13b32f1d00000000, + 0xdddfe5a000000000, 0x5806737d00000000, 0x6dd3035a00000000, + 0xe80a958700000000, 0x26665f3a00000000, 0xa3bfc9e700000000, + 0xfbb9ba9a00000000, 0x7e602c4700000000, 0xb00ce6fa00000000, + 0x35d5702700000000, 0xdaa607b400000000, 0x5f7f916900000000, + 0x91135bd400000000, 0x14cacd0900000000, 0x4cccbe7400000000, + 0xc91528a900000000, 0x0779e21400000000, 0x82a074c900000000, + 0xb77504ee00000000, 0x32ac923300000000, 0xfcc0588e00000000, + 0x7919ce5300000000, 0x211fbd2e00000000, 0xa4c62bf300000000, + 0x6aaae14e00000000, 0xef73779300000000, 0xf54b7eb300000000, + 0x7092e86e00000000, 0xbefe22d300000000, 0x3b27b40e00000000, + 0x6321c77300000000, 0xe6f851ae00000000, 0x28949b1300000000, + 0xad4d0dce00000000, 0x98987de900000000, 0x1d41eb3400000000, + 0xd32d218900000000, 0x56f4b75400000000, 0x0ef2c42900000000, + 0x8b2b52f400000000, 0x4547984900000000, 0xc09e0e9400000000, + 0x2fed790700000000, 0xaa34efda00000000, 0x6458256700000000, + 0xe181b3ba00000000, 0xb987c0c700000000, 0x3c5e561a00000000, + 0xf2329ca700000000, 0x77eb0a7a00000000, 0x423e7a5d00000000, + 0xc7e7ec8000000000, 0x098b263d00000000, 0x8c52b0e000000000, + 0xd454c39d00000000, 0x518d554000000000, 0x9fe19ffd00000000, + 0x1a38092000000000, 0xab918dbd00000000, 0x2e481b6000000000, + 0xe024d1dd00000000, 0x65fd470000000000, 0x3dfb347d00000000, + 0xb822a2a000000000, 0x764e681d00000000, 0xf397fec000000000, + 0xc6428ee700000000, 0x439b183a00000000, 0x8df7d28700000000, + 0x082e445a00000000, 0x5028372700000000, 0xd5f1a1fa00000000, + 0x1b9d6b4700000000, 0x9e44fd9a00000000, 0x71378a0900000000, + 0xf4ee1cd400000000, 0x3a82d66900000000, 0xbf5b40b400000000, + 0xe75d33c900000000, 0x6284a51400000000, 0xace86fa900000000, + 0x2931f97400000000, 0x1ce4895300000000, 0x993d1f8e00000000, + 0x5751d53300000000, 0xd28843ee00000000, 0x8a8e309300000000, + 0x0f57a64e00000000, 0xc13b6cf300000000, 0x44e2fa2e00000000, + 0x5edaf30e00000000, 0xdb0365d300000000, 0x156faf6e00000000, + 0x90b639b300000000, 0xc8b04ace00000000, 0x4d69dc1300000000, + 0x830516ae00000000, 0x06dc807300000000, 0x3309f05400000000, + 0xb6d0668900000000, 0x78bcac3400000000, 0xfd653ae900000000, + 0xa563499400000000, 0x20badf4900000000, 0xeed615f400000000, + 0x6b0f832900000000, 0x847cf4ba00000000, 0x01a5626700000000, + 0xcfc9a8da00000000, 0x4a103e0700000000, 0x12164d7a00000000, + 0x97cfdba700000000, 0x59a3111a00000000, 0xdc7a87c700000000, + 0xe9aff7e000000000, 0x6c76613d00000000, 0xa21aab8000000000, + 0x27c33d5d00000000, 0x7fc54e2000000000, 0xfa1cd8fd00000000, + 0x3470124000000000, 0xb1a9849d00000000, 0x17256aa000000000, + 0x92fcfc7d00000000, 0x5c9036c000000000, 0xd949a01d00000000, + 0x814fd36000000000, 0x049645bd00000000, 0xcafa8f0000000000, + 0x4f2319dd00000000, 0x7af669fa00000000, 0xff2fff2700000000, + 0x3143359a00000000, 0xb49aa34700000000, 0xec9cd03a00000000, + 0x694546e700000000, 0xa7298c5a00000000, 0x22f01a8700000000, + 0xcd836d1400000000, 0x485afbc900000000, 0x8636317400000000, + 0x03efa7a900000000, 0x5be9d4d400000000, 0xde30420900000000, + 0x105c88b400000000, 0x95851e6900000000, 0xa0506e4e00000000, + 0x2589f89300000000, 0xebe5322e00000000, 0x6e3ca4f300000000, + 0x363ad78e00000000, 0xb3e3415300000000, 0x7d8f8bee00000000, + 0xf8561d3300000000, 0xe26e141300000000, 0x67b782ce00000000, + 0xa9db487300000000, 0x2c02deae00000000, 0x7404add300000000, + 0xf1dd3b0e00000000, 0x3fb1f1b300000000, 0xba68676e00000000, + 0x8fbd174900000000, 0x0a64819400000000, 0xc4084b2900000000, + 0x41d1ddf400000000, 0x19d7ae8900000000, 0x9c0e385400000000, + 0x5262f2e900000000, 0xd7bb643400000000, 0x38c813a700000000, + 0xbd11857a00000000, 0x737d4fc700000000, 0xf6a4d91a00000000, + 0xaea2aa6700000000, 0x2b7b3cba00000000, 0xe517f60700000000, + 0x60ce60da00000000, 0x551b10fd00000000, 0xd0c2862000000000, + 0x1eae4c9d00000000, 0x9b77da4000000000, 0xc371a93d00000000, + 0x46a83fe000000000, 0x88c4f55d00000000, 0x0d1d638000000000, + 0xbcb4e71d00000000, 0x396d71c000000000, 0xf701bb7d00000000, + 0x72d82da000000000, 0x2ade5edd00000000, 0xaf07c80000000000, + 0x616b02bd00000000, 0xe4b2946000000000, 0xd167e44700000000, + 0x54be729a00000000, 0x9ad2b82700000000, 0x1f0b2efa00000000, + 0x470d5d8700000000, 0xc2d4cb5a00000000, 0x0cb801e700000000, + 0x8961973a00000000, 0x6612e0a900000000, 0xe3cb767400000000, + 0x2da7bcc900000000, 0xa87e2a1400000000, 0xf078596900000000, + 0x75a1cfb400000000, 0xbbcd050900000000, 0x3e1493d400000000, + 0x0bc1e3f300000000, 0x8e18752e00000000, 0x4074bf9300000000, + 0xc5ad294e00000000, 0x9dab5a3300000000, 0x1872ccee00000000, + 0xd61e065300000000, 0x53c7908e00000000, 0x49ff99ae00000000, + 0xcc260f7300000000, 0x024ac5ce00000000, 0x8793531300000000, + 0xdf95206e00000000, 0x5a4cb6b300000000, 0x94207c0e00000000, + 0x11f9ead300000000, 0x242c9af400000000, 0xa1f50c2900000000, + 0x6f99c69400000000, 0xea40504900000000, 0xb246233400000000, + 0x379fb5e900000000, 0xf9f37f5400000000, 0x7c2ae98900000000, + 0x93599e1a00000000, 0x168008c700000000, 0xd8ecc27a00000000, + 0x5d3554a700000000, 0x053327da00000000, 0x80eab10700000000, + 0x4e867bba00000000, 0xcb5fed6700000000, 0xfe8a9d4000000000, + 0x7b530b9d00000000, 0xb53fc12000000000, 0x30e657fd00000000, + 0x68e0248000000000, 0xed39b25d00000000, 0x235578e000000000, + 0xa68cee3d00000000}, + {0x0000000000000000, 0x76e10f9d00000000, 0xadc46ee100000000, + 0xdb25617c00000000, 0x1b8fac1900000000, 0x6d6ea38400000000, + 0xb64bc2f800000000, 0xc0aacd6500000000, 0x361e593300000000, + 0x40ff56ae00000000, 0x9bda37d200000000, 0xed3b384f00000000, + 0x2d91f52a00000000, 0x5b70fab700000000, 0x80559bcb00000000, + 0xf6b4945600000000, 0x6c3cb26600000000, 0x1addbdfb00000000, + 0xc1f8dc8700000000, 0xb719d31a00000000, 0x77b31e7f00000000, + 0x015211e200000000, 0xda77709e00000000, 0xac967f0300000000, + 0x5a22eb5500000000, 0x2cc3e4c800000000, 0xf7e685b400000000, + 0x81078a2900000000, 0x41ad474c00000000, 0x374c48d100000000, + 0xec6929ad00000000, 0x9a88263000000000, 0xd87864cd00000000, + 0xae996b5000000000, 0x75bc0a2c00000000, 0x035d05b100000000, + 0xc3f7c8d400000000, 0xb516c74900000000, 0x6e33a63500000000, + 0x18d2a9a800000000, 0xee663dfe00000000, 0x9887326300000000, + 0x43a2531f00000000, 0x35435c8200000000, 0xf5e991e700000000, + 0x83089e7a00000000, 0x582dff0600000000, 0x2eccf09b00000000, + 0xb444d6ab00000000, 0xc2a5d93600000000, 0x1980b84a00000000, + 0x6f61b7d700000000, 0xafcb7ab200000000, 0xd92a752f00000000, + 0x020f145300000000, 0x74ee1bce00000000, 0x825a8f9800000000, + 0xf4bb800500000000, 0x2f9ee17900000000, 0x597feee400000000, + 0x99d5238100000000, 0xef342c1c00000000, 0x34114d6000000000, + 0x42f042fd00000000, 0xf1f7b94100000000, 0x8716b6dc00000000, + 0x5c33d7a000000000, 0x2ad2d83d00000000, 0xea78155800000000, + 0x9c991ac500000000, 0x47bc7bb900000000, 0x315d742400000000, + 0xc7e9e07200000000, 0xb108efef00000000, 0x6a2d8e9300000000, + 0x1ccc810e00000000, 0xdc664c6b00000000, 0xaa8743f600000000, + 0x71a2228a00000000, 0x07432d1700000000, 0x9dcb0b2700000000, + 0xeb2a04ba00000000, 0x300f65c600000000, 0x46ee6a5b00000000, + 0x8644a73e00000000, 0xf0a5a8a300000000, 0x2b80c9df00000000, + 0x5d61c64200000000, 0xabd5521400000000, 0xdd345d8900000000, + 0x06113cf500000000, 0x70f0336800000000, 0xb05afe0d00000000, + 0xc6bbf19000000000, 0x1d9e90ec00000000, 0x6b7f9f7100000000, + 0x298fdd8c00000000, 0x5f6ed21100000000, 0x844bb36d00000000, + 0xf2aabcf000000000, 0x3200719500000000, 0x44e17e0800000000, + 0x9fc41f7400000000, 0xe92510e900000000, 0x1f9184bf00000000, + 0x69708b2200000000, 0xb255ea5e00000000, 0xc4b4e5c300000000, + 0x041e28a600000000, 0x72ff273b00000000, 0xa9da464700000000, + 0xdf3b49da00000000, 0x45b36fea00000000, 0x3352607700000000, + 0xe877010b00000000, 0x9e960e9600000000, 0x5e3cc3f300000000, + 0x28ddcc6e00000000, 0xf3f8ad1200000000, 0x8519a28f00000000, + 0x73ad36d900000000, 0x054c394400000000, 0xde69583800000000, + 0xa88857a500000000, 0x68229ac000000000, 0x1ec3955d00000000, + 0xc5e6f42100000000, 0xb307fbbc00000000, 0xe2ef738300000000, + 0x940e7c1e00000000, 0x4f2b1d6200000000, 0x39ca12ff00000000, + 0xf960df9a00000000, 0x8f81d00700000000, 0x54a4b17b00000000, + 0x2245bee600000000, 0xd4f12ab000000000, 0xa210252d00000000, + 0x7935445100000000, 0x0fd44bcc00000000, 0xcf7e86a900000000, + 0xb99f893400000000, 0x62bae84800000000, 0x145be7d500000000, + 0x8ed3c1e500000000, 0xf832ce7800000000, 0x2317af0400000000, + 0x55f6a09900000000, 0x955c6dfc00000000, 0xe3bd626100000000, + 0x3898031d00000000, 0x4e790c8000000000, 0xb8cd98d600000000, + 0xce2c974b00000000, 0x1509f63700000000, 0x63e8f9aa00000000, + 0xa34234cf00000000, 0xd5a33b5200000000, 0x0e865a2e00000000, + 0x786755b300000000, 0x3a97174e00000000, 0x4c7618d300000000, + 0x975379af00000000, 0xe1b2763200000000, 0x2118bb5700000000, + 0x57f9b4ca00000000, 0x8cdcd5b600000000, 0xfa3dda2b00000000, + 0x0c894e7d00000000, 0x7a6841e000000000, 0xa14d209c00000000, + 0xd7ac2f0100000000, 0x1706e26400000000, 0x61e7edf900000000, + 0xbac28c8500000000, 0xcc23831800000000, 0x56aba52800000000, + 0x204aaab500000000, 0xfb6fcbc900000000, 0x8d8ec45400000000, + 0x4d24093100000000, 0x3bc506ac00000000, 0xe0e067d000000000, + 0x9601684d00000000, 0x60b5fc1b00000000, 0x1654f38600000000, + 0xcd7192fa00000000, 0xbb909d6700000000, 0x7b3a500200000000, + 0x0ddb5f9f00000000, 0xd6fe3ee300000000, 0xa01f317e00000000, + 0x1318cac200000000, 0x65f9c55f00000000, 0xbedca42300000000, + 0xc83dabbe00000000, 0x089766db00000000, 0x7e76694600000000, + 0xa553083a00000000, 0xd3b207a700000000, 0x250693f100000000, + 0x53e79c6c00000000, 0x88c2fd1000000000, 0xfe23f28d00000000, + 0x3e893fe800000000, 0x4868307500000000, 0x934d510900000000, + 0xe5ac5e9400000000, 0x7f2478a400000000, 0x09c5773900000000, + 0xd2e0164500000000, 0xa40119d800000000, 0x64abd4bd00000000, + 0x124adb2000000000, 0xc96fba5c00000000, 0xbf8eb5c100000000, + 0x493a219700000000, 0x3fdb2e0a00000000, 0xe4fe4f7600000000, + 0x921f40eb00000000, 0x52b58d8e00000000, 0x2454821300000000, + 0xff71e36f00000000, 0x8990ecf200000000, 0xcb60ae0f00000000, + 0xbd81a19200000000, 0x66a4c0ee00000000, 0x1045cf7300000000, + 0xd0ef021600000000, 0xa60e0d8b00000000, 0x7d2b6cf700000000, + 0x0bca636a00000000, 0xfd7ef73c00000000, 0x8b9ff8a100000000, + 0x50ba99dd00000000, 0x265b964000000000, 0xe6f15b2500000000, + 0x901054b800000000, 0x4b3535c400000000, 0x3dd43a5900000000, + 0xa75c1c6900000000, 0xd1bd13f400000000, 0x0a98728800000000, + 0x7c797d1500000000, 0xbcd3b07000000000, 0xca32bfed00000000, + 0x1117de9100000000, 0x67f6d10c00000000, 0x9142455a00000000, + 0xe7a34ac700000000, 0x3c862bbb00000000, 0x4a67242600000000, + 0x8acde94300000000, 0xfc2ce6de00000000, 0x270987a200000000, + 0x51e8883f00000000}, + {0x0000000000000000, 0xe8dbfbb900000000, 0x91b186a800000000, + 0x796a7d1100000000, 0x63657c8a00000000, 0x8bbe873300000000, + 0xf2d4fa2200000000, 0x1a0f019b00000000, 0x87cc89cf00000000, + 0x6f17727600000000, 0x167d0f6700000000, 0xfea6f4de00000000, + 0xe4a9f54500000000, 0x0c720efc00000000, 0x751873ed00000000, + 0x9dc3885400000000, 0x4f9f624400000000, 0xa74499fd00000000, + 0xde2ee4ec00000000, 0x36f51f5500000000, 0x2cfa1ece00000000, + 0xc421e57700000000, 0xbd4b986600000000, 0x559063df00000000, + 0xc853eb8b00000000, 0x2088103200000000, 0x59e26d2300000000, + 0xb139969a00000000, 0xab36970100000000, 0x43ed6cb800000000, + 0x3a8711a900000000, 0xd25cea1000000000, 0x9e3ec58800000000, + 0x76e53e3100000000, 0x0f8f432000000000, 0xe754b89900000000, + 0xfd5bb90200000000, 0x158042bb00000000, 0x6cea3faa00000000, + 0x8431c41300000000, 0x19f24c4700000000, 0xf129b7fe00000000, + 0x8843caef00000000, 0x6098315600000000, 0x7a9730cd00000000, + 0x924ccb7400000000, 0xeb26b66500000000, 0x03fd4ddc00000000, + 0xd1a1a7cc00000000, 0x397a5c7500000000, 0x4010216400000000, + 0xa8cbdadd00000000, 0xb2c4db4600000000, 0x5a1f20ff00000000, + 0x23755dee00000000, 0xcbaea65700000000, 0x566d2e0300000000, + 0xbeb6d5ba00000000, 0xc7dca8ab00000000, 0x2f07531200000000, + 0x3508528900000000, 0xddd3a93000000000, 0xa4b9d42100000000, + 0x4c622f9800000000, 0x7d7bfbca00000000, 0x95a0007300000000, + 0xecca7d6200000000, 0x041186db00000000, 0x1e1e874000000000, + 0xf6c57cf900000000, 0x8faf01e800000000, 0x6774fa5100000000, + 0xfab7720500000000, 0x126c89bc00000000, 0x6b06f4ad00000000, + 0x83dd0f1400000000, 0x99d20e8f00000000, 0x7109f53600000000, + 0x0863882700000000, 0xe0b8739e00000000, 0x32e4998e00000000, + 0xda3f623700000000, 0xa3551f2600000000, 0x4b8ee49f00000000, + 0x5181e50400000000, 0xb95a1ebd00000000, 0xc03063ac00000000, + 0x28eb981500000000, 0xb528104100000000, 0x5df3ebf800000000, + 0x249996e900000000, 0xcc426d5000000000, 0xd64d6ccb00000000, + 0x3e96977200000000, 0x47fcea6300000000, 0xaf2711da00000000, + 0xe3453e4200000000, 0x0b9ec5fb00000000, 0x72f4b8ea00000000, + 0x9a2f435300000000, 0x802042c800000000, 0x68fbb97100000000, + 0x1191c46000000000, 0xf94a3fd900000000, 0x6489b78d00000000, + 0x8c524c3400000000, 0xf538312500000000, 0x1de3ca9c00000000, + 0x07eccb0700000000, 0xef3730be00000000, 0x965d4daf00000000, + 0x7e86b61600000000, 0xacda5c0600000000, 0x4401a7bf00000000, + 0x3d6bdaae00000000, 0xd5b0211700000000, 0xcfbf208c00000000, + 0x2764db3500000000, 0x5e0ea62400000000, 0xb6d55d9d00000000, + 0x2b16d5c900000000, 0xc3cd2e7000000000, 0xbaa7536100000000, + 0x527ca8d800000000, 0x4873a94300000000, 0xa0a852fa00000000, + 0xd9c22feb00000000, 0x3119d45200000000, 0xbbf0874e00000000, + 0x532b7cf700000000, 0x2a4101e600000000, 0xc29afa5f00000000, + 0xd895fbc400000000, 0x304e007d00000000, 0x49247d6c00000000, + 0xa1ff86d500000000, 0x3c3c0e8100000000, 0xd4e7f53800000000, + 0xad8d882900000000, 0x4556739000000000, 0x5f59720b00000000, + 0xb78289b200000000, 0xcee8f4a300000000, 0x26330f1a00000000, + 0xf46fe50a00000000, 0x1cb41eb300000000, 0x65de63a200000000, + 0x8d05981b00000000, 0x970a998000000000, 0x7fd1623900000000, + 0x06bb1f2800000000, 0xee60e49100000000, 0x73a36cc500000000, + 0x9b78977c00000000, 0xe212ea6d00000000, 0x0ac911d400000000, + 0x10c6104f00000000, 0xf81debf600000000, 0x817796e700000000, + 0x69ac6d5e00000000, 0x25ce42c600000000, 0xcd15b97f00000000, + 0xb47fc46e00000000, 0x5ca43fd700000000, 0x46ab3e4c00000000, + 0xae70c5f500000000, 0xd71ab8e400000000, 0x3fc1435d00000000, + 0xa202cb0900000000, 0x4ad930b000000000, 0x33b34da100000000, + 0xdb68b61800000000, 0xc167b78300000000, 0x29bc4c3a00000000, + 0x50d6312b00000000, 0xb80dca9200000000, 0x6a51208200000000, + 0x828adb3b00000000, 0xfbe0a62a00000000, 0x133b5d9300000000, + 0x09345c0800000000, 0xe1efa7b100000000, 0x9885daa000000000, + 0x705e211900000000, 0xed9da94d00000000, 0x054652f400000000, + 0x7c2c2fe500000000, 0x94f7d45c00000000, 0x8ef8d5c700000000, + 0x66232e7e00000000, 0x1f49536f00000000, 0xf792a8d600000000, + 0xc68b7c8400000000, 0x2e50873d00000000, 0x573afa2c00000000, + 0xbfe1019500000000, 0xa5ee000e00000000, 0x4d35fbb700000000, + 0x345f86a600000000, 0xdc847d1f00000000, 0x4147f54b00000000, + 0xa99c0ef200000000, 0xd0f673e300000000, 0x382d885a00000000, + 0x222289c100000000, 0xcaf9727800000000, 0xb3930f6900000000, + 0x5b48f4d000000000, 0x89141ec000000000, 0x61cfe57900000000, + 0x18a5986800000000, 0xf07e63d100000000, 0xea71624a00000000, + 0x02aa99f300000000, 0x7bc0e4e200000000, 0x931b1f5b00000000, + 0x0ed8970f00000000, 0xe6036cb600000000, 0x9f6911a700000000, + 0x77b2ea1e00000000, 0x6dbdeb8500000000, 0x8566103c00000000, + 0xfc0c6d2d00000000, 0x14d7969400000000, 0x58b5b90c00000000, + 0xb06e42b500000000, 0xc9043fa400000000, 0x21dfc41d00000000, + 0x3bd0c58600000000, 0xd30b3e3f00000000, 0xaa61432e00000000, + 0x42bab89700000000, 0xdf7930c300000000, 0x37a2cb7a00000000, + 0x4ec8b66b00000000, 0xa6134dd200000000, 0xbc1c4c4900000000, + 0x54c7b7f000000000, 0x2dadcae100000000, 0xc576315800000000, + 0x172adb4800000000, 0xfff120f100000000, 0x869b5de000000000, + 0x6e40a65900000000, 0x744fa7c200000000, 0x9c945c7b00000000, + 0xe5fe216a00000000, 0x0d25dad300000000, 0x90e6528700000000, + 0x783da93e00000000, 0x0157d42f00000000, 0xe98c2f9600000000, + 0xf3832e0d00000000, 0x1b58d5b400000000, 0x6232a8a500000000, + 0x8ae9531c00000000}, + {0x0000000000000000, 0x919168ae00000000, 0x6325a08700000000, + 0xf2b4c82900000000, 0x874c31d400000000, 0x16dd597a00000000, + 0xe469915300000000, 0x75f8f9fd00000000, 0x4f9f137300000000, + 0xde0e7bdd00000000, 0x2cbab3f400000000, 0xbd2bdb5a00000000, + 0xc8d322a700000000, 0x59424a0900000000, 0xabf6822000000000, + 0x3a67ea8e00000000, 0x9e3e27e600000000, 0x0faf4f4800000000, + 0xfd1b876100000000, 0x6c8aefcf00000000, 0x1972163200000000, + 0x88e37e9c00000000, 0x7a57b6b500000000, 0xebc6de1b00000000, + 0xd1a1349500000000, 0x40305c3b00000000, 0xb284941200000000, + 0x2315fcbc00000000, 0x56ed054100000000, 0xc77c6def00000000, + 0x35c8a5c600000000, 0xa459cd6800000000, 0x7d7b3f1700000000, + 0xecea57b900000000, 0x1e5e9f9000000000, 0x8fcff73e00000000, + 0xfa370ec300000000, 0x6ba6666d00000000, 0x9912ae4400000000, + 0x0883c6ea00000000, 0x32e42c6400000000, 0xa37544ca00000000, + 0x51c18ce300000000, 0xc050e44d00000000, 0xb5a81db000000000, + 0x2439751e00000000, 0xd68dbd3700000000, 0x471cd59900000000, + 0xe34518f100000000, 0x72d4705f00000000, 0x8060b87600000000, + 0x11f1d0d800000000, 0x6409292500000000, 0xf598418b00000000, + 0x072c89a200000000, 0x96bde10c00000000, 0xacda0b8200000000, + 0x3d4b632c00000000, 0xcfffab0500000000, 0x5e6ec3ab00000000, + 0x2b963a5600000000, 0xba0752f800000000, 0x48b39ad100000000, + 0xd922f27f00000000, 0xfaf67e2e00000000, 0x6b67168000000000, + 0x99d3dea900000000, 0x0842b60700000000, 0x7dba4ffa00000000, + 0xec2b275400000000, 0x1e9fef7d00000000, 0x8f0e87d300000000, + 0xb5696d5d00000000, 0x24f805f300000000, 0xd64ccdda00000000, + 0x47dda57400000000, 0x32255c8900000000, 0xa3b4342700000000, + 0x5100fc0e00000000, 0xc09194a000000000, 0x64c859c800000000, + 0xf559316600000000, 0x07edf94f00000000, 0x967c91e100000000, + 0xe384681c00000000, 0x721500b200000000, 0x80a1c89b00000000, + 0x1130a03500000000, 0x2b574abb00000000, 0xbac6221500000000, + 0x4872ea3c00000000, 0xd9e3829200000000, 0xac1b7b6f00000000, + 0x3d8a13c100000000, 0xcf3edbe800000000, 0x5eafb34600000000, + 0x878d413900000000, 0x161c299700000000, 0xe4a8e1be00000000, + 0x7539891000000000, 0x00c170ed00000000, 0x9150184300000000, + 0x63e4d06a00000000, 0xf275b8c400000000, 0xc812524a00000000, + 0x59833ae400000000, 0xab37f2cd00000000, 0x3aa69a6300000000, + 0x4f5e639e00000000, 0xdecf0b3000000000, 0x2c7bc31900000000, + 0xbdeaabb700000000, 0x19b366df00000000, 0x88220e7100000000, + 0x7a96c65800000000, 0xeb07aef600000000, 0x9eff570b00000000, + 0x0f6e3fa500000000, 0xfddaf78c00000000, 0x6c4b9f2200000000, + 0x562c75ac00000000, 0xc7bd1d0200000000, 0x3509d52b00000000, + 0xa498bd8500000000, 0xd160447800000000, 0x40f12cd600000000, + 0xb245e4ff00000000, 0x23d48c5100000000, 0xf4edfd5c00000000, + 0x657c95f200000000, 0x97c85ddb00000000, 0x0659357500000000, + 0x73a1cc8800000000, 0xe230a42600000000, 0x10846c0f00000000, + 0x811504a100000000, 0xbb72ee2f00000000, 0x2ae3868100000000, + 0xd8574ea800000000, 0x49c6260600000000, 0x3c3edffb00000000, + 0xadafb75500000000, 0x5f1b7f7c00000000, 0xce8a17d200000000, + 0x6ad3daba00000000, 0xfb42b21400000000, 0x09f67a3d00000000, + 0x9867129300000000, 0xed9feb6e00000000, 0x7c0e83c000000000, + 0x8eba4be900000000, 0x1f2b234700000000, 0x254cc9c900000000, + 0xb4dda16700000000, 0x4669694e00000000, 0xd7f801e000000000, + 0xa200f81d00000000, 0x339190b300000000, 0xc125589a00000000, + 0x50b4303400000000, 0x8996c24b00000000, 0x1807aae500000000, + 0xeab362cc00000000, 0x7b220a6200000000, 0x0edaf39f00000000, + 0x9f4b9b3100000000, 0x6dff531800000000, 0xfc6e3bb600000000, + 0xc609d13800000000, 0x5798b99600000000, 0xa52c71bf00000000, + 0x34bd191100000000, 0x4145e0ec00000000, 0xd0d4884200000000, + 0x2260406b00000000, 0xb3f128c500000000, 0x17a8e5ad00000000, + 0x86398d0300000000, 0x748d452a00000000, 0xe51c2d8400000000, + 0x90e4d47900000000, 0x0175bcd700000000, 0xf3c174fe00000000, + 0x62501c5000000000, 0x5837f6de00000000, 0xc9a69e7000000000, + 0x3b12565900000000, 0xaa833ef700000000, 0xdf7bc70a00000000, + 0x4eeaafa400000000, 0xbc5e678d00000000, 0x2dcf0f2300000000, + 0x0e1b837200000000, 0x9f8aebdc00000000, 0x6d3e23f500000000, + 0xfcaf4b5b00000000, 0x8957b2a600000000, 0x18c6da0800000000, + 0xea72122100000000, 0x7be37a8f00000000, 0x4184900100000000, + 0xd015f8af00000000, 0x22a1308600000000, 0xb330582800000000, + 0xc6c8a1d500000000, 0x5759c97b00000000, 0xa5ed015200000000, + 0x347c69fc00000000, 0x9025a49400000000, 0x01b4cc3a00000000, + 0xf300041300000000, 0x62916cbd00000000, 0x1769954000000000, + 0x86f8fdee00000000, 0x744c35c700000000, 0xe5dd5d6900000000, + 0xdfbab7e700000000, 0x4e2bdf4900000000, 0xbc9f176000000000, + 0x2d0e7fce00000000, 0x58f6863300000000, 0xc967ee9d00000000, + 0x3bd326b400000000, 0xaa424e1a00000000, 0x7360bc6500000000, + 0xe2f1d4cb00000000, 0x10451ce200000000, 0x81d4744c00000000, + 0xf42c8db100000000, 0x65bde51f00000000, 0x97092d3600000000, + 0x0698459800000000, 0x3cffaf1600000000, 0xad6ec7b800000000, + 0x5fda0f9100000000, 0xce4b673f00000000, 0xbbb39ec200000000, + 0x2a22f66c00000000, 0xd8963e4500000000, 0x490756eb00000000, + 0xed5e9b8300000000, 0x7ccff32d00000000, 0x8e7b3b0400000000, + 0x1fea53aa00000000, 0x6a12aa5700000000, 0xfb83c2f900000000, + 0x09370ad000000000, 0x98a6627e00000000, 0xa2c188f000000000, + 0x3350e05e00000000, 0xc1e4287700000000, 0x507540d900000000, + 0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000, + 0xd739710d00000000}}; + +#else /* W == 4 */ + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5, + 0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d, + 0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf, + 0xd1975082, 0x8297e060, 0x32be805d, 0xe2c4201a, 0x52ed4027, + 0x42316095, 0xf21800a8, 0x2262a0ef, 0x924bc0d2, 0x43dc9050, + 0xf3f5f06d, 0x238f502a, 0x93a63017, 0x837a10a5, 0x33537098, + 0xe329d0df, 0x5300b0e2, 0x042fc1c1, 0xb406a1fc, 0x647c01bb, + 0xd4556186, 0xc4894134, 0x74a02109, 0xa4da814e, 0x14f3e173, + 0xc564b1f1, 0x754dd1cc, 0xa537718b, 0x151e11b6, 0x05c23104, + 0xb5eb5139, 0x6591f17e, 0xd5b89143, 0x86b821a1, 0x3691419c, + 0xe6ebe1db, 0x56c281e6, 0x461ea154, 0xf637c169, 0x264d612e, + 0x96640113, 0x47f35191, 0xf7da31ac, 0x27a091eb, 0x9789f1d6, + 0x8755d164, 0x377cb159, 0xe706111e, 0x572f7123, 0x4958f358, + 0xf9719365, 0x290b3322, 0x9922531f, 0x89fe73ad, 0x39d71390, + 0xe9adb3d7, 0x5984d3ea, 0x88138368, 0x383ae355, 0xe8404312, + 0x5869232f, 0x48b5039d, 0xf89c63a0, 0x28e6c3e7, 0x98cfa3da, + 0xcbcf1338, 0x7be67305, 0xab9cd342, 0x1bb5b37f, 0x0b6993cd, + 0xbb40f3f0, 0x6b3a53b7, 0xdb13338a, 0x0a846308, 0xbaad0335, + 0x6ad7a372, 0xdafec34f, 0xca22e3fd, 0x7a0b83c0, 0xaa712387, + 0x1a5843ba, 0x4d773299, 0xfd5e52a4, 0x2d24f2e3, 0x9d0d92de, + 0x8dd1b26c, 0x3df8d251, 0xed827216, 0x5dab122b, 0x8c3c42a9, + 0x3c152294, 0xec6f82d3, 0x5c46e2ee, 0x4c9ac25c, 0xfcb3a261, + 0x2cc90226, 0x9ce0621b, 0xcfe0d2f9, 0x7fc9b2c4, 0xafb31283, + 0x1f9a72be, 0x0f46520c, 0xbf6f3231, 0x6f159276, 0xdf3cf24b, + 0x0eaba2c9, 0xbe82c2f4, 0x6ef862b3, 0xded1028e, 0xce0d223c, + 0x7e244201, 0xae5ee246, 0x1e77827b, 0x92b0e6b1, 0x2299868c, + 0xf2e326cb, 0x42ca46f6, 0x52166644, 0xe23f0679, 0x3245a63e, + 0x826cc603, 0x53fb9681, 0xe3d2f6bc, 0x33a856fb, 0x838136c6, + 0x935d1674, 0x23747649, 0xf30ed60e, 0x4327b633, 0x102706d1, + 0xa00e66ec, 0x7074c6ab, 0xc05da696, 0xd0818624, 0x60a8e619, + 0xb0d2465e, 0x00fb2663, 0xd16c76e1, 0x614516dc, 0xb13fb69b, + 0x0116d6a6, 0x11caf614, 0xa1e39629, 0x7199366e, 0xc1b05653, + 0x969f2770, 0x26b6474d, 0xf6cce70a, 0x46e58737, 0x5639a785, + 0xe610c7b8, 0x366a67ff, 0x864307c2, 0x57d45740, 0xe7fd377d, + 0x3787973a, 0x87aef707, 0x9772d7b5, 0x275bb788, 0xf72117cf, + 0x470877f2, 0x1408c710, 0xa421a72d, 0x745b076a, 0xc4726757, + 0xd4ae47e5, 0x648727d8, 0xb4fd879f, 0x04d4e7a2, 0xd543b720, + 0x656ad71d, 0xb510775a, 0x05391767, 0x15e537d5, 0xa5cc57e8, + 0x75b6f7af, 0xc59f9792, 0xdbe815e9, 0x6bc175d4, 0xbbbbd593, + 0x0b92b5ae, 0x1b4e951c, 0xab67f521, 0x7b1d5566, 0xcb34355b, + 0x1aa365d9, 0xaa8a05e4, 0x7af0a5a3, 0xcad9c59e, 0xda05e52c, + 0x6a2c8511, 0xba562556, 0x0a7f456b, 0x597ff589, 0xe95695b4, + 0x392c35f3, 0x890555ce, 0x99d9757c, 0x29f01541, 0xf98ab506, + 0x49a3d53b, 0x983485b9, 0x281de584, 0xf86745c3, 0x484e25fe, + 0x5892054c, 0xe8bb6571, 0x38c1c536, 0x88e8a50b, 0xdfc7d428, + 0x6feeb415, 0xbf941452, 0x0fbd746f, 0x1f6154dd, 0xaf4834e0, + 0x7f3294a7, 0xcf1bf49a, 0x1e8ca418, 0xaea5c425, 0x7edf6462, + 0xcef6045f, 0xde2a24ed, 0x6e0344d0, 0xbe79e497, 0x0e5084aa, + 0x5d503448, 0xed795475, 0x3d03f432, 0x8d2a940f, 0x9df6b4bd, + 0x2ddfd480, 0xfda574c7, 0x4d8c14fa, 0x9c1b4478, 0x2c322445, + 0xfc488402, 0x4c61e43f, 0x5cbdc48d, 0xec94a4b0, 0x3cee04f7, + 0x8cc764ca}, + {0x00000000, 0xa5d35ccb, 0x0ba1c84d, 0xae729486, 0x1642919b, + 0xb391cd50, 0x1de359d6, 0xb830051d, 0x6d8253ec, 0xc8510f27, + 0x66239ba1, 0xc3f0c76a, 0x7bc0c277, 0xde139ebc, 0x70610a3a, + 0xd5b256f1, 0x9b02d603, 0x3ed18ac8, 0x90a31e4e, 0x35704285, + 0x8d404798, 0x28931b53, 0x86e18fd5, 0x2332d31e, 0xf68085ef, + 0x5353d924, 0xfd214da2, 0x58f21169, 0xe0c21474, 0x451148bf, + 0xeb63dc39, 0x4eb080f2, 0x3605ac07, 0x93d6f0cc, 0x3da4644a, + 0x98773881, 0x20473d9c, 0x85946157, 0x2be6f5d1, 0x8e35a91a, + 0x5b87ffeb, 0xfe54a320, 0x502637a6, 0xf5f56b6d, 0x4dc56e70, + 0xe81632bb, 0x4664a63d, 0xe3b7faf6, 0xad077a04, 0x08d426cf, + 0xa6a6b249, 0x0375ee82, 0xbb45eb9f, 0x1e96b754, 0xb0e423d2, + 0x15377f19, 0xc08529e8, 0x65567523, 0xcb24e1a5, 0x6ef7bd6e, + 0xd6c7b873, 0x7314e4b8, 0xdd66703e, 0x78b52cf5, 0x6c0a580f, + 0xc9d904c4, 0x67ab9042, 0xc278cc89, 0x7a48c994, 0xdf9b955f, + 0x71e901d9, 0xd43a5d12, 0x01880be3, 0xa45b5728, 0x0a29c3ae, + 0xaffa9f65, 0x17ca9a78, 0xb219c6b3, 0x1c6b5235, 0xb9b80efe, + 0xf7088e0c, 0x52dbd2c7, 0xfca94641, 0x597a1a8a, 0xe14a1f97, + 0x4499435c, 0xeaebd7da, 0x4f388b11, 0x9a8adde0, 0x3f59812b, + 0x912b15ad, 0x34f84966, 0x8cc84c7b, 0x291b10b0, 0x87698436, + 0x22bad8fd, 0x5a0ff408, 0xffdca8c3, 0x51ae3c45, 0xf47d608e, + 0x4c4d6593, 0xe99e3958, 0x47ecadde, 0xe23ff115, 0x378da7e4, + 0x925efb2f, 0x3c2c6fa9, 0x99ff3362, 0x21cf367f, 0x841c6ab4, + 0x2a6efe32, 0x8fbda2f9, 0xc10d220b, 0x64de7ec0, 0xcaacea46, + 0x6f7fb68d, 0xd74fb390, 0x729cef5b, 0xdcee7bdd, 0x793d2716, + 0xac8f71e7, 0x095c2d2c, 0xa72eb9aa, 0x02fde561, 0xbacde07c, + 0x1f1ebcb7, 0xb16c2831, 0x14bf74fa, 0xd814b01e, 0x7dc7ecd5, + 0xd3b57853, 0x76662498, 0xce562185, 0x6b857d4e, 0xc5f7e9c8, + 0x6024b503, 0xb596e3f2, 0x1045bf39, 0xbe372bbf, 0x1be47774, + 0xa3d47269, 0x06072ea2, 0xa875ba24, 0x0da6e6ef, 0x4316661d, + 0xe6c53ad6, 0x48b7ae50, 0xed64f29b, 0x5554f786, 0xf087ab4d, + 0x5ef53fcb, 0xfb266300, 0x2e9435f1, 0x8b47693a, 0x2535fdbc, + 0x80e6a177, 0x38d6a46a, 0x9d05f8a1, 0x33776c27, 0x96a430ec, + 0xee111c19, 0x4bc240d2, 0xe5b0d454, 0x4063889f, 0xf8538d82, + 0x5d80d149, 0xf3f245cf, 0x56211904, 0x83934ff5, 0x2640133e, + 0x883287b8, 0x2de1db73, 0x95d1de6e, 0x300282a5, 0x9e701623, + 0x3ba34ae8, 0x7513ca1a, 0xd0c096d1, 0x7eb20257, 0xdb615e9c, + 0x63515b81, 0xc682074a, 0x68f093cc, 0xcd23cf07, 0x189199f6, + 0xbd42c53d, 0x133051bb, 0xb6e30d70, 0x0ed3086d, 0xab0054a6, + 0x0572c020, 0xa0a19ceb, 0xb41ee811, 0x11cdb4da, 0xbfbf205c, + 0x1a6c7c97, 0xa25c798a, 0x078f2541, 0xa9fdb1c7, 0x0c2eed0c, + 0xd99cbbfd, 0x7c4fe736, 0xd23d73b0, 0x77ee2f7b, 0xcfde2a66, + 0x6a0d76ad, 0xc47fe22b, 0x61acbee0, 0x2f1c3e12, 0x8acf62d9, + 0x24bdf65f, 0x816eaa94, 0x395eaf89, 0x9c8df342, 0x32ff67c4, + 0x972c3b0f, 0x429e6dfe, 0xe74d3135, 0x493fa5b3, 0xececf978, + 0x54dcfc65, 0xf10fa0ae, 0x5f7d3428, 0xfaae68e3, 0x821b4416, + 0x27c818dd, 0x89ba8c5b, 0x2c69d090, 0x9459d58d, 0x318a8946, + 0x9ff81dc0, 0x3a2b410b, 0xef9917fa, 0x4a4a4b31, 0xe438dfb7, + 0x41eb837c, 0xf9db8661, 0x5c08daaa, 0xf27a4e2c, 0x57a912e7, + 0x19199215, 0xbccacede, 0x12b85a58, 0xb76b0693, 0x0f5b038e, + 0xaa885f45, 0x04facbc3, 0xa1299708, 0x749bc1f9, 0xd1489d32, + 0x7f3a09b4, 0xdae9557f, 0x62d95062, 0xc70a0ca9, 0x6978982f, + 0xccabc4e4}, + {0x00000000, 0xb40b77a6, 0x29119f97, 0x9d1ae831, 0x13244ff4, + 0xa72f3852, 0x3a35d063, 0x8e3ea7c5, 0x674eef33, 0xd3459895, + 0x4e5f70a4, 0xfa540702, 0x746aa0c7, 0xc061d761, 0x5d7b3f50, + 0xe97048f6, 0xce9cde67, 0x7a97a9c1, 0xe78d41f0, 0x53863656, + 0xddb89193, 0x69b3e635, 0xf4a90e04, 0x40a279a2, 0xa9d23154, + 0x1dd946f2, 0x80c3aec3, 0x34c8d965, 0xbaf67ea0, 0x0efd0906, + 0x93e7e137, 0x27ec9691, 0x9c39bdcf, 0x2832ca69, 0xb5282258, + 0x012355fe, 0x8f1df23b, 0x3b16859d, 0xa60c6dac, 0x12071a0a, + 0xfb7752fc, 0x4f7c255a, 0xd266cd6b, 0x666dbacd, 0xe8531d08, + 0x5c586aae, 0xc142829f, 0x7549f539, 0x52a563a8, 0xe6ae140e, + 0x7bb4fc3f, 0xcfbf8b99, 0x41812c5c, 0xf58a5bfa, 0x6890b3cb, + 0xdc9bc46d, 0x35eb8c9b, 0x81e0fb3d, 0x1cfa130c, 0xa8f164aa, + 0x26cfc36f, 0x92c4b4c9, 0x0fde5cf8, 0xbbd52b5e, 0x79750b44, + 0xcd7e7ce2, 0x506494d3, 0xe46fe375, 0x6a5144b0, 0xde5a3316, + 0x4340db27, 0xf74bac81, 0x1e3be477, 0xaa3093d1, 0x372a7be0, + 0x83210c46, 0x0d1fab83, 0xb914dc25, 0x240e3414, 0x900543b2, + 0xb7e9d523, 0x03e2a285, 0x9ef84ab4, 0x2af33d12, 0xa4cd9ad7, + 0x10c6ed71, 0x8ddc0540, 0x39d772e6, 0xd0a73a10, 0x64ac4db6, + 0xf9b6a587, 0x4dbdd221, 0xc38375e4, 0x77880242, 0xea92ea73, + 0x5e999dd5, 0xe54cb68b, 0x5147c12d, 0xcc5d291c, 0x78565eba, + 0xf668f97f, 0x42638ed9, 0xdf7966e8, 0x6b72114e, 0x820259b8, + 0x36092e1e, 0xab13c62f, 0x1f18b189, 0x9126164c, 0x252d61ea, + 0xb83789db, 0x0c3cfe7d, 0x2bd068ec, 0x9fdb1f4a, 0x02c1f77b, + 0xb6ca80dd, 0x38f42718, 0x8cff50be, 0x11e5b88f, 0xa5eecf29, + 0x4c9e87df, 0xf895f079, 0x658f1848, 0xd1846fee, 0x5fbac82b, + 0xebb1bf8d, 0x76ab57bc, 0xc2a0201a, 0xf2ea1688, 0x46e1612e, + 0xdbfb891f, 0x6ff0feb9, 0xe1ce597c, 0x55c52eda, 0xc8dfc6eb, + 0x7cd4b14d, 0x95a4f9bb, 0x21af8e1d, 0xbcb5662c, 0x08be118a, + 0x8680b64f, 0x328bc1e9, 0xaf9129d8, 0x1b9a5e7e, 0x3c76c8ef, + 0x887dbf49, 0x15675778, 0xa16c20de, 0x2f52871b, 0x9b59f0bd, + 0x0643188c, 0xb2486f2a, 0x5b3827dc, 0xef33507a, 0x7229b84b, + 0xc622cfed, 0x481c6828, 0xfc171f8e, 0x610df7bf, 0xd5068019, + 0x6ed3ab47, 0xdad8dce1, 0x47c234d0, 0xf3c94376, 0x7df7e4b3, + 0xc9fc9315, 0x54e67b24, 0xe0ed0c82, 0x099d4474, 0xbd9633d2, + 0x208cdbe3, 0x9487ac45, 0x1ab90b80, 0xaeb27c26, 0x33a89417, + 0x87a3e3b1, 0xa04f7520, 0x14440286, 0x895eeab7, 0x3d559d11, + 0xb36b3ad4, 0x07604d72, 0x9a7aa543, 0x2e71d2e5, 0xc7019a13, + 0x730aedb5, 0xee100584, 0x5a1b7222, 0xd425d5e7, 0x602ea241, + 0xfd344a70, 0x493f3dd6, 0x8b9f1dcc, 0x3f946a6a, 0xa28e825b, + 0x1685f5fd, 0x98bb5238, 0x2cb0259e, 0xb1aacdaf, 0x05a1ba09, + 0xecd1f2ff, 0x58da8559, 0xc5c06d68, 0x71cb1ace, 0xfff5bd0b, + 0x4bfecaad, 0xd6e4229c, 0x62ef553a, 0x4503c3ab, 0xf108b40d, + 0x6c125c3c, 0xd8192b9a, 0x56278c5f, 0xe22cfbf9, 0x7f3613c8, + 0xcb3d646e, 0x224d2c98, 0x96465b3e, 0x0b5cb30f, 0xbf57c4a9, + 0x3169636c, 0x856214ca, 0x1878fcfb, 0xac738b5d, 0x17a6a003, + 0xa3add7a5, 0x3eb73f94, 0x8abc4832, 0x0482eff7, 0xb0899851, + 0x2d937060, 0x999807c6, 0x70e84f30, 0xc4e33896, 0x59f9d0a7, + 0xedf2a701, 0x63cc00c4, 0xd7c77762, 0x4add9f53, 0xfed6e8f5, + 0xd93a7e64, 0x6d3109c2, 0xf02be1f3, 0x44209655, 0xca1e3190, + 0x7e154636, 0xe30fae07, 0x5704d9a1, 0xbe749157, 0x0a7fe6f1, + 0x97650ec0, 0x236e7966, 0xad50dea3, 0x195ba905, 0x84414134, + 0x304a3692}, + {0x00000000, 0x9e00aacc, 0x7d072542, 0xe3078f8e, 0xfa0e4a84, + 0x640ee048, 0x87096fc6, 0x1909c50a, 0xb51be5d3, 0x2b1b4f1f, + 0xc81cc091, 0x561c6a5d, 0x4f15af57, 0xd115059b, 0x32128a15, + 0xac1220d9, 0x2b31bb7c, 0xb53111b0, 0x56369e3e, 0xc83634f2, + 0xd13ff1f8, 0x4f3f5b34, 0xac38d4ba, 0x32387e76, 0x9e2a5eaf, + 0x002af463, 0xe32d7bed, 0x7d2dd121, 0x6424142b, 0xfa24bee7, + 0x19233169, 0x87239ba5, 0x566276f9, 0xc862dc35, 0x2b6553bb, + 0xb565f977, 0xac6c3c7d, 0x326c96b1, 0xd16b193f, 0x4f6bb3f3, + 0xe379932a, 0x7d7939e6, 0x9e7eb668, 0x007e1ca4, 0x1977d9ae, + 0x87777362, 0x6470fcec, 0xfa705620, 0x7d53cd85, 0xe3536749, + 0x0054e8c7, 0x9e54420b, 0x875d8701, 0x195d2dcd, 0xfa5aa243, + 0x645a088f, 0xc8482856, 0x5648829a, 0xb54f0d14, 0x2b4fa7d8, + 0x324662d2, 0xac46c81e, 0x4f414790, 0xd141ed5c, 0xedc29d29, + 0x73c237e5, 0x90c5b86b, 0x0ec512a7, 0x17ccd7ad, 0x89cc7d61, + 0x6acbf2ef, 0xf4cb5823, 0x58d978fa, 0xc6d9d236, 0x25de5db8, + 0xbbdef774, 0xa2d7327e, 0x3cd798b2, 0xdfd0173c, 0x41d0bdf0, + 0xc6f32655, 0x58f38c99, 0xbbf40317, 0x25f4a9db, 0x3cfd6cd1, + 0xa2fdc61d, 0x41fa4993, 0xdffae35f, 0x73e8c386, 0xede8694a, + 0x0eefe6c4, 0x90ef4c08, 0x89e68902, 0x17e623ce, 0xf4e1ac40, + 0x6ae1068c, 0xbba0ebd0, 0x25a0411c, 0xc6a7ce92, 0x58a7645e, + 0x41aea154, 0xdfae0b98, 0x3ca98416, 0xa2a92eda, 0x0ebb0e03, + 0x90bba4cf, 0x73bc2b41, 0xedbc818d, 0xf4b54487, 0x6ab5ee4b, + 0x89b261c5, 0x17b2cb09, 0x909150ac, 0x0e91fa60, 0xed9675ee, + 0x7396df22, 0x6a9f1a28, 0xf49fb0e4, 0x17983f6a, 0x899895a6, + 0x258ab57f, 0xbb8a1fb3, 0x588d903d, 0xc68d3af1, 0xdf84fffb, + 0x41845537, 0xa283dab9, 0x3c837075, 0xda853b53, 0x4485919f, + 0xa7821e11, 0x3982b4dd, 0x208b71d7, 0xbe8bdb1b, 0x5d8c5495, + 0xc38cfe59, 0x6f9ede80, 0xf19e744c, 0x1299fbc2, 0x8c99510e, + 0x95909404, 0x0b903ec8, 0xe897b146, 0x76971b8a, 0xf1b4802f, + 0x6fb42ae3, 0x8cb3a56d, 0x12b30fa1, 0x0bbacaab, 0x95ba6067, + 0x76bdefe9, 0xe8bd4525, 0x44af65fc, 0xdaafcf30, 0x39a840be, + 0xa7a8ea72, 0xbea12f78, 0x20a185b4, 0xc3a60a3a, 0x5da6a0f6, + 0x8ce74daa, 0x12e7e766, 0xf1e068e8, 0x6fe0c224, 0x76e9072e, + 0xe8e9ade2, 0x0bee226c, 0x95ee88a0, 0x39fca879, 0xa7fc02b5, + 0x44fb8d3b, 0xdafb27f7, 0xc3f2e2fd, 0x5df24831, 0xbef5c7bf, + 0x20f56d73, 0xa7d6f6d6, 0x39d65c1a, 0xdad1d394, 0x44d17958, + 0x5dd8bc52, 0xc3d8169e, 0x20df9910, 0xbedf33dc, 0x12cd1305, + 0x8ccdb9c9, 0x6fca3647, 0xf1ca9c8b, 0xe8c35981, 0x76c3f34d, + 0x95c47cc3, 0x0bc4d60f, 0x3747a67a, 0xa9470cb6, 0x4a408338, + 0xd44029f4, 0xcd49ecfe, 0x53494632, 0xb04ec9bc, 0x2e4e6370, + 0x825c43a9, 0x1c5ce965, 0xff5b66eb, 0x615bcc27, 0x7852092d, + 0xe652a3e1, 0x05552c6f, 0x9b5586a3, 0x1c761d06, 0x8276b7ca, + 0x61713844, 0xff719288, 0xe6785782, 0x7878fd4e, 0x9b7f72c0, + 0x057fd80c, 0xa96df8d5, 0x376d5219, 0xd46add97, 0x4a6a775b, + 0x5363b251, 0xcd63189d, 0x2e649713, 0xb0643ddf, 0x6125d083, + 0xff257a4f, 0x1c22f5c1, 0x82225f0d, 0x9b2b9a07, 0x052b30cb, + 0xe62cbf45, 0x782c1589, 0xd43e3550, 0x4a3e9f9c, 0xa9391012, + 0x3739bade, 0x2e307fd4, 0xb030d518, 0x53375a96, 0xcd37f05a, + 0x4a146bff, 0xd414c133, 0x37134ebd, 0xa913e471, 0xb01a217b, + 0x2e1a8bb7, 0xcd1d0439, 0x531daef5, 0xff0f8e2c, 0x610f24e0, + 0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea, + 0xe6064b26}}; + +#endif /* W */ + +#endif /* N == 2 */ +#if N == 3 + +#if W == 8 + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}, + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000, + 0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000, + 0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000, + 0xdd84b66100000000, 0x59df2c3200000000, 0x1a148ab500000000, + 0x5168189500000000, 0x12a3be1200000000, 0x96f8244100000000, + 0xd53382c600000000, 0x7d99511700000000, 0x3e52f79000000000, + 0xba096dc300000000, 0xf9c2cb4400000000, 0xb2be596400000000, + 0xf175ffe300000000, 0x752e65b000000000, 0x36e5c33700000000, + 0xe3d641f100000000, 0xa01de77600000000, 0x24467d2500000000, + 0x678ddba200000000, 0x2cf1498200000000, 0x6f3aef0500000000, + 0xeb61755600000000, 0xa8aad3d100000000, 0xfa32a32e00000000, + 0xb9f905a900000000, 0x3da29ffa00000000, 0x7e69397d00000000, + 0x3515ab5d00000000, 0x76de0dda00000000, 0xf285978900000000, + 0xb14e310e00000000, 0x647db3c800000000, 0x27b6154f00000000, + 0xa3ed8f1c00000000, 0xe026299b00000000, 0xab5abbbb00000000, + 0xe8911d3c00000000, 0x6cca876f00000000, 0x2f0121e800000000, + 0x87abf23900000000, 0xc46054be00000000, 0x403bceed00000000, + 0x03f0686a00000000, 0x488cfa4a00000000, 0x0b475ccd00000000, + 0x8f1cc69e00000000, 0xccd7601900000000, 0x19e4e2df00000000, + 0x5a2f445800000000, 0xde74de0b00000000, 0x9dbf788c00000000, + 0xd6c3eaac00000000, 0x95084c2b00000000, 0x1153d67800000000, + 0x529870ff00000000, 0xf465465d00000000, 0xb7aee0da00000000, + 0x33f57a8900000000, 0x703edc0e00000000, 0x3b424e2e00000000, + 0x7889e8a900000000, 0xfcd272fa00000000, 0xbf19d47d00000000, + 0x6a2a56bb00000000, 0x29e1f03c00000000, 0xadba6a6f00000000, + 0xee71cce800000000, 0xa50d5ec800000000, 0xe6c6f84f00000000, + 0x629d621c00000000, 0x2156c49b00000000, 0x89fc174a00000000, + 0xca37b1cd00000000, 0x4e6c2b9e00000000, 0x0da78d1900000000, + 0x46db1f3900000000, 0x0510b9be00000000, 0x814b23ed00000000, + 0xc280856a00000000, 0x17b307ac00000000, 0x5478a12b00000000, + 0xd0233b7800000000, 0x93e89dff00000000, 0xd8940fdf00000000, + 0x9b5fa95800000000, 0x1f04330b00000000, 0x5ccf958c00000000, + 0x0e57e57300000000, 0x4d9c43f400000000, 0xc9c7d9a700000000, + 0x8a0c7f2000000000, 0xc170ed0000000000, 0x82bb4b8700000000, + 0x06e0d1d400000000, 0x452b775300000000, 0x9018f59500000000, + 0xd3d3531200000000, 0x5788c94100000000, 0x14436fc600000000, + 0x5f3ffde600000000, 0x1cf45b6100000000, 0x98afc13200000000, + 0xdb6467b500000000, 0x73ceb46400000000, 0x300512e300000000, + 0xb45e88b000000000, 0xf7952e3700000000, 0xbce9bc1700000000, + 0xff221a9000000000, 0x7b7980c300000000, 0x38b2264400000000, + 0xed81a48200000000, 0xae4a020500000000, 0x2a11985600000000, + 0x69da3ed100000000, 0x22a6acf100000000, 0x616d0a7600000000, + 0xe536902500000000, 0xa6fd36a200000000, 0xe8cb8cba00000000, + 0xab002a3d00000000, 0x2f5bb06e00000000, 0x6c9016e900000000, + 0x27ec84c900000000, 0x6427224e00000000, 0xe07cb81d00000000, + 0xa3b71e9a00000000, 0x76849c5c00000000, 0x354f3adb00000000, + 0xb114a08800000000, 0xf2df060f00000000, 0xb9a3942f00000000, + 0xfa6832a800000000, 0x7e33a8fb00000000, 0x3df80e7c00000000, + 0x9552ddad00000000, 0xd6997b2a00000000, 0x52c2e17900000000, + 0x110947fe00000000, 0x5a75d5de00000000, 0x19be735900000000, + 0x9de5e90a00000000, 0xde2e4f8d00000000, 0x0b1dcd4b00000000, + 0x48d66bcc00000000, 0xcc8df19f00000000, 0x8f46571800000000, + 0xc43ac53800000000, 0x87f163bf00000000, 0x03aaf9ec00000000, + 0x40615f6b00000000, 0x12f92f9400000000, 0x5132891300000000, + 0xd569134000000000, 0x96a2b5c700000000, 0xddde27e700000000, + 0x9e15816000000000, 0x1a4e1b3300000000, 0x5985bdb400000000, + 0x8cb63f7200000000, 0xcf7d99f500000000, 0x4b2603a600000000, + 0x08eda52100000000, 0x4391370100000000, 0x005a918600000000, + 0x84010bd500000000, 0xc7caad5200000000, 0x6f607e8300000000, + 0x2cabd80400000000, 0xa8f0425700000000, 0xeb3be4d000000000, + 0xa04776f000000000, 0xe38cd07700000000, 0x67d74a2400000000, + 0x241ceca300000000, 0xf12f6e6500000000, 0xb2e4c8e200000000, + 0x36bf52b100000000, 0x7574f43600000000, 0x3e08661600000000, + 0x7dc3c09100000000, 0xf9985ac200000000, 0xba53fc4500000000, + 0x1caecae700000000, 0x5f656c6000000000, 0xdb3ef63300000000, + 0x98f550b400000000, 0xd389c29400000000, 0x9042641300000000, + 0x1419fe4000000000, 0x57d258c700000000, 0x82e1da0100000000, + 0xc12a7c8600000000, 0x4571e6d500000000, 0x06ba405200000000, + 0x4dc6d27200000000, 0x0e0d74f500000000, 0x8a56eea600000000, + 0xc99d482100000000, 0x61379bf000000000, 0x22fc3d7700000000, + 0xa6a7a72400000000, 0xe56c01a300000000, 0xae10938300000000, + 0xeddb350400000000, 0x6980af5700000000, 0x2a4b09d000000000, + 0xff788b1600000000, 0xbcb32d9100000000, 0x38e8b7c200000000, + 0x7b23114500000000, 0x305f836500000000, 0x739425e200000000, + 0xf7cfbfb100000000, 0xb404193600000000, 0xe69c69c900000000, + 0xa557cf4e00000000, 0x210c551d00000000, 0x62c7f39a00000000, + 0x29bb61ba00000000, 0x6a70c73d00000000, 0xee2b5d6e00000000, + 0xade0fbe900000000, 0x78d3792f00000000, 0x3b18dfa800000000, + 0xbf4345fb00000000, 0xfc88e37c00000000, 0xb7f4715c00000000, + 0xf43fd7db00000000, 0x70644d8800000000, 0x33afeb0f00000000, + 0x9b0538de00000000, 0xd8ce9e5900000000, 0x5c95040a00000000, + 0x1f5ea28d00000000, 0x542230ad00000000, 0x17e9962a00000000, + 0x93b20c7900000000, 0xd079aafe00000000, 0x054a283800000000, + 0x46818ebf00000000, 0xc2da14ec00000000, 0x8111b26b00000000, + 0xca6d204b00000000, 0x89a686cc00000000, 0x0dfd1c9f00000000, + 0x4e36ba1800000000}, + {0x0000000000000000, 0xe1b652ef00000000, 0x836bd40500000000, + 0x62dd86ea00000000, 0x06d7a80b00000000, 0xe761fae400000000, + 0x85bc7c0e00000000, 0x640a2ee100000000, 0x0cae511700000000, + 0xed1803f800000000, 0x8fc5851200000000, 0x6e73d7fd00000000, + 0x0a79f91c00000000, 0xebcfabf300000000, 0x89122d1900000000, + 0x68a47ff600000000, 0x185ca32e00000000, 0xf9eaf1c100000000, + 0x9b37772b00000000, 0x7a8125c400000000, 0x1e8b0b2500000000, + 0xff3d59ca00000000, 0x9de0df2000000000, 0x7c568dcf00000000, + 0x14f2f23900000000, 0xf544a0d600000000, 0x9799263c00000000, + 0x762f74d300000000, 0x12255a3200000000, 0xf39308dd00000000, + 0x914e8e3700000000, 0x70f8dcd800000000, 0x30b8465d00000000, + 0xd10e14b200000000, 0xb3d3925800000000, 0x5265c0b700000000, + 0x366fee5600000000, 0xd7d9bcb900000000, 0xb5043a5300000000, + 0x54b268bc00000000, 0x3c16174a00000000, 0xdda045a500000000, + 0xbf7dc34f00000000, 0x5ecb91a000000000, 0x3ac1bf4100000000, + 0xdb77edae00000000, 0xb9aa6b4400000000, 0x581c39ab00000000, + 0x28e4e57300000000, 0xc952b79c00000000, 0xab8f317600000000, + 0x4a39639900000000, 0x2e334d7800000000, 0xcf851f9700000000, + 0xad58997d00000000, 0x4ceecb9200000000, 0x244ab46400000000, + 0xc5fce68b00000000, 0xa721606100000000, 0x4697328e00000000, + 0x229d1c6f00000000, 0xc32b4e8000000000, 0xa1f6c86a00000000, + 0x40409a8500000000, 0x60708dba00000000, 0x81c6df5500000000, + 0xe31b59bf00000000, 0x02ad0b5000000000, 0x66a725b100000000, + 0x8711775e00000000, 0xe5ccf1b400000000, 0x047aa35b00000000, + 0x6cdedcad00000000, 0x8d688e4200000000, 0xefb508a800000000, + 0x0e035a4700000000, 0x6a0974a600000000, 0x8bbf264900000000, + 0xe962a0a300000000, 0x08d4f24c00000000, 0x782c2e9400000000, + 0x999a7c7b00000000, 0xfb47fa9100000000, 0x1af1a87e00000000, + 0x7efb869f00000000, 0x9f4dd47000000000, 0xfd90529a00000000, + 0x1c26007500000000, 0x74827f8300000000, 0x95342d6c00000000, + 0xf7e9ab8600000000, 0x165ff96900000000, 0x7255d78800000000, + 0x93e3856700000000, 0xf13e038d00000000, 0x1088516200000000, + 0x50c8cbe700000000, 0xb17e990800000000, 0xd3a31fe200000000, + 0x32154d0d00000000, 0x561f63ec00000000, 0xb7a9310300000000, + 0xd574b7e900000000, 0x34c2e50600000000, 0x5c669af000000000, + 0xbdd0c81f00000000, 0xdf0d4ef500000000, 0x3ebb1c1a00000000, + 0x5ab132fb00000000, 0xbb07601400000000, 0xd9dae6fe00000000, + 0x386cb41100000000, 0x489468c900000000, 0xa9223a2600000000, + 0xcbffbccc00000000, 0x2a49ee2300000000, 0x4e43c0c200000000, + 0xaff5922d00000000, 0xcd2814c700000000, 0x2c9e462800000000, + 0x443a39de00000000, 0xa58c6b3100000000, 0xc751eddb00000000, + 0x26e7bf3400000000, 0x42ed91d500000000, 0xa35bc33a00000000, + 0xc18645d000000000, 0x2030173f00000000, 0x81e66bae00000000, + 0x6050394100000000, 0x028dbfab00000000, 0xe33bed4400000000, + 0x8731c3a500000000, 0x6687914a00000000, 0x045a17a000000000, + 0xe5ec454f00000000, 0x8d483ab900000000, 0x6cfe685600000000, + 0x0e23eebc00000000, 0xef95bc5300000000, 0x8b9f92b200000000, + 0x6a29c05d00000000, 0x08f446b700000000, 0xe942145800000000, + 0x99bac88000000000, 0x780c9a6f00000000, 0x1ad11c8500000000, + 0xfb674e6a00000000, 0x9f6d608b00000000, 0x7edb326400000000, + 0x1c06b48e00000000, 0xfdb0e66100000000, 0x9514999700000000, + 0x74a2cb7800000000, 0x167f4d9200000000, 0xf7c91f7d00000000, + 0x93c3319c00000000, 0x7275637300000000, 0x10a8e59900000000, + 0xf11eb77600000000, 0xb15e2df300000000, 0x50e87f1c00000000, + 0x3235f9f600000000, 0xd383ab1900000000, 0xb78985f800000000, + 0x563fd71700000000, 0x34e251fd00000000, 0xd554031200000000, + 0xbdf07ce400000000, 0x5c462e0b00000000, 0x3e9ba8e100000000, + 0xdf2dfa0e00000000, 0xbb27d4ef00000000, 0x5a91860000000000, + 0x384c00ea00000000, 0xd9fa520500000000, 0xa9028edd00000000, + 0x48b4dc3200000000, 0x2a695ad800000000, 0xcbdf083700000000, + 0xafd526d600000000, 0x4e63743900000000, 0x2cbef2d300000000, + 0xcd08a03c00000000, 0xa5acdfca00000000, 0x441a8d2500000000, + 0x26c70bcf00000000, 0xc771592000000000, 0xa37b77c100000000, + 0x42cd252e00000000, 0x2010a3c400000000, 0xc1a6f12b00000000, + 0xe196e61400000000, 0x0020b4fb00000000, 0x62fd321100000000, + 0x834b60fe00000000, 0xe7414e1f00000000, 0x06f71cf000000000, + 0x642a9a1a00000000, 0x859cc8f500000000, 0xed38b70300000000, + 0x0c8ee5ec00000000, 0x6e53630600000000, 0x8fe531e900000000, + 0xebef1f0800000000, 0x0a594de700000000, 0x6884cb0d00000000, + 0x893299e200000000, 0xf9ca453a00000000, 0x187c17d500000000, + 0x7aa1913f00000000, 0x9b17c3d000000000, 0xff1ded3100000000, + 0x1eabbfde00000000, 0x7c76393400000000, 0x9dc06bdb00000000, + 0xf564142d00000000, 0x14d246c200000000, 0x760fc02800000000, + 0x97b992c700000000, 0xf3b3bc2600000000, 0x1205eec900000000, + 0x70d8682300000000, 0x916e3acc00000000, 0xd12ea04900000000, + 0x3098f2a600000000, 0x5245744c00000000, 0xb3f326a300000000, + 0xd7f9084200000000, 0x364f5aad00000000, 0x5492dc4700000000, + 0xb5248ea800000000, 0xdd80f15e00000000, 0x3c36a3b100000000, + 0x5eeb255b00000000, 0xbf5d77b400000000, 0xdb57595500000000, + 0x3ae10bba00000000, 0x583c8d5000000000, 0xb98adfbf00000000, + 0xc972036700000000, 0x28c4518800000000, 0x4a19d76200000000, + 0xabaf858d00000000, 0xcfa5ab6c00000000, 0x2e13f98300000000, + 0x4cce7f6900000000, 0xad782d8600000000, 0xc5dc527000000000, + 0x246a009f00000000, 0x46b7867500000000, 0xa701d49a00000000, + 0xc30bfa7b00000000, 0x22bda89400000000, 0x40602e7e00000000, + 0xa1d67c9100000000}, + {0x0000000000000000, 0x5880e2d700000000, 0xf106b47400000000, + 0xa98656a300000000, 0xe20d68e900000000, 0xba8d8a3e00000000, + 0x130bdc9d00000000, 0x4b8b3e4a00000000, 0x851da10900000000, + 0xdd9d43de00000000, 0x741b157d00000000, 0x2c9bf7aa00000000, + 0x6710c9e000000000, 0x3f902b3700000000, 0x96167d9400000000, + 0xce969f4300000000, 0x0a3b421300000000, 0x52bba0c400000000, + 0xfb3df66700000000, 0xa3bd14b000000000, 0xe8362afa00000000, + 0xb0b6c82d00000000, 0x19309e8e00000000, 0x41b07c5900000000, + 0x8f26e31a00000000, 0xd7a601cd00000000, 0x7e20576e00000000, + 0x26a0b5b900000000, 0x6d2b8bf300000000, 0x35ab692400000000, + 0x9c2d3f8700000000, 0xc4addd5000000000, 0x1476842600000000, + 0x4cf666f100000000, 0xe570305200000000, 0xbdf0d28500000000, + 0xf67beccf00000000, 0xaefb0e1800000000, 0x077d58bb00000000, + 0x5ffdba6c00000000, 0x916b252f00000000, 0xc9ebc7f800000000, + 0x606d915b00000000, 0x38ed738c00000000, 0x73664dc600000000, + 0x2be6af1100000000, 0x8260f9b200000000, 0xdae01b6500000000, + 0x1e4dc63500000000, 0x46cd24e200000000, 0xef4b724100000000, + 0xb7cb909600000000, 0xfc40aedc00000000, 0xa4c04c0b00000000, + 0x0d461aa800000000, 0x55c6f87f00000000, 0x9b50673c00000000, + 0xc3d085eb00000000, 0x6a56d34800000000, 0x32d6319f00000000, + 0x795d0fd500000000, 0x21dded0200000000, 0x885bbba100000000, + 0xd0db597600000000, 0x28ec084d00000000, 0x706cea9a00000000, + 0xd9eabc3900000000, 0x816a5eee00000000, 0xcae160a400000000, + 0x9261827300000000, 0x3be7d4d000000000, 0x6367360700000000, + 0xadf1a94400000000, 0xf5714b9300000000, 0x5cf71d3000000000, + 0x0477ffe700000000, 0x4ffcc1ad00000000, 0x177c237a00000000, + 0xbefa75d900000000, 0xe67a970e00000000, 0x22d74a5e00000000, + 0x7a57a88900000000, 0xd3d1fe2a00000000, 0x8b511cfd00000000, + 0xc0da22b700000000, 0x985ac06000000000, 0x31dc96c300000000, + 0x695c741400000000, 0xa7caeb5700000000, 0xff4a098000000000, + 0x56cc5f2300000000, 0x0e4cbdf400000000, 0x45c783be00000000, + 0x1d47616900000000, 0xb4c137ca00000000, 0xec41d51d00000000, + 0x3c9a8c6b00000000, 0x641a6ebc00000000, 0xcd9c381f00000000, + 0x951cdac800000000, 0xde97e48200000000, 0x8617065500000000, + 0x2f9150f600000000, 0x7711b22100000000, 0xb9872d6200000000, + 0xe107cfb500000000, 0x4881991600000000, 0x10017bc100000000, + 0x5b8a458b00000000, 0x030aa75c00000000, 0xaa8cf1ff00000000, + 0xf20c132800000000, 0x36a1ce7800000000, 0x6e212caf00000000, + 0xc7a77a0c00000000, 0x9f2798db00000000, 0xd4aca69100000000, + 0x8c2c444600000000, 0x25aa12e500000000, 0x7d2af03200000000, + 0xb3bc6f7100000000, 0xeb3c8da600000000, 0x42badb0500000000, + 0x1a3a39d200000000, 0x51b1079800000000, 0x0931e54f00000000, + 0xa0b7b3ec00000000, 0xf837513b00000000, 0x50d8119a00000000, + 0x0858f34d00000000, 0xa1dea5ee00000000, 0xf95e473900000000, + 0xb2d5797300000000, 0xea559ba400000000, 0x43d3cd0700000000, + 0x1b532fd000000000, 0xd5c5b09300000000, 0x8d45524400000000, + 0x24c304e700000000, 0x7c43e63000000000, 0x37c8d87a00000000, + 0x6f483aad00000000, 0xc6ce6c0e00000000, 0x9e4e8ed900000000, + 0x5ae3538900000000, 0x0263b15e00000000, 0xabe5e7fd00000000, + 0xf365052a00000000, 0xb8ee3b6000000000, 0xe06ed9b700000000, + 0x49e88f1400000000, 0x11686dc300000000, 0xdffef28000000000, + 0x877e105700000000, 0x2ef846f400000000, 0x7678a42300000000, + 0x3df39a6900000000, 0x657378be00000000, 0xccf52e1d00000000, + 0x9475ccca00000000, 0x44ae95bc00000000, 0x1c2e776b00000000, + 0xb5a821c800000000, 0xed28c31f00000000, 0xa6a3fd5500000000, + 0xfe231f8200000000, 0x57a5492100000000, 0x0f25abf600000000, + 0xc1b334b500000000, 0x9933d66200000000, 0x30b580c100000000, + 0x6835621600000000, 0x23be5c5c00000000, 0x7b3ebe8b00000000, + 0xd2b8e82800000000, 0x8a380aff00000000, 0x4e95d7af00000000, + 0x1615357800000000, 0xbf9363db00000000, 0xe713810c00000000, + 0xac98bf4600000000, 0xf4185d9100000000, 0x5d9e0b3200000000, + 0x051ee9e500000000, 0xcb8876a600000000, 0x9308947100000000, + 0x3a8ec2d200000000, 0x620e200500000000, 0x29851e4f00000000, + 0x7105fc9800000000, 0xd883aa3b00000000, 0x800348ec00000000, + 0x783419d700000000, 0x20b4fb0000000000, 0x8932ada300000000, + 0xd1b24f7400000000, 0x9a39713e00000000, 0xc2b993e900000000, + 0x6b3fc54a00000000, 0x33bf279d00000000, 0xfd29b8de00000000, + 0xa5a95a0900000000, 0x0c2f0caa00000000, 0x54afee7d00000000, + 0x1f24d03700000000, 0x47a432e000000000, 0xee22644300000000, + 0xb6a2869400000000, 0x720f5bc400000000, 0x2a8fb91300000000, + 0x8309efb000000000, 0xdb890d6700000000, 0x9002332d00000000, + 0xc882d1fa00000000, 0x6104875900000000, 0x3984658e00000000, + 0xf712facd00000000, 0xaf92181a00000000, 0x06144eb900000000, + 0x5e94ac6e00000000, 0x151f922400000000, 0x4d9f70f300000000, + 0xe419265000000000, 0xbc99c48700000000, 0x6c429df100000000, + 0x34c27f2600000000, 0x9d44298500000000, 0xc5c4cb5200000000, + 0x8e4ff51800000000, 0xd6cf17cf00000000, 0x7f49416c00000000, + 0x27c9a3bb00000000, 0xe95f3cf800000000, 0xb1dfde2f00000000, + 0x1859888c00000000, 0x40d96a5b00000000, 0x0b52541100000000, + 0x53d2b6c600000000, 0xfa54e06500000000, 0xa2d402b200000000, + 0x6679dfe200000000, 0x3ef93d3500000000, 0x977f6b9600000000, + 0xcfff894100000000, 0x8474b70b00000000, 0xdcf455dc00000000, + 0x7572037f00000000, 0x2df2e1a800000000, 0xe3647eeb00000000, + 0xbbe49c3c00000000, 0x1262ca9f00000000, 0x4ae2284800000000, + 0x0169160200000000, 0x59e9f4d500000000, 0xf06fa27600000000, + 0xa8ef40a100000000}, + {0x0000000000000000, 0x463b676500000000, 0x8c76ceca00000000, + 0xca4da9af00000000, 0x59ebed4e00000000, 0x1fd08a2b00000000, + 0xd59d238400000000, 0x93a644e100000000, 0xb2d6db9d00000000, + 0xf4edbcf800000000, 0x3ea0155700000000, 0x789b723200000000, + 0xeb3d36d300000000, 0xad0651b600000000, 0x674bf81900000000, + 0x21709f7c00000000, 0x25abc6e000000000, 0x6390a18500000000, + 0xa9dd082a00000000, 0xefe66f4f00000000, 0x7c402bae00000000, + 0x3a7b4ccb00000000, 0xf036e56400000000, 0xb60d820100000000, + 0x977d1d7d00000000, 0xd1467a1800000000, 0x1b0bd3b700000000, + 0x5d30b4d200000000, 0xce96f03300000000, 0x88ad975600000000, + 0x42e03ef900000000, 0x04db599c00000000, 0x0b50fc1a00000000, + 0x4d6b9b7f00000000, 0x872632d000000000, 0xc11d55b500000000, + 0x52bb115400000000, 0x1480763100000000, 0xdecddf9e00000000, + 0x98f6b8fb00000000, 0xb986278700000000, 0xffbd40e200000000, + 0x35f0e94d00000000, 0x73cb8e2800000000, 0xe06dcac900000000, + 0xa656adac00000000, 0x6c1b040300000000, 0x2a20636600000000, + 0x2efb3afa00000000, 0x68c05d9f00000000, 0xa28df43000000000, + 0xe4b6935500000000, 0x7710d7b400000000, 0x312bb0d100000000, + 0xfb66197e00000000, 0xbd5d7e1b00000000, 0x9c2de16700000000, + 0xda16860200000000, 0x105b2fad00000000, 0x566048c800000000, + 0xc5c60c2900000000, 0x83fd6b4c00000000, 0x49b0c2e300000000, + 0x0f8ba58600000000, 0x16a0f83500000000, 0x509b9f5000000000, + 0x9ad636ff00000000, 0xdced519a00000000, 0x4f4b157b00000000, + 0x0970721e00000000, 0xc33ddbb100000000, 0x8506bcd400000000, + 0xa47623a800000000, 0xe24d44cd00000000, 0x2800ed6200000000, + 0x6e3b8a0700000000, 0xfd9dcee600000000, 0xbba6a98300000000, + 0x71eb002c00000000, 0x37d0674900000000, 0x330b3ed500000000, + 0x753059b000000000, 0xbf7df01f00000000, 0xf946977a00000000, + 0x6ae0d39b00000000, 0x2cdbb4fe00000000, 0xe6961d5100000000, + 0xa0ad7a3400000000, 0x81dde54800000000, 0xc7e6822d00000000, + 0x0dab2b8200000000, 0x4b904ce700000000, 0xd836080600000000, + 0x9e0d6f6300000000, 0x5440c6cc00000000, 0x127ba1a900000000, + 0x1df0042f00000000, 0x5bcb634a00000000, 0x9186cae500000000, + 0xd7bdad8000000000, 0x441be96100000000, 0x02208e0400000000, + 0xc86d27ab00000000, 0x8e5640ce00000000, 0xaf26dfb200000000, + 0xe91db8d700000000, 0x2350117800000000, 0x656b761d00000000, + 0xf6cd32fc00000000, 0xb0f6559900000000, 0x7abbfc3600000000, + 0x3c809b5300000000, 0x385bc2cf00000000, 0x7e60a5aa00000000, + 0xb42d0c0500000000, 0xf2166b6000000000, 0x61b02f8100000000, + 0x278b48e400000000, 0xedc6e14b00000000, 0xabfd862e00000000, + 0x8a8d195200000000, 0xccb67e3700000000, 0x06fbd79800000000, + 0x40c0b0fd00000000, 0xd366f41c00000000, 0x955d937900000000, + 0x5f103ad600000000, 0x192b5db300000000, 0x2c40f16b00000000, + 0x6a7b960e00000000, 0xa0363fa100000000, 0xe60d58c400000000, + 0x75ab1c2500000000, 0x33907b4000000000, 0xf9ddd2ef00000000, + 0xbfe6b58a00000000, 0x9e962af600000000, 0xd8ad4d9300000000, + 0x12e0e43c00000000, 0x54db835900000000, 0xc77dc7b800000000, + 0x8146a0dd00000000, 0x4b0b097200000000, 0x0d306e1700000000, + 0x09eb378b00000000, 0x4fd050ee00000000, 0x859df94100000000, + 0xc3a69e2400000000, 0x5000dac500000000, 0x163bbda000000000, + 0xdc76140f00000000, 0x9a4d736a00000000, 0xbb3dec1600000000, + 0xfd068b7300000000, 0x374b22dc00000000, 0x717045b900000000, + 0xe2d6015800000000, 0xa4ed663d00000000, 0x6ea0cf9200000000, + 0x289ba8f700000000, 0x27100d7100000000, 0x612b6a1400000000, + 0xab66c3bb00000000, 0xed5da4de00000000, 0x7efbe03f00000000, + 0x38c0875a00000000, 0xf28d2ef500000000, 0xb4b6499000000000, + 0x95c6d6ec00000000, 0xd3fdb18900000000, 0x19b0182600000000, + 0x5f8b7f4300000000, 0xcc2d3ba200000000, 0x8a165cc700000000, + 0x405bf56800000000, 0x0660920d00000000, 0x02bbcb9100000000, + 0x4480acf400000000, 0x8ecd055b00000000, 0xc8f6623e00000000, + 0x5b5026df00000000, 0x1d6b41ba00000000, 0xd726e81500000000, + 0x911d8f7000000000, 0xb06d100c00000000, 0xf656776900000000, + 0x3c1bdec600000000, 0x7a20b9a300000000, 0xe986fd4200000000, + 0xafbd9a2700000000, 0x65f0338800000000, 0x23cb54ed00000000, + 0x3ae0095e00000000, 0x7cdb6e3b00000000, 0xb696c79400000000, + 0xf0ada0f100000000, 0x630be41000000000, 0x2530837500000000, + 0xef7d2ada00000000, 0xa9464dbf00000000, 0x8836d2c300000000, + 0xce0db5a600000000, 0x04401c0900000000, 0x427b7b6c00000000, + 0xd1dd3f8d00000000, 0x97e658e800000000, 0x5dabf14700000000, + 0x1b90962200000000, 0x1f4bcfbe00000000, 0x5970a8db00000000, + 0x933d017400000000, 0xd506661100000000, 0x46a022f000000000, + 0x009b459500000000, 0xcad6ec3a00000000, 0x8ced8b5f00000000, + 0xad9d142300000000, 0xeba6734600000000, 0x21ebdae900000000, + 0x67d0bd8c00000000, 0xf476f96d00000000, 0xb24d9e0800000000, + 0x780037a700000000, 0x3e3b50c200000000, 0x31b0f54400000000, + 0x778b922100000000, 0xbdc63b8e00000000, 0xfbfd5ceb00000000, + 0x685b180a00000000, 0x2e607f6f00000000, 0xe42dd6c000000000, + 0xa216b1a500000000, 0x83662ed900000000, 0xc55d49bc00000000, + 0x0f10e01300000000, 0x492b877600000000, 0xda8dc39700000000, + 0x9cb6a4f200000000, 0x56fb0d5d00000000, 0x10c06a3800000000, + 0x141b33a400000000, 0x522054c100000000, 0x986dfd6e00000000, + 0xde569a0b00000000, 0x4df0deea00000000, 0x0bcbb98f00000000, + 0xc186102000000000, 0x87bd774500000000, 0xa6cde83900000000, + 0xe0f68f5c00000000, 0x2abb26f300000000, 0x6c80419600000000, + 0xff26057700000000, 0xb91d621200000000, 0x7350cbbd00000000, + 0x356bacd800000000}, + {0x0000000000000000, 0x9e83da9f00000000, 0x7d01c4e400000000, + 0xe3821e7b00000000, 0xbb04f91200000000, 0x2587238d00000000, + 0xc6053df600000000, 0x5886e76900000000, 0x7609f22500000000, + 0xe88a28ba00000000, 0x0b0836c100000000, 0x958bec5e00000000, + 0xcd0d0b3700000000, 0x538ed1a800000000, 0xb00ccfd300000000, + 0x2e8f154c00000000, 0xec12e44b00000000, 0x72913ed400000000, + 0x911320af00000000, 0x0f90fa3000000000, 0x57161d5900000000, + 0xc995c7c600000000, 0x2a17d9bd00000000, 0xb494032200000000, + 0x9a1b166e00000000, 0x0498ccf100000000, 0xe71ad28a00000000, + 0x7999081500000000, 0x211fef7c00000000, 0xbf9c35e300000000, + 0x5c1e2b9800000000, 0xc29df10700000000, 0xd825c89700000000, + 0x46a6120800000000, 0xa5240c7300000000, 0x3ba7d6ec00000000, + 0x6321318500000000, 0xfda2eb1a00000000, 0x1e20f56100000000, + 0x80a32ffe00000000, 0xae2c3ab200000000, 0x30afe02d00000000, + 0xd32dfe5600000000, 0x4dae24c900000000, 0x1528c3a000000000, + 0x8bab193f00000000, 0x6829074400000000, 0xf6aadddb00000000, + 0x34372cdc00000000, 0xaab4f64300000000, 0x4936e83800000000, + 0xd7b532a700000000, 0x8f33d5ce00000000, 0x11b00f5100000000, + 0xf232112a00000000, 0x6cb1cbb500000000, 0x423edef900000000, + 0xdcbd046600000000, 0x3f3f1a1d00000000, 0xa1bcc08200000000, + 0xf93a27eb00000000, 0x67b9fd7400000000, 0x843be30f00000000, + 0x1ab8399000000000, 0xf14de1f400000000, 0x6fce3b6b00000000, + 0x8c4c251000000000, 0x12cfff8f00000000, 0x4a4918e600000000, + 0xd4cac27900000000, 0x3748dc0200000000, 0xa9cb069d00000000, + 0x874413d100000000, 0x19c7c94e00000000, 0xfa45d73500000000, + 0x64c60daa00000000, 0x3c40eac300000000, 0xa2c3305c00000000, + 0x41412e2700000000, 0xdfc2f4b800000000, 0x1d5f05bf00000000, + 0x83dcdf2000000000, 0x605ec15b00000000, 0xfedd1bc400000000, + 0xa65bfcad00000000, 0x38d8263200000000, 0xdb5a384900000000, + 0x45d9e2d600000000, 0x6b56f79a00000000, 0xf5d52d0500000000, + 0x1657337e00000000, 0x88d4e9e100000000, 0xd0520e8800000000, + 0x4ed1d41700000000, 0xad53ca6c00000000, 0x33d010f300000000, + 0x2968296300000000, 0xb7ebf3fc00000000, 0x5469ed8700000000, + 0xcaea371800000000, 0x926cd07100000000, 0x0cef0aee00000000, + 0xef6d149500000000, 0x71eece0a00000000, 0x5f61db4600000000, + 0xc1e201d900000000, 0x22601fa200000000, 0xbce3c53d00000000, + 0xe465225400000000, 0x7ae6f8cb00000000, 0x9964e6b000000000, + 0x07e73c2f00000000, 0xc57acd2800000000, 0x5bf917b700000000, + 0xb87b09cc00000000, 0x26f8d35300000000, 0x7e7e343a00000000, + 0xe0fdeea500000000, 0x037ff0de00000000, 0x9dfc2a4100000000, + 0xb3733f0d00000000, 0x2df0e59200000000, 0xce72fbe900000000, + 0x50f1217600000000, 0x0877c61f00000000, 0x96f41c8000000000, + 0x757602fb00000000, 0xebf5d86400000000, 0xa39db33200000000, + 0x3d1e69ad00000000, 0xde9c77d600000000, 0x401fad4900000000, + 0x18994a2000000000, 0x861a90bf00000000, 0x65988ec400000000, + 0xfb1b545b00000000, 0xd594411700000000, 0x4b179b8800000000, + 0xa89585f300000000, 0x36165f6c00000000, 0x6e90b80500000000, + 0xf013629a00000000, 0x13917ce100000000, 0x8d12a67e00000000, + 0x4f8f577900000000, 0xd10c8de600000000, 0x328e939d00000000, + 0xac0d490200000000, 0xf48bae6b00000000, 0x6a0874f400000000, + 0x898a6a8f00000000, 0x1709b01000000000, 0x3986a55c00000000, + 0xa7057fc300000000, 0x448761b800000000, 0xda04bb2700000000, + 0x82825c4e00000000, 0x1c0186d100000000, 0xff8398aa00000000, + 0x6100423500000000, 0x7bb87ba500000000, 0xe53ba13a00000000, + 0x06b9bf4100000000, 0x983a65de00000000, 0xc0bc82b700000000, + 0x5e3f582800000000, 0xbdbd465300000000, 0x233e9ccc00000000, + 0x0db1898000000000, 0x9332531f00000000, 0x70b04d6400000000, + 0xee3397fb00000000, 0xb6b5709200000000, 0x2836aa0d00000000, + 0xcbb4b47600000000, 0x55376ee900000000, 0x97aa9fee00000000, + 0x0929457100000000, 0xeaab5b0a00000000, 0x7428819500000000, + 0x2cae66fc00000000, 0xb22dbc6300000000, 0x51afa21800000000, + 0xcf2c788700000000, 0xe1a36dcb00000000, 0x7f20b75400000000, + 0x9ca2a92f00000000, 0x022173b000000000, 0x5aa794d900000000, + 0xc4244e4600000000, 0x27a6503d00000000, 0xb9258aa200000000, + 0x52d052c600000000, 0xcc53885900000000, 0x2fd1962200000000, + 0xb1524cbd00000000, 0xe9d4abd400000000, 0x7757714b00000000, + 0x94d56f3000000000, 0x0a56b5af00000000, 0x24d9a0e300000000, + 0xba5a7a7c00000000, 0x59d8640700000000, 0xc75bbe9800000000, + 0x9fdd59f100000000, 0x015e836e00000000, 0xe2dc9d1500000000, + 0x7c5f478a00000000, 0xbec2b68d00000000, 0x20416c1200000000, + 0xc3c3726900000000, 0x5d40a8f600000000, 0x05c64f9f00000000, + 0x9b45950000000000, 0x78c78b7b00000000, 0xe64451e400000000, + 0xc8cb44a800000000, 0x56489e3700000000, 0xb5ca804c00000000, + 0x2b495ad300000000, 0x73cfbdba00000000, 0xed4c672500000000, + 0x0ece795e00000000, 0x904da3c100000000, 0x8af59a5100000000, + 0x147640ce00000000, 0xf7f45eb500000000, 0x6977842a00000000, + 0x31f1634300000000, 0xaf72b9dc00000000, 0x4cf0a7a700000000, + 0xd2737d3800000000, 0xfcfc687400000000, 0x627fb2eb00000000, + 0x81fdac9000000000, 0x1f7e760f00000000, 0x47f8916600000000, + 0xd97b4bf900000000, 0x3af9558200000000, 0xa47a8f1d00000000, + 0x66e77e1a00000000, 0xf864a48500000000, 0x1be6bafe00000000, + 0x8565606100000000, 0xdde3870800000000, 0x43605d9700000000, + 0xa0e243ec00000000, 0x3e61997300000000, 0x10ee8c3f00000000, + 0x8e6d56a000000000, 0x6def48db00000000, 0xf36c924400000000, + 0xabea752d00000000, 0x3569afb200000000, 0xd6ebb1c900000000, + 0x48686b5600000000}, + {0x0000000000000000, 0xc064281700000000, 0x80c9502e00000000, + 0x40ad783900000000, 0x0093a15c00000000, 0xc0f7894b00000000, + 0x805af17200000000, 0x403ed96500000000, 0x002643b900000000, + 0xc0426bae00000000, 0x80ef139700000000, 0x408b3b8000000000, + 0x00b5e2e500000000, 0xc0d1caf200000000, 0x807cb2cb00000000, + 0x40189adc00000000, 0x414af7a900000000, 0x812edfbe00000000, + 0xc183a78700000000, 0x01e78f9000000000, 0x41d956f500000000, + 0x81bd7ee200000000, 0xc11006db00000000, 0x01742ecc00000000, + 0x416cb41000000000, 0x81089c0700000000, 0xc1a5e43e00000000, + 0x01c1cc2900000000, 0x41ff154c00000000, 0x819b3d5b00000000, + 0xc136456200000000, 0x01526d7500000000, 0xc3929f8800000000, + 0x03f6b79f00000000, 0x435bcfa600000000, 0x833fe7b100000000, + 0xc3013ed400000000, 0x036516c300000000, 0x43c86efa00000000, + 0x83ac46ed00000000, 0xc3b4dc3100000000, 0x03d0f42600000000, + 0x437d8c1f00000000, 0x8319a40800000000, 0xc3277d6d00000000, + 0x0343557a00000000, 0x43ee2d4300000000, 0x838a055400000000, + 0x82d8682100000000, 0x42bc403600000000, 0x0211380f00000000, + 0xc275101800000000, 0x824bc97d00000000, 0x422fe16a00000000, + 0x0282995300000000, 0xc2e6b14400000000, 0x82fe2b9800000000, + 0x429a038f00000000, 0x02377bb600000000, 0xc25353a100000000, + 0x826d8ac400000000, 0x4209a2d300000000, 0x02a4daea00000000, + 0xc2c0f2fd00000000, 0xc7234eca00000000, 0x074766dd00000000, + 0x47ea1ee400000000, 0x878e36f300000000, 0xc7b0ef9600000000, + 0x07d4c78100000000, 0x4779bfb800000000, 0x871d97af00000000, + 0xc7050d7300000000, 0x0761256400000000, 0x47cc5d5d00000000, + 0x87a8754a00000000, 0xc796ac2f00000000, 0x07f2843800000000, + 0x475ffc0100000000, 0x873bd41600000000, 0x8669b96300000000, + 0x460d917400000000, 0x06a0e94d00000000, 0xc6c4c15a00000000, + 0x86fa183f00000000, 0x469e302800000000, 0x0633481100000000, + 0xc657600600000000, 0x864ffada00000000, 0x462bd2cd00000000, + 0x0686aaf400000000, 0xc6e282e300000000, 0x86dc5b8600000000, + 0x46b8739100000000, 0x06150ba800000000, 0xc67123bf00000000, + 0x04b1d14200000000, 0xc4d5f95500000000, 0x8478816c00000000, + 0x441ca97b00000000, 0x0422701e00000000, 0xc446580900000000, + 0x84eb203000000000, 0x448f082700000000, 0x049792fb00000000, + 0xc4f3baec00000000, 0x845ec2d500000000, 0x443aeac200000000, + 0x040433a700000000, 0xc4601bb000000000, 0x84cd638900000000, + 0x44a94b9e00000000, 0x45fb26eb00000000, 0x859f0efc00000000, + 0xc53276c500000000, 0x05565ed200000000, 0x456887b700000000, + 0x850cafa000000000, 0xc5a1d79900000000, 0x05c5ff8e00000000, + 0x45dd655200000000, 0x85b94d4500000000, 0xc514357c00000000, + 0x05701d6b00000000, 0x454ec40e00000000, 0x852aec1900000000, + 0xc587942000000000, 0x05e3bc3700000000, 0xcf41ed4f00000000, + 0x0f25c55800000000, 0x4f88bd6100000000, 0x8fec957600000000, + 0xcfd24c1300000000, 0x0fb6640400000000, 0x4f1b1c3d00000000, + 0x8f7f342a00000000, 0xcf67aef600000000, 0x0f0386e100000000, + 0x4faefed800000000, 0x8fcad6cf00000000, 0xcff40faa00000000, + 0x0f9027bd00000000, 0x4f3d5f8400000000, 0x8f59779300000000, + 0x8e0b1ae600000000, 0x4e6f32f100000000, 0x0ec24ac800000000, + 0xcea662df00000000, 0x8e98bbba00000000, 0x4efc93ad00000000, + 0x0e51eb9400000000, 0xce35c38300000000, 0x8e2d595f00000000, + 0x4e49714800000000, 0x0ee4097100000000, 0xce80216600000000, + 0x8ebef80300000000, 0x4edad01400000000, 0x0e77a82d00000000, + 0xce13803a00000000, 0x0cd372c700000000, 0xccb75ad000000000, + 0x8c1a22e900000000, 0x4c7e0afe00000000, 0x0c40d39b00000000, + 0xcc24fb8c00000000, 0x8c8983b500000000, 0x4cedaba200000000, + 0x0cf5317e00000000, 0xcc91196900000000, 0x8c3c615000000000, + 0x4c58494700000000, 0x0c66902200000000, 0xcc02b83500000000, + 0x8cafc00c00000000, 0x4ccbe81b00000000, 0x4d99856e00000000, + 0x8dfdad7900000000, 0xcd50d54000000000, 0x0d34fd5700000000, + 0x4d0a243200000000, 0x8d6e0c2500000000, 0xcdc3741c00000000, + 0x0da75c0b00000000, 0x4dbfc6d700000000, 0x8ddbeec000000000, + 0xcd7696f900000000, 0x0d12beee00000000, 0x4d2c678b00000000, + 0x8d484f9c00000000, 0xcde537a500000000, 0x0d811fb200000000, + 0x0862a38500000000, 0xc8068b9200000000, 0x88abf3ab00000000, + 0x48cfdbbc00000000, 0x08f102d900000000, 0xc8952ace00000000, + 0x883852f700000000, 0x485c7ae000000000, 0x0844e03c00000000, + 0xc820c82b00000000, 0x888db01200000000, 0x48e9980500000000, + 0x08d7416000000000, 0xc8b3697700000000, 0x881e114e00000000, + 0x487a395900000000, 0x4928542c00000000, 0x894c7c3b00000000, + 0xc9e1040200000000, 0x09852c1500000000, 0x49bbf57000000000, + 0x89dfdd6700000000, 0xc972a55e00000000, 0x09168d4900000000, + 0x490e179500000000, 0x896a3f8200000000, 0xc9c747bb00000000, + 0x09a36fac00000000, 0x499db6c900000000, 0x89f99ede00000000, + 0xc954e6e700000000, 0x0930cef000000000, 0xcbf03c0d00000000, + 0x0b94141a00000000, 0x4b396c2300000000, 0x8b5d443400000000, + 0xcb639d5100000000, 0x0b07b54600000000, 0x4baacd7f00000000, + 0x8bcee56800000000, 0xcbd67fb400000000, 0x0bb257a300000000, + 0x4b1f2f9a00000000, 0x8b7b078d00000000, 0xcb45dee800000000, + 0x0b21f6ff00000000, 0x4b8c8ec600000000, 0x8be8a6d100000000, + 0x8abacba400000000, 0x4adee3b300000000, 0x0a739b8a00000000, + 0xca17b39d00000000, 0x8a296af800000000, 0x4a4d42ef00000000, + 0x0ae03ad600000000, 0xca8412c100000000, 0x8a9c881d00000000, + 0x4af8a00a00000000, 0x0a55d83300000000, 0xca31f02400000000, + 0x8a0f294100000000, 0x4a6b015600000000, 0x0ac6796f00000000, + 0xcaa2517800000000}, + {0x0000000000000000, 0xd4ea739b00000000, 0xe9d396ed00000000, + 0x3d39e57600000000, 0x93a15c0000000000, 0x474b2f9b00000000, + 0x7a72caed00000000, 0xae98b97600000000, 0x2643b90000000000, + 0xf2a9ca9b00000000, 0xcf902fed00000000, 0x1b7a5c7600000000, + 0xb5e2e50000000000, 0x6108969b00000000, 0x5c3173ed00000000, + 0x88db007600000000, 0x4c86720100000000, 0x986c019a00000000, + 0xa555e4ec00000000, 0x71bf977700000000, 0xdf272e0100000000, + 0x0bcd5d9a00000000, 0x36f4b8ec00000000, 0xe21ecb7700000000, + 0x6ac5cb0100000000, 0xbe2fb89a00000000, 0x83165dec00000000, + 0x57fc2e7700000000, 0xf964970100000000, 0x2d8ee49a00000000, + 0x10b701ec00000000, 0xc45d727700000000, 0x980ce50200000000, + 0x4ce6969900000000, 0x71df73ef00000000, 0xa535007400000000, + 0x0badb90200000000, 0xdf47ca9900000000, 0xe27e2fef00000000, + 0x36945c7400000000, 0xbe4f5c0200000000, 0x6aa52f9900000000, + 0x579ccaef00000000, 0x8376b97400000000, 0x2dee000200000000, + 0xf904739900000000, 0xc43d96ef00000000, 0x10d7e57400000000, + 0xd48a970300000000, 0x0060e49800000000, 0x3d5901ee00000000, + 0xe9b3727500000000, 0x472bcb0300000000, 0x93c1b89800000000, + 0xaef85dee00000000, 0x7a122e7500000000, 0xf2c92e0300000000, + 0x26235d9800000000, 0x1b1ab8ee00000000, 0xcff0cb7500000000, + 0x6168720300000000, 0xb582019800000000, 0x88bbe4ee00000000, + 0x5c51977500000000, 0x3019ca0500000000, 0xe4f3b99e00000000, + 0xd9ca5ce800000000, 0x0d202f7300000000, 0xa3b8960500000000, + 0x7752e59e00000000, 0x4a6b00e800000000, 0x9e81737300000000, + 0x165a730500000000, 0xc2b0009e00000000, 0xff89e5e800000000, + 0x2b63967300000000, 0x85fb2f0500000000, 0x51115c9e00000000, + 0x6c28b9e800000000, 0xb8c2ca7300000000, 0x7c9fb80400000000, + 0xa875cb9f00000000, 0x954c2ee900000000, 0x41a65d7200000000, + 0xef3ee40400000000, 0x3bd4979f00000000, 0x06ed72e900000000, + 0xd207017200000000, 0x5adc010400000000, 0x8e36729f00000000, + 0xb30f97e900000000, 0x67e5e47200000000, 0xc97d5d0400000000, + 0x1d972e9f00000000, 0x20aecbe900000000, 0xf444b87200000000, + 0xa8152f0700000000, 0x7cff5c9c00000000, 0x41c6b9ea00000000, + 0x952cca7100000000, 0x3bb4730700000000, 0xef5e009c00000000, + 0xd267e5ea00000000, 0x068d967100000000, 0x8e56960700000000, + 0x5abce59c00000000, 0x678500ea00000000, 0xb36f737100000000, + 0x1df7ca0700000000, 0xc91db99c00000000, 0xf4245cea00000000, + 0x20ce2f7100000000, 0xe4935d0600000000, 0x30792e9d00000000, + 0x0d40cbeb00000000, 0xd9aab87000000000, 0x7732010600000000, + 0xa3d8729d00000000, 0x9ee197eb00000000, 0x4a0be47000000000, + 0xc2d0e40600000000, 0x163a979d00000000, 0x2b0372eb00000000, + 0xffe9017000000000, 0x5171b80600000000, 0x859bcb9d00000000, + 0xb8a22eeb00000000, 0x6c485d7000000000, 0x6032940b00000000, + 0xb4d8e79000000000, 0x89e102e600000000, 0x5d0b717d00000000, + 0xf393c80b00000000, 0x2779bb9000000000, 0x1a405ee600000000, + 0xceaa2d7d00000000, 0x46712d0b00000000, 0x929b5e9000000000, + 0xafa2bbe600000000, 0x7b48c87d00000000, 0xd5d0710b00000000, + 0x013a029000000000, 0x3c03e7e600000000, 0xe8e9947d00000000, + 0x2cb4e60a00000000, 0xf85e959100000000, 0xc56770e700000000, + 0x118d037c00000000, 0xbf15ba0a00000000, 0x6bffc99100000000, + 0x56c62ce700000000, 0x822c5f7c00000000, 0x0af75f0a00000000, + 0xde1d2c9100000000, 0xe324c9e700000000, 0x37ceba7c00000000, + 0x9956030a00000000, 0x4dbc709100000000, 0x708595e700000000, + 0xa46fe67c00000000, 0xf83e710900000000, 0x2cd4029200000000, + 0x11ede7e400000000, 0xc507947f00000000, 0x6b9f2d0900000000, + 0xbf755e9200000000, 0x824cbbe400000000, 0x56a6c87f00000000, + 0xde7dc80900000000, 0x0a97bb9200000000, 0x37ae5ee400000000, + 0xe3442d7f00000000, 0x4ddc940900000000, 0x9936e79200000000, + 0xa40f02e400000000, 0x70e5717f00000000, 0xb4b8030800000000, + 0x6052709300000000, 0x5d6b95e500000000, 0x8981e67e00000000, + 0x27195f0800000000, 0xf3f32c9300000000, 0xcecac9e500000000, + 0x1a20ba7e00000000, 0x92fbba0800000000, 0x4611c99300000000, + 0x7b282ce500000000, 0xafc25f7e00000000, 0x015ae60800000000, + 0xd5b0959300000000, 0xe88970e500000000, 0x3c63037e00000000, + 0x502b5e0e00000000, 0x84c12d9500000000, 0xb9f8c8e300000000, + 0x6d12bb7800000000, 0xc38a020e00000000, 0x1760719500000000, + 0x2a5994e300000000, 0xfeb3e77800000000, 0x7668e70e00000000, + 0xa282949500000000, 0x9fbb71e300000000, 0x4b51027800000000, + 0xe5c9bb0e00000000, 0x3123c89500000000, 0x0c1a2de300000000, + 0xd8f05e7800000000, 0x1cad2c0f00000000, 0xc8475f9400000000, + 0xf57ebae200000000, 0x2194c97900000000, 0x8f0c700f00000000, + 0x5be6039400000000, 0x66dfe6e200000000, 0xb235957900000000, + 0x3aee950f00000000, 0xee04e69400000000, 0xd33d03e200000000, + 0x07d7707900000000, 0xa94fc90f00000000, 0x7da5ba9400000000, + 0x409c5fe200000000, 0x94762c7900000000, 0xc827bb0c00000000, + 0x1ccdc89700000000, 0x21f42de100000000, 0xf51e5e7a00000000, + 0x5b86e70c00000000, 0x8f6c949700000000, 0xb25571e100000000, + 0x66bf027a00000000, 0xee64020c00000000, 0x3a8e719700000000, + 0x07b794e100000000, 0xd35de77a00000000, 0x7dc55e0c00000000, + 0xa92f2d9700000000, 0x9416c8e100000000, 0x40fcbb7a00000000, + 0x84a1c90d00000000, 0x504bba9600000000, 0x6d725fe000000000, + 0xb9982c7b00000000, 0x1700950d00000000, 0xc3eae69600000000, + 0xfed303e000000000, 0x2a39707b00000000, 0xa2e2700d00000000, + 0x7608039600000000, 0x4b31e6e000000000, 0x9fdb957b00000000, + 0x31432c0d00000000, 0xe5a95f9600000000, 0xd890bae000000000, + 0x0c7ac97b00000000}, + {0x0000000000000000, 0x2765258100000000, 0x0fcc3bd900000000, + 0x28a91e5800000000, 0x5f9e066900000000, 0x78fb23e800000000, + 0x50523db000000000, 0x7737183100000000, 0xbe3c0dd200000000, + 0x9959285300000000, 0xb1f0360b00000000, 0x9695138a00000000, + 0xe1a20bbb00000000, 0xc6c72e3a00000000, 0xee6e306200000000, + 0xc90b15e300000000, 0x3d7f6b7f00000000, 0x1a1a4efe00000000, + 0x32b350a600000000, 0x15d6752700000000, 0x62e16d1600000000, + 0x4584489700000000, 0x6d2d56cf00000000, 0x4a48734e00000000, + 0x834366ad00000000, 0xa426432c00000000, 0x8c8f5d7400000000, + 0xabea78f500000000, 0xdcdd60c400000000, 0xfbb8454500000000, + 0xd3115b1d00000000, 0xf4747e9c00000000, 0x7afed6fe00000000, + 0x5d9bf37f00000000, 0x7532ed2700000000, 0x5257c8a600000000, + 0x2560d09700000000, 0x0205f51600000000, 0x2aaceb4e00000000, + 0x0dc9cecf00000000, 0xc4c2db2c00000000, 0xe3a7fead00000000, + 0xcb0ee0f500000000, 0xec6bc57400000000, 0x9b5cdd4500000000, + 0xbc39f8c400000000, 0x9490e69c00000000, 0xb3f5c31d00000000, + 0x4781bd8100000000, 0x60e4980000000000, 0x484d865800000000, + 0x6f28a3d900000000, 0x181fbbe800000000, 0x3f7a9e6900000000, + 0x17d3803100000000, 0x30b6a5b000000000, 0xf9bdb05300000000, + 0xded895d200000000, 0xf6718b8a00000000, 0xd114ae0b00000000, + 0xa623b63a00000000, 0x814693bb00000000, 0xa9ef8de300000000, + 0x8e8aa86200000000, 0xb5fadc2600000000, 0x929ff9a700000000, + 0xba36e7ff00000000, 0x9d53c27e00000000, 0xea64da4f00000000, + 0xcd01ffce00000000, 0xe5a8e19600000000, 0xc2cdc41700000000, + 0x0bc6d1f400000000, 0x2ca3f47500000000, 0x040aea2d00000000, + 0x236fcfac00000000, 0x5458d79d00000000, 0x733df21c00000000, + 0x5b94ec4400000000, 0x7cf1c9c500000000, 0x8885b75900000000, + 0xafe092d800000000, 0x87498c8000000000, 0xa02ca90100000000, + 0xd71bb13000000000, 0xf07e94b100000000, 0xd8d78ae900000000, + 0xffb2af6800000000, 0x36b9ba8b00000000, 0x11dc9f0a00000000, + 0x3975815200000000, 0x1e10a4d300000000, 0x6927bce200000000, + 0x4e42996300000000, 0x66eb873b00000000, 0x418ea2ba00000000, + 0xcf040ad800000000, 0xe8612f5900000000, 0xc0c8310100000000, + 0xe7ad148000000000, 0x909a0cb100000000, 0xb7ff293000000000, + 0x9f56376800000000, 0xb83312e900000000, 0x7138070a00000000, + 0x565d228b00000000, 0x7ef43cd300000000, 0x5991195200000000, + 0x2ea6016300000000, 0x09c324e200000000, 0x216a3aba00000000, + 0x060f1f3b00000000, 0xf27b61a700000000, 0xd51e442600000000, + 0xfdb75a7e00000000, 0xdad27fff00000000, 0xade567ce00000000, + 0x8a80424f00000000, 0xa2295c1700000000, 0x854c799600000000, + 0x4c476c7500000000, 0x6b2249f400000000, 0x438b57ac00000000, + 0x64ee722d00000000, 0x13d96a1c00000000, 0x34bc4f9d00000000, + 0x1c1551c500000000, 0x3b70744400000000, 0x6af5b94d00000000, + 0x4d909ccc00000000, 0x6539829400000000, 0x425ca71500000000, + 0x356bbf2400000000, 0x120e9aa500000000, 0x3aa784fd00000000, + 0x1dc2a17c00000000, 0xd4c9b49f00000000, 0xf3ac911e00000000, + 0xdb058f4600000000, 0xfc60aac700000000, 0x8b57b2f600000000, + 0xac32977700000000, 0x849b892f00000000, 0xa3feacae00000000, + 0x578ad23200000000, 0x70eff7b300000000, 0x5846e9eb00000000, + 0x7f23cc6a00000000, 0x0814d45b00000000, 0x2f71f1da00000000, + 0x07d8ef8200000000, 0x20bdca0300000000, 0xe9b6dfe000000000, + 0xced3fa6100000000, 0xe67ae43900000000, 0xc11fc1b800000000, + 0xb628d98900000000, 0x914dfc0800000000, 0xb9e4e25000000000, + 0x9e81c7d100000000, 0x100b6fb300000000, 0x376e4a3200000000, + 0x1fc7546a00000000, 0x38a271eb00000000, 0x4f9569da00000000, + 0x68f04c5b00000000, 0x4059520300000000, 0x673c778200000000, + 0xae37626100000000, 0x895247e000000000, 0xa1fb59b800000000, + 0x869e7c3900000000, 0xf1a9640800000000, 0xd6cc418900000000, + 0xfe655fd100000000, 0xd9007a5000000000, 0x2d7404cc00000000, + 0x0a11214d00000000, 0x22b83f1500000000, 0x05dd1a9400000000, + 0x72ea02a500000000, 0x558f272400000000, 0x7d26397c00000000, + 0x5a431cfd00000000, 0x9348091e00000000, 0xb42d2c9f00000000, + 0x9c8432c700000000, 0xbbe1174600000000, 0xccd60f7700000000, + 0xebb32af600000000, 0xc31a34ae00000000, 0xe47f112f00000000, + 0xdf0f656b00000000, 0xf86a40ea00000000, 0xd0c35eb200000000, + 0xf7a67b3300000000, 0x8091630200000000, 0xa7f4468300000000, + 0x8f5d58db00000000, 0xa8387d5a00000000, 0x613368b900000000, + 0x46564d3800000000, 0x6eff536000000000, 0x499a76e100000000, + 0x3ead6ed000000000, 0x19c84b5100000000, 0x3161550900000000, + 0x1604708800000000, 0xe2700e1400000000, 0xc5152b9500000000, + 0xedbc35cd00000000, 0xcad9104c00000000, 0xbdee087d00000000, + 0x9a8b2dfc00000000, 0xb22233a400000000, 0x9547162500000000, + 0x5c4c03c600000000, 0x7b29264700000000, 0x5380381f00000000, + 0x74e51d9e00000000, 0x03d205af00000000, 0x24b7202e00000000, + 0x0c1e3e7600000000, 0x2b7b1bf700000000, 0xa5f1b39500000000, + 0x8294961400000000, 0xaa3d884c00000000, 0x8d58adcd00000000, + 0xfa6fb5fc00000000, 0xdd0a907d00000000, 0xf5a38e2500000000, + 0xd2c6aba400000000, 0x1bcdbe4700000000, 0x3ca89bc600000000, + 0x1401859e00000000, 0x3364a01f00000000, 0x4453b82e00000000, + 0x63369daf00000000, 0x4b9f83f700000000, 0x6cfaa67600000000, + 0x988ed8ea00000000, 0xbfebfd6b00000000, 0x9742e33300000000, + 0xb027c6b200000000, 0xc710de8300000000, 0xe075fb0200000000, + 0xc8dce55a00000000, 0xefb9c0db00000000, 0x26b2d53800000000, + 0x01d7f0b900000000, 0x297eeee100000000, 0x0e1bcb6000000000, + 0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000, + 0x5185cd0900000000}}; + +#else /* W == 4 */ + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d, + 0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac, + 0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8, + 0xd1cfb9df, 0x7142c0ac, 0x3256bbbb, 0xf76a3682, 0xb47e4d95, + 0x7d132cf1, 0x3e0757e6, 0xfb3bdadf, 0xb82fa1c8, 0x69e01817, + 0x2af46300, 0xefc8ee39, 0xacdc952e, 0x65b1f44a, 0x26a58f5d, + 0xe3990264, 0xa08d7973, 0xa382f182, 0xe0968a95, 0x25aa07ac, + 0x66be7cbb, 0xafd31ddf, 0xecc766c8, 0x29fbebf1, 0x6aef90e6, + 0xbb202939, 0xf834522e, 0x3d08df17, 0x7e1ca400, 0xb771c564, + 0xf465be73, 0x3159334a, 0x724d485d, 0xd2c0312e, 0x91d44a39, + 0x54e8c700, 0x17fcbc17, 0xde91dd73, 0x9d85a664, 0x58b92b5d, + 0x1bad504a, 0xca62e995, 0x89769282, 0x4c4a1fbb, 0x0f5e64ac, + 0xc63305c8, 0x85277edf, 0x401bf3e6, 0x030f88f1, 0x070392de, + 0x4417e9c9, 0x812b64f0, 0xc23f1fe7, 0x0b527e83, 0x48460594, + 0x8d7a88ad, 0xce6ef3ba, 0x1fa14a65, 0x5cb53172, 0x9989bc4b, + 0xda9dc75c, 0x13f0a638, 0x50e4dd2f, 0x95d85016, 0xd6cc2b01, + 0x76415272, 0x35552965, 0xf069a45c, 0xb37ddf4b, 0x7a10be2f, + 0x3904c538, 0xfc384801, 0xbf2c3316, 0x6ee38ac9, 0x2df7f1de, + 0xe8cb7ce7, 0xabdf07f0, 0x62b26694, 0x21a61d83, 0xe49a90ba, + 0xa78eebad, 0xa481635c, 0xe795184b, 0x22a99572, 0x61bdee65, + 0xa8d08f01, 0xebc4f416, 0x2ef8792f, 0x6dec0238, 0xbc23bbe7, + 0xff37c0f0, 0x3a0b4dc9, 0x791f36de, 0xb07257ba, 0xf3662cad, + 0x365aa194, 0x754eda83, 0xd5c3a3f0, 0x96d7d8e7, 0x53eb55de, + 0x10ff2ec9, 0xd9924fad, 0x9a8634ba, 0x5fbab983, 0x1caec294, + 0xcd617b4b, 0x8e75005c, 0x4b498d65, 0x085df672, 0xc1309716, + 0x8224ec01, 0x47186138, 0x040c1a2f, 0x4f005566, 0x0c142e71, + 0xc928a348, 0x8a3cd85f, 0x4351b93b, 0x0045c22c, 0xc5794f15, + 0x866d3402, 0x57a28ddd, 0x14b6f6ca, 0xd18a7bf3, 0x929e00e4, + 0x5bf36180, 0x18e71a97, 0xdddb97ae, 0x9ecfecb9, 0x3e4295ca, + 0x7d56eedd, 0xb86a63e4, 0xfb7e18f3, 0x32137997, 0x71070280, + 0xb43b8fb9, 0xf72ff4ae, 0x26e04d71, 0x65f43666, 0xa0c8bb5f, + 0xe3dcc048, 0x2ab1a12c, 0x69a5da3b, 0xac995702, 0xef8d2c15, + 0xec82a4e4, 0xaf96dff3, 0x6aaa52ca, 0x29be29dd, 0xe0d348b9, + 0xa3c733ae, 0x66fbbe97, 0x25efc580, 0xf4207c5f, 0xb7340748, + 0x72088a71, 0x311cf166, 0xf8719002, 0xbb65eb15, 0x7e59662c, + 0x3d4d1d3b, 0x9dc06448, 0xded41f5f, 0x1be89266, 0x58fce971, + 0x91918815, 0xd285f302, 0x17b97e3b, 0x54ad052c, 0x8562bcf3, + 0xc676c7e4, 0x034a4add, 0x405e31ca, 0x893350ae, 0xca272bb9, + 0x0f1ba680, 0x4c0fdd97, 0x4803c7b8, 0x0b17bcaf, 0xce2b3196, + 0x8d3f4a81, 0x44522be5, 0x074650f2, 0xc27addcb, 0x816ea6dc, + 0x50a11f03, 0x13b56414, 0xd689e92d, 0x959d923a, 0x5cf0f35e, + 0x1fe48849, 0xdad80570, 0x99cc7e67, 0x39410714, 0x7a557c03, + 0xbf69f13a, 0xfc7d8a2d, 0x3510eb49, 0x7604905e, 0xb3381d67, + 0xf02c6670, 0x21e3dfaf, 0x62f7a4b8, 0xa7cb2981, 0xe4df5296, + 0x2db233f2, 0x6ea648e5, 0xab9ac5dc, 0xe88ebecb, 0xeb81363a, + 0xa8954d2d, 0x6da9c014, 0x2ebdbb03, 0xe7d0da67, 0xa4c4a170, + 0x61f82c49, 0x22ec575e, 0xf323ee81, 0xb0379596, 0x750b18af, + 0x361f63b8, 0xff7202dc, 0xbc6679cb, 0x795af4f2, 0x3a4e8fe5, + 0x9ac3f696, 0xd9d78d81, 0x1ceb00b8, 0x5fff7baf, 0x96921acb, + 0xd58661dc, 0x10baece5, 0x53ae97f2, 0x82612e2d, 0xc175553a, + 0x0449d803, 0x475da314, 0x8e30c270, 0xcd24b967, 0x0818345e, + 0x4b0c4f49}, + {0x00000000, 0x3e6bc2ef, 0x3dd0f504, 0x03bb37eb, 0x7aa0eb09, + 0x44cb29e6, 0x47701e0d, 0x791bdce2, 0xf440d713, 0xca2b15fc, + 0xc9902217, 0xf7fbe0f8, 0x8ee03c1a, 0xb08bfef5, 0xb330c91e, + 0x8d5b0bf1, 0xe881ae27, 0xd6ea6cc8, 0xd5515b23, 0xeb3a99cc, + 0x9221452e, 0xac4a87c1, 0xaff1b02a, 0x919a72c5, 0x1cc17934, + 0x22aabbdb, 0x21118c30, 0x1f7a4edf, 0x6661923d, 0x580a50d2, + 0x5bb16739, 0x65daa5d6, 0xd0035d4f, 0xee689fa0, 0xedd3a84b, + 0xd3b86aa4, 0xaaa3b646, 0x94c874a9, 0x97734342, 0xa91881ad, + 0x24438a5c, 0x1a2848b3, 0x19937f58, 0x27f8bdb7, 0x5ee36155, + 0x6088a3ba, 0x63339451, 0x5d5856be, 0x3882f368, 0x06e93187, + 0x0552066c, 0x3b39c483, 0x42221861, 0x7c49da8e, 0x7ff2ed65, + 0x41992f8a, 0xccc2247b, 0xf2a9e694, 0xf112d17f, 0xcf791390, + 0xb662cf72, 0x88090d9d, 0x8bb23a76, 0xb5d9f899, 0xa007ba9e, + 0x9e6c7871, 0x9dd74f9a, 0xa3bc8d75, 0xdaa75197, 0xe4cc9378, + 0xe777a493, 0xd91c667c, 0x54476d8d, 0x6a2caf62, 0x69979889, + 0x57fc5a66, 0x2ee78684, 0x108c446b, 0x13377380, 0x2d5cb16f, + 0x488614b9, 0x76edd656, 0x7556e1bd, 0x4b3d2352, 0x3226ffb0, + 0x0c4d3d5f, 0x0ff60ab4, 0x319dc85b, 0xbcc6c3aa, 0x82ad0145, + 0x811636ae, 0xbf7df441, 0xc66628a3, 0xf80dea4c, 0xfbb6dda7, + 0xc5dd1f48, 0x7004e7d1, 0x4e6f253e, 0x4dd412d5, 0x73bfd03a, + 0x0aa40cd8, 0x34cfce37, 0x3774f9dc, 0x091f3b33, 0x844430c2, + 0xba2ff22d, 0xb994c5c6, 0x87ff0729, 0xfee4dbcb, 0xc08f1924, + 0xc3342ecf, 0xfd5fec20, 0x988549f6, 0xa6ee8b19, 0xa555bcf2, + 0x9b3e7e1d, 0xe225a2ff, 0xdc4e6010, 0xdff557fb, 0xe19e9514, + 0x6cc59ee5, 0x52ae5c0a, 0x51156be1, 0x6f7ea90e, 0x166575ec, + 0x280eb703, 0x2bb580e8, 0x15de4207, 0x010905e6, 0x3f62c709, + 0x3cd9f0e2, 0x02b2320d, 0x7ba9eeef, 0x45c22c00, 0x46791beb, + 0x7812d904, 0xf549d2f5, 0xcb22101a, 0xc89927f1, 0xf6f2e51e, + 0x8fe939fc, 0xb182fb13, 0xb239ccf8, 0x8c520e17, 0xe988abc1, + 0xd7e3692e, 0xd4585ec5, 0xea339c2a, 0x932840c8, 0xad438227, + 0xaef8b5cc, 0x90937723, 0x1dc87cd2, 0x23a3be3d, 0x201889d6, + 0x1e734b39, 0x676897db, 0x59035534, 0x5ab862df, 0x64d3a030, + 0xd10a58a9, 0xef619a46, 0xecdaadad, 0xd2b16f42, 0xabaab3a0, + 0x95c1714f, 0x967a46a4, 0xa811844b, 0x254a8fba, 0x1b214d55, + 0x189a7abe, 0x26f1b851, 0x5fea64b3, 0x6181a65c, 0x623a91b7, + 0x5c515358, 0x398bf68e, 0x07e03461, 0x045b038a, 0x3a30c165, + 0x432b1d87, 0x7d40df68, 0x7efbe883, 0x40902a6c, 0xcdcb219d, + 0xf3a0e372, 0xf01bd499, 0xce701676, 0xb76bca94, 0x8900087b, + 0x8abb3f90, 0xb4d0fd7f, 0xa10ebf78, 0x9f657d97, 0x9cde4a7c, + 0xa2b58893, 0xdbae5471, 0xe5c5969e, 0xe67ea175, 0xd815639a, + 0x554e686b, 0x6b25aa84, 0x689e9d6f, 0x56f55f80, 0x2fee8362, + 0x1185418d, 0x123e7666, 0x2c55b489, 0x498f115f, 0x77e4d3b0, + 0x745fe45b, 0x4a3426b4, 0x332ffa56, 0x0d4438b9, 0x0eff0f52, + 0x3094cdbd, 0xbdcfc64c, 0x83a404a3, 0x801f3348, 0xbe74f1a7, + 0xc76f2d45, 0xf904efaa, 0xfabfd841, 0xc4d41aae, 0x710de237, + 0x4f6620d8, 0x4cdd1733, 0x72b6d5dc, 0x0bad093e, 0x35c6cbd1, + 0x367dfc3a, 0x08163ed5, 0x854d3524, 0xbb26f7cb, 0xb89dc020, + 0x86f602cf, 0xffedde2d, 0xc1861cc2, 0xc23d2b29, 0xfc56e9c6, + 0x998c4c10, 0xa7e78eff, 0xa45cb914, 0x9a377bfb, 0xe32ca719, + 0xdd4765f6, 0xdefc521d, 0xe09790f2, 0x6dcc9b03, 0x53a759ec, + 0x501c6e07, 0x6e77ace8, 0x176c700a, 0x2907b2e5, 0x2abc850e, + 0x14d747e1}, + {0x00000000, 0xc0df8ec1, 0xc1b96c58, 0x0166e299, 0x8273d9b0, + 0x42ac5771, 0x43cab5e8, 0x83153b29, 0x45e1c3ba, 0x853e4d7b, + 0x8458afe2, 0x44872123, 0xc7921a0a, 0x074d94cb, 0x062b7652, + 0xc6f4f893, 0xcbc4f6ae, 0x0b1b786f, 0x0a7d9af6, 0xcaa21437, + 0x49b72f1e, 0x8968a1df, 0x880e4346, 0x48d1cd87, 0x8e253514, + 0x4efabbd5, 0x4f9c594c, 0x8f43d78d, 0x0c56eca4, 0xcc896265, + 0xcdef80fc, 0x0d300e3d, 0xd78f9c86, 0x17501247, 0x1636f0de, + 0xd6e97e1f, 0x55fc4536, 0x9523cbf7, 0x9445296e, 0x549aa7af, + 0x926e5f3c, 0x52b1d1fd, 0x53d73364, 0x9308bda5, 0x101d868c, + 0xd0c2084d, 0xd1a4ead4, 0x117b6415, 0x1c4b6a28, 0xdc94e4e9, + 0xddf20670, 0x1d2d88b1, 0x9e38b398, 0x5ee73d59, 0x5f81dfc0, + 0x9f5e5101, 0x59aaa992, 0x99752753, 0x9813c5ca, 0x58cc4b0b, + 0xdbd97022, 0x1b06fee3, 0x1a601c7a, 0xdabf92bb, 0xef1948d6, + 0x2fc6c617, 0x2ea0248e, 0xee7faa4f, 0x6d6a9166, 0xadb51fa7, + 0xacd3fd3e, 0x6c0c73ff, 0xaaf88b6c, 0x6a2705ad, 0x6b41e734, + 0xab9e69f5, 0x288b52dc, 0xe854dc1d, 0xe9323e84, 0x29edb045, + 0x24ddbe78, 0xe40230b9, 0xe564d220, 0x25bb5ce1, 0xa6ae67c8, + 0x6671e909, 0x67170b90, 0xa7c88551, 0x613c7dc2, 0xa1e3f303, + 0xa085119a, 0x605a9f5b, 0xe34fa472, 0x23902ab3, 0x22f6c82a, + 0xe22946eb, 0x3896d450, 0xf8495a91, 0xf92fb808, 0x39f036c9, + 0xbae50de0, 0x7a3a8321, 0x7b5c61b8, 0xbb83ef79, 0x7d7717ea, + 0xbda8992b, 0xbcce7bb2, 0x7c11f573, 0xff04ce5a, 0x3fdb409b, + 0x3ebda202, 0xfe622cc3, 0xf35222fe, 0x338dac3f, 0x32eb4ea6, + 0xf234c067, 0x7121fb4e, 0xb1fe758f, 0xb0989716, 0x704719d7, + 0xb6b3e144, 0x766c6f85, 0x770a8d1c, 0xb7d503dd, 0x34c038f4, + 0xf41fb635, 0xf57954ac, 0x35a6da6d, 0x9f35e177, 0x5fea6fb6, + 0x5e8c8d2f, 0x9e5303ee, 0x1d4638c7, 0xdd99b606, 0xdcff549f, + 0x1c20da5e, 0xdad422cd, 0x1a0bac0c, 0x1b6d4e95, 0xdbb2c054, + 0x58a7fb7d, 0x987875bc, 0x991e9725, 0x59c119e4, 0x54f117d9, + 0x942e9918, 0x95487b81, 0x5597f540, 0xd682ce69, 0x165d40a8, + 0x173ba231, 0xd7e42cf0, 0x1110d463, 0xd1cf5aa2, 0xd0a9b83b, + 0x107636fa, 0x93630dd3, 0x53bc8312, 0x52da618b, 0x9205ef4a, + 0x48ba7df1, 0x8865f330, 0x890311a9, 0x49dc9f68, 0xcac9a441, + 0x0a162a80, 0x0b70c819, 0xcbaf46d8, 0x0d5bbe4b, 0xcd84308a, + 0xcce2d213, 0x0c3d5cd2, 0x8f2867fb, 0x4ff7e93a, 0x4e910ba3, + 0x8e4e8562, 0x837e8b5f, 0x43a1059e, 0x42c7e707, 0x821869c6, + 0x010d52ef, 0xc1d2dc2e, 0xc0b43eb7, 0x006bb076, 0xc69f48e5, + 0x0640c624, 0x072624bd, 0xc7f9aa7c, 0x44ec9155, 0x84331f94, + 0x8555fd0d, 0x458a73cc, 0x702ca9a1, 0xb0f32760, 0xb195c5f9, + 0x714a4b38, 0xf25f7011, 0x3280fed0, 0x33e61c49, 0xf3399288, + 0x35cd6a1b, 0xf512e4da, 0xf4740643, 0x34ab8882, 0xb7beb3ab, + 0x77613d6a, 0x7607dff3, 0xb6d85132, 0xbbe85f0f, 0x7b37d1ce, + 0x7a513357, 0xba8ebd96, 0x399b86bf, 0xf944087e, 0xf822eae7, + 0x38fd6426, 0xfe099cb5, 0x3ed61274, 0x3fb0f0ed, 0xff6f7e2c, + 0x7c7a4505, 0xbca5cbc4, 0xbdc3295d, 0x7d1ca79c, 0xa7a33527, + 0x677cbbe6, 0x661a597f, 0xa6c5d7be, 0x25d0ec97, 0xe50f6256, + 0xe46980cf, 0x24b60e0e, 0xe242f69d, 0x229d785c, 0x23fb9ac5, + 0xe3241404, 0x60312f2d, 0xa0eea1ec, 0xa1884375, 0x6157cdb4, + 0x6c67c389, 0xacb84d48, 0xaddeafd1, 0x6d012110, 0xee141a39, + 0x2ecb94f8, 0x2fad7661, 0xef72f8a0, 0x29860033, 0xe9598ef2, + 0xe83f6c6b, 0x28e0e2aa, 0xabf5d983, 0x6b2a5742, 0x6a4cb5db, + 0xaa933b1a}, + {0x00000000, 0x6f4ca59b, 0x9f9e3bec, 0xf0d29e77, 0x7f3b0603, + 0x1077a398, 0xe0a53def, 0x8fe99874, 0xfe760c06, 0x913aa99d, + 0x61e837ea, 0x0ea49271, 0x814d0a05, 0xee01af9e, 0x1ed331e9, + 0x719f9472, 0xfced180c, 0x93a1bd97, 0x637323e0, 0x0c3f867b, + 0x83d61e0f, 0xec9abb94, 0x1c4825e3, 0x73048078, 0x029b140a, + 0x6dd7b191, 0x9d052fe6, 0xf2498a7d, 0x7da01209, 0x12ecb792, + 0xe23e29e5, 0x8d728c7e, 0xf8db3118, 0x97979483, 0x67450af4, + 0x0809af6f, 0x87e0371b, 0xe8ac9280, 0x187e0cf7, 0x7732a96c, + 0x06ad3d1e, 0x69e19885, 0x993306f2, 0xf67fa369, 0x79963b1d, + 0x16da9e86, 0xe60800f1, 0x8944a56a, 0x04362914, 0x6b7a8c8f, + 0x9ba812f8, 0xf4e4b763, 0x7b0d2f17, 0x14418a8c, 0xe49314fb, + 0x8bdfb160, 0xfa402512, 0x950c8089, 0x65de1efe, 0x0a92bb65, + 0x857b2311, 0xea37868a, 0x1ae518fd, 0x75a9bd66, 0xf0b76330, + 0x9ffbc6ab, 0x6f2958dc, 0x0065fd47, 0x8f8c6533, 0xe0c0c0a8, + 0x10125edf, 0x7f5efb44, 0x0ec16f36, 0x618dcaad, 0x915f54da, + 0xfe13f141, 0x71fa6935, 0x1eb6ccae, 0xee6452d9, 0x8128f742, + 0x0c5a7b3c, 0x6316dea7, 0x93c440d0, 0xfc88e54b, 0x73617d3f, + 0x1c2dd8a4, 0xecff46d3, 0x83b3e348, 0xf22c773a, 0x9d60d2a1, + 0x6db24cd6, 0x02fee94d, 0x8d177139, 0xe25bd4a2, 0x12894ad5, + 0x7dc5ef4e, 0x086c5228, 0x6720f7b3, 0x97f269c4, 0xf8becc5f, + 0x7757542b, 0x181bf1b0, 0xe8c96fc7, 0x8785ca5c, 0xf61a5e2e, + 0x9956fbb5, 0x698465c2, 0x06c8c059, 0x8921582d, 0xe66dfdb6, + 0x16bf63c1, 0x79f3c65a, 0xf4814a24, 0x9bcdefbf, 0x6b1f71c8, + 0x0453d453, 0x8bba4c27, 0xe4f6e9bc, 0x142477cb, 0x7b68d250, + 0x0af74622, 0x65bbe3b9, 0x95697dce, 0xfa25d855, 0x75cc4021, + 0x1a80e5ba, 0xea527bcd, 0x851ede56, 0xe06fc760, 0x8f2362fb, + 0x7ff1fc8c, 0x10bd5917, 0x9f54c163, 0xf01864f8, 0x00cafa8f, + 0x6f865f14, 0x1e19cb66, 0x71556efd, 0x8187f08a, 0xeecb5511, + 0x6122cd65, 0x0e6e68fe, 0xfebcf689, 0x91f05312, 0x1c82df6c, + 0x73ce7af7, 0x831ce480, 0xec50411b, 0x63b9d96f, 0x0cf57cf4, + 0xfc27e283, 0x936b4718, 0xe2f4d36a, 0x8db876f1, 0x7d6ae886, + 0x12264d1d, 0x9dcfd569, 0xf28370f2, 0x0251ee85, 0x6d1d4b1e, + 0x18b4f678, 0x77f853e3, 0x872acd94, 0xe866680f, 0x678ff07b, + 0x08c355e0, 0xf811cb97, 0x975d6e0c, 0xe6c2fa7e, 0x898e5fe5, + 0x795cc192, 0x16106409, 0x99f9fc7d, 0xf6b559e6, 0x0667c791, + 0x692b620a, 0xe459ee74, 0x8b154bef, 0x7bc7d598, 0x148b7003, + 0x9b62e877, 0xf42e4dec, 0x04fcd39b, 0x6bb07600, 0x1a2fe272, + 0x756347e9, 0x85b1d99e, 0xeafd7c05, 0x6514e471, 0x0a5841ea, + 0xfa8adf9d, 0x95c67a06, 0x10d8a450, 0x7f9401cb, 0x8f469fbc, + 0xe00a3a27, 0x6fe3a253, 0x00af07c8, 0xf07d99bf, 0x9f313c24, + 0xeeaea856, 0x81e20dcd, 0x713093ba, 0x1e7c3621, 0x9195ae55, + 0xfed90bce, 0x0e0b95b9, 0x61473022, 0xec35bc5c, 0x837919c7, + 0x73ab87b0, 0x1ce7222b, 0x930eba5f, 0xfc421fc4, 0x0c9081b3, + 0x63dc2428, 0x1243b05a, 0x7d0f15c1, 0x8ddd8bb6, 0xe2912e2d, + 0x6d78b659, 0x023413c2, 0xf2e68db5, 0x9daa282e, 0xe8039548, + 0x874f30d3, 0x779daea4, 0x18d10b3f, 0x9738934b, 0xf87436d0, + 0x08a6a8a7, 0x67ea0d3c, 0x1675994e, 0x79393cd5, 0x89eba2a2, + 0xe6a70739, 0x694e9f4d, 0x06023ad6, 0xf6d0a4a1, 0x999c013a, + 0x14ee8d44, 0x7ba228df, 0x8b70b6a8, 0xe43c1333, 0x6bd58b47, + 0x04992edc, 0xf44bb0ab, 0x9b071530, 0xea988142, 0x85d424d9, + 0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad, + 0x65711936}}; + +#endif /* W */ + +#endif /* N == 3 */ +#if N == 4 + +#if W == 8 + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a, + 0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe, + 0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b, + 0x5b8126c1, 0x1d596ee9, 0xec836b43, 0x259c63fc, 0xd4466656, + 0x6cd374c3, 0x9d097169, 0x541679d6, 0xa5cc7c7c, 0xfe4d5abd, + 0x0f975f17, 0xc68857a8, 0x37525202, 0x8fc74097, 0x7e1d453d, + 0xb7024d82, 0x46d84828, 0x3ab2ddd2, 0xcb68d878, 0x0277d0c7, + 0xf3add56d, 0x4b38c7f8, 0xbae2c252, 0x73fdcaed, 0x8227cf47, + 0xd9a6e986, 0x287cec2c, 0xe163e493, 0x10b9e139, 0xa82cf3ac, + 0x59f6f606, 0x90e9feb9, 0x6133fb13, 0x27ebb33b, 0xd631b691, + 0x1f2ebe2e, 0xeef4bb84, 0x5661a911, 0xa7bbacbb, 0x6ea4a404, + 0x9f7ea1ae, 0xc4ff876f, 0x352582c5, 0xfc3a8a7a, 0x0de08fd0, + 0xb5759d45, 0x44af98ef, 0x8db09050, 0x7c6a95fa, 0x7565bba4, + 0x84bfbe0e, 0x4da0b6b1, 0xbc7ab31b, 0x04efa18e, 0xf535a424, + 0x3c2aac9b, 0xcdf0a931, 0x96718ff0, 0x67ab8a5a, 0xaeb482e5, + 0x5f6e874f, 0xe7fb95da, 0x16219070, 0xdf3e98cf, 0x2ee49d65, + 0x683cd54d, 0x99e6d0e7, 0x50f9d858, 0xa123ddf2, 0x19b6cf67, + 0xe86ccacd, 0x2173c272, 0xd0a9c7d8, 0x8b28e119, 0x7af2e4b3, + 0xb3edec0c, 0x4237e9a6, 0xfaa2fb33, 0x0b78fe99, 0xc267f626, + 0x33bdf38c, 0x4fd76676, 0xbe0d63dc, 0x77126b63, 0x86c86ec9, + 0x3e5d7c5c, 0xcf8779f6, 0x06987149, 0xf74274e3, 0xacc35222, + 0x5d195788, 0x94065f37, 0x65dc5a9d, 0xdd494808, 0x2c934da2, + 0xe58c451d, 0x145640b7, 0x528e089f, 0xa3540d35, 0x6a4b058a, + 0x9b910020, 0x230412b5, 0xd2de171f, 0x1bc11fa0, 0xea1b1a0a, + 0xb19a3ccb, 0x40403961, 0x895f31de, 0x78853474, 0xc01026e1, + 0x31ca234b, 0xf8d52bf4, 0x090f2e5e, 0xeacb7748, 0x1b1172e2, + 0xd20e7a5d, 0x23d47ff7, 0x9b416d62, 0x6a9b68c8, 0xa3846077, + 0x525e65dd, 0x09df431c, 0xf80546b6, 0x311a4e09, 0xc0c04ba3, + 0x78555936, 0x898f5c9c, 0x40905423, 0xb14a5189, 0xf79219a1, + 0x06481c0b, 0xcf5714b4, 0x3e8d111e, 0x8618038b, 0x77c20621, + 0xbedd0e9e, 0x4f070b34, 0x14862df5, 0xe55c285f, 0x2c4320e0, + 0xdd99254a, 0x650c37df, 0x94d63275, 0x5dc93aca, 0xac133f60, + 0xd079aa9a, 0x21a3af30, 0xe8bca78f, 0x1966a225, 0xa1f3b0b0, + 0x5029b51a, 0x9936bda5, 0x68ecb80f, 0x336d9ece, 0xc2b79b64, + 0x0ba893db, 0xfa729671, 0x42e784e4, 0xb33d814e, 0x7a2289f1, + 0x8bf88c5b, 0xcd20c473, 0x3cfac1d9, 0xf5e5c966, 0x043fcccc, + 0xbcaade59, 0x4d70dbf3, 0x846fd34c, 0x75b5d6e6, 0x2e34f027, + 0xdfeef58d, 0x16f1fd32, 0xe72bf898, 0x5fbeea0d, 0xae64efa7, + 0x677be718, 0x96a1e2b2, 0x9faeccec, 0x6e74c946, 0xa76bc1f9, + 0x56b1c453, 0xee24d6c6, 0x1ffed36c, 0xd6e1dbd3, 0x273bde79, + 0x7cbaf8b8, 0x8d60fd12, 0x447ff5ad, 0xb5a5f007, 0x0d30e292, + 0xfceae738, 0x35f5ef87, 0xc42fea2d, 0x82f7a205, 0x732da7af, + 0xba32af10, 0x4be8aaba, 0xf37db82f, 0x02a7bd85, 0xcbb8b53a, + 0x3a62b090, 0x61e39651, 0x903993fb, 0x59269b44, 0xa8fc9eee, + 0x10698c7b, 0xe1b389d1, 0x28ac816e, 0xd97684c4, 0xa51c113e, + 0x54c61494, 0x9dd91c2b, 0x6c031981, 0xd4960b14, 0x254c0ebe, + 0xec530601, 0x1d8903ab, 0x4608256a, 0xb7d220c0, 0x7ecd287f, + 0x8f172dd5, 0x37823f40, 0xc6583aea, 0x0f473255, 0xfe9d37ff, + 0xb8457fd7, 0x499f7a7d, 0x808072c2, 0x715a7768, 0xc9cf65fd, + 0x38156057, 0xf10a68e8, 0x00d06d42, 0x5b514b83, 0xaa8b4e29, + 0x63944696, 0x924e433c, 0x2adb51a9, 0xdb015403, 0x121e5cbc, + 0xe3c45916}, + {0x00000000, 0x0ee7e8d1, 0x1dcfd1a2, 0x13283973, 0x3b9fa344, + 0x35784b95, 0x265072e6, 0x28b79a37, 0x773f4688, 0x79d8ae59, + 0x6af0972a, 0x64177ffb, 0x4ca0e5cc, 0x42470d1d, 0x516f346e, + 0x5f88dcbf, 0xee7e8d10, 0xe09965c1, 0xf3b15cb2, 0xfd56b463, + 0xd5e12e54, 0xdb06c685, 0xc82efff6, 0xc6c91727, 0x9941cb98, + 0x97a62349, 0x848e1a3a, 0x8a69f2eb, 0xa2de68dc, 0xac39800d, + 0xbf11b97e, 0xb1f651af, 0x078c1c61, 0x096bf4b0, 0x1a43cdc3, + 0x14a42512, 0x3c13bf25, 0x32f457f4, 0x21dc6e87, 0x2f3b8656, + 0x70b35ae9, 0x7e54b238, 0x6d7c8b4b, 0x639b639a, 0x4b2cf9ad, + 0x45cb117c, 0x56e3280f, 0x5804c0de, 0xe9f29171, 0xe71579a0, + 0xf43d40d3, 0xfadaa802, 0xd26d3235, 0xdc8adae4, 0xcfa2e397, + 0xc1450b46, 0x9ecdd7f9, 0x902a3f28, 0x8302065b, 0x8de5ee8a, + 0xa55274bd, 0xabb59c6c, 0xb89da51f, 0xb67a4dce, 0x0f1838c2, + 0x01ffd013, 0x12d7e960, 0x1c3001b1, 0x34879b86, 0x3a607357, + 0x29484a24, 0x27afa2f5, 0x78277e4a, 0x76c0969b, 0x65e8afe8, + 0x6b0f4739, 0x43b8dd0e, 0x4d5f35df, 0x5e770cac, 0x5090e47d, + 0xe166b5d2, 0xef815d03, 0xfca96470, 0xf24e8ca1, 0xdaf91696, + 0xd41efe47, 0xc736c734, 0xc9d12fe5, 0x9659f35a, 0x98be1b8b, + 0x8b9622f8, 0x8571ca29, 0xadc6501e, 0xa321b8cf, 0xb00981bc, + 0xbeee696d, 0x089424a3, 0x0673cc72, 0x155bf501, 0x1bbc1dd0, + 0x330b87e7, 0x3dec6f36, 0x2ec45645, 0x2023be94, 0x7fab622b, + 0x714c8afa, 0x6264b389, 0x6c835b58, 0x4434c16f, 0x4ad329be, + 0x59fb10cd, 0x571cf81c, 0xe6eaa9b3, 0xe80d4162, 0xfb257811, + 0xf5c290c0, 0xdd750af7, 0xd392e226, 0xc0badb55, 0xce5d3384, + 0x91d5ef3b, 0x9f3207ea, 0x8c1a3e99, 0x82fdd648, 0xaa4a4c7f, + 0xa4ada4ae, 0xb7859ddd, 0xb962750c, 0x1e307184, 0x10d79955, + 0x03ffa026, 0x0d1848f7, 0x25afd2c0, 0x2b483a11, 0x38600362, + 0x3687ebb3, 0x690f370c, 0x67e8dfdd, 0x74c0e6ae, 0x7a270e7f, + 0x52909448, 0x5c777c99, 0x4f5f45ea, 0x41b8ad3b, 0xf04efc94, + 0xfea91445, 0xed812d36, 0xe366c5e7, 0xcbd15fd0, 0xc536b701, + 0xd61e8e72, 0xd8f966a3, 0x8771ba1c, 0x899652cd, 0x9abe6bbe, + 0x9459836f, 0xbcee1958, 0xb209f189, 0xa121c8fa, 0xafc6202b, + 0x19bc6de5, 0x175b8534, 0x0473bc47, 0x0a945496, 0x2223cea1, + 0x2cc42670, 0x3fec1f03, 0x310bf7d2, 0x6e832b6d, 0x6064c3bc, + 0x734cfacf, 0x7dab121e, 0x551c8829, 0x5bfb60f8, 0x48d3598b, + 0x4634b15a, 0xf7c2e0f5, 0xf9250824, 0xea0d3157, 0xe4ead986, + 0xcc5d43b1, 0xc2baab60, 0xd1929213, 0xdf757ac2, 0x80fda67d, + 0x8e1a4eac, 0x9d3277df, 0x93d59f0e, 0xbb620539, 0xb585ede8, + 0xa6add49b, 0xa84a3c4a, 0x11284946, 0x1fcfa197, 0x0ce798e4, + 0x02007035, 0x2ab7ea02, 0x245002d3, 0x37783ba0, 0x399fd371, + 0x66170fce, 0x68f0e71f, 0x7bd8de6c, 0x753f36bd, 0x5d88ac8a, + 0x536f445b, 0x40477d28, 0x4ea095f9, 0xff56c456, 0xf1b12c87, + 0xe29915f4, 0xec7efd25, 0xc4c96712, 0xca2e8fc3, 0xd906b6b0, + 0xd7e15e61, 0x886982de, 0x868e6a0f, 0x95a6537c, 0x9b41bbad, + 0xb3f6219a, 0xbd11c94b, 0xae39f038, 0xa0de18e9, 0x16a45527, + 0x1843bdf6, 0x0b6b8485, 0x058c6c54, 0x2d3bf663, 0x23dc1eb2, + 0x30f427c1, 0x3e13cf10, 0x619b13af, 0x6f7cfb7e, 0x7c54c20d, + 0x72b32adc, 0x5a04b0eb, 0x54e3583a, 0x47cb6149, 0x492c8998, + 0xf8dad837, 0xf63d30e6, 0xe5150995, 0xebf2e144, 0xc3457b73, + 0xcda293a2, 0xde8aaad1, 0xd06d4200, 0x8fe59ebf, 0x8102766e, + 0x922a4f1d, 0x9ccda7cc, 0xb47a3dfb, 0xba9dd52a, 0xa9b5ec59, + 0xa7520488}, + {0x00000000, 0x3c60e308, 0x78c1c610, 0x44a12518, 0xf1838c20, + 0xcde36f28, 0x89424a30, 0xb522a938, 0x38761e01, 0x0416fd09, + 0x40b7d811, 0x7cd73b19, 0xc9f59221, 0xf5957129, 0xb1345431, + 0x8d54b739, 0x70ec3c02, 0x4c8cdf0a, 0x082dfa12, 0x344d191a, + 0x816fb022, 0xbd0f532a, 0xf9ae7632, 0xc5ce953a, 0x489a2203, + 0x74fac10b, 0x305be413, 0x0c3b071b, 0xb919ae23, 0x85794d2b, + 0xc1d86833, 0xfdb88b3b, 0xe1d87804, 0xddb89b0c, 0x9919be14, + 0xa5795d1c, 0x105bf424, 0x2c3b172c, 0x689a3234, 0x54fad13c, + 0xd9ae6605, 0xe5ce850d, 0xa16fa015, 0x9d0f431d, 0x282dea25, + 0x144d092d, 0x50ec2c35, 0x6c8ccf3d, 0x91344406, 0xad54a70e, + 0xe9f58216, 0xd595611e, 0x60b7c826, 0x5cd72b2e, 0x18760e36, + 0x2416ed3e, 0xa9425a07, 0x9522b90f, 0xd1839c17, 0xede37f1f, + 0x58c1d627, 0x64a1352f, 0x20001037, 0x1c60f33f, 0x18c1f649, + 0x24a11541, 0x60003059, 0x5c60d351, 0xe9427a69, 0xd5229961, + 0x9183bc79, 0xade35f71, 0x20b7e848, 0x1cd70b40, 0x58762e58, + 0x6416cd50, 0xd1346468, 0xed548760, 0xa9f5a278, 0x95954170, + 0x682dca4b, 0x544d2943, 0x10ec0c5b, 0x2c8cef53, 0x99ae466b, + 0xa5cea563, 0xe16f807b, 0xdd0f6373, 0x505bd44a, 0x6c3b3742, + 0x289a125a, 0x14faf152, 0xa1d8586a, 0x9db8bb62, 0xd9199e7a, + 0xe5797d72, 0xf9198e4d, 0xc5796d45, 0x81d8485d, 0xbdb8ab55, + 0x089a026d, 0x34fae165, 0x705bc47d, 0x4c3b2775, 0xc16f904c, + 0xfd0f7344, 0xb9ae565c, 0x85ceb554, 0x30ec1c6c, 0x0c8cff64, + 0x482dda7c, 0x744d3974, 0x89f5b24f, 0xb5955147, 0xf134745f, + 0xcd549757, 0x78763e6f, 0x4416dd67, 0x00b7f87f, 0x3cd71b77, + 0xb183ac4e, 0x8de34f46, 0xc9426a5e, 0xf5228956, 0x4000206e, + 0x7c60c366, 0x38c1e67e, 0x04a10576, 0x3183ec92, 0x0de30f9a, + 0x49422a82, 0x7522c98a, 0xc00060b2, 0xfc6083ba, 0xb8c1a6a2, + 0x84a145aa, 0x09f5f293, 0x3595119b, 0x71343483, 0x4d54d78b, + 0xf8767eb3, 0xc4169dbb, 0x80b7b8a3, 0xbcd75bab, 0x416fd090, + 0x7d0f3398, 0x39ae1680, 0x05cef588, 0xb0ec5cb0, 0x8c8cbfb8, + 0xc82d9aa0, 0xf44d79a8, 0x7919ce91, 0x45792d99, 0x01d80881, + 0x3db8eb89, 0x889a42b1, 0xb4faa1b9, 0xf05b84a1, 0xcc3b67a9, + 0xd05b9496, 0xec3b779e, 0xa89a5286, 0x94fab18e, 0x21d818b6, + 0x1db8fbbe, 0x5919dea6, 0x65793dae, 0xe82d8a97, 0xd44d699f, + 0x90ec4c87, 0xac8caf8f, 0x19ae06b7, 0x25cee5bf, 0x616fc0a7, + 0x5d0f23af, 0xa0b7a894, 0x9cd74b9c, 0xd8766e84, 0xe4168d8c, + 0x513424b4, 0x6d54c7bc, 0x29f5e2a4, 0x159501ac, 0x98c1b695, + 0xa4a1559d, 0xe0007085, 0xdc60938d, 0x69423ab5, 0x5522d9bd, + 0x1183fca5, 0x2de31fad, 0x29421adb, 0x1522f9d3, 0x5183dccb, + 0x6de33fc3, 0xd8c196fb, 0xe4a175f3, 0xa00050eb, 0x9c60b3e3, + 0x113404da, 0x2d54e7d2, 0x69f5c2ca, 0x559521c2, 0xe0b788fa, + 0xdcd76bf2, 0x98764eea, 0xa416ade2, 0x59ae26d9, 0x65cec5d1, + 0x216fe0c9, 0x1d0f03c1, 0xa82daaf9, 0x944d49f1, 0xd0ec6ce9, + 0xec8c8fe1, 0x61d838d8, 0x5db8dbd0, 0x1919fec8, 0x25791dc0, + 0x905bb4f8, 0xac3b57f0, 0xe89a72e8, 0xd4fa91e0, 0xc89a62df, + 0xf4fa81d7, 0xb05ba4cf, 0x8c3b47c7, 0x3919eeff, 0x05790df7, + 0x41d828ef, 0x7db8cbe7, 0xf0ec7cde, 0xcc8c9fd6, 0x882dbace, + 0xb44d59c6, 0x016ff0fe, 0x3d0f13f6, 0x79ae36ee, 0x45ced5e6, + 0xb8765edd, 0x8416bdd5, 0xc0b798cd, 0xfcd77bc5, 0x49f5d2fd, + 0x759531f5, 0x313414ed, 0x0d54f7e5, 0x800040dc, 0xbc60a3d4, + 0xf8c186cc, 0xc4a165c4, 0x7183ccfc, 0x4de32ff4, 0x09420aec, + 0x3522e9e4}, + {0x00000000, 0x6307d924, 0xc60fb248, 0xa5086b6c, 0x576e62d1, + 0x3469bbf5, 0x9161d099, 0xf26609bd, 0xaedcc5a2, 0xcddb1c86, + 0x68d377ea, 0x0bd4aece, 0xf9b2a773, 0x9ab57e57, 0x3fbd153b, + 0x5cbacc1f, 0x86c88d05, 0xe5cf5421, 0x40c73f4d, 0x23c0e669, + 0xd1a6efd4, 0xb2a136f0, 0x17a95d9c, 0x74ae84b8, 0x281448a7, + 0x4b139183, 0xee1bfaef, 0x8d1c23cb, 0x7f7a2a76, 0x1c7df352, + 0xb975983e, 0xda72411a, 0xd6e01c4b, 0xb5e7c56f, 0x10efae03, + 0x73e87727, 0x818e7e9a, 0xe289a7be, 0x4781ccd2, 0x248615f6, + 0x783cd9e9, 0x1b3b00cd, 0xbe336ba1, 0xdd34b285, 0x2f52bb38, + 0x4c55621c, 0xe95d0970, 0x8a5ad054, 0x5028914e, 0x332f486a, + 0x96272306, 0xf520fa22, 0x0746f39f, 0x64412abb, 0xc14941d7, + 0xa24e98f3, 0xfef454ec, 0x9df38dc8, 0x38fbe6a4, 0x5bfc3f80, + 0xa99a363d, 0xca9def19, 0x6f958475, 0x0c925d51, 0x76b13ed7, + 0x15b6e7f3, 0xb0be8c9f, 0xd3b955bb, 0x21df5c06, 0x42d88522, + 0xe7d0ee4e, 0x84d7376a, 0xd86dfb75, 0xbb6a2251, 0x1e62493d, + 0x7d659019, 0x8f0399a4, 0xec044080, 0x490c2bec, 0x2a0bf2c8, + 0xf079b3d2, 0x937e6af6, 0x3676019a, 0x5571d8be, 0xa717d103, + 0xc4100827, 0x6118634b, 0x021fba6f, 0x5ea57670, 0x3da2af54, + 0x98aac438, 0xfbad1d1c, 0x09cb14a1, 0x6acccd85, 0xcfc4a6e9, + 0xacc37fcd, 0xa051229c, 0xc356fbb8, 0x665e90d4, 0x055949f0, + 0xf73f404d, 0x94389969, 0x3130f205, 0x52372b21, 0x0e8de73e, + 0x6d8a3e1a, 0xc8825576, 0xab858c52, 0x59e385ef, 0x3ae45ccb, + 0x9fec37a7, 0xfcebee83, 0x2699af99, 0x459e76bd, 0xe0961dd1, + 0x8391c4f5, 0x71f7cd48, 0x12f0146c, 0xb7f87f00, 0xd4ffa624, + 0x88456a3b, 0xeb42b31f, 0x4e4ad873, 0x2d4d0157, 0xdf2b08ea, + 0xbc2cd1ce, 0x1924baa2, 0x7a236386, 0xed627dae, 0x8e65a48a, + 0x2b6dcfe6, 0x486a16c2, 0xba0c1f7f, 0xd90bc65b, 0x7c03ad37, + 0x1f047413, 0x43beb80c, 0x20b96128, 0x85b10a44, 0xe6b6d360, + 0x14d0dadd, 0x77d703f9, 0xd2df6895, 0xb1d8b1b1, 0x6baaf0ab, + 0x08ad298f, 0xada542e3, 0xcea29bc7, 0x3cc4927a, 0x5fc34b5e, + 0xfacb2032, 0x99ccf916, 0xc5763509, 0xa671ec2d, 0x03798741, + 0x607e5e65, 0x921857d8, 0xf11f8efc, 0x5417e590, 0x37103cb4, + 0x3b8261e5, 0x5885b8c1, 0xfd8dd3ad, 0x9e8a0a89, 0x6cec0334, + 0x0febda10, 0xaae3b17c, 0xc9e46858, 0x955ea447, 0xf6597d63, + 0x5351160f, 0x3056cf2b, 0xc230c696, 0xa1371fb2, 0x043f74de, + 0x6738adfa, 0xbd4aece0, 0xde4d35c4, 0x7b455ea8, 0x1842878c, + 0xea248e31, 0x89235715, 0x2c2b3c79, 0x4f2ce55d, 0x13962942, + 0x7091f066, 0xd5999b0a, 0xb69e422e, 0x44f84b93, 0x27ff92b7, + 0x82f7f9db, 0xe1f020ff, 0x9bd34379, 0xf8d49a5d, 0x5ddcf131, + 0x3edb2815, 0xccbd21a8, 0xafbaf88c, 0x0ab293e0, 0x69b54ac4, + 0x350f86db, 0x56085fff, 0xf3003493, 0x9007edb7, 0x6261e40a, + 0x01663d2e, 0xa46e5642, 0xc7698f66, 0x1d1bce7c, 0x7e1c1758, + 0xdb147c34, 0xb813a510, 0x4a75acad, 0x29727589, 0x8c7a1ee5, + 0xef7dc7c1, 0xb3c70bde, 0xd0c0d2fa, 0x75c8b996, 0x16cf60b2, + 0xe4a9690f, 0x87aeb02b, 0x22a6db47, 0x41a10263, 0x4d335f32, + 0x2e348616, 0x8b3ced7a, 0xe83b345e, 0x1a5d3de3, 0x795ae4c7, + 0xdc528fab, 0xbf55568f, 0xe3ef9a90, 0x80e843b4, 0x25e028d8, + 0x46e7f1fc, 0xb481f841, 0xd7862165, 0x728e4a09, 0x1189932d, + 0xcbfbd237, 0xa8fc0b13, 0x0df4607f, 0x6ef3b95b, 0x9c95b0e6, + 0xff9269c2, 0x5a9a02ae, 0x399ddb8a, 0x65271795, 0x0620ceb1, + 0xa328a5dd, 0xc02f7cf9, 0x32497544, 0x514eac60, 0xf446c70c, + 0x97411e28}, + {0x00000000, 0x01b5fd1d, 0x036bfa3a, 0x02de0727, 0x06d7f474, + 0x07620969, 0x05bc0e4e, 0x0409f353, 0x0dafe8e8, 0x0c1a15f5, + 0x0ec412d2, 0x0f71efcf, 0x0b781c9c, 0x0acde181, 0x0813e6a6, + 0x09a61bbb, 0x1b5fd1d0, 0x1aea2ccd, 0x18342bea, 0x1981d6f7, + 0x1d8825a4, 0x1c3dd8b9, 0x1ee3df9e, 0x1f562283, 0x16f03938, + 0x1745c425, 0x159bc302, 0x142e3e1f, 0x1027cd4c, 0x11923051, + 0x134c3776, 0x12f9ca6b, 0x36bfa3a0, 0x370a5ebd, 0x35d4599a, + 0x3461a487, 0x306857d4, 0x31ddaac9, 0x3303adee, 0x32b650f3, + 0x3b104b48, 0x3aa5b655, 0x387bb172, 0x39ce4c6f, 0x3dc7bf3c, + 0x3c724221, 0x3eac4506, 0x3f19b81b, 0x2de07270, 0x2c558f6d, + 0x2e8b884a, 0x2f3e7557, 0x2b378604, 0x2a827b19, 0x285c7c3e, + 0x29e98123, 0x204f9a98, 0x21fa6785, 0x232460a2, 0x22919dbf, + 0x26986eec, 0x272d93f1, 0x25f394d6, 0x244669cb, 0x6d7f4740, + 0x6ccaba5d, 0x6e14bd7a, 0x6fa14067, 0x6ba8b334, 0x6a1d4e29, + 0x68c3490e, 0x6976b413, 0x60d0afa8, 0x616552b5, 0x63bb5592, + 0x620ea88f, 0x66075bdc, 0x67b2a6c1, 0x656ca1e6, 0x64d95cfb, + 0x76209690, 0x77956b8d, 0x754b6caa, 0x74fe91b7, 0x70f762e4, + 0x71429ff9, 0x739c98de, 0x722965c3, 0x7b8f7e78, 0x7a3a8365, + 0x78e48442, 0x7951795f, 0x7d588a0c, 0x7ced7711, 0x7e337036, + 0x7f868d2b, 0x5bc0e4e0, 0x5a7519fd, 0x58ab1eda, 0x591ee3c7, + 0x5d171094, 0x5ca2ed89, 0x5e7ceaae, 0x5fc917b3, 0x566f0c08, + 0x57daf115, 0x5504f632, 0x54b10b2f, 0x50b8f87c, 0x510d0561, + 0x53d30246, 0x5266ff5b, 0x409f3530, 0x412ac82d, 0x43f4cf0a, + 0x42413217, 0x4648c144, 0x47fd3c59, 0x45233b7e, 0x4496c663, + 0x4d30ddd8, 0x4c8520c5, 0x4e5b27e2, 0x4feedaff, 0x4be729ac, + 0x4a52d4b1, 0x488cd396, 0x49392e8b, 0xdafe8e80, 0xdb4b739d, + 0xd99574ba, 0xd82089a7, 0xdc297af4, 0xdd9c87e9, 0xdf4280ce, + 0xdef77dd3, 0xd7516668, 0xd6e49b75, 0xd43a9c52, 0xd58f614f, + 0xd186921c, 0xd0336f01, 0xd2ed6826, 0xd358953b, 0xc1a15f50, + 0xc014a24d, 0xc2caa56a, 0xc37f5877, 0xc776ab24, 0xc6c35639, + 0xc41d511e, 0xc5a8ac03, 0xcc0eb7b8, 0xcdbb4aa5, 0xcf654d82, + 0xced0b09f, 0xcad943cc, 0xcb6cbed1, 0xc9b2b9f6, 0xc80744eb, + 0xec412d20, 0xedf4d03d, 0xef2ad71a, 0xee9f2a07, 0xea96d954, + 0xeb232449, 0xe9fd236e, 0xe848de73, 0xe1eec5c8, 0xe05b38d5, + 0xe2853ff2, 0xe330c2ef, 0xe73931bc, 0xe68ccca1, 0xe452cb86, + 0xe5e7369b, 0xf71efcf0, 0xf6ab01ed, 0xf47506ca, 0xf5c0fbd7, + 0xf1c90884, 0xf07cf599, 0xf2a2f2be, 0xf3170fa3, 0xfab11418, + 0xfb04e905, 0xf9daee22, 0xf86f133f, 0xfc66e06c, 0xfdd31d71, + 0xff0d1a56, 0xfeb8e74b, 0xb781c9c0, 0xb63434dd, 0xb4ea33fa, + 0xb55fcee7, 0xb1563db4, 0xb0e3c0a9, 0xb23dc78e, 0xb3883a93, + 0xba2e2128, 0xbb9bdc35, 0xb945db12, 0xb8f0260f, 0xbcf9d55c, + 0xbd4c2841, 0xbf922f66, 0xbe27d27b, 0xacde1810, 0xad6be50d, + 0xafb5e22a, 0xae001f37, 0xaa09ec64, 0xabbc1179, 0xa962165e, + 0xa8d7eb43, 0xa171f0f8, 0xa0c40de5, 0xa21a0ac2, 0xa3aff7df, + 0xa7a6048c, 0xa613f991, 0xa4cdfeb6, 0xa57803ab, 0x813e6a60, + 0x808b977d, 0x8255905a, 0x83e06d47, 0x87e99e14, 0x865c6309, + 0x8482642e, 0x85379933, 0x8c918288, 0x8d247f95, 0x8ffa78b2, + 0x8e4f85af, 0x8a4676fc, 0x8bf38be1, 0x892d8cc6, 0x889871db, + 0x9a61bbb0, 0x9bd446ad, 0x990a418a, 0x98bfbc97, 0x9cb64fc4, + 0x9d03b2d9, 0x9fddb5fe, 0x9e6848e3, 0x97ce5358, 0x967bae45, + 0x94a5a962, 0x9510547f, 0x9119a72c, 0x90ac5a31, 0x92725d16, + 0x93c7a00b}, + {0x00000000, 0x6e8c1b41, 0xdd183682, 0xb3942dc3, 0x61416b45, + 0x0fcd7004, 0xbc595dc7, 0xd2d54686, 0xc282d68a, 0xac0ecdcb, + 0x1f9ae008, 0x7116fb49, 0xa3c3bdcf, 0xcd4fa68e, 0x7edb8b4d, + 0x1057900c, 0x5e74ab55, 0x30f8b014, 0x836c9dd7, 0xede08696, + 0x3f35c010, 0x51b9db51, 0xe22df692, 0x8ca1edd3, 0x9cf67ddf, + 0xf27a669e, 0x41ee4b5d, 0x2f62501c, 0xfdb7169a, 0x933b0ddb, + 0x20af2018, 0x4e233b59, 0xbce956aa, 0xd2654deb, 0x61f16028, + 0x0f7d7b69, 0xdda83def, 0xb32426ae, 0x00b00b6d, 0x6e3c102c, + 0x7e6b8020, 0x10e79b61, 0xa373b6a2, 0xcdffade3, 0x1f2aeb65, + 0x71a6f024, 0xc232dde7, 0xacbec6a6, 0xe29dfdff, 0x8c11e6be, + 0x3f85cb7d, 0x5109d03c, 0x83dc96ba, 0xed508dfb, 0x5ec4a038, + 0x3048bb79, 0x201f2b75, 0x4e933034, 0xfd071df7, 0x938b06b6, + 0x415e4030, 0x2fd25b71, 0x9c4676b2, 0xf2ca6df3, 0xa2a3ab15, + 0xcc2fb054, 0x7fbb9d97, 0x113786d6, 0xc3e2c050, 0xad6edb11, + 0x1efaf6d2, 0x7076ed93, 0x60217d9f, 0x0ead66de, 0xbd394b1d, + 0xd3b5505c, 0x016016da, 0x6fec0d9b, 0xdc782058, 0xb2f43b19, + 0xfcd70040, 0x925b1b01, 0x21cf36c2, 0x4f432d83, 0x9d966b05, + 0xf31a7044, 0x408e5d87, 0x2e0246c6, 0x3e55d6ca, 0x50d9cd8b, + 0xe34de048, 0x8dc1fb09, 0x5f14bd8f, 0x3198a6ce, 0x820c8b0d, + 0xec80904c, 0x1e4afdbf, 0x70c6e6fe, 0xc352cb3d, 0xadded07c, + 0x7f0b96fa, 0x11878dbb, 0xa213a078, 0xcc9fbb39, 0xdcc82b35, + 0xb2443074, 0x01d01db7, 0x6f5c06f6, 0xbd894070, 0xd3055b31, + 0x609176f2, 0x0e1d6db3, 0x403e56ea, 0x2eb24dab, 0x9d266068, + 0xf3aa7b29, 0x217f3daf, 0x4ff326ee, 0xfc670b2d, 0x92eb106c, + 0x82bc8060, 0xec309b21, 0x5fa4b6e2, 0x3128ada3, 0xe3fdeb25, + 0x8d71f064, 0x3ee5dda7, 0x5069c6e6, 0x9e36506b, 0xf0ba4b2a, + 0x432e66e9, 0x2da27da8, 0xff773b2e, 0x91fb206f, 0x226f0dac, + 0x4ce316ed, 0x5cb486e1, 0x32389da0, 0x81acb063, 0xef20ab22, + 0x3df5eda4, 0x5379f6e5, 0xe0eddb26, 0x8e61c067, 0xc042fb3e, + 0xaecee07f, 0x1d5acdbc, 0x73d6d6fd, 0xa103907b, 0xcf8f8b3a, + 0x7c1ba6f9, 0x1297bdb8, 0x02c02db4, 0x6c4c36f5, 0xdfd81b36, + 0xb1540077, 0x638146f1, 0x0d0d5db0, 0xbe997073, 0xd0156b32, + 0x22df06c1, 0x4c531d80, 0xffc73043, 0x914b2b02, 0x439e6d84, + 0x2d1276c5, 0x9e865b06, 0xf00a4047, 0xe05dd04b, 0x8ed1cb0a, + 0x3d45e6c9, 0x53c9fd88, 0x811cbb0e, 0xef90a04f, 0x5c048d8c, + 0x328896cd, 0x7cabad94, 0x1227b6d5, 0xa1b39b16, 0xcf3f8057, + 0x1deac6d1, 0x7366dd90, 0xc0f2f053, 0xae7eeb12, 0xbe297b1e, + 0xd0a5605f, 0x63314d9c, 0x0dbd56dd, 0xdf68105b, 0xb1e40b1a, + 0x027026d9, 0x6cfc3d98, 0x3c95fb7e, 0x5219e03f, 0xe18dcdfc, + 0x8f01d6bd, 0x5dd4903b, 0x33588b7a, 0x80cca6b9, 0xee40bdf8, + 0xfe172df4, 0x909b36b5, 0x230f1b76, 0x4d830037, 0x9f5646b1, + 0xf1da5df0, 0x424e7033, 0x2cc26b72, 0x62e1502b, 0x0c6d4b6a, + 0xbff966a9, 0xd1757de8, 0x03a03b6e, 0x6d2c202f, 0xdeb80dec, + 0xb03416ad, 0xa06386a1, 0xceef9de0, 0x7d7bb023, 0x13f7ab62, + 0xc122ede4, 0xafaef6a5, 0x1c3adb66, 0x72b6c027, 0x807cadd4, + 0xeef0b695, 0x5d649b56, 0x33e88017, 0xe13dc691, 0x8fb1ddd0, + 0x3c25f013, 0x52a9eb52, 0x42fe7b5e, 0x2c72601f, 0x9fe64ddc, + 0xf16a569d, 0x23bf101b, 0x4d330b5a, 0xfea72699, 0x902b3dd8, + 0xde080681, 0xb0841dc0, 0x03103003, 0x6d9c2b42, 0xbf496dc4, + 0xd1c57685, 0x62515b46, 0x0cdd4007, 0x1c8ad00b, 0x7206cb4a, + 0xc192e689, 0xaf1efdc8, 0x7dcbbb4e, 0x1347a00f, 0xa0d38dcc, + 0xce5f968d}, + {0x00000000, 0xe71da697, 0x154a4b6f, 0xf257edf8, 0x2a9496de, + 0xcd893049, 0x3fdeddb1, 0xd8c37b26, 0x55292dbc, 0xb2348b2b, + 0x406366d3, 0xa77ec044, 0x7fbdbb62, 0x98a01df5, 0x6af7f00d, + 0x8dea569a, 0xaa525b78, 0x4d4ffdef, 0xbf181017, 0x5805b680, + 0x80c6cda6, 0x67db6b31, 0x958c86c9, 0x7291205e, 0xff7b76c4, + 0x1866d053, 0xea313dab, 0x0d2c9b3c, 0xd5efe01a, 0x32f2468d, + 0xc0a5ab75, 0x27b80de2, 0x8fd5b0b1, 0x68c81626, 0x9a9ffbde, + 0x7d825d49, 0xa541266f, 0x425c80f8, 0xb00b6d00, 0x5716cb97, + 0xdafc9d0d, 0x3de13b9a, 0xcfb6d662, 0x28ab70f5, 0xf0680bd3, + 0x1775ad44, 0xe52240bc, 0x023fe62b, 0x2587ebc9, 0xc29a4d5e, + 0x30cda0a6, 0xd7d00631, 0x0f137d17, 0xe80edb80, 0x1a593678, + 0xfd4490ef, 0x70aec675, 0x97b360e2, 0x65e48d1a, 0x82f92b8d, + 0x5a3a50ab, 0xbd27f63c, 0x4f701bc4, 0xa86dbd53, 0xc4da6723, + 0x23c7c1b4, 0xd1902c4c, 0x368d8adb, 0xee4ef1fd, 0x0953576a, + 0xfb04ba92, 0x1c191c05, 0x91f34a9f, 0x76eeec08, 0x84b901f0, + 0x63a4a767, 0xbb67dc41, 0x5c7a7ad6, 0xae2d972e, 0x493031b9, + 0x6e883c5b, 0x89959acc, 0x7bc27734, 0x9cdfd1a3, 0x441caa85, + 0xa3010c12, 0x5156e1ea, 0xb64b477d, 0x3ba111e7, 0xdcbcb770, + 0x2eeb5a88, 0xc9f6fc1f, 0x11358739, 0xf62821ae, 0x047fcc56, + 0xe3626ac1, 0x4b0fd792, 0xac127105, 0x5e459cfd, 0xb9583a6a, + 0x619b414c, 0x8686e7db, 0x74d10a23, 0x93ccacb4, 0x1e26fa2e, + 0xf93b5cb9, 0x0b6cb141, 0xec7117d6, 0x34b26cf0, 0xd3afca67, + 0x21f8279f, 0xc6e58108, 0xe15d8cea, 0x06402a7d, 0xf417c785, + 0x130a6112, 0xcbc91a34, 0x2cd4bca3, 0xde83515b, 0x399ef7cc, + 0xb474a156, 0x536907c1, 0xa13eea39, 0x46234cae, 0x9ee03788, + 0x79fd911f, 0x8baa7ce7, 0x6cb7da70, 0x52c5c807, 0xb5d86e90, + 0x478f8368, 0xa09225ff, 0x78515ed9, 0x9f4cf84e, 0x6d1b15b6, + 0x8a06b321, 0x07ece5bb, 0xe0f1432c, 0x12a6aed4, 0xf5bb0843, + 0x2d787365, 0xca65d5f2, 0x3832380a, 0xdf2f9e9d, 0xf897937f, + 0x1f8a35e8, 0xedddd810, 0x0ac07e87, 0xd20305a1, 0x351ea336, + 0xc7494ece, 0x2054e859, 0xadbebec3, 0x4aa31854, 0xb8f4f5ac, + 0x5fe9533b, 0x872a281d, 0x60378e8a, 0x92606372, 0x757dc5e5, + 0xdd1078b6, 0x3a0dde21, 0xc85a33d9, 0x2f47954e, 0xf784ee68, + 0x109948ff, 0xe2cea507, 0x05d30390, 0x8839550a, 0x6f24f39d, + 0x9d731e65, 0x7a6eb8f2, 0xa2adc3d4, 0x45b06543, 0xb7e788bb, + 0x50fa2e2c, 0x774223ce, 0x905f8559, 0x620868a1, 0x8515ce36, + 0x5dd6b510, 0xbacb1387, 0x489cfe7f, 0xaf8158e8, 0x226b0e72, + 0xc576a8e5, 0x3721451d, 0xd03ce38a, 0x08ff98ac, 0xefe23e3b, + 0x1db5d3c3, 0xfaa87554, 0x961faf24, 0x710209b3, 0x8355e44b, + 0x644842dc, 0xbc8b39fa, 0x5b969f6d, 0xa9c17295, 0x4edcd402, + 0xc3368298, 0x242b240f, 0xd67cc9f7, 0x31616f60, 0xe9a21446, + 0x0ebfb2d1, 0xfce85f29, 0x1bf5f9be, 0x3c4df45c, 0xdb5052cb, + 0x2907bf33, 0xce1a19a4, 0x16d96282, 0xf1c4c415, 0x039329ed, + 0xe48e8f7a, 0x6964d9e0, 0x8e797f77, 0x7c2e928f, 0x9b333418, + 0x43f04f3e, 0xa4ede9a9, 0x56ba0451, 0xb1a7a2c6, 0x19ca1f95, + 0xfed7b902, 0x0c8054fa, 0xeb9df26d, 0x335e894b, 0xd4432fdc, + 0x2614c224, 0xc10964b3, 0x4ce33229, 0xabfe94be, 0x59a97946, + 0xbeb4dfd1, 0x6677a4f7, 0x816a0260, 0x733def98, 0x9420490f, + 0xb39844ed, 0x5485e27a, 0xa6d20f82, 0x41cfa915, 0x990cd233, + 0x7e1174a4, 0x8c46995c, 0x6b5b3fcb, 0xe6b16951, 0x01accfc6, + 0xf3fb223e, 0x14e684a9, 0xcc25ff8f, 0x2b385918, 0xd96fb4e0, + 0x3e721277}, + {0x00000000, 0xa58b900e, 0x9066265d, 0x35edb653, 0xfbbd4afb, + 0x5e36daf5, 0x6bdb6ca6, 0xce50fca8, 0x2c0b93b7, 0x898003b9, + 0xbc6db5ea, 0x19e625e4, 0xd7b6d94c, 0x723d4942, 0x47d0ff11, + 0xe25b6f1f, 0x5817276e, 0xfd9cb760, 0xc8710133, 0x6dfa913d, + 0xa3aa6d95, 0x0621fd9b, 0x33cc4bc8, 0x9647dbc6, 0x741cb4d9, + 0xd19724d7, 0xe47a9284, 0x41f1028a, 0x8fa1fe22, 0x2a2a6e2c, + 0x1fc7d87f, 0xba4c4871, 0xb02e4edc, 0x15a5ded2, 0x20486881, + 0x85c3f88f, 0x4b930427, 0xee189429, 0xdbf5227a, 0x7e7eb274, + 0x9c25dd6b, 0x39ae4d65, 0x0c43fb36, 0xa9c86b38, 0x67989790, + 0xc213079e, 0xf7feb1cd, 0x527521c3, 0xe83969b2, 0x4db2f9bc, + 0x785f4fef, 0xddd4dfe1, 0x13842349, 0xb60fb347, 0x83e20514, + 0x2669951a, 0xc432fa05, 0x61b96a0b, 0x5454dc58, 0xf1df4c56, + 0x3f8fb0fe, 0x9a0420f0, 0xafe996a3, 0x0a6206ad, 0xbb2d9bf9, + 0x1ea60bf7, 0x2b4bbda4, 0x8ec02daa, 0x4090d102, 0xe51b410c, + 0xd0f6f75f, 0x757d6751, 0x9726084e, 0x32ad9840, 0x07402e13, + 0xa2cbbe1d, 0x6c9b42b5, 0xc910d2bb, 0xfcfd64e8, 0x5976f4e6, + 0xe33abc97, 0x46b12c99, 0x735c9aca, 0xd6d70ac4, 0x1887f66c, + 0xbd0c6662, 0x88e1d031, 0x2d6a403f, 0xcf312f20, 0x6ababf2e, + 0x5f57097d, 0xfadc9973, 0x348c65db, 0x9107f5d5, 0xa4ea4386, + 0x0161d388, 0x0b03d525, 0xae88452b, 0x9b65f378, 0x3eee6376, + 0xf0be9fde, 0x55350fd0, 0x60d8b983, 0xc553298d, 0x27084692, + 0x8283d69c, 0xb76e60cf, 0x12e5f0c1, 0xdcb50c69, 0x793e9c67, + 0x4cd32a34, 0xe958ba3a, 0x5314f24b, 0xf69f6245, 0xc372d416, + 0x66f94418, 0xa8a9b8b0, 0x0d2228be, 0x38cf9eed, 0x9d440ee3, + 0x7f1f61fc, 0xda94f1f2, 0xef7947a1, 0x4af2d7af, 0x84a22b07, + 0x2129bb09, 0x14c40d5a, 0xb14f9d54, 0xad2a31b3, 0x08a1a1bd, + 0x3d4c17ee, 0x98c787e0, 0x56977b48, 0xf31ceb46, 0xc6f15d15, + 0x637acd1b, 0x8121a204, 0x24aa320a, 0x11478459, 0xb4cc1457, + 0x7a9ce8ff, 0xdf1778f1, 0xeafacea2, 0x4f715eac, 0xf53d16dd, + 0x50b686d3, 0x655b3080, 0xc0d0a08e, 0x0e805c26, 0xab0bcc28, + 0x9ee67a7b, 0x3b6dea75, 0xd936856a, 0x7cbd1564, 0x4950a337, + 0xecdb3339, 0x228bcf91, 0x87005f9f, 0xb2ede9cc, 0x176679c2, + 0x1d047f6f, 0xb88fef61, 0x8d625932, 0x28e9c93c, 0xe6b93594, + 0x4332a59a, 0x76df13c9, 0xd35483c7, 0x310fecd8, 0x94847cd6, + 0xa169ca85, 0x04e25a8b, 0xcab2a623, 0x6f39362d, 0x5ad4807e, + 0xff5f1070, 0x45135801, 0xe098c80f, 0xd5757e5c, 0x70feee52, + 0xbeae12fa, 0x1b2582f4, 0x2ec834a7, 0x8b43a4a9, 0x6918cbb6, + 0xcc935bb8, 0xf97eedeb, 0x5cf57de5, 0x92a5814d, 0x372e1143, + 0x02c3a710, 0xa748371e, 0x1607aa4a, 0xb38c3a44, 0x86618c17, + 0x23ea1c19, 0xedbae0b1, 0x483170bf, 0x7ddcc6ec, 0xd85756e2, + 0x3a0c39fd, 0x9f87a9f3, 0xaa6a1fa0, 0x0fe18fae, 0xc1b17306, + 0x643ae308, 0x51d7555b, 0xf45cc555, 0x4e108d24, 0xeb9b1d2a, + 0xde76ab79, 0x7bfd3b77, 0xb5adc7df, 0x102657d1, 0x25cbe182, + 0x8040718c, 0x621b1e93, 0xc7908e9d, 0xf27d38ce, 0x57f6a8c0, + 0x99a65468, 0x3c2dc466, 0x09c07235, 0xac4be23b, 0xa629e496, + 0x03a27498, 0x364fc2cb, 0x93c452c5, 0x5d94ae6d, 0xf81f3e63, + 0xcdf28830, 0x6879183e, 0x8a227721, 0x2fa9e72f, 0x1a44517c, + 0xbfcfc172, 0x719f3dda, 0xd414add4, 0xe1f91b87, 0x44728b89, + 0xfe3ec3f8, 0x5bb553f6, 0x6e58e5a5, 0xcbd375ab, 0x05838903, + 0xa008190d, 0x95e5af5e, 0x306e3f50, 0xd235504f, 0x77bec041, + 0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9, + 0x1c65ace7}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000, + 0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000, + 0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000, + 0xb903808900000000, 0xeab56dbc00000000, 0xe425e61900000000, + 0x4cd9b6d700000000, 0x42493d7200000000, 0x11ffd04700000000, + 0x1f6f5be200000000, 0x6e27175800000000, 0x60b79cfd00000000, + 0x330171c800000000, 0x3d91fa6d00000000, 0x956daaa300000000, + 0x9bfd210600000000, 0xc84bcc3300000000, 0xc6db479600000000, + 0xd9b41c7400000000, 0xd72497d100000000, 0x84927ae400000000, + 0x8a02f14100000000, 0x22fea18f00000000, 0x2c6e2a2a00000000, + 0x7fd8c71f00000000, 0x71484cba00000000, 0xdc4e2eb000000000, + 0xd2dea51500000000, 0x8168482000000000, 0x8ff8c38500000000, + 0x2704934b00000000, 0x299418ee00000000, 0x7a22f5db00000000, + 0x74b27e7e00000000, 0x6bdd259c00000000, 0x654dae3900000000, + 0x36fb430c00000000, 0x386bc8a900000000, 0x9097986700000000, + 0x9e0713c200000000, 0xcdb1fef700000000, 0xc321755200000000, + 0xb26939e800000000, 0xbcf9b24d00000000, 0xef4f5f7800000000, + 0xe1dfd4dd00000000, 0x4923841300000000, 0x47b30fb600000000, + 0x1405e28300000000, 0x1a95692600000000, 0x05fa32c400000000, + 0x0b6ab96100000000, 0x58dc545400000000, 0x564cdff100000000, + 0xfeb08f3f00000000, 0xf020049a00000000, 0xa396e9af00000000, + 0xad06620a00000000, 0xf99b2dbb00000000, 0xf70ba61e00000000, + 0xa4bd4b2b00000000, 0xaa2dc08e00000000, 0x02d1904000000000, + 0x0c411be500000000, 0x5ff7f6d000000000, 0x51677d7500000000, + 0x4e08269700000000, 0x4098ad3200000000, 0x132e400700000000, + 0x1dbecba200000000, 0xb5429b6c00000000, 0xbbd210c900000000, + 0xe864fdfc00000000, 0xe6f4765900000000, 0x97bc3ae300000000, + 0x992cb14600000000, 0xca9a5c7300000000, 0xc40ad7d600000000, + 0x6cf6871800000000, 0x62660cbd00000000, 0x31d0e18800000000, + 0x3f406a2d00000000, 0x202f31cf00000000, 0x2ebfba6a00000000, + 0x7d09575f00000000, 0x7399dcfa00000000, 0xdb658c3400000000, + 0xd5f5079100000000, 0x8643eaa400000000, 0x88d3610100000000, + 0x25d5030b00000000, 0x2b4588ae00000000, 0x78f3659b00000000, + 0x7663ee3e00000000, 0xde9fbef000000000, 0xd00f355500000000, + 0x83b9d86000000000, 0x8d2953c500000000, 0x9246082700000000, + 0x9cd6838200000000, 0xcf606eb700000000, 0xc1f0e51200000000, + 0x690cb5dc00000000, 0x679c3e7900000000, 0x342ad34c00000000, + 0x3aba58e900000000, 0x4bf2145300000000, 0x45629ff600000000, + 0x16d472c300000000, 0x1844f96600000000, 0xb0b8a9a800000000, + 0xbe28220d00000000, 0xed9ecf3800000000, 0xe30e449d00000000, + 0xfc611f7f00000000, 0xf2f194da00000000, 0xa14779ef00000000, + 0xafd7f24a00000000, 0x072ba28400000000, 0x09bb292100000000, + 0x5a0dc41400000000, 0x549d4fb100000000, 0xb3312aad00000000, + 0xbda1a10800000000, 0xee174c3d00000000, 0xe087c79800000000, + 0x487b975600000000, 0x46eb1cf300000000, 0x155df1c600000000, + 0x1bcd7a6300000000, 0x04a2218100000000, 0x0a32aa2400000000, + 0x5984471100000000, 0x5714ccb400000000, 0xffe89c7a00000000, + 0xf17817df00000000, 0xa2cefaea00000000, 0xac5e714f00000000, + 0xdd163df500000000, 0xd386b65000000000, 0x80305b6500000000, + 0x8ea0d0c000000000, 0x265c800e00000000, 0x28cc0bab00000000, + 0x7b7ae69e00000000, 0x75ea6d3b00000000, 0x6a8536d900000000, + 0x6415bd7c00000000, 0x37a3504900000000, 0x3933dbec00000000, + 0x91cf8b2200000000, 0x9f5f008700000000, 0xcce9edb200000000, + 0xc279661700000000, 0x6f7f041d00000000, 0x61ef8fb800000000, + 0x3259628d00000000, 0x3cc9e92800000000, 0x9435b9e600000000, + 0x9aa5324300000000, 0xc913df7600000000, 0xc78354d300000000, + 0xd8ec0f3100000000, 0xd67c849400000000, 0x85ca69a100000000, + 0x8b5ae20400000000, 0x23a6b2ca00000000, 0x2d36396f00000000, + 0x7e80d45a00000000, 0x70105fff00000000, 0x0158134500000000, + 0x0fc898e000000000, 0x5c7e75d500000000, 0x52eefe7000000000, + 0xfa12aebe00000000, 0xf482251b00000000, 0xa734c82e00000000, + 0xa9a4438b00000000, 0xb6cb186900000000, 0xb85b93cc00000000, + 0xebed7ef900000000, 0xe57df55c00000000, 0x4d81a59200000000, + 0x43112e3700000000, 0x10a7c30200000000, 0x1e3748a700000000, + 0x4aaa071600000000, 0x443a8cb300000000, 0x178c618600000000, + 0x191cea2300000000, 0xb1e0baed00000000, 0xbf70314800000000, + 0xecc6dc7d00000000, 0xe25657d800000000, 0xfd390c3a00000000, + 0xf3a9879f00000000, 0xa01f6aaa00000000, 0xae8fe10f00000000, + 0x0673b1c100000000, 0x08e33a6400000000, 0x5b55d75100000000, + 0x55c55cf400000000, 0x248d104e00000000, 0x2a1d9beb00000000, + 0x79ab76de00000000, 0x773bfd7b00000000, 0xdfc7adb500000000, + 0xd157261000000000, 0x82e1cb2500000000, 0x8c71408000000000, + 0x931e1b6200000000, 0x9d8e90c700000000, 0xce387df200000000, + 0xc0a8f65700000000, 0x6854a69900000000, 0x66c42d3c00000000, + 0x3572c00900000000, 0x3be24bac00000000, 0x96e429a600000000, + 0x9874a20300000000, 0xcbc24f3600000000, 0xc552c49300000000, + 0x6dae945d00000000, 0x633e1ff800000000, 0x3088f2cd00000000, + 0x3e18796800000000, 0x2177228a00000000, 0x2fe7a92f00000000, + 0x7c51441a00000000, 0x72c1cfbf00000000, 0xda3d9f7100000000, + 0xd4ad14d400000000, 0x871bf9e100000000, 0x898b724400000000, + 0xf8c33efe00000000, 0xf653b55b00000000, 0xa5e5586e00000000, + 0xab75d3cb00000000, 0x0389830500000000, 0x0d1908a000000000, + 0x5eafe59500000000, 0x503f6e3000000000, 0x4f5035d200000000, + 0x41c0be7700000000, 0x1276534200000000, 0x1ce6d8e700000000, + 0xb41a882900000000, 0xba8a038c00000000, 0xe93ceeb900000000, + 0xe7ac651c00000000}, + {0x0000000000000000, 0x97a61de700000000, 0x6f4b4a1500000000, + 0xf8ed57f200000000, 0xde96942a00000000, 0x493089cd00000000, + 0xb1ddde3f00000000, 0x267bc3d800000000, 0xbc2d295500000000, + 0x2b8b34b200000000, 0xd366634000000000, 0x44c07ea700000000, + 0x62bbbd7f00000000, 0xf51da09800000000, 0x0df0f76a00000000, + 0x9a56ea8d00000000, 0x785b52aa00000000, 0xeffd4f4d00000000, + 0x171018bf00000000, 0x80b6055800000000, 0xa6cdc68000000000, + 0x316bdb6700000000, 0xc9868c9500000000, 0x5e20917200000000, + 0xc4767bff00000000, 0x53d0661800000000, 0xab3d31ea00000000, + 0x3c9b2c0d00000000, 0x1ae0efd500000000, 0x8d46f23200000000, + 0x75aba5c000000000, 0xe20db82700000000, 0xb1b0d58f00000000, + 0x2616c86800000000, 0xdefb9f9a00000000, 0x495d827d00000000, + 0x6f2641a500000000, 0xf8805c4200000000, 0x006d0bb000000000, + 0x97cb165700000000, 0x0d9dfcda00000000, 0x9a3be13d00000000, + 0x62d6b6cf00000000, 0xf570ab2800000000, 0xd30b68f000000000, + 0x44ad751700000000, 0xbc4022e500000000, 0x2be63f0200000000, + 0xc9eb872500000000, 0x5e4d9ac200000000, 0xa6a0cd3000000000, + 0x3106d0d700000000, 0x177d130f00000000, 0x80db0ee800000000, + 0x7836591a00000000, 0xef9044fd00000000, 0x75c6ae7000000000, + 0xe260b39700000000, 0x1a8de46500000000, 0x8d2bf98200000000, + 0xab503a5a00000000, 0x3cf627bd00000000, 0xc41b704f00000000, + 0x53bd6da800000000, 0x2367dac400000000, 0xb4c1c72300000000, + 0x4c2c90d100000000, 0xdb8a8d3600000000, 0xfdf14eee00000000, + 0x6a57530900000000, 0x92ba04fb00000000, 0x051c191c00000000, + 0x9f4af39100000000, 0x08ecee7600000000, 0xf001b98400000000, + 0x67a7a46300000000, 0x41dc67bb00000000, 0xd67a7a5c00000000, + 0x2e972dae00000000, 0xb931304900000000, 0x5b3c886e00000000, + 0xcc9a958900000000, 0x3477c27b00000000, 0xa3d1df9c00000000, + 0x85aa1c4400000000, 0x120c01a300000000, 0xeae1565100000000, + 0x7d474bb600000000, 0xe711a13b00000000, 0x70b7bcdc00000000, + 0x885aeb2e00000000, 0x1ffcf6c900000000, 0x3987351100000000, + 0xae2128f600000000, 0x56cc7f0400000000, 0xc16a62e300000000, + 0x92d70f4b00000000, 0x057112ac00000000, 0xfd9c455e00000000, + 0x6a3a58b900000000, 0x4c419b6100000000, 0xdbe7868600000000, + 0x230ad17400000000, 0xb4accc9300000000, 0x2efa261e00000000, + 0xb95c3bf900000000, 0x41b16c0b00000000, 0xd61771ec00000000, + 0xf06cb23400000000, 0x67caafd300000000, 0x9f27f82100000000, + 0x0881e5c600000000, 0xea8c5de100000000, 0x7d2a400600000000, + 0x85c717f400000000, 0x12610a1300000000, 0x341ac9cb00000000, + 0xa3bcd42c00000000, 0x5b5183de00000000, 0xccf79e3900000000, + 0x56a174b400000000, 0xc107695300000000, 0x39ea3ea100000000, + 0xae4c234600000000, 0x8837e09e00000000, 0x1f91fd7900000000, + 0xe77caa8b00000000, 0x70dab76c00000000, 0x07c8c55200000000, + 0x906ed8b500000000, 0x68838f4700000000, 0xff2592a000000000, + 0xd95e517800000000, 0x4ef84c9f00000000, 0xb6151b6d00000000, + 0x21b3068a00000000, 0xbbe5ec0700000000, 0x2c43f1e000000000, + 0xd4aea61200000000, 0x4308bbf500000000, 0x6573782d00000000, + 0xf2d565ca00000000, 0x0a38323800000000, 0x9d9e2fdf00000000, + 0x7f9397f800000000, 0xe8358a1f00000000, 0x10d8dded00000000, + 0x877ec00a00000000, 0xa10503d200000000, 0x36a31e3500000000, + 0xce4e49c700000000, 0x59e8542000000000, 0xc3bebead00000000, + 0x5418a34a00000000, 0xacf5f4b800000000, 0x3b53e95f00000000, + 0x1d282a8700000000, 0x8a8e376000000000, 0x7263609200000000, + 0xe5c57d7500000000, 0xb67810dd00000000, 0x21de0d3a00000000, + 0xd9335ac800000000, 0x4e95472f00000000, 0x68ee84f700000000, + 0xff48991000000000, 0x07a5cee200000000, 0x9003d30500000000, + 0x0a55398800000000, 0x9df3246f00000000, 0x651e739d00000000, + 0xf2b86e7a00000000, 0xd4c3ada200000000, 0x4365b04500000000, + 0xbb88e7b700000000, 0x2c2efa5000000000, 0xce23427700000000, + 0x59855f9000000000, 0xa168086200000000, 0x36ce158500000000, + 0x10b5d65d00000000, 0x8713cbba00000000, 0x7ffe9c4800000000, + 0xe85881af00000000, 0x720e6b2200000000, 0xe5a876c500000000, + 0x1d45213700000000, 0x8ae33cd000000000, 0xac98ff0800000000, + 0x3b3ee2ef00000000, 0xc3d3b51d00000000, 0x5475a8fa00000000, + 0x24af1f9600000000, 0xb309027100000000, 0x4be4558300000000, + 0xdc42486400000000, 0xfa398bbc00000000, 0x6d9f965b00000000, + 0x9572c1a900000000, 0x02d4dc4e00000000, 0x988236c300000000, + 0x0f242b2400000000, 0xf7c97cd600000000, 0x606f613100000000, + 0x4614a2e900000000, 0xd1b2bf0e00000000, 0x295fe8fc00000000, + 0xbef9f51b00000000, 0x5cf44d3c00000000, 0xcb5250db00000000, + 0x33bf072900000000, 0xa4191ace00000000, 0x8262d91600000000, + 0x15c4c4f100000000, 0xed29930300000000, 0x7a8f8ee400000000, + 0xe0d9646900000000, 0x777f798e00000000, 0x8f922e7c00000000, + 0x1834339b00000000, 0x3e4ff04300000000, 0xa9e9eda400000000, + 0x5104ba5600000000, 0xc6a2a7b100000000, 0x951fca1900000000, + 0x02b9d7fe00000000, 0xfa54800c00000000, 0x6df29deb00000000, + 0x4b895e3300000000, 0xdc2f43d400000000, 0x24c2142600000000, + 0xb36409c100000000, 0x2932e34c00000000, 0xbe94feab00000000, + 0x4679a95900000000, 0xd1dfb4be00000000, 0xf7a4776600000000, + 0x60026a8100000000, 0x98ef3d7300000000, 0x0f49209400000000, + 0xed4498b300000000, 0x7ae2855400000000, 0x820fd2a600000000, + 0x15a9cf4100000000, 0x33d20c9900000000, 0xa474117e00000000, + 0x5c99468c00000000, 0xcb3f5b6b00000000, 0x5169b1e600000000, + 0xc6cfac0100000000, 0x3e22fbf300000000, 0xa984e61400000000, + 0x8fff25cc00000000, 0x1859382b00000000, 0xe0b46fd900000000, + 0x7712723e00000000}, + {0x0000000000000000, 0x411b8c6e00000000, 0x823618dd00000000, + 0xc32d94b300000000, 0x456b416100000000, 0x0470cd0f00000000, + 0xc75d59bc00000000, 0x8646d5d200000000, 0x8ad682c200000000, + 0xcbcd0eac00000000, 0x08e09a1f00000000, 0x49fb167100000000, + 0xcfbdc3a300000000, 0x8ea64fcd00000000, 0x4d8bdb7e00000000, + 0x0c90571000000000, 0x55ab745e00000000, 0x14b0f83000000000, + 0xd79d6c8300000000, 0x9686e0ed00000000, 0x10c0353f00000000, + 0x51dbb95100000000, 0x92f62de200000000, 0xd3eda18c00000000, + 0xdf7df69c00000000, 0x9e667af200000000, 0x5d4bee4100000000, + 0x1c50622f00000000, 0x9a16b7fd00000000, 0xdb0d3b9300000000, + 0x1820af2000000000, 0x593b234e00000000, 0xaa56e9bc00000000, + 0xeb4d65d200000000, 0x2860f16100000000, 0x697b7d0f00000000, + 0xef3da8dd00000000, 0xae2624b300000000, 0x6d0bb00000000000, + 0x2c103c6e00000000, 0x20806b7e00000000, 0x619be71000000000, + 0xa2b673a300000000, 0xe3adffcd00000000, 0x65eb2a1f00000000, + 0x24f0a67100000000, 0xe7dd32c200000000, 0xa6c6beac00000000, + 0xfffd9de200000000, 0xbee6118c00000000, 0x7dcb853f00000000, + 0x3cd0095100000000, 0xba96dc8300000000, 0xfb8d50ed00000000, + 0x38a0c45e00000000, 0x79bb483000000000, 0x752b1f2000000000, + 0x3430934e00000000, 0xf71d07fd00000000, 0xb6068b9300000000, + 0x30405e4100000000, 0x715bd22f00000000, 0xb276469c00000000, + 0xf36dcaf200000000, 0x15aba3a200000000, 0x54b02fcc00000000, + 0x979dbb7f00000000, 0xd686371100000000, 0x50c0e2c300000000, + 0x11db6ead00000000, 0xd2f6fa1e00000000, 0x93ed767000000000, + 0x9f7d216000000000, 0xde66ad0e00000000, 0x1d4b39bd00000000, + 0x5c50b5d300000000, 0xda16600100000000, 0x9b0dec6f00000000, + 0x582078dc00000000, 0x193bf4b200000000, 0x4000d7fc00000000, + 0x011b5b9200000000, 0xc236cf2100000000, 0x832d434f00000000, + 0x056b969d00000000, 0x44701af300000000, 0x875d8e4000000000, + 0xc646022e00000000, 0xcad6553e00000000, 0x8bcdd95000000000, + 0x48e04de300000000, 0x09fbc18d00000000, 0x8fbd145f00000000, + 0xcea6983100000000, 0x0d8b0c8200000000, 0x4c9080ec00000000, + 0xbffd4a1e00000000, 0xfee6c67000000000, 0x3dcb52c300000000, + 0x7cd0dead00000000, 0xfa960b7f00000000, 0xbb8d871100000000, + 0x78a013a200000000, 0x39bb9fcc00000000, 0x352bc8dc00000000, + 0x743044b200000000, 0xb71dd00100000000, 0xf6065c6f00000000, + 0x704089bd00000000, 0x315b05d300000000, 0xf276916000000000, + 0xb36d1d0e00000000, 0xea563e4000000000, 0xab4db22e00000000, + 0x6860269d00000000, 0x297baaf300000000, 0xaf3d7f2100000000, + 0xee26f34f00000000, 0x2d0b67fc00000000, 0x6c10eb9200000000, + 0x6080bc8200000000, 0x219b30ec00000000, 0xe2b6a45f00000000, + 0xa3ad283100000000, 0x25ebfde300000000, 0x64f0718d00000000, + 0xa7dde53e00000000, 0xe6c6695000000000, 0x6b50369e00000000, + 0x2a4bbaf000000000, 0xe9662e4300000000, 0xa87da22d00000000, + 0x2e3b77ff00000000, 0x6f20fb9100000000, 0xac0d6f2200000000, + 0xed16e34c00000000, 0xe186b45c00000000, 0xa09d383200000000, + 0x63b0ac8100000000, 0x22ab20ef00000000, 0xa4edf53d00000000, + 0xe5f6795300000000, 0x26dbede000000000, 0x67c0618e00000000, + 0x3efb42c000000000, 0x7fe0ceae00000000, 0xbccd5a1d00000000, + 0xfdd6d67300000000, 0x7b9003a100000000, 0x3a8b8fcf00000000, + 0xf9a61b7c00000000, 0xb8bd971200000000, 0xb42dc00200000000, + 0xf5364c6c00000000, 0x361bd8df00000000, 0x770054b100000000, + 0xf146816300000000, 0xb05d0d0d00000000, 0x737099be00000000, + 0x326b15d000000000, 0xc106df2200000000, 0x801d534c00000000, + 0x4330c7ff00000000, 0x022b4b9100000000, 0x846d9e4300000000, + 0xc576122d00000000, 0x065b869e00000000, 0x47400af000000000, + 0x4bd05de000000000, 0x0acbd18e00000000, 0xc9e6453d00000000, + 0x88fdc95300000000, 0x0ebb1c8100000000, 0x4fa090ef00000000, + 0x8c8d045c00000000, 0xcd96883200000000, 0x94adab7c00000000, + 0xd5b6271200000000, 0x169bb3a100000000, 0x57803fcf00000000, + 0xd1c6ea1d00000000, 0x90dd667300000000, 0x53f0f2c000000000, + 0x12eb7eae00000000, 0x1e7b29be00000000, 0x5f60a5d000000000, + 0x9c4d316300000000, 0xdd56bd0d00000000, 0x5b1068df00000000, + 0x1a0be4b100000000, 0xd926700200000000, 0x983dfc6c00000000, + 0x7efb953c00000000, 0x3fe0195200000000, 0xfccd8de100000000, + 0xbdd6018f00000000, 0x3b90d45d00000000, 0x7a8b583300000000, + 0xb9a6cc8000000000, 0xf8bd40ee00000000, 0xf42d17fe00000000, + 0xb5369b9000000000, 0x761b0f2300000000, 0x3700834d00000000, + 0xb146569f00000000, 0xf05ddaf100000000, 0x33704e4200000000, + 0x726bc22c00000000, 0x2b50e16200000000, 0x6a4b6d0c00000000, + 0xa966f9bf00000000, 0xe87d75d100000000, 0x6e3ba00300000000, + 0x2f202c6d00000000, 0xec0db8de00000000, 0xad1634b000000000, + 0xa18663a000000000, 0xe09defce00000000, 0x23b07b7d00000000, + 0x62abf71300000000, 0xe4ed22c100000000, 0xa5f6aeaf00000000, + 0x66db3a1c00000000, 0x27c0b67200000000, 0xd4ad7c8000000000, + 0x95b6f0ee00000000, 0x569b645d00000000, 0x1780e83300000000, + 0x91c63de100000000, 0xd0ddb18f00000000, 0x13f0253c00000000, + 0x52eba95200000000, 0x5e7bfe4200000000, 0x1f60722c00000000, + 0xdc4de69f00000000, 0x9d566af100000000, 0x1b10bf2300000000, + 0x5a0b334d00000000, 0x9926a7fe00000000, 0xd83d2b9000000000, + 0x810608de00000000, 0xc01d84b000000000, 0x0330100300000000, + 0x422b9c6d00000000, 0xc46d49bf00000000, 0x8576c5d100000000, + 0x465b516200000000, 0x0740dd0c00000000, 0x0bd08a1c00000000, + 0x4acb067200000000, 0x89e692c100000000, 0xc8fd1eaf00000000, + 0x4ebbcb7d00000000, 0x0fa0471300000000, 0xcc8dd3a000000000, + 0x8d965fce00000000}, + {0x0000000000000000, 0x1dfdb50100000000, 0x3afa6b0300000000, + 0x2707de0200000000, 0x74f4d70600000000, 0x6909620700000000, + 0x4e0ebc0500000000, 0x53f3090400000000, 0xe8e8af0d00000000, + 0xf5151a0c00000000, 0xd212c40e00000000, 0xcfef710f00000000, + 0x9c1c780b00000000, 0x81e1cd0a00000000, 0xa6e6130800000000, + 0xbb1ba60900000000, 0xd0d15f1b00000000, 0xcd2cea1a00000000, + 0xea2b341800000000, 0xf7d6811900000000, 0xa425881d00000000, + 0xb9d83d1c00000000, 0x9edfe31e00000000, 0x8322561f00000000, + 0x3839f01600000000, 0x25c4451700000000, 0x02c39b1500000000, + 0x1f3e2e1400000000, 0x4ccd271000000000, 0x5130921100000000, + 0x76374c1300000000, 0x6bcaf91200000000, 0xa0a3bf3600000000, + 0xbd5e0a3700000000, 0x9a59d43500000000, 0x87a4613400000000, + 0xd457683000000000, 0xc9aadd3100000000, 0xeead033300000000, + 0xf350b63200000000, 0x484b103b00000000, 0x55b6a53a00000000, + 0x72b17b3800000000, 0x6f4cce3900000000, 0x3cbfc73d00000000, + 0x2142723c00000000, 0x0645ac3e00000000, 0x1bb8193f00000000, + 0x7072e02d00000000, 0x6d8f552c00000000, 0x4a888b2e00000000, + 0x57753e2f00000000, 0x0486372b00000000, 0x197b822a00000000, + 0x3e7c5c2800000000, 0x2381e92900000000, 0x989a4f2000000000, + 0x8567fa2100000000, 0xa260242300000000, 0xbf9d912200000000, + 0xec6e982600000000, 0xf1932d2700000000, 0xd694f32500000000, + 0xcb69462400000000, 0x40477f6d00000000, 0x5dbaca6c00000000, + 0x7abd146e00000000, 0x6740a16f00000000, 0x34b3a86b00000000, + 0x294e1d6a00000000, 0x0e49c36800000000, 0x13b4766900000000, + 0xa8afd06000000000, 0xb552656100000000, 0x9255bb6300000000, + 0x8fa80e6200000000, 0xdc5b076600000000, 0xc1a6b26700000000, + 0xe6a16c6500000000, 0xfb5cd96400000000, 0x9096207600000000, + 0x8d6b957700000000, 0xaa6c4b7500000000, 0xb791fe7400000000, + 0xe462f77000000000, 0xf99f427100000000, 0xde989c7300000000, + 0xc365297200000000, 0x787e8f7b00000000, 0x65833a7a00000000, + 0x4284e47800000000, 0x5f79517900000000, 0x0c8a587d00000000, + 0x1177ed7c00000000, 0x3670337e00000000, 0x2b8d867f00000000, + 0xe0e4c05b00000000, 0xfd19755a00000000, 0xda1eab5800000000, + 0xc7e31e5900000000, 0x9410175d00000000, 0x89eda25c00000000, + 0xaeea7c5e00000000, 0xb317c95f00000000, 0x080c6f5600000000, + 0x15f1da5700000000, 0x32f6045500000000, 0x2f0bb15400000000, + 0x7cf8b85000000000, 0x61050d5100000000, 0x4602d35300000000, + 0x5bff665200000000, 0x30359f4000000000, 0x2dc82a4100000000, + 0x0acff44300000000, 0x1732414200000000, 0x44c1484600000000, + 0x593cfd4700000000, 0x7e3b234500000000, 0x63c6964400000000, + 0xd8dd304d00000000, 0xc520854c00000000, 0xe2275b4e00000000, + 0xffdaee4f00000000, 0xac29e74b00000000, 0xb1d4524a00000000, + 0x96d38c4800000000, 0x8b2e394900000000, 0x808efeda00000000, + 0x9d734bdb00000000, 0xba7495d900000000, 0xa78920d800000000, + 0xf47a29dc00000000, 0xe9879cdd00000000, 0xce8042df00000000, + 0xd37df7de00000000, 0x686651d700000000, 0x759be4d600000000, + 0x529c3ad400000000, 0x4f618fd500000000, 0x1c9286d100000000, + 0x016f33d000000000, 0x2668edd200000000, 0x3b9558d300000000, + 0x505fa1c100000000, 0x4da214c000000000, 0x6aa5cac200000000, + 0x77587fc300000000, 0x24ab76c700000000, 0x3956c3c600000000, + 0x1e511dc400000000, 0x03aca8c500000000, 0xb8b70ecc00000000, + 0xa54abbcd00000000, 0x824d65cf00000000, 0x9fb0d0ce00000000, + 0xcc43d9ca00000000, 0xd1be6ccb00000000, 0xf6b9b2c900000000, + 0xeb4407c800000000, 0x202d41ec00000000, 0x3dd0f4ed00000000, + 0x1ad72aef00000000, 0x072a9fee00000000, 0x54d996ea00000000, + 0x492423eb00000000, 0x6e23fde900000000, 0x73de48e800000000, + 0xc8c5eee100000000, 0xd5385be000000000, 0xf23f85e200000000, + 0xefc230e300000000, 0xbc3139e700000000, 0xa1cc8ce600000000, + 0x86cb52e400000000, 0x9b36e7e500000000, 0xf0fc1ef700000000, + 0xed01abf600000000, 0xca0675f400000000, 0xd7fbc0f500000000, + 0x8408c9f100000000, 0x99f57cf000000000, 0xbef2a2f200000000, + 0xa30f17f300000000, 0x1814b1fa00000000, 0x05e904fb00000000, + 0x22eedaf900000000, 0x3f136ff800000000, 0x6ce066fc00000000, + 0x711dd3fd00000000, 0x561a0dff00000000, 0x4be7b8fe00000000, + 0xc0c981b700000000, 0xdd3434b600000000, 0xfa33eab400000000, + 0xe7ce5fb500000000, 0xb43d56b100000000, 0xa9c0e3b000000000, + 0x8ec73db200000000, 0x933a88b300000000, 0x28212eba00000000, + 0x35dc9bbb00000000, 0x12db45b900000000, 0x0f26f0b800000000, + 0x5cd5f9bc00000000, 0x41284cbd00000000, 0x662f92bf00000000, + 0x7bd227be00000000, 0x1018deac00000000, 0x0de56bad00000000, + 0x2ae2b5af00000000, 0x371f00ae00000000, 0x64ec09aa00000000, + 0x7911bcab00000000, 0x5e1662a900000000, 0x43ebd7a800000000, + 0xf8f071a100000000, 0xe50dc4a000000000, 0xc20a1aa200000000, + 0xdff7afa300000000, 0x8c04a6a700000000, 0x91f913a600000000, + 0xb6fecda400000000, 0xab0378a500000000, 0x606a3e8100000000, + 0x7d978b8000000000, 0x5a90558200000000, 0x476de08300000000, + 0x149ee98700000000, 0x09635c8600000000, 0x2e64828400000000, + 0x3399378500000000, 0x8882918c00000000, 0x957f248d00000000, + 0xb278fa8f00000000, 0xaf854f8e00000000, 0xfc76468a00000000, + 0xe18bf38b00000000, 0xc68c2d8900000000, 0xdb71988800000000, + 0xb0bb619a00000000, 0xad46d49b00000000, 0x8a410a9900000000, + 0x97bcbf9800000000, 0xc44fb69c00000000, 0xd9b2039d00000000, + 0xfeb5dd9f00000000, 0xe348689e00000000, 0x5853ce9700000000, + 0x45ae7b9600000000, 0x62a9a59400000000, 0x7f54109500000000, + 0x2ca7199100000000, 0x315aac9000000000, 0x165d729200000000, + 0x0ba0c79300000000}, + {0x0000000000000000, 0x24d9076300000000, 0x48b20fc600000000, + 0x6c6b08a500000000, 0xd1626e5700000000, 0xf5bb693400000000, + 0x99d0619100000000, 0xbd0966f200000000, 0xa2c5dcae00000000, + 0x861cdbcd00000000, 0xea77d36800000000, 0xceaed40b00000000, + 0x73a7b2f900000000, 0x577eb59a00000000, 0x3b15bd3f00000000, + 0x1fccba5c00000000, 0x058dc88600000000, 0x2154cfe500000000, + 0x4d3fc74000000000, 0x69e6c02300000000, 0xd4efa6d100000000, + 0xf036a1b200000000, 0x9c5da91700000000, 0xb884ae7400000000, + 0xa748142800000000, 0x8391134b00000000, 0xeffa1bee00000000, + 0xcb231c8d00000000, 0x762a7a7f00000000, 0x52f37d1c00000000, + 0x3e9875b900000000, 0x1a4172da00000000, 0x4b1ce0d600000000, + 0x6fc5e7b500000000, 0x03aeef1000000000, 0x2777e87300000000, + 0x9a7e8e8100000000, 0xbea789e200000000, 0xd2cc814700000000, + 0xf615862400000000, 0xe9d93c7800000000, 0xcd003b1b00000000, + 0xa16b33be00000000, 0x85b234dd00000000, 0x38bb522f00000000, + 0x1c62554c00000000, 0x70095de900000000, 0x54d05a8a00000000, + 0x4e91285000000000, 0x6a482f3300000000, 0x0623279600000000, + 0x22fa20f500000000, 0x9ff3460700000000, 0xbb2a416400000000, + 0xd74149c100000000, 0xf3984ea200000000, 0xec54f4fe00000000, + 0xc88df39d00000000, 0xa4e6fb3800000000, 0x803ffc5b00000000, + 0x3d369aa900000000, 0x19ef9dca00000000, 0x7584956f00000000, + 0x515d920c00000000, 0xd73eb17600000000, 0xf3e7b61500000000, + 0x9f8cbeb000000000, 0xbb55b9d300000000, 0x065cdf2100000000, + 0x2285d84200000000, 0x4eeed0e700000000, 0x6a37d78400000000, + 0x75fb6dd800000000, 0x51226abb00000000, 0x3d49621e00000000, + 0x1990657d00000000, 0xa499038f00000000, 0x804004ec00000000, + 0xec2b0c4900000000, 0xc8f20b2a00000000, 0xd2b379f000000000, + 0xf66a7e9300000000, 0x9a01763600000000, 0xbed8715500000000, + 0x03d117a700000000, 0x270810c400000000, 0x4b63186100000000, + 0x6fba1f0200000000, 0x7076a55e00000000, 0x54afa23d00000000, + 0x38c4aa9800000000, 0x1c1dadfb00000000, 0xa114cb0900000000, + 0x85cdcc6a00000000, 0xe9a6c4cf00000000, 0xcd7fc3ac00000000, + 0x9c2251a000000000, 0xb8fb56c300000000, 0xd4905e6600000000, + 0xf049590500000000, 0x4d403ff700000000, 0x6999389400000000, + 0x05f2303100000000, 0x212b375200000000, 0x3ee78d0e00000000, + 0x1a3e8a6d00000000, 0x765582c800000000, 0x528c85ab00000000, + 0xef85e35900000000, 0xcb5ce43a00000000, 0xa737ec9f00000000, + 0x83eeebfc00000000, 0x99af992600000000, 0xbd769e4500000000, + 0xd11d96e000000000, 0xf5c4918300000000, 0x48cdf77100000000, + 0x6c14f01200000000, 0x007ff8b700000000, 0x24a6ffd400000000, + 0x3b6a458800000000, 0x1fb342eb00000000, 0x73d84a4e00000000, + 0x57014d2d00000000, 0xea082bdf00000000, 0xced12cbc00000000, + 0xa2ba241900000000, 0x8663237a00000000, 0xae7d62ed00000000, + 0x8aa4658e00000000, 0xe6cf6d2b00000000, 0xc2166a4800000000, + 0x7f1f0cba00000000, 0x5bc60bd900000000, 0x37ad037c00000000, + 0x1374041f00000000, 0x0cb8be4300000000, 0x2861b92000000000, + 0x440ab18500000000, 0x60d3b6e600000000, 0xdddad01400000000, + 0xf903d77700000000, 0x9568dfd200000000, 0xb1b1d8b100000000, + 0xabf0aa6b00000000, 0x8f29ad0800000000, 0xe342a5ad00000000, + 0xc79ba2ce00000000, 0x7a92c43c00000000, 0x5e4bc35f00000000, + 0x3220cbfa00000000, 0x16f9cc9900000000, 0x093576c500000000, + 0x2dec71a600000000, 0x4187790300000000, 0x655e7e6000000000, + 0xd857189200000000, 0xfc8e1ff100000000, 0x90e5175400000000, + 0xb43c103700000000, 0xe561823b00000000, 0xc1b8855800000000, + 0xadd38dfd00000000, 0x890a8a9e00000000, 0x3403ec6c00000000, + 0x10daeb0f00000000, 0x7cb1e3aa00000000, 0x5868e4c900000000, + 0x47a45e9500000000, 0x637d59f600000000, 0x0f16515300000000, + 0x2bcf563000000000, 0x96c630c200000000, 0xb21f37a100000000, + 0xde743f0400000000, 0xfaad386700000000, 0xe0ec4abd00000000, + 0xc4354dde00000000, 0xa85e457b00000000, 0x8c87421800000000, + 0x318e24ea00000000, 0x1557238900000000, 0x793c2b2c00000000, + 0x5de52c4f00000000, 0x4229961300000000, 0x66f0917000000000, + 0x0a9b99d500000000, 0x2e429eb600000000, 0x934bf84400000000, + 0xb792ff2700000000, 0xdbf9f78200000000, 0xff20f0e100000000, + 0x7943d39b00000000, 0x5d9ad4f800000000, 0x31f1dc5d00000000, + 0x1528db3e00000000, 0xa821bdcc00000000, 0x8cf8baaf00000000, + 0xe093b20a00000000, 0xc44ab56900000000, 0xdb860f3500000000, + 0xff5f085600000000, 0x933400f300000000, 0xb7ed079000000000, + 0x0ae4616200000000, 0x2e3d660100000000, 0x42566ea400000000, + 0x668f69c700000000, 0x7cce1b1d00000000, 0x58171c7e00000000, + 0x347c14db00000000, 0x10a513b800000000, 0xadac754a00000000, + 0x8975722900000000, 0xe51e7a8c00000000, 0xc1c77def00000000, + 0xde0bc7b300000000, 0xfad2c0d000000000, 0x96b9c87500000000, + 0xb260cf1600000000, 0x0f69a9e400000000, 0x2bb0ae8700000000, + 0x47dba62200000000, 0x6302a14100000000, 0x325f334d00000000, + 0x1686342e00000000, 0x7aed3c8b00000000, 0x5e343be800000000, + 0xe33d5d1a00000000, 0xc7e45a7900000000, 0xab8f52dc00000000, + 0x8f5655bf00000000, 0x909aefe300000000, 0xb443e88000000000, + 0xd828e02500000000, 0xfcf1e74600000000, 0x41f881b400000000, + 0x652186d700000000, 0x094a8e7200000000, 0x2d93891100000000, + 0x37d2fbcb00000000, 0x130bfca800000000, 0x7f60f40d00000000, + 0x5bb9f36e00000000, 0xe6b0959c00000000, 0xc26992ff00000000, + 0xae029a5a00000000, 0x8adb9d3900000000, 0x9517276500000000, + 0xb1ce200600000000, 0xdda528a300000000, 0xf97c2fc000000000, + 0x4475493200000000, 0x60ac4e5100000000, 0x0cc746f400000000, + 0x281e419700000000}, + {0x0000000000000000, 0x08e3603c00000000, 0x10c6c17800000000, + 0x1825a14400000000, 0x208c83f100000000, 0x286fe3cd00000000, + 0x304a428900000000, 0x38a922b500000000, 0x011e763800000000, + 0x09fd160400000000, 0x11d8b74000000000, 0x193bd77c00000000, + 0x2192f5c900000000, 0x297195f500000000, 0x315434b100000000, + 0x39b7548d00000000, 0x023cec7000000000, 0x0adf8c4c00000000, + 0x12fa2d0800000000, 0x1a194d3400000000, 0x22b06f8100000000, + 0x2a530fbd00000000, 0x3276aef900000000, 0x3a95cec500000000, + 0x03229a4800000000, 0x0bc1fa7400000000, 0x13e45b3000000000, + 0x1b073b0c00000000, 0x23ae19b900000000, 0x2b4d798500000000, + 0x3368d8c100000000, 0x3b8bb8fd00000000, 0x0478d8e100000000, + 0x0c9bb8dd00000000, 0x14be199900000000, 0x1c5d79a500000000, + 0x24f45b1000000000, 0x2c173b2c00000000, 0x34329a6800000000, + 0x3cd1fa5400000000, 0x0566aed900000000, 0x0d85cee500000000, + 0x15a06fa100000000, 0x1d430f9d00000000, 0x25ea2d2800000000, + 0x2d094d1400000000, 0x352cec5000000000, 0x3dcf8c6c00000000, + 0x0644349100000000, 0x0ea754ad00000000, 0x1682f5e900000000, + 0x1e6195d500000000, 0x26c8b76000000000, 0x2e2bd75c00000000, + 0x360e761800000000, 0x3eed162400000000, 0x075a42a900000000, + 0x0fb9229500000000, 0x179c83d100000000, 0x1f7fe3ed00000000, + 0x27d6c15800000000, 0x2f35a16400000000, 0x3710002000000000, + 0x3ff3601c00000000, 0x49f6c11800000000, 0x4115a12400000000, + 0x5930006000000000, 0x51d3605c00000000, 0x697a42e900000000, + 0x619922d500000000, 0x79bc839100000000, 0x715fe3ad00000000, + 0x48e8b72000000000, 0x400bd71c00000000, 0x582e765800000000, + 0x50cd166400000000, 0x686434d100000000, 0x608754ed00000000, + 0x78a2f5a900000000, 0x7041959500000000, 0x4bca2d6800000000, + 0x43294d5400000000, 0x5b0cec1000000000, 0x53ef8c2c00000000, + 0x6b46ae9900000000, 0x63a5cea500000000, 0x7b806fe100000000, + 0x73630fdd00000000, 0x4ad45b5000000000, 0x42373b6c00000000, + 0x5a129a2800000000, 0x52f1fa1400000000, 0x6a58d8a100000000, + 0x62bbb89d00000000, 0x7a9e19d900000000, 0x727d79e500000000, + 0x4d8e19f900000000, 0x456d79c500000000, 0x5d48d88100000000, + 0x55abb8bd00000000, 0x6d029a0800000000, 0x65e1fa3400000000, + 0x7dc45b7000000000, 0x75273b4c00000000, 0x4c906fc100000000, + 0x44730ffd00000000, 0x5c56aeb900000000, 0x54b5ce8500000000, + 0x6c1cec3000000000, 0x64ff8c0c00000000, 0x7cda2d4800000000, + 0x74394d7400000000, 0x4fb2f58900000000, 0x475195b500000000, + 0x5f7434f100000000, 0x579754cd00000000, 0x6f3e767800000000, + 0x67dd164400000000, 0x7ff8b70000000000, 0x771bd73c00000000, + 0x4eac83b100000000, 0x464fe38d00000000, 0x5e6a42c900000000, + 0x568922f500000000, 0x6e20004000000000, 0x66c3607c00000000, + 0x7ee6c13800000000, 0x7605a10400000000, 0x92ec833100000000, + 0x9a0fe30d00000000, 0x822a424900000000, 0x8ac9227500000000, + 0xb26000c000000000, 0xba8360fc00000000, 0xa2a6c1b800000000, + 0xaa45a18400000000, 0x93f2f50900000000, 0x9b11953500000000, + 0x8334347100000000, 0x8bd7544d00000000, 0xb37e76f800000000, + 0xbb9d16c400000000, 0xa3b8b78000000000, 0xab5bd7bc00000000, + 0x90d06f4100000000, 0x98330f7d00000000, 0x8016ae3900000000, + 0x88f5ce0500000000, 0xb05cecb000000000, 0xb8bf8c8c00000000, + 0xa09a2dc800000000, 0xa8794df400000000, 0x91ce197900000000, + 0x992d794500000000, 0x8108d80100000000, 0x89ebb83d00000000, + 0xb1429a8800000000, 0xb9a1fab400000000, 0xa1845bf000000000, + 0xa9673bcc00000000, 0x96945bd000000000, 0x9e773bec00000000, + 0x86529aa800000000, 0x8eb1fa9400000000, 0xb618d82100000000, + 0xbefbb81d00000000, 0xa6de195900000000, 0xae3d796500000000, + 0x978a2de800000000, 0x9f694dd400000000, 0x874cec9000000000, + 0x8faf8cac00000000, 0xb706ae1900000000, 0xbfe5ce2500000000, + 0xa7c06f6100000000, 0xaf230f5d00000000, 0x94a8b7a000000000, + 0x9c4bd79c00000000, 0x846e76d800000000, 0x8c8d16e400000000, + 0xb424345100000000, 0xbcc7546d00000000, 0xa4e2f52900000000, + 0xac01951500000000, 0x95b6c19800000000, 0x9d55a1a400000000, + 0x857000e000000000, 0x8d9360dc00000000, 0xb53a426900000000, + 0xbdd9225500000000, 0xa5fc831100000000, 0xad1fe32d00000000, + 0xdb1a422900000000, 0xd3f9221500000000, 0xcbdc835100000000, + 0xc33fe36d00000000, 0xfb96c1d800000000, 0xf375a1e400000000, + 0xeb5000a000000000, 0xe3b3609c00000000, 0xda04341100000000, + 0xd2e7542d00000000, 0xcac2f56900000000, 0xc221955500000000, + 0xfa88b7e000000000, 0xf26bd7dc00000000, 0xea4e769800000000, + 0xe2ad16a400000000, 0xd926ae5900000000, 0xd1c5ce6500000000, + 0xc9e06f2100000000, 0xc1030f1d00000000, 0xf9aa2da800000000, + 0xf1494d9400000000, 0xe96cecd000000000, 0xe18f8cec00000000, + 0xd838d86100000000, 0xd0dbb85d00000000, 0xc8fe191900000000, + 0xc01d792500000000, 0xf8b45b9000000000, 0xf0573bac00000000, + 0xe8729ae800000000, 0xe091fad400000000, 0xdf629ac800000000, + 0xd781faf400000000, 0xcfa45bb000000000, 0xc7473b8c00000000, + 0xffee193900000000, 0xf70d790500000000, 0xef28d84100000000, + 0xe7cbb87d00000000, 0xde7cecf000000000, 0xd69f8ccc00000000, + 0xceba2d8800000000, 0xc6594db400000000, 0xfef06f0100000000, + 0xf6130f3d00000000, 0xee36ae7900000000, 0xe6d5ce4500000000, + 0xdd5e76b800000000, 0xd5bd168400000000, 0xcd98b7c000000000, + 0xc57bd7fc00000000, 0xfdd2f54900000000, 0xf531957500000000, + 0xed14343100000000, 0xe5f7540d00000000, 0xdc40008000000000, + 0xd4a360bc00000000, 0xcc86c1f800000000, 0xc465a1c400000000, + 0xfccc837100000000, 0xf42fe34d00000000, 0xec0a420900000000, + 0xe4e9223500000000}, + {0x0000000000000000, 0xd1e8e70e00000000, 0xa2d1cf1d00000000, + 0x7339281300000000, 0x44a39f3b00000000, 0x954b783500000000, + 0xe672502600000000, 0x379ab72800000000, 0x88463f7700000000, + 0x59aed87900000000, 0x2a97f06a00000000, 0xfb7f176400000000, + 0xcce5a04c00000000, 0x1d0d474200000000, 0x6e346f5100000000, + 0xbfdc885f00000000, 0x108d7eee00000000, 0xc16599e000000000, + 0xb25cb1f300000000, 0x63b456fd00000000, 0x542ee1d500000000, + 0x85c606db00000000, 0xf6ff2ec800000000, 0x2717c9c600000000, + 0x98cb419900000000, 0x4923a69700000000, 0x3a1a8e8400000000, + 0xebf2698a00000000, 0xdc68dea200000000, 0x0d8039ac00000000, + 0x7eb911bf00000000, 0xaf51f6b100000000, 0x611c8c0700000000, + 0xb0f46b0900000000, 0xc3cd431a00000000, 0x1225a41400000000, + 0x25bf133c00000000, 0xf457f43200000000, 0x876edc2100000000, + 0x56863b2f00000000, 0xe95ab37000000000, 0x38b2547e00000000, + 0x4b8b7c6d00000000, 0x9a639b6300000000, 0xadf92c4b00000000, + 0x7c11cb4500000000, 0x0f28e35600000000, 0xdec0045800000000, + 0x7191f2e900000000, 0xa07915e700000000, 0xd3403df400000000, + 0x02a8dafa00000000, 0x35326dd200000000, 0xe4da8adc00000000, + 0x97e3a2cf00000000, 0x460b45c100000000, 0xf9d7cd9e00000000, + 0x283f2a9000000000, 0x5b06028300000000, 0x8aeee58d00000000, + 0xbd7452a500000000, 0x6c9cb5ab00000000, 0x1fa59db800000000, + 0xce4d7ab600000000, 0xc238180f00000000, 0x13d0ff0100000000, + 0x60e9d71200000000, 0xb101301c00000000, 0x869b873400000000, + 0x5773603a00000000, 0x244a482900000000, 0xf5a2af2700000000, + 0x4a7e277800000000, 0x9b96c07600000000, 0xe8afe86500000000, + 0x39470f6b00000000, 0x0eddb84300000000, 0xdf355f4d00000000, + 0xac0c775e00000000, 0x7de4905000000000, 0xd2b566e100000000, + 0x035d81ef00000000, 0x7064a9fc00000000, 0xa18c4ef200000000, + 0x9616f9da00000000, 0x47fe1ed400000000, 0x34c736c700000000, + 0xe52fd1c900000000, 0x5af3599600000000, 0x8b1bbe9800000000, + 0xf822968b00000000, 0x29ca718500000000, 0x1e50c6ad00000000, + 0xcfb821a300000000, 0xbc8109b000000000, 0x6d69eebe00000000, + 0xa324940800000000, 0x72cc730600000000, 0x01f55b1500000000, + 0xd01dbc1b00000000, 0xe7870b3300000000, 0x366fec3d00000000, + 0x4556c42e00000000, 0x94be232000000000, 0x2b62ab7f00000000, + 0xfa8a4c7100000000, 0x89b3646200000000, 0x585b836c00000000, + 0x6fc1344400000000, 0xbe29d34a00000000, 0xcd10fb5900000000, + 0x1cf81c5700000000, 0xb3a9eae600000000, 0x62410de800000000, + 0x117825fb00000000, 0xc090c2f500000000, 0xf70a75dd00000000, + 0x26e292d300000000, 0x55dbbac000000000, 0x84335dce00000000, + 0x3befd59100000000, 0xea07329f00000000, 0x993e1a8c00000000, + 0x48d6fd8200000000, 0x7f4c4aaa00000000, 0xaea4ada400000000, + 0xdd9d85b700000000, 0x0c7562b900000000, 0x8471301e00000000, + 0x5599d71000000000, 0x26a0ff0300000000, 0xf748180d00000000, + 0xc0d2af2500000000, 0x113a482b00000000, 0x6203603800000000, + 0xb3eb873600000000, 0x0c370f6900000000, 0xdddfe86700000000, + 0xaee6c07400000000, 0x7f0e277a00000000, 0x4894905200000000, + 0x997c775c00000000, 0xea455f4f00000000, 0x3badb84100000000, + 0x94fc4ef000000000, 0x4514a9fe00000000, 0x362d81ed00000000, + 0xe7c566e300000000, 0xd05fd1cb00000000, 0x01b736c500000000, + 0x728e1ed600000000, 0xa366f9d800000000, 0x1cba718700000000, + 0xcd52968900000000, 0xbe6bbe9a00000000, 0x6f83599400000000, + 0x5819eebc00000000, 0x89f109b200000000, 0xfac821a100000000, + 0x2b20c6af00000000, 0xe56dbc1900000000, 0x34855b1700000000, + 0x47bc730400000000, 0x9654940a00000000, 0xa1ce232200000000, + 0x7026c42c00000000, 0x031fec3f00000000, 0xd2f70b3100000000, + 0x6d2b836e00000000, 0xbcc3646000000000, 0xcffa4c7300000000, + 0x1e12ab7d00000000, 0x29881c5500000000, 0xf860fb5b00000000, + 0x8b59d34800000000, 0x5ab1344600000000, 0xf5e0c2f700000000, + 0x240825f900000000, 0x57310dea00000000, 0x86d9eae400000000, + 0xb1435dcc00000000, 0x60abbac200000000, 0x139292d100000000, + 0xc27a75df00000000, 0x7da6fd8000000000, 0xac4e1a8e00000000, + 0xdf77329d00000000, 0x0e9fd59300000000, 0x390562bb00000000, + 0xe8ed85b500000000, 0x9bd4ada600000000, 0x4a3c4aa800000000, + 0x4649281100000000, 0x97a1cf1f00000000, 0xe498e70c00000000, + 0x3570000200000000, 0x02eab72a00000000, 0xd302502400000000, + 0xa03b783700000000, 0x71d39f3900000000, 0xce0f176600000000, + 0x1fe7f06800000000, 0x6cded87b00000000, 0xbd363f7500000000, + 0x8aac885d00000000, 0x5b446f5300000000, 0x287d474000000000, + 0xf995a04e00000000, 0x56c456ff00000000, 0x872cb1f100000000, + 0xf41599e200000000, 0x25fd7eec00000000, 0x1267c9c400000000, + 0xc38f2eca00000000, 0xb0b606d900000000, 0x615ee1d700000000, + 0xde82698800000000, 0x0f6a8e8600000000, 0x7c53a69500000000, + 0xadbb419b00000000, 0x9a21f6b300000000, 0x4bc911bd00000000, + 0x38f039ae00000000, 0xe918dea000000000, 0x2755a41600000000, + 0xf6bd431800000000, 0x85846b0b00000000, 0x546c8c0500000000, + 0x63f63b2d00000000, 0xb21edc2300000000, 0xc127f43000000000, + 0x10cf133e00000000, 0xaf139b6100000000, 0x7efb7c6f00000000, + 0x0dc2547c00000000, 0xdc2ab37200000000, 0xebb0045a00000000, + 0x3a58e35400000000, 0x4961cb4700000000, 0x98892c4900000000, + 0x37d8daf800000000, 0xe6303df600000000, 0x950915e500000000, + 0x44e1f2eb00000000, 0x737b45c300000000, 0xa293a2cd00000000, + 0xd1aa8ade00000000, 0x00426dd000000000, 0xbf9ee58f00000000, + 0x6e76028100000000, 0x1d4f2a9200000000, 0xcca7cd9c00000000, + 0xfb3d7ab400000000, 0x2ad59dba00000000, 0x59ecb5a900000000, + 0x880452a700000000}, + {0x0000000000000000, 0xaa05daf100000000, 0x150dc53800000000, + 0xbf081fc900000000, 0x2a1a8a7100000000, 0x801f508000000000, + 0x3f174f4900000000, 0x951295b800000000, 0x543414e300000000, + 0xfe31ce1200000000, 0x4139d1db00000000, 0xeb3c0b2a00000000, + 0x7e2e9e9200000000, 0xd42b446300000000, 0x6b235baa00000000, + 0xc126815b00000000, 0xe96e591d00000000, 0x436b83ec00000000, + 0xfc639c2500000000, 0x566646d400000000, 0xc374d36c00000000, + 0x6971099d00000000, 0xd679165400000000, 0x7c7ccca500000000, + 0xbd5a4dfe00000000, 0x175f970f00000000, 0xa85788c600000000, + 0x0252523700000000, 0x9740c78f00000000, 0x3d451d7e00000000, + 0x824d02b700000000, 0x2848d84600000000, 0xd2ddb23a00000000, + 0x78d868cb00000000, 0xc7d0770200000000, 0x6dd5adf300000000, + 0xf8c7384b00000000, 0x52c2e2ba00000000, 0xedcafd7300000000, + 0x47cf278200000000, 0x86e9a6d900000000, 0x2cec7c2800000000, + 0x93e463e100000000, 0x39e1b91000000000, 0xacf32ca800000000, + 0x06f6f65900000000, 0xb9fee99000000000, 0x13fb336100000000, + 0x3bb3eb2700000000, 0x91b631d600000000, 0x2ebe2e1f00000000, + 0x84bbf4ee00000000, 0x11a9615600000000, 0xbbacbba700000000, + 0x04a4a46e00000000, 0xaea17e9f00000000, 0x6f87ffc400000000, + 0xc582253500000000, 0x7a8a3afc00000000, 0xd08fe00d00000000, + 0x459d75b500000000, 0xef98af4400000000, 0x5090b08d00000000, + 0xfa956a7c00000000, 0xa4bb657500000000, 0x0ebebf8400000000, + 0xb1b6a04d00000000, 0x1bb37abc00000000, 0x8ea1ef0400000000, + 0x24a435f500000000, 0x9bac2a3c00000000, 0x31a9f0cd00000000, + 0xf08f719600000000, 0x5a8aab6700000000, 0xe582b4ae00000000, + 0x4f876e5f00000000, 0xda95fbe700000000, 0x7090211600000000, + 0xcf983edf00000000, 0x659de42e00000000, 0x4dd53c6800000000, + 0xe7d0e69900000000, 0x58d8f95000000000, 0xf2dd23a100000000, + 0x67cfb61900000000, 0xcdca6ce800000000, 0x72c2732100000000, + 0xd8c7a9d000000000, 0x19e1288b00000000, 0xb3e4f27a00000000, + 0x0cecedb300000000, 0xa6e9374200000000, 0x33fba2fa00000000, + 0x99fe780b00000000, 0x26f667c200000000, 0x8cf3bd3300000000, + 0x7666d74f00000000, 0xdc630dbe00000000, 0x636b127700000000, + 0xc96ec88600000000, 0x5c7c5d3e00000000, 0xf67987cf00000000, + 0x4971980600000000, 0xe37442f700000000, 0x2252c3ac00000000, + 0x8857195d00000000, 0x375f069400000000, 0x9d5adc6500000000, + 0x084849dd00000000, 0xa24d932c00000000, 0x1d458ce500000000, + 0xb740561400000000, 0x9f088e5200000000, 0x350d54a300000000, + 0x8a054b6a00000000, 0x2000919b00000000, 0xb512042300000000, + 0x1f17ded200000000, 0xa01fc11b00000000, 0x0a1a1bea00000000, + 0xcb3c9ab100000000, 0x6139404000000000, 0xde315f8900000000, + 0x7434857800000000, 0xe12610c000000000, 0x4b23ca3100000000, + 0xf42bd5f800000000, 0x5e2e0f0900000000, 0x4877cbea00000000, + 0xe272111b00000000, 0x5d7a0ed200000000, 0xf77fd42300000000, + 0x626d419b00000000, 0xc8689b6a00000000, 0x776084a300000000, + 0xdd655e5200000000, 0x1c43df0900000000, 0xb64605f800000000, + 0x094e1a3100000000, 0xa34bc0c000000000, 0x3659557800000000, + 0x9c5c8f8900000000, 0x2354904000000000, 0x89514ab100000000, + 0xa11992f700000000, 0x0b1c480600000000, 0xb41457cf00000000, + 0x1e118d3e00000000, 0x8b03188600000000, 0x2106c27700000000, + 0x9e0eddbe00000000, 0x340b074f00000000, 0xf52d861400000000, + 0x5f285ce500000000, 0xe020432c00000000, 0x4a2599dd00000000, + 0xdf370c6500000000, 0x7532d69400000000, 0xca3ac95d00000000, + 0x603f13ac00000000, 0x9aaa79d000000000, 0x30afa32100000000, + 0x8fa7bce800000000, 0x25a2661900000000, 0xb0b0f3a100000000, + 0x1ab5295000000000, 0xa5bd369900000000, 0x0fb8ec6800000000, + 0xce9e6d3300000000, 0x649bb7c200000000, 0xdb93a80b00000000, + 0x719672fa00000000, 0xe484e74200000000, 0x4e813db300000000, + 0xf189227a00000000, 0x5b8cf88b00000000, 0x73c420cd00000000, + 0xd9c1fa3c00000000, 0x66c9e5f500000000, 0xcccc3f0400000000, + 0x59deaabc00000000, 0xf3db704d00000000, 0x4cd36f8400000000, + 0xe6d6b57500000000, 0x27f0342e00000000, 0x8df5eedf00000000, + 0x32fdf11600000000, 0x98f82be700000000, 0x0deabe5f00000000, + 0xa7ef64ae00000000, 0x18e77b6700000000, 0xb2e2a19600000000, + 0xecccae9f00000000, 0x46c9746e00000000, 0xf9c16ba700000000, + 0x53c4b15600000000, 0xc6d624ee00000000, 0x6cd3fe1f00000000, + 0xd3dbe1d600000000, 0x79de3b2700000000, 0xb8f8ba7c00000000, + 0x12fd608d00000000, 0xadf57f4400000000, 0x07f0a5b500000000, + 0x92e2300d00000000, 0x38e7eafc00000000, 0x87eff53500000000, + 0x2dea2fc400000000, 0x05a2f78200000000, 0xafa72d7300000000, + 0x10af32ba00000000, 0xbaaae84b00000000, 0x2fb87df300000000, + 0x85bda70200000000, 0x3ab5b8cb00000000, 0x90b0623a00000000, + 0x5196e36100000000, 0xfb93399000000000, 0x449b265900000000, + 0xee9efca800000000, 0x7b8c691000000000, 0xd189b3e100000000, + 0x6e81ac2800000000, 0xc48476d900000000, 0x3e111ca500000000, + 0x9414c65400000000, 0x2b1cd99d00000000, 0x8119036c00000000, + 0x140b96d400000000, 0xbe0e4c2500000000, 0x010653ec00000000, + 0xab03891d00000000, 0x6a25084600000000, 0xc020d2b700000000, + 0x7f28cd7e00000000, 0xd52d178f00000000, 0x403f823700000000, + 0xea3a58c600000000, 0x5532470f00000000, 0xff379dfe00000000, + 0xd77f45b800000000, 0x7d7a9f4900000000, 0xc272808000000000, + 0x68775a7100000000, 0xfd65cfc900000000, 0x5760153800000000, + 0xe8680af100000000, 0x426dd00000000000, 0x834b515b00000000, + 0x294e8baa00000000, 0x9646946300000000, 0x3c434e9200000000, + 0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000, + 0x1659c4e300000000}}; + +#else /* W == 4 */ + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0, + 0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587, + 0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa, + 0x35d57027, 0xdaa607b4, 0x5f7f9169, 0x91135bd4, 0x14cacd09, + 0x4cccbe74, 0xc91528a9, 0x0779e214, 0x82a074c9, 0xb77504ee, + 0x32ac9233, 0xfcc0588e, 0x7919ce53, 0x211fbd2e, 0xa4c62bf3, + 0x6aaae14e, 0xef737793, 0xf54b7eb3, 0x7092e86e, 0xbefe22d3, + 0x3b27b40e, 0x6321c773, 0xe6f851ae, 0x28949b13, 0xad4d0dce, + 0x98987de9, 0x1d41eb34, 0xd32d2189, 0x56f4b754, 0x0ef2c429, + 0x8b2b52f4, 0x45479849, 0xc09e0e94, 0x2fed7907, 0xaa34efda, + 0x64582567, 0xe181b3ba, 0xb987c0c7, 0x3c5e561a, 0xf2329ca7, + 0x77eb0a7a, 0x423e7a5d, 0xc7e7ec80, 0x098b263d, 0x8c52b0e0, + 0xd454c39d, 0x518d5540, 0x9fe19ffd, 0x1a380920, 0xab918dbd, + 0x2e481b60, 0xe024d1dd, 0x65fd4700, 0x3dfb347d, 0xb822a2a0, + 0x764e681d, 0xf397fec0, 0xc6428ee7, 0x439b183a, 0x8df7d287, + 0x082e445a, 0x50283727, 0xd5f1a1fa, 0x1b9d6b47, 0x9e44fd9a, + 0x71378a09, 0xf4ee1cd4, 0x3a82d669, 0xbf5b40b4, 0xe75d33c9, + 0x6284a514, 0xace86fa9, 0x2931f974, 0x1ce48953, 0x993d1f8e, + 0x5751d533, 0xd28843ee, 0x8a8e3093, 0x0f57a64e, 0xc13b6cf3, + 0x44e2fa2e, 0x5edaf30e, 0xdb0365d3, 0x156faf6e, 0x90b639b3, + 0xc8b04ace, 0x4d69dc13, 0x830516ae, 0x06dc8073, 0x3309f054, + 0xb6d06689, 0x78bcac34, 0xfd653ae9, 0xa5634994, 0x20badf49, + 0xeed615f4, 0x6b0f8329, 0x847cf4ba, 0x01a56267, 0xcfc9a8da, + 0x4a103e07, 0x12164d7a, 0x97cfdba7, 0x59a3111a, 0xdc7a87c7, + 0xe9aff7e0, 0x6c76613d, 0xa21aab80, 0x27c33d5d, 0x7fc54e20, + 0xfa1cd8fd, 0x34701240, 0xb1a9849d, 0x17256aa0, 0x92fcfc7d, + 0x5c9036c0, 0xd949a01d, 0x814fd360, 0x049645bd, 0xcafa8f00, + 0x4f2319dd, 0x7af669fa, 0xff2fff27, 0x3143359a, 0xb49aa347, + 0xec9cd03a, 0x694546e7, 0xa7298c5a, 0x22f01a87, 0xcd836d14, + 0x485afbc9, 0x86363174, 0x03efa7a9, 0x5be9d4d4, 0xde304209, + 0x105c88b4, 0x95851e69, 0xa0506e4e, 0x2589f893, 0xebe5322e, + 0x6e3ca4f3, 0x363ad78e, 0xb3e34153, 0x7d8f8bee, 0xf8561d33, + 0xe26e1413, 0x67b782ce, 0xa9db4873, 0x2c02deae, 0x7404add3, + 0xf1dd3b0e, 0x3fb1f1b3, 0xba68676e, 0x8fbd1749, 0x0a648194, + 0xc4084b29, 0x41d1ddf4, 0x19d7ae89, 0x9c0e3854, 0x5262f2e9, + 0xd7bb6434, 0x38c813a7, 0xbd11857a, 0x737d4fc7, 0xf6a4d91a, + 0xaea2aa67, 0x2b7b3cba, 0xe517f607, 0x60ce60da, 0x551b10fd, + 0xd0c28620, 0x1eae4c9d, 0x9b77da40, 0xc371a93d, 0x46a83fe0, + 0x88c4f55d, 0x0d1d6380, 0xbcb4e71d, 0x396d71c0, 0xf701bb7d, + 0x72d82da0, 0x2ade5edd, 0xaf07c800, 0x616b02bd, 0xe4b29460, + 0xd167e447, 0x54be729a, 0x9ad2b827, 0x1f0b2efa, 0x470d5d87, + 0xc2d4cb5a, 0x0cb801e7, 0x8961973a, 0x6612e0a9, 0xe3cb7674, + 0x2da7bcc9, 0xa87e2a14, 0xf0785969, 0x75a1cfb4, 0xbbcd0509, + 0x3e1493d4, 0x0bc1e3f3, 0x8e18752e, 0x4074bf93, 0xc5ad294e, + 0x9dab5a33, 0x1872ccee, 0xd61e0653, 0x53c7908e, 0x49ff99ae, + 0xcc260f73, 0x024ac5ce, 0x87935313, 0xdf95206e, 0x5a4cb6b3, + 0x94207c0e, 0x11f9ead3, 0x242c9af4, 0xa1f50c29, 0x6f99c694, + 0xea405049, 0xb2462334, 0x379fb5e9, 0xf9f37f54, 0x7c2ae989, + 0x93599e1a, 0x168008c7, 0xd8ecc27a, 0x5d3554a7, 0x053327da, + 0x80eab107, 0x4e867bba, 0xcb5fed67, 0xfe8a9d40, 0x7b530b9d, + 0xb53fc120, 0x30e657fd, 0x68e02480, 0xed39b25d, 0x235578e0, + 0xa68cee3d}, + {0x00000000, 0x76e10f9d, 0xadc46ee1, 0xdb25617c, 0x1b8fac19, + 0x6d6ea384, 0xb64bc2f8, 0xc0aacd65, 0x361e5933, 0x40ff56ae, + 0x9bda37d2, 0xed3b384f, 0x2d91f52a, 0x5b70fab7, 0x80559bcb, + 0xf6b49456, 0x6c3cb266, 0x1addbdfb, 0xc1f8dc87, 0xb719d31a, + 0x77b31e7f, 0x015211e2, 0xda77709e, 0xac967f03, 0x5a22eb55, + 0x2cc3e4c8, 0xf7e685b4, 0x81078a29, 0x41ad474c, 0x374c48d1, + 0xec6929ad, 0x9a882630, 0xd87864cd, 0xae996b50, 0x75bc0a2c, + 0x035d05b1, 0xc3f7c8d4, 0xb516c749, 0x6e33a635, 0x18d2a9a8, + 0xee663dfe, 0x98873263, 0x43a2531f, 0x35435c82, 0xf5e991e7, + 0x83089e7a, 0x582dff06, 0x2eccf09b, 0xb444d6ab, 0xc2a5d936, + 0x1980b84a, 0x6f61b7d7, 0xafcb7ab2, 0xd92a752f, 0x020f1453, + 0x74ee1bce, 0x825a8f98, 0xf4bb8005, 0x2f9ee179, 0x597feee4, + 0x99d52381, 0xef342c1c, 0x34114d60, 0x42f042fd, 0xf1f7b941, + 0x8716b6dc, 0x5c33d7a0, 0x2ad2d83d, 0xea781558, 0x9c991ac5, + 0x47bc7bb9, 0x315d7424, 0xc7e9e072, 0xb108efef, 0x6a2d8e93, + 0x1ccc810e, 0xdc664c6b, 0xaa8743f6, 0x71a2228a, 0x07432d17, + 0x9dcb0b27, 0xeb2a04ba, 0x300f65c6, 0x46ee6a5b, 0x8644a73e, + 0xf0a5a8a3, 0x2b80c9df, 0x5d61c642, 0xabd55214, 0xdd345d89, + 0x06113cf5, 0x70f03368, 0xb05afe0d, 0xc6bbf190, 0x1d9e90ec, + 0x6b7f9f71, 0x298fdd8c, 0x5f6ed211, 0x844bb36d, 0xf2aabcf0, + 0x32007195, 0x44e17e08, 0x9fc41f74, 0xe92510e9, 0x1f9184bf, + 0x69708b22, 0xb255ea5e, 0xc4b4e5c3, 0x041e28a6, 0x72ff273b, + 0xa9da4647, 0xdf3b49da, 0x45b36fea, 0x33526077, 0xe877010b, + 0x9e960e96, 0x5e3cc3f3, 0x28ddcc6e, 0xf3f8ad12, 0x8519a28f, + 0x73ad36d9, 0x054c3944, 0xde695838, 0xa88857a5, 0x68229ac0, + 0x1ec3955d, 0xc5e6f421, 0xb307fbbc, 0xe2ef7383, 0x940e7c1e, + 0x4f2b1d62, 0x39ca12ff, 0xf960df9a, 0x8f81d007, 0x54a4b17b, + 0x2245bee6, 0xd4f12ab0, 0xa210252d, 0x79354451, 0x0fd44bcc, + 0xcf7e86a9, 0xb99f8934, 0x62bae848, 0x145be7d5, 0x8ed3c1e5, + 0xf832ce78, 0x2317af04, 0x55f6a099, 0x955c6dfc, 0xe3bd6261, + 0x3898031d, 0x4e790c80, 0xb8cd98d6, 0xce2c974b, 0x1509f637, + 0x63e8f9aa, 0xa34234cf, 0xd5a33b52, 0x0e865a2e, 0x786755b3, + 0x3a97174e, 0x4c7618d3, 0x975379af, 0xe1b27632, 0x2118bb57, + 0x57f9b4ca, 0x8cdcd5b6, 0xfa3dda2b, 0x0c894e7d, 0x7a6841e0, + 0xa14d209c, 0xd7ac2f01, 0x1706e264, 0x61e7edf9, 0xbac28c85, + 0xcc238318, 0x56aba528, 0x204aaab5, 0xfb6fcbc9, 0x8d8ec454, + 0x4d240931, 0x3bc506ac, 0xe0e067d0, 0x9601684d, 0x60b5fc1b, + 0x1654f386, 0xcd7192fa, 0xbb909d67, 0x7b3a5002, 0x0ddb5f9f, + 0xd6fe3ee3, 0xa01f317e, 0x1318cac2, 0x65f9c55f, 0xbedca423, + 0xc83dabbe, 0x089766db, 0x7e766946, 0xa553083a, 0xd3b207a7, + 0x250693f1, 0x53e79c6c, 0x88c2fd10, 0xfe23f28d, 0x3e893fe8, + 0x48683075, 0x934d5109, 0xe5ac5e94, 0x7f2478a4, 0x09c57739, + 0xd2e01645, 0xa40119d8, 0x64abd4bd, 0x124adb20, 0xc96fba5c, + 0xbf8eb5c1, 0x493a2197, 0x3fdb2e0a, 0xe4fe4f76, 0x921f40eb, + 0x52b58d8e, 0x24548213, 0xff71e36f, 0x8990ecf2, 0xcb60ae0f, + 0xbd81a192, 0x66a4c0ee, 0x1045cf73, 0xd0ef0216, 0xa60e0d8b, + 0x7d2b6cf7, 0x0bca636a, 0xfd7ef73c, 0x8b9ff8a1, 0x50ba99dd, + 0x265b9640, 0xe6f15b25, 0x901054b8, 0x4b3535c4, 0x3dd43a59, + 0xa75c1c69, 0xd1bd13f4, 0x0a987288, 0x7c797d15, 0xbcd3b070, + 0xca32bfed, 0x1117de91, 0x67f6d10c, 0x9142455a, 0xe7a34ac7, + 0x3c862bbb, 0x4a672426, 0x8acde943, 0xfc2ce6de, 0x270987a2, + 0x51e8883f}, + {0x00000000, 0xe8dbfbb9, 0x91b186a8, 0x796a7d11, 0x63657c8a, + 0x8bbe8733, 0xf2d4fa22, 0x1a0f019b, 0x87cc89cf, 0x6f177276, + 0x167d0f67, 0xfea6f4de, 0xe4a9f545, 0x0c720efc, 0x751873ed, + 0x9dc38854, 0x4f9f6244, 0xa74499fd, 0xde2ee4ec, 0x36f51f55, + 0x2cfa1ece, 0xc421e577, 0xbd4b9866, 0x559063df, 0xc853eb8b, + 0x20881032, 0x59e26d23, 0xb139969a, 0xab369701, 0x43ed6cb8, + 0x3a8711a9, 0xd25cea10, 0x9e3ec588, 0x76e53e31, 0x0f8f4320, + 0xe754b899, 0xfd5bb902, 0x158042bb, 0x6cea3faa, 0x8431c413, + 0x19f24c47, 0xf129b7fe, 0x8843caef, 0x60983156, 0x7a9730cd, + 0x924ccb74, 0xeb26b665, 0x03fd4ddc, 0xd1a1a7cc, 0x397a5c75, + 0x40102164, 0xa8cbdadd, 0xb2c4db46, 0x5a1f20ff, 0x23755dee, + 0xcbaea657, 0x566d2e03, 0xbeb6d5ba, 0xc7dca8ab, 0x2f075312, + 0x35085289, 0xddd3a930, 0xa4b9d421, 0x4c622f98, 0x7d7bfbca, + 0x95a00073, 0xecca7d62, 0x041186db, 0x1e1e8740, 0xf6c57cf9, + 0x8faf01e8, 0x6774fa51, 0xfab77205, 0x126c89bc, 0x6b06f4ad, + 0x83dd0f14, 0x99d20e8f, 0x7109f536, 0x08638827, 0xe0b8739e, + 0x32e4998e, 0xda3f6237, 0xa3551f26, 0x4b8ee49f, 0x5181e504, + 0xb95a1ebd, 0xc03063ac, 0x28eb9815, 0xb5281041, 0x5df3ebf8, + 0x249996e9, 0xcc426d50, 0xd64d6ccb, 0x3e969772, 0x47fcea63, + 0xaf2711da, 0xe3453e42, 0x0b9ec5fb, 0x72f4b8ea, 0x9a2f4353, + 0x802042c8, 0x68fbb971, 0x1191c460, 0xf94a3fd9, 0x6489b78d, + 0x8c524c34, 0xf5383125, 0x1de3ca9c, 0x07eccb07, 0xef3730be, + 0x965d4daf, 0x7e86b616, 0xacda5c06, 0x4401a7bf, 0x3d6bdaae, + 0xd5b02117, 0xcfbf208c, 0x2764db35, 0x5e0ea624, 0xb6d55d9d, + 0x2b16d5c9, 0xc3cd2e70, 0xbaa75361, 0x527ca8d8, 0x4873a943, + 0xa0a852fa, 0xd9c22feb, 0x3119d452, 0xbbf0874e, 0x532b7cf7, + 0x2a4101e6, 0xc29afa5f, 0xd895fbc4, 0x304e007d, 0x49247d6c, + 0xa1ff86d5, 0x3c3c0e81, 0xd4e7f538, 0xad8d8829, 0x45567390, + 0x5f59720b, 0xb78289b2, 0xcee8f4a3, 0x26330f1a, 0xf46fe50a, + 0x1cb41eb3, 0x65de63a2, 0x8d05981b, 0x970a9980, 0x7fd16239, + 0x06bb1f28, 0xee60e491, 0x73a36cc5, 0x9b78977c, 0xe212ea6d, + 0x0ac911d4, 0x10c6104f, 0xf81debf6, 0x817796e7, 0x69ac6d5e, + 0x25ce42c6, 0xcd15b97f, 0xb47fc46e, 0x5ca43fd7, 0x46ab3e4c, + 0xae70c5f5, 0xd71ab8e4, 0x3fc1435d, 0xa202cb09, 0x4ad930b0, + 0x33b34da1, 0xdb68b618, 0xc167b783, 0x29bc4c3a, 0x50d6312b, + 0xb80dca92, 0x6a512082, 0x828adb3b, 0xfbe0a62a, 0x133b5d93, + 0x09345c08, 0xe1efa7b1, 0x9885daa0, 0x705e2119, 0xed9da94d, + 0x054652f4, 0x7c2c2fe5, 0x94f7d45c, 0x8ef8d5c7, 0x66232e7e, + 0x1f49536f, 0xf792a8d6, 0xc68b7c84, 0x2e50873d, 0x573afa2c, + 0xbfe10195, 0xa5ee000e, 0x4d35fbb7, 0x345f86a6, 0xdc847d1f, + 0x4147f54b, 0xa99c0ef2, 0xd0f673e3, 0x382d885a, 0x222289c1, + 0xcaf97278, 0xb3930f69, 0x5b48f4d0, 0x89141ec0, 0x61cfe579, + 0x18a59868, 0xf07e63d1, 0xea71624a, 0x02aa99f3, 0x7bc0e4e2, + 0x931b1f5b, 0x0ed8970f, 0xe6036cb6, 0x9f6911a7, 0x77b2ea1e, + 0x6dbdeb85, 0x8566103c, 0xfc0c6d2d, 0x14d79694, 0x58b5b90c, + 0xb06e42b5, 0xc9043fa4, 0x21dfc41d, 0x3bd0c586, 0xd30b3e3f, + 0xaa61432e, 0x42bab897, 0xdf7930c3, 0x37a2cb7a, 0x4ec8b66b, + 0xa6134dd2, 0xbc1c4c49, 0x54c7b7f0, 0x2dadcae1, 0xc5763158, + 0x172adb48, 0xfff120f1, 0x869b5de0, 0x6e40a659, 0x744fa7c2, + 0x9c945c7b, 0xe5fe216a, 0x0d25dad3, 0x90e65287, 0x783da93e, + 0x0157d42f, 0xe98c2f96, 0xf3832e0d, 0x1b58d5b4, 0x6232a8a5, + 0x8ae9531c}, + {0x00000000, 0x919168ae, 0x6325a087, 0xf2b4c829, 0x874c31d4, + 0x16dd597a, 0xe4699153, 0x75f8f9fd, 0x4f9f1373, 0xde0e7bdd, + 0x2cbab3f4, 0xbd2bdb5a, 0xc8d322a7, 0x59424a09, 0xabf68220, + 0x3a67ea8e, 0x9e3e27e6, 0x0faf4f48, 0xfd1b8761, 0x6c8aefcf, + 0x19721632, 0x88e37e9c, 0x7a57b6b5, 0xebc6de1b, 0xd1a13495, + 0x40305c3b, 0xb2849412, 0x2315fcbc, 0x56ed0541, 0xc77c6def, + 0x35c8a5c6, 0xa459cd68, 0x7d7b3f17, 0xecea57b9, 0x1e5e9f90, + 0x8fcff73e, 0xfa370ec3, 0x6ba6666d, 0x9912ae44, 0x0883c6ea, + 0x32e42c64, 0xa37544ca, 0x51c18ce3, 0xc050e44d, 0xb5a81db0, + 0x2439751e, 0xd68dbd37, 0x471cd599, 0xe34518f1, 0x72d4705f, + 0x8060b876, 0x11f1d0d8, 0x64092925, 0xf598418b, 0x072c89a2, + 0x96bde10c, 0xacda0b82, 0x3d4b632c, 0xcfffab05, 0x5e6ec3ab, + 0x2b963a56, 0xba0752f8, 0x48b39ad1, 0xd922f27f, 0xfaf67e2e, + 0x6b671680, 0x99d3dea9, 0x0842b607, 0x7dba4ffa, 0xec2b2754, + 0x1e9fef7d, 0x8f0e87d3, 0xb5696d5d, 0x24f805f3, 0xd64ccdda, + 0x47dda574, 0x32255c89, 0xa3b43427, 0x5100fc0e, 0xc09194a0, + 0x64c859c8, 0xf5593166, 0x07edf94f, 0x967c91e1, 0xe384681c, + 0x721500b2, 0x80a1c89b, 0x1130a035, 0x2b574abb, 0xbac62215, + 0x4872ea3c, 0xd9e38292, 0xac1b7b6f, 0x3d8a13c1, 0xcf3edbe8, + 0x5eafb346, 0x878d4139, 0x161c2997, 0xe4a8e1be, 0x75398910, + 0x00c170ed, 0x91501843, 0x63e4d06a, 0xf275b8c4, 0xc812524a, + 0x59833ae4, 0xab37f2cd, 0x3aa69a63, 0x4f5e639e, 0xdecf0b30, + 0x2c7bc319, 0xbdeaabb7, 0x19b366df, 0x88220e71, 0x7a96c658, + 0xeb07aef6, 0x9eff570b, 0x0f6e3fa5, 0xfddaf78c, 0x6c4b9f22, + 0x562c75ac, 0xc7bd1d02, 0x3509d52b, 0xa498bd85, 0xd1604478, + 0x40f12cd6, 0xb245e4ff, 0x23d48c51, 0xf4edfd5c, 0x657c95f2, + 0x97c85ddb, 0x06593575, 0x73a1cc88, 0xe230a426, 0x10846c0f, + 0x811504a1, 0xbb72ee2f, 0x2ae38681, 0xd8574ea8, 0x49c62606, + 0x3c3edffb, 0xadafb755, 0x5f1b7f7c, 0xce8a17d2, 0x6ad3daba, + 0xfb42b214, 0x09f67a3d, 0x98671293, 0xed9feb6e, 0x7c0e83c0, + 0x8eba4be9, 0x1f2b2347, 0x254cc9c9, 0xb4dda167, 0x4669694e, + 0xd7f801e0, 0xa200f81d, 0x339190b3, 0xc125589a, 0x50b43034, + 0x8996c24b, 0x1807aae5, 0xeab362cc, 0x7b220a62, 0x0edaf39f, + 0x9f4b9b31, 0x6dff5318, 0xfc6e3bb6, 0xc609d138, 0x5798b996, + 0xa52c71bf, 0x34bd1911, 0x4145e0ec, 0xd0d48842, 0x2260406b, + 0xb3f128c5, 0x17a8e5ad, 0x86398d03, 0x748d452a, 0xe51c2d84, + 0x90e4d479, 0x0175bcd7, 0xf3c174fe, 0x62501c50, 0x5837f6de, + 0xc9a69e70, 0x3b125659, 0xaa833ef7, 0xdf7bc70a, 0x4eeaafa4, + 0xbc5e678d, 0x2dcf0f23, 0x0e1b8372, 0x9f8aebdc, 0x6d3e23f5, + 0xfcaf4b5b, 0x8957b2a6, 0x18c6da08, 0xea721221, 0x7be37a8f, + 0x41849001, 0xd015f8af, 0x22a13086, 0xb3305828, 0xc6c8a1d5, + 0x5759c97b, 0xa5ed0152, 0x347c69fc, 0x9025a494, 0x01b4cc3a, + 0xf3000413, 0x62916cbd, 0x17699540, 0x86f8fdee, 0x744c35c7, + 0xe5dd5d69, 0xdfbab7e7, 0x4e2bdf49, 0xbc9f1760, 0x2d0e7fce, + 0x58f68633, 0xc967ee9d, 0x3bd326b4, 0xaa424e1a, 0x7360bc65, + 0xe2f1d4cb, 0x10451ce2, 0x81d4744c, 0xf42c8db1, 0x65bde51f, + 0x97092d36, 0x06984598, 0x3cffaf16, 0xad6ec7b8, 0x5fda0f91, + 0xce4b673f, 0xbbb39ec2, 0x2a22f66c, 0xd8963e45, 0x490756eb, + 0xed5e9b83, 0x7ccff32d, 0x8e7b3b04, 0x1fea53aa, 0x6a12aa57, + 0xfb83c2f9, 0x09370ad0, 0x98a6627e, 0xa2c188f0, 0x3350e05e, + 0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3, + 0xd739710d}}; + +#endif /* W */ + +#endif /* N == 4 */ +#if N == 5 + +#if W == 8 + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df, + 0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8, + 0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef, + 0x804e72a8, 0xf4e703fe, 0x5ba391b9, 0x711f2131, 0xde5bb376, + 0x24664021, 0x8b22d266, 0xa19e62ee, 0x0edaf0a9, 0x8e948201, + 0x21d01046, 0x0b6ca0ce, 0xa4283289, 0x5e15c1de, 0xf1515399, + 0xdbede311, 0x74a97156, 0x32bf01bd, 0x9dfb93fa, 0xb7472372, + 0x1803b135, 0xe23e4262, 0x4d7ad025, 0x67c660ad, 0xc882f2ea, + 0x48cc8042, 0xe7881205, 0xcd34a28d, 0x627030ca, 0x984dc39d, + 0x370951da, 0x1db5e152, 0xb2f17315, 0xc6580243, 0x691c9004, + 0x43a0208c, 0xece4b2cb, 0x16d9419c, 0xb99dd3db, 0x93216353, + 0x3c65f114, 0xbc2b83bc, 0x136f11fb, 0x39d3a173, 0x96973334, + 0x6caac063, 0xc3ee5224, 0xe952e2ac, 0x461670eb, 0x657e037a, + 0xca3a913d, 0xe08621b5, 0x4fc2b3f2, 0xb5ff40a5, 0x1abbd2e2, + 0x3007626a, 0x9f43f02d, 0x1f0d8285, 0xb04910c2, 0x9af5a04a, + 0x35b1320d, 0xcf8cc15a, 0x60c8531d, 0x4a74e395, 0xe53071d2, + 0x91990084, 0x3edd92c3, 0x1461224b, 0xbb25b00c, 0x4118435b, + 0xee5cd11c, 0xc4e06194, 0x6ba4f3d3, 0xebea817b, 0x44ae133c, + 0x6e12a3b4, 0xc15631f3, 0x3b6bc2a4, 0x942f50e3, 0xbe93e06b, + 0x11d7722c, 0x57c102c7, 0xf8859080, 0xd2392008, 0x7d7db24f, + 0x87404118, 0x2804d35f, 0x02b863d7, 0xadfcf190, 0x2db28338, + 0x82f6117f, 0xa84aa1f7, 0x070e33b0, 0xfd33c0e7, 0x527752a0, + 0x78cbe228, 0xd78f706f, 0xa3260139, 0x0c62937e, 0x26de23f6, + 0x899ab1b1, 0x73a742e6, 0xdce3d0a1, 0xf65f6029, 0x591bf26e, + 0xd95580c6, 0x76111281, 0x5cada209, 0xf3e9304e, 0x09d4c319, + 0xa690515e, 0x8c2ce1d6, 0x23687391, 0xcafc06f4, 0x65b894b3, + 0x4f04243b, 0xe040b67c, 0x1a7d452b, 0xb539d76c, 0x9f8567e4, + 0x30c1f5a3, 0xb08f870b, 0x1fcb154c, 0x3577a5c4, 0x9a333783, + 0x600ec4d4, 0xcf4a5693, 0xe5f6e61b, 0x4ab2745c, 0x3e1b050a, + 0x915f974d, 0xbbe327c5, 0x14a7b582, 0xee9a46d5, 0x41ded492, + 0x6b62641a, 0xc426f65d, 0x446884f5, 0xeb2c16b2, 0xc190a63a, + 0x6ed4347d, 0x94e9c72a, 0x3bad556d, 0x1111e5e5, 0xbe5577a2, + 0xf8430749, 0x5707950e, 0x7dbb2586, 0xd2ffb7c1, 0x28c24496, + 0x8786d6d1, 0xad3a6659, 0x027ef41e, 0x823086b6, 0x2d7414f1, + 0x07c8a479, 0xa88c363e, 0x52b1c569, 0xfdf5572e, 0xd749e7a6, + 0x780d75e1, 0x0ca404b7, 0xa3e096f0, 0x895c2678, 0x2618b43f, + 0xdc254768, 0x7361d52f, 0x59dd65a7, 0xf699f7e0, 0x76d78548, + 0xd993170f, 0xf32fa787, 0x5c6b35c0, 0xa656c697, 0x091254d0, + 0x23aee458, 0x8cea761f, 0xaf82058e, 0x00c697c9, 0x2a7a2741, + 0x853eb506, 0x7f034651, 0xd047d416, 0xfafb649e, 0x55bff6d9, + 0xd5f18471, 0x7ab51636, 0x5009a6be, 0xff4d34f9, 0x0570c7ae, + 0xaa3455e9, 0x8088e561, 0x2fcc7726, 0x5b650670, 0xf4219437, + 0xde9d24bf, 0x71d9b6f8, 0x8be445af, 0x24a0d7e8, 0x0e1c6760, + 0xa158f527, 0x2116878f, 0x8e5215c8, 0xa4eea540, 0x0baa3707, + 0xf197c450, 0x5ed35617, 0x746fe69f, 0xdb2b74d8, 0x9d3d0433, + 0x32799674, 0x18c526fc, 0xb781b4bb, 0x4dbc47ec, 0xe2f8d5ab, + 0xc8446523, 0x6700f764, 0xe74e85cc, 0x480a178b, 0x62b6a703, + 0xcdf23544, 0x37cfc613, 0x988b5454, 0xb237e4dc, 0x1d73769b, + 0x69da07cd, 0xc69e958a, 0xec222502, 0x4366b745, 0xb95b4412, + 0x161fd655, 0x3ca366dd, 0x93e7f49a, 0x13a98632, 0xbced1475, + 0x9651a4fd, 0x391536ba, 0xc328c5ed, 0x6c6c57aa, 0x46d0e722, + 0xe9947565}, + {0x00000000, 0x4e890ba9, 0x9d121752, 0xd39b1cfb, 0xe15528e5, + 0xafdc234c, 0x7c473fb7, 0x32ce341e, 0x19db578b, 0x57525c22, + 0x84c940d9, 0xca404b70, 0xf88e7f6e, 0xb60774c7, 0x659c683c, + 0x2b156395, 0x33b6af16, 0x7d3fa4bf, 0xaea4b844, 0xe02db3ed, + 0xd2e387f3, 0x9c6a8c5a, 0x4ff190a1, 0x01789b08, 0x2a6df89d, + 0x64e4f334, 0xb77fefcf, 0xf9f6e466, 0xcb38d078, 0x85b1dbd1, + 0x562ac72a, 0x18a3cc83, 0x676d5e2c, 0x29e45585, 0xfa7f497e, + 0xb4f642d7, 0x863876c9, 0xc8b17d60, 0x1b2a619b, 0x55a36a32, + 0x7eb609a7, 0x303f020e, 0xe3a41ef5, 0xad2d155c, 0x9fe32142, + 0xd16a2aeb, 0x02f13610, 0x4c783db9, 0x54dbf13a, 0x1a52fa93, + 0xc9c9e668, 0x8740edc1, 0xb58ed9df, 0xfb07d276, 0x289cce8d, + 0x6615c524, 0x4d00a6b1, 0x0389ad18, 0xd012b1e3, 0x9e9bba4a, + 0xac558e54, 0xe2dc85fd, 0x31479906, 0x7fce92af, 0xcedabc58, + 0x8053b7f1, 0x53c8ab0a, 0x1d41a0a3, 0x2f8f94bd, 0x61069f14, + 0xb29d83ef, 0xfc148846, 0xd701ebd3, 0x9988e07a, 0x4a13fc81, + 0x049af728, 0x3654c336, 0x78ddc89f, 0xab46d464, 0xe5cfdfcd, + 0xfd6c134e, 0xb3e518e7, 0x607e041c, 0x2ef70fb5, 0x1c393bab, + 0x52b03002, 0x812b2cf9, 0xcfa22750, 0xe4b744c5, 0xaa3e4f6c, + 0x79a55397, 0x372c583e, 0x05e26c20, 0x4b6b6789, 0x98f07b72, + 0xd67970db, 0xa9b7e274, 0xe73ee9dd, 0x34a5f526, 0x7a2cfe8f, + 0x48e2ca91, 0x066bc138, 0xd5f0ddc3, 0x9b79d66a, 0xb06cb5ff, + 0xfee5be56, 0x2d7ea2ad, 0x63f7a904, 0x51399d1a, 0x1fb096b3, + 0xcc2b8a48, 0x82a281e1, 0x9a014d62, 0xd48846cb, 0x07135a30, + 0x499a5199, 0x7b546587, 0x35dd6e2e, 0xe64672d5, 0xa8cf797c, + 0x83da1ae9, 0xcd531140, 0x1ec80dbb, 0x50410612, 0x628f320c, + 0x2c0639a5, 0xff9d255e, 0xb1142ef7, 0x46c47ef1, 0x084d7558, + 0xdbd669a3, 0x955f620a, 0xa7915614, 0xe9185dbd, 0x3a834146, + 0x740a4aef, 0x5f1f297a, 0x119622d3, 0xc20d3e28, 0x8c843581, + 0xbe4a019f, 0xf0c30a36, 0x235816cd, 0x6dd11d64, 0x7572d1e7, + 0x3bfbda4e, 0xe860c6b5, 0xa6e9cd1c, 0x9427f902, 0xdaaef2ab, + 0x0935ee50, 0x47bce5f9, 0x6ca9866c, 0x22208dc5, 0xf1bb913e, + 0xbf329a97, 0x8dfcae89, 0xc375a520, 0x10eeb9db, 0x5e67b272, + 0x21a920dd, 0x6f202b74, 0xbcbb378f, 0xf2323c26, 0xc0fc0838, + 0x8e750391, 0x5dee1f6a, 0x136714c3, 0x38727756, 0x76fb7cff, + 0xa5606004, 0xebe96bad, 0xd9275fb3, 0x97ae541a, 0x443548e1, + 0x0abc4348, 0x121f8fcb, 0x5c968462, 0x8f0d9899, 0xc1849330, + 0xf34aa72e, 0xbdc3ac87, 0x6e58b07c, 0x20d1bbd5, 0x0bc4d840, + 0x454dd3e9, 0x96d6cf12, 0xd85fc4bb, 0xea91f0a5, 0xa418fb0c, + 0x7783e7f7, 0x390aec5e, 0x881ec2a9, 0xc697c900, 0x150cd5fb, + 0x5b85de52, 0x694bea4c, 0x27c2e1e5, 0xf459fd1e, 0xbad0f6b7, + 0x91c59522, 0xdf4c9e8b, 0x0cd78270, 0x425e89d9, 0x7090bdc7, + 0x3e19b66e, 0xed82aa95, 0xa30ba13c, 0xbba86dbf, 0xf5216616, + 0x26ba7aed, 0x68337144, 0x5afd455a, 0x14744ef3, 0xc7ef5208, + 0x896659a1, 0xa2733a34, 0xecfa319d, 0x3f612d66, 0x71e826cf, + 0x432612d1, 0x0daf1978, 0xde340583, 0x90bd0e2a, 0xef739c85, + 0xa1fa972c, 0x72618bd7, 0x3ce8807e, 0x0e26b460, 0x40afbfc9, + 0x9334a332, 0xddbda89b, 0xf6a8cb0e, 0xb821c0a7, 0x6bbadc5c, + 0x2533d7f5, 0x17fde3eb, 0x5974e842, 0x8aeff4b9, 0xc466ff10, + 0xdcc53393, 0x924c383a, 0x41d724c1, 0x0f5e2f68, 0x3d901b76, + 0x731910df, 0xa0820c24, 0xee0b078d, 0xc51e6418, 0x8b976fb1, + 0x580c734a, 0x168578e3, 0x244b4cfd, 0x6ac24754, 0xb9595baf, + 0xf7d05006}, + {0x00000000, 0x8d88fde2, 0xc060fd85, 0x4de80067, 0x5bb0fd4b, + 0xd63800a9, 0x9bd000ce, 0x1658fd2c, 0xb761fa96, 0x3ae90774, + 0x77010713, 0xfa89faf1, 0xecd107dd, 0x6159fa3f, 0x2cb1fa58, + 0xa13907ba, 0xb5b2f36d, 0x383a0e8f, 0x75d20ee8, 0xf85af30a, + 0xee020e26, 0x638af3c4, 0x2e62f3a3, 0xa3ea0e41, 0x02d309fb, + 0x8f5bf419, 0xc2b3f47e, 0x4f3b099c, 0x5963f4b0, 0xd4eb0952, + 0x99030935, 0x148bf4d7, 0xb014e09b, 0x3d9c1d79, 0x70741d1e, + 0xfdfce0fc, 0xeba41dd0, 0x662ce032, 0x2bc4e055, 0xa64c1db7, + 0x07751a0d, 0x8afde7ef, 0xc715e788, 0x4a9d1a6a, 0x5cc5e746, + 0xd14d1aa4, 0x9ca51ac3, 0x112de721, 0x05a613f6, 0x882eee14, + 0xc5c6ee73, 0x484e1391, 0x5e16eebd, 0xd39e135f, 0x9e761338, + 0x13feeeda, 0xb2c7e960, 0x3f4f1482, 0x72a714e5, 0xff2fe907, + 0xe977142b, 0x64ffe9c9, 0x2917e9ae, 0xa49f144c, 0xbb58c777, + 0x36d03a95, 0x7b383af2, 0xf6b0c710, 0xe0e83a3c, 0x6d60c7de, + 0x2088c7b9, 0xad003a5b, 0x0c393de1, 0x81b1c003, 0xcc59c064, + 0x41d13d86, 0x5789c0aa, 0xda013d48, 0x97e93d2f, 0x1a61c0cd, + 0x0eea341a, 0x8362c9f8, 0xce8ac99f, 0x4302347d, 0x555ac951, + 0xd8d234b3, 0x953a34d4, 0x18b2c936, 0xb98bce8c, 0x3403336e, + 0x79eb3309, 0xf463ceeb, 0xe23b33c7, 0x6fb3ce25, 0x225bce42, + 0xafd333a0, 0x0b4c27ec, 0x86c4da0e, 0xcb2cda69, 0x46a4278b, + 0x50fcdaa7, 0xdd742745, 0x909c2722, 0x1d14dac0, 0xbc2ddd7a, + 0x31a52098, 0x7c4d20ff, 0xf1c5dd1d, 0xe79d2031, 0x6a15ddd3, + 0x27fdddb4, 0xaa752056, 0xbefed481, 0x33762963, 0x7e9e2904, + 0xf316d4e6, 0xe54e29ca, 0x68c6d428, 0x252ed44f, 0xa8a629ad, + 0x099f2e17, 0x8417d3f5, 0xc9ffd392, 0x44772e70, 0x522fd35c, + 0xdfa72ebe, 0x924f2ed9, 0x1fc7d33b, 0xadc088af, 0x2048754d, + 0x6da0752a, 0xe02888c8, 0xf67075e4, 0x7bf88806, 0x36108861, + 0xbb987583, 0x1aa17239, 0x97298fdb, 0xdac18fbc, 0x5749725e, + 0x41118f72, 0xcc997290, 0x817172f7, 0x0cf98f15, 0x18727bc2, + 0x95fa8620, 0xd8128647, 0x559a7ba5, 0x43c28689, 0xce4a7b6b, + 0x83a27b0c, 0x0e2a86ee, 0xaf138154, 0x229b7cb6, 0x6f737cd1, + 0xe2fb8133, 0xf4a37c1f, 0x792b81fd, 0x34c3819a, 0xb94b7c78, + 0x1dd46834, 0x905c95d6, 0xddb495b1, 0x503c6853, 0x4664957f, + 0xcbec689d, 0x860468fa, 0x0b8c9518, 0xaab592a2, 0x273d6f40, + 0x6ad56f27, 0xe75d92c5, 0xf1056fe9, 0x7c8d920b, 0x3165926c, + 0xbced6f8e, 0xa8669b59, 0x25ee66bb, 0x680666dc, 0xe58e9b3e, + 0xf3d66612, 0x7e5e9bf0, 0x33b69b97, 0xbe3e6675, 0x1f0761cf, + 0x928f9c2d, 0xdf679c4a, 0x52ef61a8, 0x44b79c84, 0xc93f6166, + 0x84d76101, 0x095f9ce3, 0x16984fd8, 0x9b10b23a, 0xd6f8b25d, + 0x5b704fbf, 0x4d28b293, 0xc0a04f71, 0x8d484f16, 0x00c0b2f4, + 0xa1f9b54e, 0x2c7148ac, 0x619948cb, 0xec11b529, 0xfa494805, + 0x77c1b5e7, 0x3a29b580, 0xb7a14862, 0xa32abcb5, 0x2ea24157, + 0x634a4130, 0xeec2bcd2, 0xf89a41fe, 0x7512bc1c, 0x38fabc7b, + 0xb5724199, 0x144b4623, 0x99c3bbc1, 0xd42bbba6, 0x59a34644, + 0x4ffbbb68, 0xc273468a, 0x8f9b46ed, 0x0213bb0f, 0xa68caf43, + 0x2b0452a1, 0x66ec52c6, 0xeb64af24, 0xfd3c5208, 0x70b4afea, + 0x3d5caf8d, 0xb0d4526f, 0x11ed55d5, 0x9c65a837, 0xd18da850, + 0x5c0555b2, 0x4a5da89e, 0xc7d5557c, 0x8a3d551b, 0x07b5a8f9, + 0x133e5c2e, 0x9eb6a1cc, 0xd35ea1ab, 0x5ed65c49, 0x488ea165, + 0xc5065c87, 0x88ee5ce0, 0x0566a102, 0xa45fa6b8, 0x29d75b5a, + 0x643f5b3d, 0xe9b7a6df, 0xffef5bf3, 0x7267a611, 0x3f8fa676, + 0xb2075b94}, + {0x00000000, 0x80f0171f, 0xda91287f, 0x5a613f60, 0x6e5356bf, + 0xeea341a0, 0xb4c27ec0, 0x343269df, 0xdca6ad7e, 0x5c56ba61, + 0x06378501, 0x86c7921e, 0xb2f5fbc1, 0x3205ecde, 0x6864d3be, + 0xe894c4a1, 0x623c5cbd, 0xe2cc4ba2, 0xb8ad74c2, 0x385d63dd, + 0x0c6f0a02, 0x8c9f1d1d, 0xd6fe227d, 0x560e3562, 0xbe9af1c3, + 0x3e6ae6dc, 0x640bd9bc, 0xe4fbcea3, 0xd0c9a77c, 0x5039b063, + 0x0a588f03, 0x8aa8981c, 0xc478b97a, 0x4488ae65, 0x1ee99105, + 0x9e19861a, 0xaa2befc5, 0x2adbf8da, 0x70bac7ba, 0xf04ad0a5, + 0x18de1404, 0x982e031b, 0xc24f3c7b, 0x42bf2b64, 0x768d42bb, + 0xf67d55a4, 0xac1c6ac4, 0x2cec7ddb, 0xa644e5c7, 0x26b4f2d8, + 0x7cd5cdb8, 0xfc25daa7, 0xc817b378, 0x48e7a467, 0x12869b07, + 0x92768c18, 0x7ae248b9, 0xfa125fa6, 0xa07360c6, 0x208377d9, + 0x14b11e06, 0x94410919, 0xce203679, 0x4ed02166, 0x538074b5, + 0xd37063aa, 0x89115cca, 0x09e14bd5, 0x3dd3220a, 0xbd233515, + 0xe7420a75, 0x67b21d6a, 0x8f26d9cb, 0x0fd6ced4, 0x55b7f1b4, + 0xd547e6ab, 0xe1758f74, 0x6185986b, 0x3be4a70b, 0xbb14b014, + 0x31bc2808, 0xb14c3f17, 0xeb2d0077, 0x6bdd1768, 0x5fef7eb7, + 0xdf1f69a8, 0x857e56c8, 0x058e41d7, 0xed1a8576, 0x6dea9269, + 0x378bad09, 0xb77bba16, 0x8349d3c9, 0x03b9c4d6, 0x59d8fbb6, + 0xd928eca9, 0x97f8cdcf, 0x1708dad0, 0x4d69e5b0, 0xcd99f2af, + 0xf9ab9b70, 0x795b8c6f, 0x233ab30f, 0xa3caa410, 0x4b5e60b1, + 0xcbae77ae, 0x91cf48ce, 0x113f5fd1, 0x250d360e, 0xa5fd2111, + 0xff9c1e71, 0x7f6c096e, 0xf5c49172, 0x7534866d, 0x2f55b90d, + 0xafa5ae12, 0x9b97c7cd, 0x1b67d0d2, 0x4106efb2, 0xc1f6f8ad, + 0x29623c0c, 0xa9922b13, 0xf3f31473, 0x7303036c, 0x47316ab3, + 0xc7c17dac, 0x9da042cc, 0x1d5055d3, 0xa700e96a, 0x27f0fe75, + 0x7d91c115, 0xfd61d60a, 0xc953bfd5, 0x49a3a8ca, 0x13c297aa, + 0x933280b5, 0x7ba64414, 0xfb56530b, 0xa1376c6b, 0x21c77b74, + 0x15f512ab, 0x950505b4, 0xcf643ad4, 0x4f942dcb, 0xc53cb5d7, + 0x45cca2c8, 0x1fad9da8, 0x9f5d8ab7, 0xab6fe368, 0x2b9ff477, + 0x71fecb17, 0xf10edc08, 0x199a18a9, 0x996a0fb6, 0xc30b30d6, + 0x43fb27c9, 0x77c94e16, 0xf7395909, 0xad586669, 0x2da87176, + 0x63785010, 0xe388470f, 0xb9e9786f, 0x39196f70, 0x0d2b06af, + 0x8ddb11b0, 0xd7ba2ed0, 0x574a39cf, 0xbfdefd6e, 0x3f2eea71, + 0x654fd511, 0xe5bfc20e, 0xd18dabd1, 0x517dbcce, 0x0b1c83ae, + 0x8bec94b1, 0x01440cad, 0x81b41bb2, 0xdbd524d2, 0x5b2533cd, + 0x6f175a12, 0xefe74d0d, 0xb586726d, 0x35766572, 0xdde2a1d3, + 0x5d12b6cc, 0x077389ac, 0x87839eb3, 0xb3b1f76c, 0x3341e073, + 0x6920df13, 0xe9d0c80c, 0xf4809ddf, 0x74708ac0, 0x2e11b5a0, + 0xaee1a2bf, 0x9ad3cb60, 0x1a23dc7f, 0x4042e31f, 0xc0b2f400, + 0x282630a1, 0xa8d627be, 0xf2b718de, 0x72470fc1, 0x4675661e, + 0xc6857101, 0x9ce44e61, 0x1c14597e, 0x96bcc162, 0x164cd67d, + 0x4c2de91d, 0xccddfe02, 0xf8ef97dd, 0x781f80c2, 0x227ebfa2, + 0xa28ea8bd, 0x4a1a6c1c, 0xcaea7b03, 0x908b4463, 0x107b537c, + 0x24493aa3, 0xa4b92dbc, 0xfed812dc, 0x7e2805c3, 0x30f824a5, + 0xb00833ba, 0xea690cda, 0x6a991bc5, 0x5eab721a, 0xde5b6505, + 0x843a5a65, 0x04ca4d7a, 0xec5e89db, 0x6cae9ec4, 0x36cfa1a4, + 0xb63fb6bb, 0x820ddf64, 0x02fdc87b, 0x589cf71b, 0xd86ce004, + 0x52c47818, 0xd2346f07, 0x88555067, 0x08a54778, 0x3c972ea7, + 0xbc6739b8, 0xe60606d8, 0x66f611c7, 0x8e62d566, 0x0e92c279, + 0x54f3fd19, 0xd403ea06, 0xe03183d9, 0x60c194c6, 0x3aa0aba6, + 0xba50bcb9}, + {0x00000000, 0x9570d495, 0xf190af6b, 0x64e07bfe, 0x38505897, + 0xad208c02, 0xc9c0f7fc, 0x5cb02369, 0x70a0b12e, 0xe5d065bb, + 0x81301e45, 0x1440cad0, 0x48f0e9b9, 0xdd803d2c, 0xb96046d2, + 0x2c109247, 0xe141625c, 0x7431b6c9, 0x10d1cd37, 0x85a119a2, + 0xd9113acb, 0x4c61ee5e, 0x288195a0, 0xbdf14135, 0x91e1d372, + 0x049107e7, 0x60717c19, 0xf501a88c, 0xa9b18be5, 0x3cc15f70, + 0x5821248e, 0xcd51f01b, 0x19f3c2f9, 0x8c83166c, 0xe8636d92, + 0x7d13b907, 0x21a39a6e, 0xb4d34efb, 0xd0333505, 0x4543e190, + 0x695373d7, 0xfc23a742, 0x98c3dcbc, 0x0db30829, 0x51032b40, + 0xc473ffd5, 0xa093842b, 0x35e350be, 0xf8b2a0a5, 0x6dc27430, + 0x09220fce, 0x9c52db5b, 0xc0e2f832, 0x55922ca7, 0x31725759, + 0xa40283cc, 0x8812118b, 0x1d62c51e, 0x7982bee0, 0xecf26a75, + 0xb042491c, 0x25329d89, 0x41d2e677, 0xd4a232e2, 0x33e785f2, + 0xa6975167, 0xc2772a99, 0x5707fe0c, 0x0bb7dd65, 0x9ec709f0, + 0xfa27720e, 0x6f57a69b, 0x434734dc, 0xd637e049, 0xb2d79bb7, + 0x27a74f22, 0x7b176c4b, 0xee67b8de, 0x8a87c320, 0x1ff717b5, + 0xd2a6e7ae, 0x47d6333b, 0x233648c5, 0xb6469c50, 0xeaf6bf39, + 0x7f866bac, 0x1b661052, 0x8e16c4c7, 0xa2065680, 0x37768215, + 0x5396f9eb, 0xc6e62d7e, 0x9a560e17, 0x0f26da82, 0x6bc6a17c, + 0xfeb675e9, 0x2a14470b, 0xbf64939e, 0xdb84e860, 0x4ef43cf5, + 0x12441f9c, 0x8734cb09, 0xe3d4b0f7, 0x76a46462, 0x5ab4f625, + 0xcfc422b0, 0xab24594e, 0x3e548ddb, 0x62e4aeb2, 0xf7947a27, + 0x937401d9, 0x0604d54c, 0xcb552557, 0x5e25f1c2, 0x3ac58a3c, + 0xafb55ea9, 0xf3057dc0, 0x6675a955, 0x0295d2ab, 0x97e5063e, + 0xbbf59479, 0x2e8540ec, 0x4a653b12, 0xdf15ef87, 0x83a5ccee, + 0x16d5187b, 0x72356385, 0xe745b710, 0x67cf0be4, 0xf2bfdf71, + 0x965fa48f, 0x032f701a, 0x5f9f5373, 0xcaef87e6, 0xae0ffc18, + 0x3b7f288d, 0x176fbaca, 0x821f6e5f, 0xe6ff15a1, 0x738fc134, + 0x2f3fe25d, 0xba4f36c8, 0xdeaf4d36, 0x4bdf99a3, 0x868e69b8, + 0x13febd2d, 0x771ec6d3, 0xe26e1246, 0xbede312f, 0x2baee5ba, + 0x4f4e9e44, 0xda3e4ad1, 0xf62ed896, 0x635e0c03, 0x07be77fd, + 0x92cea368, 0xce7e8001, 0x5b0e5494, 0x3fee2f6a, 0xaa9efbff, + 0x7e3cc91d, 0xeb4c1d88, 0x8fac6676, 0x1adcb2e3, 0x466c918a, + 0xd31c451f, 0xb7fc3ee1, 0x228cea74, 0x0e9c7833, 0x9becaca6, + 0xff0cd758, 0x6a7c03cd, 0x36cc20a4, 0xa3bcf431, 0xc75c8fcf, + 0x522c5b5a, 0x9f7dab41, 0x0a0d7fd4, 0x6eed042a, 0xfb9dd0bf, + 0xa72df3d6, 0x325d2743, 0x56bd5cbd, 0xc3cd8828, 0xefdd1a6f, + 0x7aadcefa, 0x1e4db504, 0x8b3d6191, 0xd78d42f8, 0x42fd966d, + 0x261ded93, 0xb36d3906, 0x54288e16, 0xc1585a83, 0xa5b8217d, + 0x30c8f5e8, 0x6c78d681, 0xf9080214, 0x9de879ea, 0x0898ad7f, + 0x24883f38, 0xb1f8ebad, 0xd5189053, 0x406844c6, 0x1cd867af, + 0x89a8b33a, 0xed48c8c4, 0x78381c51, 0xb569ec4a, 0x201938df, + 0x44f94321, 0xd18997b4, 0x8d39b4dd, 0x18496048, 0x7ca91bb6, + 0xe9d9cf23, 0xc5c95d64, 0x50b989f1, 0x3459f20f, 0xa129269a, + 0xfd9905f3, 0x68e9d166, 0x0c09aa98, 0x99797e0d, 0x4ddb4cef, + 0xd8ab987a, 0xbc4be384, 0x293b3711, 0x758b1478, 0xe0fbc0ed, + 0x841bbb13, 0x116b6f86, 0x3d7bfdc1, 0xa80b2954, 0xcceb52aa, + 0x599b863f, 0x052ba556, 0x905b71c3, 0xf4bb0a3d, 0x61cbdea8, + 0xac9a2eb3, 0x39eafa26, 0x5d0a81d8, 0xc87a554d, 0x94ca7624, + 0x01baa2b1, 0x655ad94f, 0xf02a0dda, 0xdc3a9f9d, 0x494a4b08, + 0x2daa30f6, 0xb8dae463, 0xe46ac70a, 0x711a139f, 0x15fa6861, + 0x808abcf4}, + {0x00000000, 0xcf9e17c8, 0x444d29d1, 0x8bd33e19, 0x889a53a2, + 0x4704446a, 0xccd77a73, 0x03496dbb, 0xca45a105, 0x05dbb6cd, + 0x8e0888d4, 0x41969f1c, 0x42dff2a7, 0x8d41e56f, 0x0692db76, + 0xc90cccbe, 0x4ffa444b, 0x80645383, 0x0bb76d9a, 0xc4297a52, + 0xc76017e9, 0x08fe0021, 0x832d3e38, 0x4cb329f0, 0x85bfe54e, + 0x4a21f286, 0xc1f2cc9f, 0x0e6cdb57, 0x0d25b6ec, 0xc2bba124, + 0x49689f3d, 0x86f688f5, 0x9ff48896, 0x506a9f5e, 0xdbb9a147, + 0x1427b68f, 0x176edb34, 0xd8f0ccfc, 0x5323f2e5, 0x9cbde52d, + 0x55b12993, 0x9a2f3e5b, 0x11fc0042, 0xde62178a, 0xdd2b7a31, + 0x12b56df9, 0x996653e0, 0x56f84428, 0xd00eccdd, 0x1f90db15, + 0x9443e50c, 0x5bddf2c4, 0x58949f7f, 0x970a88b7, 0x1cd9b6ae, + 0xd347a166, 0x1a4b6dd8, 0xd5d57a10, 0x5e064409, 0x919853c1, + 0x92d13e7a, 0x5d4f29b2, 0xd69c17ab, 0x19020063, 0xe498176d, + 0x2b0600a5, 0xa0d53ebc, 0x6f4b2974, 0x6c0244cf, 0xa39c5307, + 0x284f6d1e, 0xe7d17ad6, 0x2eddb668, 0xe143a1a0, 0x6a909fb9, + 0xa50e8871, 0xa647e5ca, 0x69d9f202, 0xe20acc1b, 0x2d94dbd3, + 0xab625326, 0x64fc44ee, 0xef2f7af7, 0x20b16d3f, 0x23f80084, + 0xec66174c, 0x67b52955, 0xa82b3e9d, 0x6127f223, 0xaeb9e5eb, + 0x256adbf2, 0xeaf4cc3a, 0xe9bda181, 0x2623b649, 0xadf08850, + 0x626e9f98, 0x7b6c9ffb, 0xb4f28833, 0x3f21b62a, 0xf0bfa1e2, + 0xf3f6cc59, 0x3c68db91, 0xb7bbe588, 0x7825f240, 0xb1293efe, + 0x7eb72936, 0xf564172f, 0x3afa00e7, 0x39b36d5c, 0xf62d7a94, + 0x7dfe448d, 0xb2605345, 0x3496dbb0, 0xfb08cc78, 0x70dbf261, + 0xbf45e5a9, 0xbc0c8812, 0x73929fda, 0xf841a1c3, 0x37dfb60b, + 0xfed37ab5, 0x314d6d7d, 0xba9e5364, 0x750044ac, 0x76492917, + 0xb9d73edf, 0x320400c6, 0xfd9a170e, 0x1241289b, 0xdddf3f53, + 0x560c014a, 0x99921682, 0x9adb7b39, 0x55456cf1, 0xde9652e8, + 0x11084520, 0xd804899e, 0x179a9e56, 0x9c49a04f, 0x53d7b787, + 0x509eda3c, 0x9f00cdf4, 0x14d3f3ed, 0xdb4de425, 0x5dbb6cd0, + 0x92257b18, 0x19f64501, 0xd66852c9, 0xd5213f72, 0x1abf28ba, + 0x916c16a3, 0x5ef2016b, 0x97fecdd5, 0x5860da1d, 0xd3b3e404, + 0x1c2df3cc, 0x1f649e77, 0xd0fa89bf, 0x5b29b7a6, 0x94b7a06e, + 0x8db5a00d, 0x422bb7c5, 0xc9f889dc, 0x06669e14, 0x052ff3af, + 0xcab1e467, 0x4162da7e, 0x8efccdb6, 0x47f00108, 0x886e16c0, + 0x03bd28d9, 0xcc233f11, 0xcf6a52aa, 0x00f44562, 0x8b277b7b, + 0x44b96cb3, 0xc24fe446, 0x0dd1f38e, 0x8602cd97, 0x499cda5f, + 0x4ad5b7e4, 0x854ba02c, 0x0e989e35, 0xc10689fd, 0x080a4543, + 0xc794528b, 0x4c476c92, 0x83d97b5a, 0x809016e1, 0x4f0e0129, + 0xc4dd3f30, 0x0b4328f8, 0xf6d93ff6, 0x3947283e, 0xb2941627, + 0x7d0a01ef, 0x7e436c54, 0xb1dd7b9c, 0x3a0e4585, 0xf590524d, + 0x3c9c9ef3, 0xf302893b, 0x78d1b722, 0xb74fa0ea, 0xb406cd51, + 0x7b98da99, 0xf04be480, 0x3fd5f348, 0xb9237bbd, 0x76bd6c75, + 0xfd6e526c, 0x32f045a4, 0x31b9281f, 0xfe273fd7, 0x75f401ce, + 0xba6a1606, 0x7366dab8, 0xbcf8cd70, 0x372bf369, 0xf8b5e4a1, + 0xfbfc891a, 0x34629ed2, 0xbfb1a0cb, 0x702fb703, 0x692db760, + 0xa6b3a0a8, 0x2d609eb1, 0xe2fe8979, 0xe1b7e4c2, 0x2e29f30a, + 0xa5facd13, 0x6a64dadb, 0xa3681665, 0x6cf601ad, 0xe7253fb4, + 0x28bb287c, 0x2bf245c7, 0xe46c520f, 0x6fbf6c16, 0xa0217bde, + 0x26d7f32b, 0xe949e4e3, 0x629adafa, 0xad04cd32, 0xae4da089, + 0x61d3b741, 0xea008958, 0x259e9e90, 0xec92522e, 0x230c45e6, + 0xa8df7bff, 0x67416c37, 0x6408018c, 0xab961644, 0x2045285d, + 0xefdb3f95}, + {0x00000000, 0x24825136, 0x4904a26c, 0x6d86f35a, 0x920944d8, + 0xb68b15ee, 0xdb0de6b4, 0xff8fb782, 0xff638ff1, 0xdbe1dec7, + 0xb6672d9d, 0x92e57cab, 0x6d6acb29, 0x49e89a1f, 0x246e6945, + 0x00ec3873, 0x25b619a3, 0x01344895, 0x6cb2bbcf, 0x4830eaf9, + 0xb7bf5d7b, 0x933d0c4d, 0xfebbff17, 0xda39ae21, 0xdad59652, + 0xfe57c764, 0x93d1343e, 0xb7536508, 0x48dcd28a, 0x6c5e83bc, + 0x01d870e6, 0x255a21d0, 0x4b6c3346, 0x6fee6270, 0x0268912a, + 0x26eac01c, 0xd965779e, 0xfde726a8, 0x9061d5f2, 0xb4e384c4, + 0xb40fbcb7, 0x908ded81, 0xfd0b1edb, 0xd9894fed, 0x2606f86f, + 0x0284a959, 0x6f025a03, 0x4b800b35, 0x6eda2ae5, 0x4a587bd3, + 0x27de8889, 0x035cd9bf, 0xfcd36e3d, 0xd8513f0b, 0xb5d7cc51, + 0x91559d67, 0x91b9a514, 0xb53bf422, 0xd8bd0778, 0xfc3f564e, + 0x03b0e1cc, 0x2732b0fa, 0x4ab443a0, 0x6e361296, 0x96d8668c, + 0xb25a37ba, 0xdfdcc4e0, 0xfb5e95d6, 0x04d12254, 0x20537362, + 0x4dd58038, 0x6957d10e, 0x69bbe97d, 0x4d39b84b, 0x20bf4b11, + 0x043d1a27, 0xfbb2ada5, 0xdf30fc93, 0xb2b60fc9, 0x96345eff, + 0xb36e7f2f, 0x97ec2e19, 0xfa6add43, 0xdee88c75, 0x21673bf7, + 0x05e56ac1, 0x6863999b, 0x4ce1c8ad, 0x4c0df0de, 0x688fa1e8, + 0x050952b2, 0x218b0384, 0xde04b406, 0xfa86e530, 0x9700166a, + 0xb382475c, 0xddb455ca, 0xf93604fc, 0x94b0f7a6, 0xb032a690, + 0x4fbd1112, 0x6b3f4024, 0x06b9b37e, 0x223be248, 0x22d7da3b, + 0x06558b0d, 0x6bd37857, 0x4f512961, 0xb0de9ee3, 0x945ccfd5, + 0xf9da3c8f, 0xdd586db9, 0xf8024c69, 0xdc801d5f, 0xb106ee05, + 0x9584bf33, 0x6a0b08b1, 0x4e895987, 0x230faadd, 0x078dfbeb, + 0x0761c398, 0x23e392ae, 0x4e6561f4, 0x6ae730c2, 0x95688740, + 0xb1ead676, 0xdc6c252c, 0xf8ee741a, 0xf6c1cb59, 0xd2439a6f, + 0xbfc56935, 0x9b473803, 0x64c88f81, 0x404adeb7, 0x2dcc2ded, + 0x094e7cdb, 0x09a244a8, 0x2d20159e, 0x40a6e6c4, 0x6424b7f2, + 0x9bab0070, 0xbf295146, 0xd2afa21c, 0xf62df32a, 0xd377d2fa, + 0xf7f583cc, 0x9a737096, 0xbef121a0, 0x417e9622, 0x65fcc714, + 0x087a344e, 0x2cf86578, 0x2c145d0b, 0x08960c3d, 0x6510ff67, + 0x4192ae51, 0xbe1d19d3, 0x9a9f48e5, 0xf719bbbf, 0xd39bea89, + 0xbdadf81f, 0x992fa929, 0xf4a95a73, 0xd02b0b45, 0x2fa4bcc7, + 0x0b26edf1, 0x66a01eab, 0x42224f9d, 0x42ce77ee, 0x664c26d8, + 0x0bcad582, 0x2f4884b4, 0xd0c73336, 0xf4456200, 0x99c3915a, + 0xbd41c06c, 0x981be1bc, 0xbc99b08a, 0xd11f43d0, 0xf59d12e6, + 0x0a12a564, 0x2e90f452, 0x43160708, 0x6794563e, 0x67786e4d, + 0x43fa3f7b, 0x2e7ccc21, 0x0afe9d17, 0xf5712a95, 0xd1f37ba3, + 0xbc7588f9, 0x98f7d9cf, 0x6019add5, 0x449bfce3, 0x291d0fb9, + 0x0d9f5e8f, 0xf210e90d, 0xd692b83b, 0xbb144b61, 0x9f961a57, + 0x9f7a2224, 0xbbf87312, 0xd67e8048, 0xf2fcd17e, 0x0d7366fc, + 0x29f137ca, 0x4477c490, 0x60f595a6, 0x45afb476, 0x612de540, + 0x0cab161a, 0x2829472c, 0xd7a6f0ae, 0xf324a198, 0x9ea252c2, + 0xba2003f4, 0xbacc3b87, 0x9e4e6ab1, 0xf3c899eb, 0xd74ac8dd, + 0x28c57f5f, 0x0c472e69, 0x61c1dd33, 0x45438c05, 0x2b759e93, + 0x0ff7cfa5, 0x62713cff, 0x46f36dc9, 0xb97cda4b, 0x9dfe8b7d, + 0xf0787827, 0xd4fa2911, 0xd4161162, 0xf0944054, 0x9d12b30e, + 0xb990e238, 0x461f55ba, 0x629d048c, 0x0f1bf7d6, 0x2b99a6e0, + 0x0ec38730, 0x2a41d606, 0x47c7255c, 0x6345746a, 0x9ccac3e8, + 0xb84892de, 0xd5ce6184, 0xf14c30b2, 0xf1a008c1, 0xd52259f7, + 0xb8a4aaad, 0x9c26fb9b, 0x63a94c19, 0x472b1d2f, 0x2aadee75, + 0x0e2fbf43}, + {0x00000000, 0x36f290f3, 0x6de521e6, 0x5b17b115, 0xdbca43cc, + 0xed38d33f, 0xb62f622a, 0x80ddf2d9, 0x6ce581d9, 0x5a17112a, + 0x0100a03f, 0x37f230cc, 0xb72fc215, 0x81dd52e6, 0xdacae3f3, + 0xec387300, 0xd9cb03b2, 0xef399341, 0xb42e2254, 0x82dcb2a7, + 0x0201407e, 0x34f3d08d, 0x6fe46198, 0x5916f16b, 0xb52e826b, + 0x83dc1298, 0xd8cba38d, 0xee39337e, 0x6ee4c1a7, 0x58165154, + 0x0301e041, 0x35f370b2, 0x68e70125, 0x5e1591d6, 0x050220c3, + 0x33f0b030, 0xb32d42e9, 0x85dfd21a, 0xdec8630f, 0xe83af3fc, + 0x040280fc, 0x32f0100f, 0x69e7a11a, 0x5f1531e9, 0xdfc8c330, + 0xe93a53c3, 0xb22de2d6, 0x84df7225, 0xb12c0297, 0x87de9264, + 0xdcc92371, 0xea3bb382, 0x6ae6415b, 0x5c14d1a8, 0x070360bd, + 0x31f1f04e, 0xddc9834e, 0xeb3b13bd, 0xb02ca2a8, 0x86de325b, + 0x0603c082, 0x30f15071, 0x6be6e164, 0x5d147197, 0xd1ce024a, + 0xe73c92b9, 0xbc2b23ac, 0x8ad9b35f, 0x0a044186, 0x3cf6d175, + 0x67e16060, 0x5113f093, 0xbd2b8393, 0x8bd91360, 0xd0cea275, + 0xe63c3286, 0x66e1c05f, 0x501350ac, 0x0b04e1b9, 0x3df6714a, + 0x080501f8, 0x3ef7910b, 0x65e0201e, 0x5312b0ed, 0xd3cf4234, + 0xe53dd2c7, 0xbe2a63d2, 0x88d8f321, 0x64e08021, 0x521210d2, + 0x0905a1c7, 0x3ff73134, 0xbf2ac3ed, 0x89d8531e, 0xd2cfe20b, + 0xe43d72f8, 0xb929036f, 0x8fdb939c, 0xd4cc2289, 0xe23eb27a, + 0x62e340a3, 0x5411d050, 0x0f066145, 0x39f4f1b6, 0xd5cc82b6, + 0xe33e1245, 0xb829a350, 0x8edb33a3, 0x0e06c17a, 0x38f45189, + 0x63e3e09c, 0x5511706f, 0x60e200dd, 0x5610902e, 0x0d07213b, + 0x3bf5b1c8, 0xbb284311, 0x8ddad3e2, 0xd6cd62f7, 0xe03ff204, + 0x0c078104, 0x3af511f7, 0x61e2a0e2, 0x57103011, 0xd7cdc2c8, + 0xe13f523b, 0xba28e32e, 0x8cda73dd, 0x78ed02d5, 0x4e1f9226, + 0x15082333, 0x23fab3c0, 0xa3274119, 0x95d5d1ea, 0xcec260ff, + 0xf830f00c, 0x1408830c, 0x22fa13ff, 0x79eda2ea, 0x4f1f3219, + 0xcfc2c0c0, 0xf9305033, 0xa227e126, 0x94d571d5, 0xa1260167, + 0x97d49194, 0xccc32081, 0xfa31b072, 0x7aec42ab, 0x4c1ed258, + 0x1709634d, 0x21fbf3be, 0xcdc380be, 0xfb31104d, 0xa026a158, + 0x96d431ab, 0x1609c372, 0x20fb5381, 0x7bece294, 0x4d1e7267, + 0x100a03f0, 0x26f89303, 0x7def2216, 0x4b1db2e5, 0xcbc0403c, + 0xfd32d0cf, 0xa62561da, 0x90d7f129, 0x7cef8229, 0x4a1d12da, + 0x110aa3cf, 0x27f8333c, 0xa725c1e5, 0x91d75116, 0xcac0e003, + 0xfc3270f0, 0xc9c10042, 0xff3390b1, 0xa42421a4, 0x92d6b157, + 0x120b438e, 0x24f9d37d, 0x7fee6268, 0x491cf29b, 0xa524819b, + 0x93d61168, 0xc8c1a07d, 0xfe33308e, 0x7eeec257, 0x481c52a4, + 0x130be3b1, 0x25f97342, 0xa923009f, 0x9fd1906c, 0xc4c62179, + 0xf234b18a, 0x72e94353, 0x441bd3a0, 0x1f0c62b5, 0x29fef246, + 0xc5c68146, 0xf33411b5, 0xa823a0a0, 0x9ed13053, 0x1e0cc28a, + 0x28fe5279, 0x73e9e36c, 0x451b739f, 0x70e8032d, 0x461a93de, + 0x1d0d22cb, 0x2bffb238, 0xab2240e1, 0x9dd0d012, 0xc6c76107, + 0xf035f1f4, 0x1c0d82f4, 0x2aff1207, 0x71e8a312, 0x471a33e1, + 0xc7c7c138, 0xf13551cb, 0xaa22e0de, 0x9cd0702d, 0xc1c401ba, + 0xf7369149, 0xac21205c, 0x9ad3b0af, 0x1a0e4276, 0x2cfcd285, + 0x77eb6390, 0x4119f363, 0xad218063, 0x9bd31090, 0xc0c4a185, + 0xf6363176, 0x76ebc3af, 0x4019535c, 0x1b0ee249, 0x2dfc72ba, + 0x180f0208, 0x2efd92fb, 0x75ea23ee, 0x4318b31d, 0xc3c541c4, + 0xf537d137, 0xae206022, 0x98d2f0d1, 0x74ea83d1, 0x42181322, + 0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb, + 0xf4377108}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000, + 0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000, + 0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000, + 0x2a11175a00000000, 0x3fa0000100000000, 0xcc30f23700000000, + 0x15c22fb700000000, 0xe652dd8100000000, 0xf3e3cada00000000, + 0x007338ec00000000, 0xb203cbd900000000, 0x419339ef00000000, + 0x54222eb400000000, 0xa7b2dc8200000000, 0x7e40010200000000, + 0x8dd0f33400000000, 0x9861e46f00000000, 0x6bf1165900000000, + 0x6b822eb500000000, 0x9812dc8300000000, 0x8da3cbd800000000, + 0x7e3339ee00000000, 0xa7c1e46e00000000, 0x5451165800000000, + 0x41e0010300000000, 0xb270f33500000000, 0x2501e76800000000, + 0xd691155e00000000, 0xc320020500000000, 0x30b0f03300000000, + 0xe9422db300000000, 0x1ad2df8500000000, 0x0f63c8de00000000, + 0xfcf33ae800000000, 0xfc80020400000000, 0x0f10f03200000000, + 0x1aa1e76900000000, 0xe931155f00000000, 0x30c3c8df00000000, + 0xc3533ae900000000, 0xd6e22db200000000, 0x2572df8400000000, + 0x97022cb100000000, 0x6492de8700000000, 0x7123c9dc00000000, + 0x82b33bea00000000, 0x5b41e66a00000000, 0xa8d1145c00000000, + 0xbd60030700000000, 0x4ef0f13100000000, 0x4e83c9dd00000000, + 0xbd133beb00000000, 0xa8a22cb000000000, 0x5b32de8600000000, + 0x82c0030600000000, 0x7150f13000000000, 0x64e1e66b00000000, + 0x9771145d00000000, 0x4a02ced100000000, 0xb9923ce700000000, + 0xac232bbc00000000, 0x5fb3d98a00000000, 0x8641040a00000000, + 0x75d1f63c00000000, 0x6060e16700000000, 0x93f0135100000000, + 0x93832bbd00000000, 0x6013d98b00000000, 0x75a2ced000000000, + 0x86323ce600000000, 0x5fc0e16600000000, 0xac50135000000000, + 0xb9e1040b00000000, 0x4a71f63d00000000, 0xf801050800000000, + 0x0b91f73e00000000, 0x1e20e06500000000, 0xedb0125300000000, + 0x3442cfd300000000, 0xc7d23de500000000, 0xd2632abe00000000, + 0x21f3d88800000000, 0x2180e06400000000, 0xd210125200000000, + 0xc7a1050900000000, 0x3431f73f00000000, 0xedc32abf00000000, + 0x1e53d88900000000, 0x0be2cfd200000000, 0xf8723de400000000, + 0x6f0329b900000000, 0x9c93db8f00000000, 0x8922ccd400000000, + 0x7ab23ee200000000, 0xa340e36200000000, 0x50d0115400000000, + 0x4561060f00000000, 0xb6f1f43900000000, 0xb682ccd500000000, + 0x45123ee300000000, 0x50a329b800000000, 0xa333db8e00000000, + 0x7ac1060e00000000, 0x8951f43800000000, 0x9ce0e36300000000, + 0x6f70115500000000, 0xdd00e26000000000, 0x2e90105600000000, + 0x3b21070d00000000, 0xc8b1f53b00000000, 0x114328bb00000000, + 0xe2d3da8d00000000, 0xf762cdd600000000, 0x04f23fe000000000, + 0x0481070c00000000, 0xf711f53a00000000, 0xe2a0e26100000000, + 0x1130105700000000, 0xc8c2cdd700000000, 0x3b523fe100000000, + 0x2ee328ba00000000, 0xdd73da8c00000000, 0xd502ed7800000000, + 0x26921f4e00000000, 0x3323081500000000, 0xc0b3fa2300000000, + 0x194127a300000000, 0xead1d59500000000, 0xff60c2ce00000000, + 0x0cf030f800000000, 0x0c83081400000000, 0xff13fa2200000000, + 0xeaa2ed7900000000, 0x19321f4f00000000, 0xc0c0c2cf00000000, + 0x335030f900000000, 0x26e127a200000000, 0xd571d59400000000, + 0x670126a100000000, 0x9491d49700000000, 0x8120c3cc00000000, + 0x72b031fa00000000, 0xab42ec7a00000000, 0x58d21e4c00000000, + 0x4d63091700000000, 0xbef3fb2100000000, 0xbe80c3cd00000000, + 0x4d1031fb00000000, 0x58a126a000000000, 0xab31d49600000000, + 0x72c3091600000000, 0x8153fb2000000000, 0x94e2ec7b00000000, + 0x67721e4d00000000, 0xf0030a1000000000, 0x0393f82600000000, + 0x1622ef7d00000000, 0xe5b21d4b00000000, 0x3c40c0cb00000000, + 0xcfd032fd00000000, 0xda6125a600000000, 0x29f1d79000000000, + 0x2982ef7c00000000, 0xda121d4a00000000, 0xcfa30a1100000000, + 0x3c33f82700000000, 0xe5c125a700000000, 0x1651d79100000000, + 0x03e0c0ca00000000, 0xf07032fc00000000, 0x4200c1c900000000, + 0xb19033ff00000000, 0xa42124a400000000, 0x57b1d69200000000, + 0x8e430b1200000000, 0x7dd3f92400000000, 0x6862ee7f00000000, + 0x9bf21c4900000000, 0x9b8124a500000000, 0x6811d69300000000, + 0x7da0c1c800000000, 0x8e3033fe00000000, 0x57c2ee7e00000000, + 0xa4521c4800000000, 0xb1e30b1300000000, 0x4273f92500000000, + 0x9f0023a900000000, 0x6c90d19f00000000, 0x7921c6c400000000, + 0x8ab134f200000000, 0x5343e97200000000, 0xa0d31b4400000000, + 0xb5620c1f00000000, 0x46f2fe2900000000, 0x4681c6c500000000, + 0xb51134f300000000, 0xa0a023a800000000, 0x5330d19e00000000, + 0x8ac20c1e00000000, 0x7952fe2800000000, 0x6ce3e97300000000, + 0x9f731b4500000000, 0x2d03e87000000000, 0xde931a4600000000, + 0xcb220d1d00000000, 0x38b2ff2b00000000, 0xe14022ab00000000, + 0x12d0d09d00000000, 0x0761c7c600000000, 0xf4f135f000000000, + 0xf4820d1c00000000, 0x0712ff2a00000000, 0x12a3e87100000000, + 0xe1331a4700000000, 0x38c1c7c700000000, 0xcb5135f100000000, + 0xdee022aa00000000, 0x2d70d09c00000000, 0xba01c4c100000000, + 0x499136f700000000, 0x5c2021ac00000000, 0xafb0d39a00000000, + 0x76420e1a00000000, 0x85d2fc2c00000000, 0x9063eb7700000000, + 0x63f3194100000000, 0x638021ad00000000, 0x9010d39b00000000, + 0x85a1c4c000000000, 0x763136f600000000, 0xafc3eb7600000000, + 0x5c53194000000000, 0x49e20e1b00000000, 0xba72fc2d00000000, + 0x08020f1800000000, 0xfb92fd2e00000000, 0xee23ea7500000000, + 0x1db3184300000000, 0xc441c5c300000000, 0x37d137f500000000, + 0x226020ae00000000, 0xd1f0d29800000000, 0xd183ea7400000000, + 0x2213184200000000, 0x37a20f1900000000, 0xc432fd2f00000000, + 0x1dc020af00000000, 0xee50d29900000000, 0xfbe1c5c200000000, + 0x087137f400000000}, + {0x0000000000000000, 0x3651822400000000, 0x6ca2044900000000, + 0x5af3866d00000000, 0xd844099200000000, 0xee158bb600000000, + 0xb4e60ddb00000000, 0x82b78fff00000000, 0xf18f63ff00000000, + 0xc7dee1db00000000, 0x9d2d67b600000000, 0xab7ce59200000000, + 0x29cb6a6d00000000, 0x1f9ae84900000000, 0x45696e2400000000, + 0x7338ec0000000000, 0xa319b62500000000, 0x9548340100000000, + 0xcfbbb26c00000000, 0xf9ea304800000000, 0x7b5dbfb700000000, + 0x4d0c3d9300000000, 0x17ffbbfe00000000, 0x21ae39da00000000, + 0x5296d5da00000000, 0x64c757fe00000000, 0x3e34d19300000000, + 0x086553b700000000, 0x8ad2dc4800000000, 0xbc835e6c00000000, + 0xe670d80100000000, 0xd0215a2500000000, 0x46336c4b00000000, + 0x7062ee6f00000000, 0x2a91680200000000, 0x1cc0ea2600000000, + 0x9e7765d900000000, 0xa826e7fd00000000, 0xf2d5619000000000, + 0xc484e3b400000000, 0xb7bc0fb400000000, 0x81ed8d9000000000, + 0xdb1e0bfd00000000, 0xed4f89d900000000, 0x6ff8062600000000, + 0x59a9840200000000, 0x035a026f00000000, 0x350b804b00000000, + 0xe52ada6e00000000, 0xd37b584a00000000, 0x8988de2700000000, + 0xbfd95c0300000000, 0x3d6ed3fc00000000, 0x0b3f51d800000000, + 0x51ccd7b500000000, 0x679d559100000000, 0x14a5b99100000000, + 0x22f43bb500000000, 0x7807bdd800000000, 0x4e563ffc00000000, + 0xcce1b00300000000, 0xfab0322700000000, 0xa043b44a00000000, + 0x9612366e00000000, 0x8c66d89600000000, 0xba375ab200000000, + 0xe0c4dcdf00000000, 0xd6955efb00000000, 0x5422d10400000000, + 0x6273532000000000, 0x3880d54d00000000, 0x0ed1576900000000, + 0x7de9bb6900000000, 0x4bb8394d00000000, 0x114bbf2000000000, + 0x271a3d0400000000, 0xa5adb2fb00000000, 0x93fc30df00000000, + 0xc90fb6b200000000, 0xff5e349600000000, 0x2f7f6eb300000000, + 0x192eec9700000000, 0x43dd6afa00000000, 0x758ce8de00000000, + 0xf73b672100000000, 0xc16ae50500000000, 0x9b99636800000000, + 0xadc8e14c00000000, 0xdef00d4c00000000, 0xe8a18f6800000000, + 0xb252090500000000, 0x84038b2100000000, 0x06b404de00000000, + 0x30e586fa00000000, 0x6a16009700000000, 0x5c4782b300000000, + 0xca55b4dd00000000, 0xfc0436f900000000, 0xa6f7b09400000000, + 0x90a632b000000000, 0x1211bd4f00000000, 0x24403f6b00000000, + 0x7eb3b90600000000, 0x48e23b2200000000, 0x3bdad72200000000, + 0x0d8b550600000000, 0x5778d36b00000000, 0x6129514f00000000, + 0xe39edeb000000000, 0xd5cf5c9400000000, 0x8f3cdaf900000000, + 0xb96d58dd00000000, 0x694c02f800000000, 0x5f1d80dc00000000, + 0x05ee06b100000000, 0x33bf849500000000, 0xb1080b6a00000000, + 0x8759894e00000000, 0xddaa0f2300000000, 0xebfb8d0700000000, + 0x98c3610700000000, 0xae92e32300000000, 0xf461654e00000000, + 0xc230e76a00000000, 0x4087689500000000, 0x76d6eab100000000, + 0x2c256cdc00000000, 0x1a74eef800000000, 0x59cbc1f600000000, + 0x6f9a43d200000000, 0x3569c5bf00000000, 0x0338479b00000000, + 0x818fc86400000000, 0xb7de4a4000000000, 0xed2dcc2d00000000, + 0xdb7c4e0900000000, 0xa844a20900000000, 0x9e15202d00000000, + 0xc4e6a64000000000, 0xf2b7246400000000, 0x7000ab9b00000000, + 0x465129bf00000000, 0x1ca2afd200000000, 0x2af32df600000000, + 0xfad277d300000000, 0xcc83f5f700000000, 0x9670739a00000000, + 0xa021f1be00000000, 0x22967e4100000000, 0x14c7fc6500000000, + 0x4e347a0800000000, 0x7865f82c00000000, 0x0b5d142c00000000, + 0x3d0c960800000000, 0x67ff106500000000, 0x51ae924100000000, + 0xd3191dbe00000000, 0xe5489f9a00000000, 0xbfbb19f700000000, + 0x89ea9bd300000000, 0x1ff8adbd00000000, 0x29a92f9900000000, + 0x735aa9f400000000, 0x450b2bd000000000, 0xc7bca42f00000000, + 0xf1ed260b00000000, 0xab1ea06600000000, 0x9d4f224200000000, + 0xee77ce4200000000, 0xd8264c6600000000, 0x82d5ca0b00000000, + 0xb484482f00000000, 0x3633c7d000000000, 0x006245f400000000, + 0x5a91c39900000000, 0x6cc041bd00000000, 0xbce11b9800000000, + 0x8ab099bc00000000, 0xd0431fd100000000, 0xe6129df500000000, + 0x64a5120a00000000, 0x52f4902e00000000, 0x0807164300000000, + 0x3e56946700000000, 0x4d6e786700000000, 0x7b3ffa4300000000, + 0x21cc7c2e00000000, 0x179dfe0a00000000, 0x952a71f500000000, + 0xa37bf3d100000000, 0xf98875bc00000000, 0xcfd9f79800000000, + 0xd5ad196000000000, 0xe3fc9b4400000000, 0xb90f1d2900000000, + 0x8f5e9f0d00000000, 0x0de910f200000000, 0x3bb892d600000000, + 0x614b14bb00000000, 0x571a969f00000000, 0x24227a9f00000000, + 0x1273f8bb00000000, 0x48807ed600000000, 0x7ed1fcf200000000, + 0xfc66730d00000000, 0xca37f12900000000, 0x90c4774400000000, + 0xa695f56000000000, 0x76b4af4500000000, 0x40e52d6100000000, + 0x1a16ab0c00000000, 0x2c47292800000000, 0xaef0a6d700000000, + 0x98a124f300000000, 0xc252a29e00000000, 0xf40320ba00000000, + 0x873bccba00000000, 0xb16a4e9e00000000, 0xeb99c8f300000000, + 0xddc84ad700000000, 0x5f7fc52800000000, 0x692e470c00000000, + 0x33ddc16100000000, 0x058c434500000000, 0x939e752b00000000, + 0xa5cff70f00000000, 0xff3c716200000000, 0xc96df34600000000, + 0x4bda7cb900000000, 0x7d8bfe9d00000000, 0x277878f000000000, + 0x1129fad400000000, 0x621116d400000000, 0x544094f000000000, + 0x0eb3129d00000000, 0x38e290b900000000, 0xba551f4600000000, + 0x8c049d6200000000, 0xd6f71b0f00000000, 0xe0a6992b00000000, + 0x3087c30e00000000, 0x06d6412a00000000, 0x5c25c74700000000, + 0x6a74456300000000, 0xe8c3ca9c00000000, 0xde9248b800000000, + 0x8461ced500000000, 0xb2304cf100000000, 0xc108a0f100000000, + 0xf75922d500000000, 0xadaaa4b800000000, 0x9bfb269c00000000, + 0x194ca96300000000, 0x2f1d2b4700000000, 0x75eead2a00000000, + 0x43bf2f0e00000000}, + {0x0000000000000000, 0xc8179ecf00000000, 0xd1294d4400000000, + 0x193ed38b00000000, 0xa2539a8800000000, 0x6a44044700000000, + 0x737ad7cc00000000, 0xbb6d490300000000, 0x05a145ca00000000, + 0xcdb6db0500000000, 0xd488088e00000000, 0x1c9f964100000000, + 0xa7f2df4200000000, 0x6fe5418d00000000, 0x76db920600000000, + 0xbecc0cc900000000, 0x4b44fa4f00000000, 0x8353648000000000, + 0x9a6db70b00000000, 0x527a29c400000000, 0xe91760c700000000, + 0x2100fe0800000000, 0x383e2d8300000000, 0xf029b34c00000000, + 0x4ee5bf8500000000, 0x86f2214a00000000, 0x9fccf2c100000000, + 0x57db6c0e00000000, 0xecb6250d00000000, 0x24a1bbc200000000, + 0x3d9f684900000000, 0xf588f68600000000, 0x9688f49f00000000, + 0x5e9f6a5000000000, 0x47a1b9db00000000, 0x8fb6271400000000, + 0x34db6e1700000000, 0xfcccf0d800000000, 0xe5f2235300000000, + 0x2de5bd9c00000000, 0x9329b15500000000, 0x5b3e2f9a00000000, + 0x4200fc1100000000, 0x8a1762de00000000, 0x317a2bdd00000000, + 0xf96db51200000000, 0xe053669900000000, 0x2844f85600000000, + 0xddcc0ed000000000, 0x15db901f00000000, 0x0ce5439400000000, + 0xc4f2dd5b00000000, 0x7f9f945800000000, 0xb7880a9700000000, + 0xaeb6d91c00000000, 0x66a147d300000000, 0xd86d4b1a00000000, + 0x107ad5d500000000, 0x0944065e00000000, 0xc153989100000000, + 0x7a3ed19200000000, 0xb2294f5d00000000, 0xab179cd600000000, + 0x6300021900000000, 0x6d1798e400000000, 0xa500062b00000000, + 0xbc3ed5a000000000, 0x74294b6f00000000, 0xcf44026c00000000, + 0x07539ca300000000, 0x1e6d4f2800000000, 0xd67ad1e700000000, + 0x68b6dd2e00000000, 0xa0a143e100000000, 0xb99f906a00000000, + 0x71880ea500000000, 0xcae547a600000000, 0x02f2d96900000000, + 0x1bcc0ae200000000, 0xd3db942d00000000, 0x265362ab00000000, + 0xee44fc6400000000, 0xf77a2fef00000000, 0x3f6db12000000000, + 0x8400f82300000000, 0x4c1766ec00000000, 0x5529b56700000000, + 0x9d3e2ba800000000, 0x23f2276100000000, 0xebe5b9ae00000000, + 0xf2db6a2500000000, 0x3accf4ea00000000, 0x81a1bde900000000, + 0x49b6232600000000, 0x5088f0ad00000000, 0x989f6e6200000000, + 0xfb9f6c7b00000000, 0x3388f2b400000000, 0x2ab6213f00000000, + 0xe2a1bff000000000, 0x59ccf6f300000000, 0x91db683c00000000, + 0x88e5bbb700000000, 0x40f2257800000000, 0xfe3e29b100000000, + 0x3629b77e00000000, 0x2f1764f500000000, 0xe700fa3a00000000, + 0x5c6db33900000000, 0x947a2df600000000, 0x8d44fe7d00000000, + 0x455360b200000000, 0xb0db963400000000, 0x78cc08fb00000000, + 0x61f2db7000000000, 0xa9e545bf00000000, 0x12880cbc00000000, + 0xda9f927300000000, 0xc3a141f800000000, 0x0bb6df3700000000, + 0xb57ad3fe00000000, 0x7d6d4d3100000000, 0x64539eba00000000, + 0xac44007500000000, 0x1729497600000000, 0xdf3ed7b900000000, + 0xc600043200000000, 0x0e179afd00000000, 0x9b28411200000000, + 0x533fdfdd00000000, 0x4a010c5600000000, 0x8216929900000000, + 0x397bdb9a00000000, 0xf16c455500000000, 0xe85296de00000000, + 0x2045081100000000, 0x9e8904d800000000, 0x569e9a1700000000, + 0x4fa0499c00000000, 0x87b7d75300000000, 0x3cda9e5000000000, + 0xf4cd009f00000000, 0xedf3d31400000000, 0x25e44ddb00000000, + 0xd06cbb5d00000000, 0x187b259200000000, 0x0145f61900000000, + 0xc95268d600000000, 0x723f21d500000000, 0xba28bf1a00000000, + 0xa3166c9100000000, 0x6b01f25e00000000, 0xd5cdfe9700000000, + 0x1dda605800000000, 0x04e4b3d300000000, 0xccf32d1c00000000, + 0x779e641f00000000, 0xbf89fad000000000, 0xa6b7295b00000000, + 0x6ea0b79400000000, 0x0da0b58d00000000, 0xc5b72b4200000000, + 0xdc89f8c900000000, 0x149e660600000000, 0xaff32f0500000000, + 0x67e4b1ca00000000, 0x7eda624100000000, 0xb6cdfc8e00000000, + 0x0801f04700000000, 0xc0166e8800000000, 0xd928bd0300000000, + 0x113f23cc00000000, 0xaa526acf00000000, 0x6245f40000000000, + 0x7b7b278b00000000, 0xb36cb94400000000, 0x46e44fc200000000, + 0x8ef3d10d00000000, 0x97cd028600000000, 0x5fda9c4900000000, + 0xe4b7d54a00000000, 0x2ca04b8500000000, 0x359e980e00000000, + 0xfd8906c100000000, 0x43450a0800000000, 0x8b5294c700000000, + 0x926c474c00000000, 0x5a7bd98300000000, 0xe116908000000000, + 0x29010e4f00000000, 0x303fddc400000000, 0xf828430b00000000, + 0xf63fd9f600000000, 0x3e28473900000000, 0x271694b200000000, + 0xef010a7d00000000, 0x546c437e00000000, 0x9c7bddb100000000, + 0x85450e3a00000000, 0x4d5290f500000000, 0xf39e9c3c00000000, + 0x3b8902f300000000, 0x22b7d17800000000, 0xeaa04fb700000000, + 0x51cd06b400000000, 0x99da987b00000000, 0x80e44bf000000000, + 0x48f3d53f00000000, 0xbd7b23b900000000, 0x756cbd7600000000, + 0x6c526efd00000000, 0xa445f03200000000, 0x1f28b93100000000, + 0xd73f27fe00000000, 0xce01f47500000000, 0x06166aba00000000, + 0xb8da667300000000, 0x70cdf8bc00000000, 0x69f32b3700000000, + 0xa1e4b5f800000000, 0x1a89fcfb00000000, 0xd29e623400000000, + 0xcba0b1bf00000000, 0x03b72f7000000000, 0x60b72d6900000000, + 0xa8a0b3a600000000, 0xb19e602d00000000, 0x7989fee200000000, + 0xc2e4b7e100000000, 0x0af3292e00000000, 0x13cdfaa500000000, + 0xdbda646a00000000, 0x651668a300000000, 0xad01f66c00000000, + 0xb43f25e700000000, 0x7c28bb2800000000, 0xc745f22b00000000, + 0x0f526ce400000000, 0x166cbf6f00000000, 0xde7b21a000000000, + 0x2bf3d72600000000, 0xe3e449e900000000, 0xfada9a6200000000, + 0x32cd04ad00000000, 0x89a04dae00000000, 0x41b7d36100000000, + 0x588900ea00000000, 0x909e9e2500000000, 0x2e5292ec00000000, + 0xe6450c2300000000, 0xff7bdfa800000000, 0x376c416700000000, + 0x8c01086400000000, 0x441696ab00000000, 0x5d28452000000000, + 0x953fdbef00000000}, + {0x0000000000000000, 0x95d4709500000000, 0x6baf90f100000000, + 0xfe7be06400000000, 0x9758503800000000, 0x028c20ad00000000, + 0xfcf7c0c900000000, 0x6923b05c00000000, 0x2eb1a07000000000, + 0xbb65d0e500000000, 0x451e308100000000, 0xd0ca401400000000, + 0xb9e9f04800000000, 0x2c3d80dd00000000, 0xd24660b900000000, + 0x4792102c00000000, 0x5c6241e100000000, 0xc9b6317400000000, + 0x37cdd11000000000, 0xa219a18500000000, 0xcb3a11d900000000, + 0x5eee614c00000000, 0xa095812800000000, 0x3541f1bd00000000, + 0x72d3e19100000000, 0xe707910400000000, 0x197c716000000000, + 0x8ca801f500000000, 0xe58bb1a900000000, 0x705fc13c00000000, + 0x8e24215800000000, 0x1bf051cd00000000, 0xf9c2f31900000000, + 0x6c16838c00000000, 0x926d63e800000000, 0x07b9137d00000000, + 0x6e9aa32100000000, 0xfb4ed3b400000000, 0x053533d000000000, + 0x90e1434500000000, 0xd773536900000000, 0x42a723fc00000000, + 0xbcdcc39800000000, 0x2908b30d00000000, 0x402b035100000000, + 0xd5ff73c400000000, 0x2b8493a000000000, 0xbe50e33500000000, + 0xa5a0b2f800000000, 0x3074c26d00000000, 0xce0f220900000000, + 0x5bdb529c00000000, 0x32f8e2c000000000, 0xa72c925500000000, + 0x5957723100000000, 0xcc8302a400000000, 0x8b11128800000000, + 0x1ec5621d00000000, 0xe0be827900000000, 0x756af2ec00000000, + 0x1c4942b000000000, 0x899d322500000000, 0x77e6d24100000000, + 0xe232a2d400000000, 0xf285e73300000000, 0x675197a600000000, + 0x992a77c200000000, 0x0cfe075700000000, 0x65ddb70b00000000, + 0xf009c79e00000000, 0x0e7227fa00000000, 0x9ba6576f00000000, + 0xdc34474300000000, 0x49e037d600000000, 0xb79bd7b200000000, + 0x224fa72700000000, 0x4b6c177b00000000, 0xdeb867ee00000000, + 0x20c3878a00000000, 0xb517f71f00000000, 0xaee7a6d200000000, + 0x3b33d64700000000, 0xc548362300000000, 0x509c46b600000000, + 0x39bff6ea00000000, 0xac6b867f00000000, 0x5210661b00000000, + 0xc7c4168e00000000, 0x805606a200000000, 0x1582763700000000, + 0xebf9965300000000, 0x7e2de6c600000000, 0x170e569a00000000, + 0x82da260f00000000, 0x7ca1c66b00000000, 0xe975b6fe00000000, + 0x0b47142a00000000, 0x9e9364bf00000000, 0x60e884db00000000, + 0xf53cf44e00000000, 0x9c1f441200000000, 0x09cb348700000000, + 0xf7b0d4e300000000, 0x6264a47600000000, 0x25f6b45a00000000, + 0xb022c4cf00000000, 0x4e5924ab00000000, 0xdb8d543e00000000, + 0xb2aee46200000000, 0x277a94f700000000, 0xd901749300000000, + 0x4cd5040600000000, 0x572555cb00000000, 0xc2f1255e00000000, + 0x3c8ac53a00000000, 0xa95eb5af00000000, 0xc07d05f300000000, + 0x55a9756600000000, 0xabd2950200000000, 0x3e06e59700000000, + 0x7994f5bb00000000, 0xec40852e00000000, 0x123b654a00000000, + 0x87ef15df00000000, 0xeecca58300000000, 0x7b18d51600000000, + 0x8563357200000000, 0x10b745e700000000, 0xe40bcf6700000000, + 0x71dfbff200000000, 0x8fa45f9600000000, 0x1a702f0300000000, + 0x73539f5f00000000, 0xe687efca00000000, 0x18fc0fae00000000, + 0x8d287f3b00000000, 0xcaba6f1700000000, 0x5f6e1f8200000000, + 0xa115ffe600000000, 0x34c18f7300000000, 0x5de23f2f00000000, + 0xc8364fba00000000, 0x364dafde00000000, 0xa399df4b00000000, + 0xb8698e8600000000, 0x2dbdfe1300000000, 0xd3c61e7700000000, + 0x46126ee200000000, 0x2f31debe00000000, 0xbae5ae2b00000000, + 0x449e4e4f00000000, 0xd14a3eda00000000, 0x96d82ef600000000, + 0x030c5e6300000000, 0xfd77be0700000000, 0x68a3ce9200000000, + 0x01807ece00000000, 0x94540e5b00000000, 0x6a2fee3f00000000, + 0xfffb9eaa00000000, 0x1dc93c7e00000000, 0x881d4ceb00000000, + 0x7666ac8f00000000, 0xe3b2dc1a00000000, 0x8a916c4600000000, + 0x1f451cd300000000, 0xe13efcb700000000, 0x74ea8c2200000000, + 0x33789c0e00000000, 0xa6acec9b00000000, 0x58d70cff00000000, + 0xcd037c6a00000000, 0xa420cc3600000000, 0x31f4bca300000000, + 0xcf8f5cc700000000, 0x5a5b2c5200000000, 0x41ab7d9f00000000, + 0xd47f0d0a00000000, 0x2a04ed6e00000000, 0xbfd09dfb00000000, + 0xd6f32da700000000, 0x43275d3200000000, 0xbd5cbd5600000000, + 0x2888cdc300000000, 0x6f1addef00000000, 0xfacead7a00000000, + 0x04b54d1e00000000, 0x91613d8b00000000, 0xf8428dd700000000, + 0x6d96fd4200000000, 0x93ed1d2600000000, 0x06396db300000000, + 0x168e285400000000, 0x835a58c100000000, 0x7d21b8a500000000, + 0xe8f5c83000000000, 0x81d6786c00000000, 0x140208f900000000, + 0xea79e89d00000000, 0x7fad980800000000, 0x383f882400000000, + 0xadebf8b100000000, 0x539018d500000000, 0xc644684000000000, + 0xaf67d81c00000000, 0x3ab3a88900000000, 0xc4c848ed00000000, + 0x511c387800000000, 0x4aec69b500000000, 0xdf38192000000000, + 0x2143f94400000000, 0xb49789d100000000, 0xddb4398d00000000, + 0x4860491800000000, 0xb61ba97c00000000, 0x23cfd9e900000000, + 0x645dc9c500000000, 0xf189b95000000000, 0x0ff2593400000000, + 0x9a2629a100000000, 0xf30599fd00000000, 0x66d1e96800000000, + 0x98aa090c00000000, 0x0d7e799900000000, 0xef4cdb4d00000000, + 0x7a98abd800000000, 0x84e34bbc00000000, 0x11373b2900000000, + 0x78148b7500000000, 0xedc0fbe000000000, 0x13bb1b8400000000, + 0x866f6b1100000000, 0xc1fd7b3d00000000, 0x54290ba800000000, + 0xaa52ebcc00000000, 0x3f869b5900000000, 0x56a52b0500000000, + 0xc3715b9000000000, 0x3d0abbf400000000, 0xa8decb6100000000, + 0xb32e9aac00000000, 0x26faea3900000000, 0xd8810a5d00000000, + 0x4d557ac800000000, 0x2476ca9400000000, 0xb1a2ba0100000000, + 0x4fd95a6500000000, 0xda0d2af000000000, 0x9d9f3adc00000000, + 0x084b4a4900000000, 0xf630aa2d00000000, 0x63e4dab800000000, + 0x0ac76ae400000000, 0x9f131a7100000000, 0x6168fa1500000000, + 0xf4bc8a8000000000}, + {0x0000000000000000, 0x1f17f08000000000, 0x7f2891da00000000, + 0x603f615a00000000, 0xbf56536e00000000, 0xa041a3ee00000000, + 0xc07ec2b400000000, 0xdf69323400000000, 0x7eada6dc00000000, + 0x61ba565c00000000, 0x0185370600000000, 0x1e92c78600000000, + 0xc1fbf5b200000000, 0xdeec053200000000, 0xbed3646800000000, + 0xa1c494e800000000, 0xbd5c3c6200000000, 0xa24bcce200000000, + 0xc274adb800000000, 0xdd635d3800000000, 0x020a6f0c00000000, + 0x1d1d9f8c00000000, 0x7d22fed600000000, 0x62350e5600000000, + 0xc3f19abe00000000, 0xdce66a3e00000000, 0xbcd90b6400000000, + 0xa3cefbe400000000, 0x7ca7c9d000000000, 0x63b0395000000000, + 0x038f580a00000000, 0x1c98a88a00000000, 0x7ab978c400000000, + 0x65ae884400000000, 0x0591e91e00000000, 0x1a86199e00000000, + 0xc5ef2baa00000000, 0xdaf8db2a00000000, 0xbac7ba7000000000, + 0xa5d04af000000000, 0x0414de1800000000, 0x1b032e9800000000, + 0x7b3c4fc200000000, 0x642bbf4200000000, 0xbb428d7600000000, + 0xa4557df600000000, 0xc46a1cac00000000, 0xdb7dec2c00000000, + 0xc7e544a600000000, 0xd8f2b42600000000, 0xb8cdd57c00000000, + 0xa7da25fc00000000, 0x78b317c800000000, 0x67a4e74800000000, + 0x079b861200000000, 0x188c769200000000, 0xb948e27a00000000, + 0xa65f12fa00000000, 0xc66073a000000000, 0xd977832000000000, + 0x061eb11400000000, 0x1909419400000000, 0x793620ce00000000, + 0x6621d04e00000000, 0xb574805300000000, 0xaa6370d300000000, + 0xca5c118900000000, 0xd54be10900000000, 0x0a22d33d00000000, + 0x153523bd00000000, 0x750a42e700000000, 0x6a1db26700000000, + 0xcbd9268f00000000, 0xd4ced60f00000000, 0xb4f1b75500000000, + 0xabe647d500000000, 0x748f75e100000000, 0x6b98856100000000, + 0x0ba7e43b00000000, 0x14b014bb00000000, 0x0828bc3100000000, + 0x173f4cb100000000, 0x77002deb00000000, 0x6817dd6b00000000, + 0xb77eef5f00000000, 0xa8691fdf00000000, 0xc8567e8500000000, + 0xd7418e0500000000, 0x76851aed00000000, 0x6992ea6d00000000, + 0x09ad8b3700000000, 0x16ba7bb700000000, 0xc9d3498300000000, + 0xd6c4b90300000000, 0xb6fbd85900000000, 0xa9ec28d900000000, + 0xcfcdf89700000000, 0xd0da081700000000, 0xb0e5694d00000000, + 0xaff299cd00000000, 0x709babf900000000, 0x6f8c5b7900000000, + 0x0fb33a2300000000, 0x10a4caa300000000, 0xb1605e4b00000000, + 0xae77aecb00000000, 0xce48cf9100000000, 0xd15f3f1100000000, + 0x0e360d2500000000, 0x1121fda500000000, 0x711e9cff00000000, + 0x6e096c7f00000000, 0x7291c4f500000000, 0x6d86347500000000, + 0x0db9552f00000000, 0x12aea5af00000000, 0xcdc7979b00000000, + 0xd2d0671b00000000, 0xb2ef064100000000, 0xadf8f6c100000000, + 0x0c3c622900000000, 0x132b92a900000000, 0x7314f3f300000000, + 0x6c03037300000000, 0xb36a314700000000, 0xac7dc1c700000000, + 0xcc42a09d00000000, 0xd355501d00000000, 0x6ae900a700000000, + 0x75fef02700000000, 0x15c1917d00000000, 0x0ad661fd00000000, + 0xd5bf53c900000000, 0xcaa8a34900000000, 0xaa97c21300000000, + 0xb580329300000000, 0x1444a67b00000000, 0x0b5356fb00000000, + 0x6b6c37a100000000, 0x747bc72100000000, 0xab12f51500000000, + 0xb405059500000000, 0xd43a64cf00000000, 0xcb2d944f00000000, + 0xd7b53cc500000000, 0xc8a2cc4500000000, 0xa89dad1f00000000, + 0xb78a5d9f00000000, 0x68e36fab00000000, 0x77f49f2b00000000, + 0x17cbfe7100000000, 0x08dc0ef100000000, 0xa9189a1900000000, + 0xb60f6a9900000000, 0xd6300bc300000000, 0xc927fb4300000000, + 0x164ec97700000000, 0x095939f700000000, 0x696658ad00000000, + 0x7671a82d00000000, 0x1050786300000000, 0x0f4788e300000000, + 0x6f78e9b900000000, 0x706f193900000000, 0xaf062b0d00000000, + 0xb011db8d00000000, 0xd02ebad700000000, 0xcf394a5700000000, + 0x6efddebf00000000, 0x71ea2e3f00000000, 0x11d54f6500000000, + 0x0ec2bfe500000000, 0xd1ab8dd100000000, 0xcebc7d5100000000, + 0xae831c0b00000000, 0xb194ec8b00000000, 0xad0c440100000000, + 0xb21bb48100000000, 0xd224d5db00000000, 0xcd33255b00000000, + 0x125a176f00000000, 0x0d4de7ef00000000, 0x6d7286b500000000, + 0x7265763500000000, 0xd3a1e2dd00000000, 0xccb6125d00000000, + 0xac89730700000000, 0xb39e838700000000, 0x6cf7b1b300000000, + 0x73e0413300000000, 0x13df206900000000, 0x0cc8d0e900000000, + 0xdf9d80f400000000, 0xc08a707400000000, 0xa0b5112e00000000, + 0xbfa2e1ae00000000, 0x60cbd39a00000000, 0x7fdc231a00000000, + 0x1fe3424000000000, 0x00f4b2c000000000, 0xa130262800000000, + 0xbe27d6a800000000, 0xde18b7f200000000, 0xc10f477200000000, + 0x1e66754600000000, 0x017185c600000000, 0x614ee49c00000000, + 0x7e59141c00000000, 0x62c1bc9600000000, 0x7dd64c1600000000, + 0x1de92d4c00000000, 0x02feddcc00000000, 0xdd97eff800000000, + 0xc2801f7800000000, 0xa2bf7e2200000000, 0xbda88ea200000000, + 0x1c6c1a4a00000000, 0x037beaca00000000, 0x63448b9000000000, + 0x7c537b1000000000, 0xa33a492400000000, 0xbc2db9a400000000, + 0xdc12d8fe00000000, 0xc305287e00000000, 0xa524f83000000000, + 0xba3308b000000000, 0xda0c69ea00000000, 0xc51b996a00000000, + 0x1a72ab5e00000000, 0x05655bde00000000, 0x655a3a8400000000, + 0x7a4dca0400000000, 0xdb895eec00000000, 0xc49eae6c00000000, + 0xa4a1cf3600000000, 0xbbb63fb600000000, 0x64df0d8200000000, + 0x7bc8fd0200000000, 0x1bf79c5800000000, 0x04e06cd800000000, + 0x1878c45200000000, 0x076f34d200000000, 0x6750558800000000, + 0x7847a50800000000, 0xa72e973c00000000, 0xb83967bc00000000, + 0xd80606e600000000, 0xc711f66600000000, 0x66d5628e00000000, + 0x79c2920e00000000, 0x19fdf35400000000, 0x06ea03d400000000, + 0xd98331e000000000, 0xc694c16000000000, 0xa6aba03a00000000, + 0xb9bc50ba00000000}, + {0x0000000000000000, 0xe2fd888d00000000, 0x85fd60c000000000, + 0x6700e84d00000000, 0x4bfdb05b00000000, 0xa90038d600000000, + 0xce00d09b00000000, 0x2cfd581600000000, 0x96fa61b700000000, + 0x7407e93a00000000, 0x1307017700000000, 0xf1fa89fa00000000, + 0xdd07d1ec00000000, 0x3ffa596100000000, 0x58fab12c00000000, + 0xba0739a100000000, 0x6df3b2b500000000, 0x8f0e3a3800000000, + 0xe80ed27500000000, 0x0af35af800000000, 0x260e02ee00000000, + 0xc4f38a6300000000, 0xa3f3622e00000000, 0x410eeaa300000000, + 0xfb09d30200000000, 0x19f45b8f00000000, 0x7ef4b3c200000000, + 0x9c093b4f00000000, 0xb0f4635900000000, 0x5209ebd400000000, + 0x3509039900000000, 0xd7f48b1400000000, 0x9be014b000000000, + 0x791d9c3d00000000, 0x1e1d747000000000, 0xfce0fcfd00000000, + 0xd01da4eb00000000, 0x32e02c6600000000, 0x55e0c42b00000000, + 0xb71d4ca600000000, 0x0d1a750700000000, 0xefe7fd8a00000000, + 0x88e715c700000000, 0x6a1a9d4a00000000, 0x46e7c55c00000000, + 0xa41a4dd100000000, 0xc31aa59c00000000, 0x21e72d1100000000, + 0xf613a60500000000, 0x14ee2e8800000000, 0x73eec6c500000000, + 0x91134e4800000000, 0xbdee165e00000000, 0x5f139ed300000000, + 0x3813769e00000000, 0xdaeefe1300000000, 0x60e9c7b200000000, + 0x82144f3f00000000, 0xe514a77200000000, 0x07e92fff00000000, + 0x2b1477e900000000, 0xc9e9ff6400000000, 0xaee9172900000000, + 0x4c149fa400000000, 0x77c758bb00000000, 0x953ad03600000000, + 0xf23a387b00000000, 0x10c7b0f600000000, 0x3c3ae8e000000000, + 0xdec7606d00000000, 0xb9c7882000000000, 0x5b3a00ad00000000, + 0xe13d390c00000000, 0x03c0b18100000000, 0x64c059cc00000000, + 0x863dd14100000000, 0xaac0895700000000, 0x483d01da00000000, + 0x2f3de99700000000, 0xcdc0611a00000000, 0x1a34ea0e00000000, + 0xf8c9628300000000, 0x9fc98ace00000000, 0x7d34024300000000, + 0x51c95a5500000000, 0xb334d2d800000000, 0xd4343a9500000000, + 0x36c9b21800000000, 0x8cce8bb900000000, 0x6e33033400000000, + 0x0933eb7900000000, 0xebce63f400000000, 0xc7333be200000000, + 0x25ceb36f00000000, 0x42ce5b2200000000, 0xa033d3af00000000, + 0xec274c0b00000000, 0x0edac48600000000, 0x69da2ccb00000000, + 0x8b27a44600000000, 0xa7dafc5000000000, 0x452774dd00000000, + 0x22279c9000000000, 0xc0da141d00000000, 0x7add2dbc00000000, + 0x9820a53100000000, 0xff204d7c00000000, 0x1dddc5f100000000, + 0x31209de700000000, 0xd3dd156a00000000, 0xb4ddfd2700000000, + 0x562075aa00000000, 0x81d4febe00000000, 0x6329763300000000, + 0x04299e7e00000000, 0xe6d416f300000000, 0xca294ee500000000, + 0x28d4c66800000000, 0x4fd42e2500000000, 0xad29a6a800000000, + 0x172e9f0900000000, 0xf5d3178400000000, 0x92d3ffc900000000, + 0x702e774400000000, 0x5cd32f5200000000, 0xbe2ea7df00000000, + 0xd92e4f9200000000, 0x3bd3c71f00000000, 0xaf88c0ad00000000, + 0x4d75482000000000, 0x2a75a06d00000000, 0xc88828e000000000, + 0xe47570f600000000, 0x0688f87b00000000, 0x6188103600000000, + 0x837598bb00000000, 0x3972a11a00000000, 0xdb8f299700000000, + 0xbc8fc1da00000000, 0x5e72495700000000, 0x728f114100000000, + 0x907299cc00000000, 0xf772718100000000, 0x158ff90c00000000, + 0xc27b721800000000, 0x2086fa9500000000, 0x478612d800000000, + 0xa57b9a5500000000, 0x8986c24300000000, 0x6b7b4ace00000000, + 0x0c7ba28300000000, 0xee862a0e00000000, 0x548113af00000000, + 0xb67c9b2200000000, 0xd17c736f00000000, 0x3381fbe200000000, + 0x1f7ca3f400000000, 0xfd812b7900000000, 0x9a81c33400000000, + 0x787c4bb900000000, 0x3468d41d00000000, 0xd6955c9000000000, + 0xb195b4dd00000000, 0x53683c5000000000, 0x7f95644600000000, + 0x9d68eccb00000000, 0xfa68048600000000, 0x18958c0b00000000, + 0xa292b5aa00000000, 0x406f3d2700000000, 0x276fd56a00000000, + 0xc5925de700000000, 0xe96f05f100000000, 0x0b928d7c00000000, + 0x6c92653100000000, 0x8e6fedbc00000000, 0x599b66a800000000, + 0xbb66ee2500000000, 0xdc66066800000000, 0x3e9b8ee500000000, + 0x1266d6f300000000, 0xf09b5e7e00000000, 0x979bb63300000000, + 0x75663ebe00000000, 0xcf61071f00000000, 0x2d9c8f9200000000, + 0x4a9c67df00000000, 0xa861ef5200000000, 0x849cb74400000000, + 0x66613fc900000000, 0x0161d78400000000, 0xe39c5f0900000000, + 0xd84f981600000000, 0x3ab2109b00000000, 0x5db2f8d600000000, + 0xbf4f705b00000000, 0x93b2284d00000000, 0x714fa0c000000000, + 0x164f488d00000000, 0xf4b2c00000000000, 0x4eb5f9a100000000, + 0xac48712c00000000, 0xcb48996100000000, 0x29b511ec00000000, + 0x054849fa00000000, 0xe7b5c17700000000, 0x80b5293a00000000, + 0x6248a1b700000000, 0xb5bc2aa300000000, 0x5741a22e00000000, + 0x30414a6300000000, 0xd2bcc2ee00000000, 0xfe419af800000000, + 0x1cbc127500000000, 0x7bbcfa3800000000, 0x994172b500000000, + 0x23464b1400000000, 0xc1bbc39900000000, 0xa6bb2bd400000000, + 0x4446a35900000000, 0x68bbfb4f00000000, 0x8a4673c200000000, + 0xed469b8f00000000, 0x0fbb130200000000, 0x43af8ca600000000, + 0xa152042b00000000, 0xc652ec6600000000, 0x24af64eb00000000, + 0x08523cfd00000000, 0xeaafb47000000000, 0x8daf5c3d00000000, + 0x6f52d4b000000000, 0xd555ed1100000000, 0x37a8659c00000000, + 0x50a88dd100000000, 0xb255055c00000000, 0x9ea85d4a00000000, + 0x7c55d5c700000000, 0x1b553d8a00000000, 0xf9a8b50700000000, + 0x2e5c3e1300000000, 0xcca1b69e00000000, 0xaba15ed300000000, + 0x495cd65e00000000, 0x65a18e4800000000, 0x875c06c500000000, + 0xe05cee8800000000, 0x02a1660500000000, 0xb8a65fa400000000, + 0x5a5bd72900000000, 0x3d5b3f6400000000, 0xdfa6b7e900000000, + 0xf35befff00000000, 0x11a6677200000000, 0x76a68f3f00000000, + 0x945b07b200000000}, + {0x0000000000000000, 0xa90b894e00000000, 0x5217129d00000000, + 0xfb1c9bd300000000, 0xe52855e100000000, 0x4c23dcaf00000000, + 0xb73f477c00000000, 0x1e34ce3200000000, 0x8b57db1900000000, + 0x225c525700000000, 0xd940c98400000000, 0x704b40ca00000000, + 0x6e7f8ef800000000, 0xc77407b600000000, 0x3c689c6500000000, + 0x9563152b00000000, 0x16afb63300000000, 0xbfa43f7d00000000, + 0x44b8a4ae00000000, 0xedb32de000000000, 0xf387e3d200000000, + 0x5a8c6a9c00000000, 0xa190f14f00000000, 0x089b780100000000, + 0x9df86d2a00000000, 0x34f3e46400000000, 0xcfef7fb700000000, + 0x66e4f6f900000000, 0x78d038cb00000000, 0xd1dbb18500000000, + 0x2ac72a5600000000, 0x83cca31800000000, 0x2c5e6d6700000000, + 0x8555e42900000000, 0x7e497ffa00000000, 0xd742f6b400000000, + 0xc976388600000000, 0x607db1c800000000, 0x9b612a1b00000000, + 0x326aa35500000000, 0xa709b67e00000000, 0x0e023f3000000000, + 0xf51ea4e300000000, 0x5c152dad00000000, 0x4221e39f00000000, + 0xeb2a6ad100000000, 0x1036f10200000000, 0xb93d784c00000000, + 0x3af1db5400000000, 0x93fa521a00000000, 0x68e6c9c900000000, + 0xc1ed408700000000, 0xdfd98eb500000000, 0x76d207fb00000000, + 0x8dce9c2800000000, 0x24c5156600000000, 0xb1a6004d00000000, + 0x18ad890300000000, 0xe3b112d000000000, 0x4aba9b9e00000000, + 0x548e55ac00000000, 0xfd85dce200000000, 0x0699473100000000, + 0xaf92ce7f00000000, 0x58bcdace00000000, 0xf1b7538000000000, + 0x0aabc85300000000, 0xa3a0411d00000000, 0xbd948f2f00000000, + 0x149f066100000000, 0xef839db200000000, 0x468814fc00000000, + 0xd3eb01d700000000, 0x7ae0889900000000, 0x81fc134a00000000, + 0x28f79a0400000000, 0x36c3543600000000, 0x9fc8dd7800000000, + 0x64d446ab00000000, 0xcddfcfe500000000, 0x4e136cfd00000000, + 0xe718e5b300000000, 0x1c047e6000000000, 0xb50ff72e00000000, + 0xab3b391c00000000, 0x0230b05200000000, 0xf92c2b8100000000, + 0x5027a2cf00000000, 0xc544b7e400000000, 0x6c4f3eaa00000000, + 0x9753a57900000000, 0x3e582c3700000000, 0x206ce20500000000, + 0x89676b4b00000000, 0x727bf09800000000, 0xdb7079d600000000, + 0x74e2b7a900000000, 0xdde93ee700000000, 0x26f5a53400000000, + 0x8ffe2c7a00000000, 0x91cae24800000000, 0x38c16b0600000000, + 0xc3ddf0d500000000, 0x6ad6799b00000000, 0xffb56cb000000000, + 0x56bee5fe00000000, 0xada27e2d00000000, 0x04a9f76300000000, + 0x1a9d395100000000, 0xb396b01f00000000, 0x488a2bcc00000000, + 0xe181a28200000000, 0x624d019a00000000, 0xcb4688d400000000, + 0x305a130700000000, 0x99519a4900000000, 0x8765547b00000000, + 0x2e6edd3500000000, 0xd57246e600000000, 0x7c79cfa800000000, + 0xe91ada8300000000, 0x401153cd00000000, 0xbb0dc81e00000000, + 0x1206415000000000, 0x0c328f6200000000, 0xa539062c00000000, + 0x5e259dff00000000, 0xf72e14b100000000, 0xf17ec44600000000, + 0x58754d0800000000, 0xa369d6db00000000, 0x0a625f9500000000, + 0x145691a700000000, 0xbd5d18e900000000, 0x4641833a00000000, + 0xef4a0a7400000000, 0x7a291f5f00000000, 0xd322961100000000, + 0x283e0dc200000000, 0x8135848c00000000, 0x9f014abe00000000, + 0x360ac3f000000000, 0xcd16582300000000, 0x641dd16d00000000, + 0xe7d1727500000000, 0x4edafb3b00000000, 0xb5c660e800000000, + 0x1ccde9a600000000, 0x02f9279400000000, 0xabf2aeda00000000, + 0x50ee350900000000, 0xf9e5bc4700000000, 0x6c86a96c00000000, + 0xc58d202200000000, 0x3e91bbf100000000, 0x979a32bf00000000, + 0x89aefc8d00000000, 0x20a575c300000000, 0xdbb9ee1000000000, + 0x72b2675e00000000, 0xdd20a92100000000, 0x742b206f00000000, + 0x8f37bbbc00000000, 0x263c32f200000000, 0x3808fcc000000000, + 0x9103758e00000000, 0x6a1fee5d00000000, 0xc314671300000000, + 0x5677723800000000, 0xff7cfb7600000000, 0x046060a500000000, + 0xad6be9eb00000000, 0xb35f27d900000000, 0x1a54ae9700000000, + 0xe148354400000000, 0x4843bc0a00000000, 0xcb8f1f1200000000, + 0x6284965c00000000, 0x99980d8f00000000, 0x309384c100000000, + 0x2ea74af300000000, 0x87acc3bd00000000, 0x7cb0586e00000000, + 0xd5bbd12000000000, 0x40d8c40b00000000, 0xe9d34d4500000000, + 0x12cfd69600000000, 0xbbc45fd800000000, 0xa5f091ea00000000, + 0x0cfb18a400000000, 0xf7e7837700000000, 0x5eec0a3900000000, + 0xa9c21e8800000000, 0x00c997c600000000, 0xfbd50c1500000000, + 0x52de855b00000000, 0x4cea4b6900000000, 0xe5e1c22700000000, + 0x1efd59f400000000, 0xb7f6d0ba00000000, 0x2295c59100000000, + 0x8b9e4cdf00000000, 0x7082d70c00000000, 0xd9895e4200000000, + 0xc7bd907000000000, 0x6eb6193e00000000, 0x95aa82ed00000000, + 0x3ca10ba300000000, 0xbf6da8bb00000000, 0x166621f500000000, + 0xed7aba2600000000, 0x4471336800000000, 0x5a45fd5a00000000, + 0xf34e741400000000, 0x0852efc700000000, 0xa159668900000000, + 0x343a73a200000000, 0x9d31faec00000000, 0x662d613f00000000, + 0xcf26e87100000000, 0xd112264300000000, 0x7819af0d00000000, + 0x830534de00000000, 0x2a0ebd9000000000, 0x859c73ef00000000, + 0x2c97faa100000000, 0xd78b617200000000, 0x7e80e83c00000000, + 0x60b4260e00000000, 0xc9bfaf4000000000, 0x32a3349300000000, + 0x9ba8bddd00000000, 0x0ecba8f600000000, 0xa7c021b800000000, + 0x5cdcba6b00000000, 0xf5d7332500000000, 0xebe3fd1700000000, + 0x42e8745900000000, 0xb9f4ef8a00000000, 0x10ff66c400000000, + 0x9333c5dc00000000, 0x3a384c9200000000, 0xc124d74100000000, + 0x682f5e0f00000000, 0x761b903d00000000, 0xdf10197300000000, + 0x240c82a000000000, 0x8d070bee00000000, 0x18641ec500000000, + 0xb16f978b00000000, 0x4a730c5800000000, 0xe378851600000000, + 0xfd4c4b2400000000, 0x5447c26a00000000, 0xaf5b59b900000000, + 0x0650d0f700000000}, + {0x0000000000000000, 0x479244af00000000, 0xcf22f88500000000, + 0x88b0bc2a00000000, 0xdf4381d000000000, 0x98d1c57f00000000, + 0x1061795500000000, 0x57f33dfa00000000, 0xff81737a00000000, + 0xb81337d500000000, 0x30a38bff00000000, 0x7731cf5000000000, + 0x20c2f2aa00000000, 0x6750b60500000000, 0xefe00a2f00000000, + 0xa8724e8000000000, 0xfe03e7f400000000, 0xb991a35b00000000, + 0x31211f7100000000, 0x76b35bde00000000, 0x2140662400000000, + 0x66d2228b00000000, 0xee629ea100000000, 0xa9f0da0e00000000, + 0x0182948e00000000, 0x4610d02100000000, 0xcea06c0b00000000, + 0x893228a400000000, 0xdec1155e00000000, 0x995351f100000000, + 0x11e3eddb00000000, 0x5671a97400000000, 0xbd01bf3200000000, + 0xfa93fb9d00000000, 0x722347b700000000, 0x35b1031800000000, + 0x62423ee200000000, 0x25d07a4d00000000, 0xad60c66700000000, + 0xeaf282c800000000, 0x4280cc4800000000, 0x051288e700000000, + 0x8da234cd00000000, 0xca30706200000000, 0x9dc34d9800000000, + 0xda51093700000000, 0x52e1b51d00000000, 0x1573f1b200000000, + 0x430258c600000000, 0x04901c6900000000, 0x8c20a04300000000, + 0xcbb2e4ec00000000, 0x9c41d91600000000, 0xdbd39db900000000, + 0x5363219300000000, 0x14f1653c00000000, 0xbc832bbc00000000, + 0xfb116f1300000000, 0x73a1d33900000000, 0x3433979600000000, + 0x63c0aa6c00000000, 0x2452eec300000000, 0xace252e900000000, + 0xeb70164600000000, 0x7a037e6500000000, 0x3d913aca00000000, + 0xb52186e000000000, 0xf2b3c24f00000000, 0xa540ffb500000000, + 0xe2d2bb1a00000000, 0x6a62073000000000, 0x2df0439f00000000, + 0x85820d1f00000000, 0xc21049b000000000, 0x4aa0f59a00000000, + 0x0d32b13500000000, 0x5ac18ccf00000000, 0x1d53c86000000000, + 0x95e3744a00000000, 0xd27130e500000000, 0x8400999100000000, + 0xc392dd3e00000000, 0x4b22611400000000, 0x0cb025bb00000000, + 0x5b43184100000000, 0x1cd15cee00000000, 0x9461e0c400000000, + 0xd3f3a46b00000000, 0x7b81eaeb00000000, 0x3c13ae4400000000, + 0xb4a3126e00000000, 0xf33156c100000000, 0xa4c26b3b00000000, + 0xe3502f9400000000, 0x6be093be00000000, 0x2c72d71100000000, + 0xc702c15700000000, 0x809085f800000000, 0x082039d200000000, + 0x4fb27d7d00000000, 0x1841408700000000, 0x5fd3042800000000, + 0xd763b80200000000, 0x90f1fcad00000000, 0x3883b22d00000000, + 0x7f11f68200000000, 0xf7a14aa800000000, 0xb0330e0700000000, + 0xe7c033fd00000000, 0xa052775200000000, 0x28e2cb7800000000, + 0x6f708fd700000000, 0x390126a300000000, 0x7e93620c00000000, + 0xf623de2600000000, 0xb1b19a8900000000, 0xe642a77300000000, + 0xa1d0e3dc00000000, 0x29605ff600000000, 0x6ef21b5900000000, + 0xc68055d900000000, 0x8112117600000000, 0x09a2ad5c00000000, + 0x4e30e9f300000000, 0x19c3d40900000000, 0x5e5190a600000000, + 0xd6e12c8c00000000, 0x9173682300000000, 0xf406fcca00000000, + 0xb394b86500000000, 0x3b24044f00000000, 0x7cb640e000000000, + 0x2b457d1a00000000, 0x6cd739b500000000, 0xe467859f00000000, + 0xa3f5c13000000000, 0x0b878fb000000000, 0x4c15cb1f00000000, + 0xc4a5773500000000, 0x8337339a00000000, 0xd4c40e6000000000, + 0x93564acf00000000, 0x1be6f6e500000000, 0x5c74b24a00000000, + 0x0a051b3e00000000, 0x4d975f9100000000, 0xc527e3bb00000000, + 0x82b5a71400000000, 0xd5469aee00000000, 0x92d4de4100000000, + 0x1a64626b00000000, 0x5df626c400000000, 0xf584684400000000, + 0xb2162ceb00000000, 0x3aa690c100000000, 0x7d34d46e00000000, + 0x2ac7e99400000000, 0x6d55ad3b00000000, 0xe5e5111100000000, + 0xa27755be00000000, 0x490743f800000000, 0x0e95075700000000, + 0x8625bb7d00000000, 0xc1b7ffd200000000, 0x9644c22800000000, + 0xd1d6868700000000, 0x59663aad00000000, 0x1ef47e0200000000, + 0xb686308200000000, 0xf114742d00000000, 0x79a4c80700000000, + 0x3e368ca800000000, 0x69c5b15200000000, 0x2e57f5fd00000000, + 0xa6e749d700000000, 0xe1750d7800000000, 0xb704a40c00000000, + 0xf096e0a300000000, 0x78265c8900000000, 0x3fb4182600000000, + 0x684725dc00000000, 0x2fd5617300000000, 0xa765dd5900000000, + 0xe0f799f600000000, 0x4885d77600000000, 0x0f1793d900000000, + 0x87a72ff300000000, 0xc0356b5c00000000, 0x97c656a600000000, + 0xd054120900000000, 0x58e4ae2300000000, 0x1f76ea8c00000000, + 0x8e0582af00000000, 0xc997c60000000000, 0x41277a2a00000000, + 0x06b53e8500000000, 0x5146037f00000000, 0x16d447d000000000, + 0x9e64fbfa00000000, 0xd9f6bf5500000000, 0x7184f1d500000000, + 0x3616b57a00000000, 0xbea6095000000000, 0xf9344dff00000000, + 0xaec7700500000000, 0xe95534aa00000000, 0x61e5888000000000, + 0x2677cc2f00000000, 0x7006655b00000000, 0x379421f400000000, + 0xbf249dde00000000, 0xf8b6d97100000000, 0xaf45e48b00000000, + 0xe8d7a02400000000, 0x60671c0e00000000, 0x27f558a100000000, + 0x8f87162100000000, 0xc815528e00000000, 0x40a5eea400000000, + 0x0737aa0b00000000, 0x50c497f100000000, 0x1756d35e00000000, + 0x9fe66f7400000000, 0xd8742bdb00000000, 0x33043d9d00000000, + 0x7496793200000000, 0xfc26c51800000000, 0xbbb481b700000000, + 0xec47bc4d00000000, 0xabd5f8e200000000, 0x236544c800000000, + 0x64f7006700000000, 0xcc854ee700000000, 0x8b170a4800000000, + 0x03a7b66200000000, 0x4435f2cd00000000, 0x13c6cf3700000000, + 0x54548b9800000000, 0xdce437b200000000, 0x9b76731d00000000, + 0xcd07da6900000000, 0x8a959ec600000000, 0x022522ec00000000, + 0x45b7664300000000, 0x12445bb900000000, 0x55d61f1600000000, + 0xdd66a33c00000000, 0x9af4e79300000000, 0x3286a91300000000, + 0x7514edbc00000000, 0xfda4519600000000, 0xba36153900000000, + 0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000, + 0x657594e900000000}}; + +#else /* W == 4 */ + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873, + 0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661, + 0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441, + 0xd53382c6, 0x7d995117, 0x3e52f790, 0xba096dc3, 0xf9c2cb44, + 0xb2be5964, 0xf175ffe3, 0x752e65b0, 0x36e5c337, 0xe3d641f1, + 0xa01de776, 0x24467d25, 0x678ddba2, 0x2cf14982, 0x6f3aef05, + 0xeb617556, 0xa8aad3d1, 0xfa32a32e, 0xb9f905a9, 0x3da29ffa, + 0x7e69397d, 0x3515ab5d, 0x76de0dda, 0xf2859789, 0xb14e310e, + 0x647db3c8, 0x27b6154f, 0xa3ed8f1c, 0xe026299b, 0xab5abbbb, + 0xe8911d3c, 0x6cca876f, 0x2f0121e8, 0x87abf239, 0xc46054be, + 0x403bceed, 0x03f0686a, 0x488cfa4a, 0x0b475ccd, 0x8f1cc69e, + 0xccd76019, 0x19e4e2df, 0x5a2f4458, 0xde74de0b, 0x9dbf788c, + 0xd6c3eaac, 0x95084c2b, 0x1153d678, 0x529870ff, 0xf465465d, + 0xb7aee0da, 0x33f57a89, 0x703edc0e, 0x3b424e2e, 0x7889e8a9, + 0xfcd272fa, 0xbf19d47d, 0x6a2a56bb, 0x29e1f03c, 0xadba6a6f, + 0xee71cce8, 0xa50d5ec8, 0xe6c6f84f, 0x629d621c, 0x2156c49b, + 0x89fc174a, 0xca37b1cd, 0x4e6c2b9e, 0x0da78d19, 0x46db1f39, + 0x0510b9be, 0x814b23ed, 0xc280856a, 0x17b307ac, 0x5478a12b, + 0xd0233b78, 0x93e89dff, 0xd8940fdf, 0x9b5fa958, 0x1f04330b, + 0x5ccf958c, 0x0e57e573, 0x4d9c43f4, 0xc9c7d9a7, 0x8a0c7f20, + 0xc170ed00, 0x82bb4b87, 0x06e0d1d4, 0x452b7753, 0x9018f595, + 0xd3d35312, 0x5788c941, 0x14436fc6, 0x5f3ffde6, 0x1cf45b61, + 0x98afc132, 0xdb6467b5, 0x73ceb464, 0x300512e3, 0xb45e88b0, + 0xf7952e37, 0xbce9bc17, 0xff221a90, 0x7b7980c3, 0x38b22644, + 0xed81a482, 0xae4a0205, 0x2a119856, 0x69da3ed1, 0x22a6acf1, + 0x616d0a76, 0xe5369025, 0xa6fd36a2, 0xe8cb8cba, 0xab002a3d, + 0x2f5bb06e, 0x6c9016e9, 0x27ec84c9, 0x6427224e, 0xe07cb81d, + 0xa3b71e9a, 0x76849c5c, 0x354f3adb, 0xb114a088, 0xf2df060f, + 0xb9a3942f, 0xfa6832a8, 0x7e33a8fb, 0x3df80e7c, 0x9552ddad, + 0xd6997b2a, 0x52c2e179, 0x110947fe, 0x5a75d5de, 0x19be7359, + 0x9de5e90a, 0xde2e4f8d, 0x0b1dcd4b, 0x48d66bcc, 0xcc8df19f, + 0x8f465718, 0xc43ac538, 0x87f163bf, 0x03aaf9ec, 0x40615f6b, + 0x12f92f94, 0x51328913, 0xd5691340, 0x96a2b5c7, 0xddde27e7, + 0x9e158160, 0x1a4e1b33, 0x5985bdb4, 0x8cb63f72, 0xcf7d99f5, + 0x4b2603a6, 0x08eda521, 0x43913701, 0x005a9186, 0x84010bd5, + 0xc7caad52, 0x6f607e83, 0x2cabd804, 0xa8f04257, 0xeb3be4d0, + 0xa04776f0, 0xe38cd077, 0x67d74a24, 0x241ceca3, 0xf12f6e65, + 0xb2e4c8e2, 0x36bf52b1, 0x7574f436, 0x3e086616, 0x7dc3c091, + 0xf9985ac2, 0xba53fc45, 0x1caecae7, 0x5f656c60, 0xdb3ef633, + 0x98f550b4, 0xd389c294, 0x90426413, 0x1419fe40, 0x57d258c7, + 0x82e1da01, 0xc12a7c86, 0x4571e6d5, 0x06ba4052, 0x4dc6d272, + 0x0e0d74f5, 0x8a56eea6, 0xc99d4821, 0x61379bf0, 0x22fc3d77, + 0xa6a7a724, 0xe56c01a3, 0xae109383, 0xeddb3504, 0x6980af57, + 0x2a4b09d0, 0xff788b16, 0xbcb32d91, 0x38e8b7c2, 0x7b231145, + 0x305f8365, 0x739425e2, 0xf7cfbfb1, 0xb4041936, 0xe69c69c9, + 0xa557cf4e, 0x210c551d, 0x62c7f39a, 0x29bb61ba, 0x6a70c73d, + 0xee2b5d6e, 0xade0fbe9, 0x78d3792f, 0x3b18dfa8, 0xbf4345fb, + 0xfc88e37c, 0xb7f4715c, 0xf43fd7db, 0x70644d88, 0x33afeb0f, + 0x9b0538de, 0xd8ce9e59, 0x5c95040a, 0x1f5ea28d, 0x542230ad, + 0x17e9962a, 0x93b20c79, 0xd079aafe, 0x054a2838, 0x46818ebf, + 0xc2da14ec, 0x8111b26b, 0xca6d204b, 0x89a686cc, 0x0dfd1c9f, + 0x4e36ba18}, + {0x00000000, 0xe1b652ef, 0x836bd405, 0x62dd86ea, 0x06d7a80b, + 0xe761fae4, 0x85bc7c0e, 0x640a2ee1, 0x0cae5117, 0xed1803f8, + 0x8fc58512, 0x6e73d7fd, 0x0a79f91c, 0xebcfabf3, 0x89122d19, + 0x68a47ff6, 0x185ca32e, 0xf9eaf1c1, 0x9b37772b, 0x7a8125c4, + 0x1e8b0b25, 0xff3d59ca, 0x9de0df20, 0x7c568dcf, 0x14f2f239, + 0xf544a0d6, 0x9799263c, 0x762f74d3, 0x12255a32, 0xf39308dd, + 0x914e8e37, 0x70f8dcd8, 0x30b8465d, 0xd10e14b2, 0xb3d39258, + 0x5265c0b7, 0x366fee56, 0xd7d9bcb9, 0xb5043a53, 0x54b268bc, + 0x3c16174a, 0xdda045a5, 0xbf7dc34f, 0x5ecb91a0, 0x3ac1bf41, + 0xdb77edae, 0xb9aa6b44, 0x581c39ab, 0x28e4e573, 0xc952b79c, + 0xab8f3176, 0x4a396399, 0x2e334d78, 0xcf851f97, 0xad58997d, + 0x4ceecb92, 0x244ab464, 0xc5fce68b, 0xa7216061, 0x4697328e, + 0x229d1c6f, 0xc32b4e80, 0xa1f6c86a, 0x40409a85, 0x60708dba, + 0x81c6df55, 0xe31b59bf, 0x02ad0b50, 0x66a725b1, 0x8711775e, + 0xe5ccf1b4, 0x047aa35b, 0x6cdedcad, 0x8d688e42, 0xefb508a8, + 0x0e035a47, 0x6a0974a6, 0x8bbf2649, 0xe962a0a3, 0x08d4f24c, + 0x782c2e94, 0x999a7c7b, 0xfb47fa91, 0x1af1a87e, 0x7efb869f, + 0x9f4dd470, 0xfd90529a, 0x1c260075, 0x74827f83, 0x95342d6c, + 0xf7e9ab86, 0x165ff969, 0x7255d788, 0x93e38567, 0xf13e038d, + 0x10885162, 0x50c8cbe7, 0xb17e9908, 0xd3a31fe2, 0x32154d0d, + 0x561f63ec, 0xb7a93103, 0xd574b7e9, 0x34c2e506, 0x5c669af0, + 0xbdd0c81f, 0xdf0d4ef5, 0x3ebb1c1a, 0x5ab132fb, 0xbb076014, + 0xd9dae6fe, 0x386cb411, 0x489468c9, 0xa9223a26, 0xcbffbccc, + 0x2a49ee23, 0x4e43c0c2, 0xaff5922d, 0xcd2814c7, 0x2c9e4628, + 0x443a39de, 0xa58c6b31, 0xc751eddb, 0x26e7bf34, 0x42ed91d5, + 0xa35bc33a, 0xc18645d0, 0x2030173f, 0x81e66bae, 0x60503941, + 0x028dbfab, 0xe33bed44, 0x8731c3a5, 0x6687914a, 0x045a17a0, + 0xe5ec454f, 0x8d483ab9, 0x6cfe6856, 0x0e23eebc, 0xef95bc53, + 0x8b9f92b2, 0x6a29c05d, 0x08f446b7, 0xe9421458, 0x99bac880, + 0x780c9a6f, 0x1ad11c85, 0xfb674e6a, 0x9f6d608b, 0x7edb3264, + 0x1c06b48e, 0xfdb0e661, 0x95149997, 0x74a2cb78, 0x167f4d92, + 0xf7c91f7d, 0x93c3319c, 0x72756373, 0x10a8e599, 0xf11eb776, + 0xb15e2df3, 0x50e87f1c, 0x3235f9f6, 0xd383ab19, 0xb78985f8, + 0x563fd717, 0x34e251fd, 0xd5540312, 0xbdf07ce4, 0x5c462e0b, + 0x3e9ba8e1, 0xdf2dfa0e, 0xbb27d4ef, 0x5a918600, 0x384c00ea, + 0xd9fa5205, 0xa9028edd, 0x48b4dc32, 0x2a695ad8, 0xcbdf0837, + 0xafd526d6, 0x4e637439, 0x2cbef2d3, 0xcd08a03c, 0xa5acdfca, + 0x441a8d25, 0x26c70bcf, 0xc7715920, 0xa37b77c1, 0x42cd252e, + 0x2010a3c4, 0xc1a6f12b, 0xe196e614, 0x0020b4fb, 0x62fd3211, + 0x834b60fe, 0xe7414e1f, 0x06f71cf0, 0x642a9a1a, 0x859cc8f5, + 0xed38b703, 0x0c8ee5ec, 0x6e536306, 0x8fe531e9, 0xebef1f08, + 0x0a594de7, 0x6884cb0d, 0x893299e2, 0xf9ca453a, 0x187c17d5, + 0x7aa1913f, 0x9b17c3d0, 0xff1ded31, 0x1eabbfde, 0x7c763934, + 0x9dc06bdb, 0xf564142d, 0x14d246c2, 0x760fc028, 0x97b992c7, + 0xf3b3bc26, 0x1205eec9, 0x70d86823, 0x916e3acc, 0xd12ea049, + 0x3098f2a6, 0x5245744c, 0xb3f326a3, 0xd7f90842, 0x364f5aad, + 0x5492dc47, 0xb5248ea8, 0xdd80f15e, 0x3c36a3b1, 0x5eeb255b, + 0xbf5d77b4, 0xdb575955, 0x3ae10bba, 0x583c8d50, 0xb98adfbf, + 0xc9720367, 0x28c45188, 0x4a19d762, 0xabaf858d, 0xcfa5ab6c, + 0x2e13f983, 0x4cce7f69, 0xad782d86, 0xc5dc5270, 0x246a009f, + 0x46b78675, 0xa701d49a, 0xc30bfa7b, 0x22bda894, 0x40602e7e, + 0xa1d67c91}, + {0x00000000, 0x5880e2d7, 0xf106b474, 0xa98656a3, 0xe20d68e9, + 0xba8d8a3e, 0x130bdc9d, 0x4b8b3e4a, 0x851da109, 0xdd9d43de, + 0x741b157d, 0x2c9bf7aa, 0x6710c9e0, 0x3f902b37, 0x96167d94, + 0xce969f43, 0x0a3b4213, 0x52bba0c4, 0xfb3df667, 0xa3bd14b0, + 0xe8362afa, 0xb0b6c82d, 0x19309e8e, 0x41b07c59, 0x8f26e31a, + 0xd7a601cd, 0x7e20576e, 0x26a0b5b9, 0x6d2b8bf3, 0x35ab6924, + 0x9c2d3f87, 0xc4addd50, 0x14768426, 0x4cf666f1, 0xe5703052, + 0xbdf0d285, 0xf67beccf, 0xaefb0e18, 0x077d58bb, 0x5ffdba6c, + 0x916b252f, 0xc9ebc7f8, 0x606d915b, 0x38ed738c, 0x73664dc6, + 0x2be6af11, 0x8260f9b2, 0xdae01b65, 0x1e4dc635, 0x46cd24e2, + 0xef4b7241, 0xb7cb9096, 0xfc40aedc, 0xa4c04c0b, 0x0d461aa8, + 0x55c6f87f, 0x9b50673c, 0xc3d085eb, 0x6a56d348, 0x32d6319f, + 0x795d0fd5, 0x21dded02, 0x885bbba1, 0xd0db5976, 0x28ec084d, + 0x706cea9a, 0xd9eabc39, 0x816a5eee, 0xcae160a4, 0x92618273, + 0x3be7d4d0, 0x63673607, 0xadf1a944, 0xf5714b93, 0x5cf71d30, + 0x0477ffe7, 0x4ffcc1ad, 0x177c237a, 0xbefa75d9, 0xe67a970e, + 0x22d74a5e, 0x7a57a889, 0xd3d1fe2a, 0x8b511cfd, 0xc0da22b7, + 0x985ac060, 0x31dc96c3, 0x695c7414, 0xa7caeb57, 0xff4a0980, + 0x56cc5f23, 0x0e4cbdf4, 0x45c783be, 0x1d476169, 0xb4c137ca, + 0xec41d51d, 0x3c9a8c6b, 0x641a6ebc, 0xcd9c381f, 0x951cdac8, + 0xde97e482, 0x86170655, 0x2f9150f6, 0x7711b221, 0xb9872d62, + 0xe107cfb5, 0x48819916, 0x10017bc1, 0x5b8a458b, 0x030aa75c, + 0xaa8cf1ff, 0xf20c1328, 0x36a1ce78, 0x6e212caf, 0xc7a77a0c, + 0x9f2798db, 0xd4aca691, 0x8c2c4446, 0x25aa12e5, 0x7d2af032, + 0xb3bc6f71, 0xeb3c8da6, 0x42badb05, 0x1a3a39d2, 0x51b10798, + 0x0931e54f, 0xa0b7b3ec, 0xf837513b, 0x50d8119a, 0x0858f34d, + 0xa1dea5ee, 0xf95e4739, 0xb2d57973, 0xea559ba4, 0x43d3cd07, + 0x1b532fd0, 0xd5c5b093, 0x8d455244, 0x24c304e7, 0x7c43e630, + 0x37c8d87a, 0x6f483aad, 0xc6ce6c0e, 0x9e4e8ed9, 0x5ae35389, + 0x0263b15e, 0xabe5e7fd, 0xf365052a, 0xb8ee3b60, 0xe06ed9b7, + 0x49e88f14, 0x11686dc3, 0xdffef280, 0x877e1057, 0x2ef846f4, + 0x7678a423, 0x3df39a69, 0x657378be, 0xccf52e1d, 0x9475ccca, + 0x44ae95bc, 0x1c2e776b, 0xb5a821c8, 0xed28c31f, 0xa6a3fd55, + 0xfe231f82, 0x57a54921, 0x0f25abf6, 0xc1b334b5, 0x9933d662, + 0x30b580c1, 0x68356216, 0x23be5c5c, 0x7b3ebe8b, 0xd2b8e828, + 0x8a380aff, 0x4e95d7af, 0x16153578, 0xbf9363db, 0xe713810c, + 0xac98bf46, 0xf4185d91, 0x5d9e0b32, 0x051ee9e5, 0xcb8876a6, + 0x93089471, 0x3a8ec2d2, 0x620e2005, 0x29851e4f, 0x7105fc98, + 0xd883aa3b, 0x800348ec, 0x783419d7, 0x20b4fb00, 0x8932ada3, + 0xd1b24f74, 0x9a39713e, 0xc2b993e9, 0x6b3fc54a, 0x33bf279d, + 0xfd29b8de, 0xa5a95a09, 0x0c2f0caa, 0x54afee7d, 0x1f24d037, + 0x47a432e0, 0xee226443, 0xb6a28694, 0x720f5bc4, 0x2a8fb913, + 0x8309efb0, 0xdb890d67, 0x9002332d, 0xc882d1fa, 0x61048759, + 0x3984658e, 0xf712facd, 0xaf92181a, 0x06144eb9, 0x5e94ac6e, + 0x151f9224, 0x4d9f70f3, 0xe4192650, 0xbc99c487, 0x6c429df1, + 0x34c27f26, 0x9d442985, 0xc5c4cb52, 0x8e4ff518, 0xd6cf17cf, + 0x7f49416c, 0x27c9a3bb, 0xe95f3cf8, 0xb1dfde2f, 0x1859888c, + 0x40d96a5b, 0x0b525411, 0x53d2b6c6, 0xfa54e065, 0xa2d402b2, + 0x6679dfe2, 0x3ef93d35, 0x977f6b96, 0xcfff8941, 0x8474b70b, + 0xdcf455dc, 0x7572037f, 0x2df2e1a8, 0xe3647eeb, 0xbbe49c3c, + 0x1262ca9f, 0x4ae22848, 0x01691602, 0x59e9f4d5, 0xf06fa276, + 0xa8ef40a1}, + {0x00000000, 0x463b6765, 0x8c76ceca, 0xca4da9af, 0x59ebed4e, + 0x1fd08a2b, 0xd59d2384, 0x93a644e1, 0xb2d6db9d, 0xf4edbcf8, + 0x3ea01557, 0x789b7232, 0xeb3d36d3, 0xad0651b6, 0x674bf819, + 0x21709f7c, 0x25abc6e0, 0x6390a185, 0xa9dd082a, 0xefe66f4f, + 0x7c402bae, 0x3a7b4ccb, 0xf036e564, 0xb60d8201, 0x977d1d7d, + 0xd1467a18, 0x1b0bd3b7, 0x5d30b4d2, 0xce96f033, 0x88ad9756, + 0x42e03ef9, 0x04db599c, 0x0b50fc1a, 0x4d6b9b7f, 0x872632d0, + 0xc11d55b5, 0x52bb1154, 0x14807631, 0xdecddf9e, 0x98f6b8fb, + 0xb9862787, 0xffbd40e2, 0x35f0e94d, 0x73cb8e28, 0xe06dcac9, + 0xa656adac, 0x6c1b0403, 0x2a206366, 0x2efb3afa, 0x68c05d9f, + 0xa28df430, 0xe4b69355, 0x7710d7b4, 0x312bb0d1, 0xfb66197e, + 0xbd5d7e1b, 0x9c2de167, 0xda168602, 0x105b2fad, 0x566048c8, + 0xc5c60c29, 0x83fd6b4c, 0x49b0c2e3, 0x0f8ba586, 0x16a0f835, + 0x509b9f50, 0x9ad636ff, 0xdced519a, 0x4f4b157b, 0x0970721e, + 0xc33ddbb1, 0x8506bcd4, 0xa47623a8, 0xe24d44cd, 0x2800ed62, + 0x6e3b8a07, 0xfd9dcee6, 0xbba6a983, 0x71eb002c, 0x37d06749, + 0x330b3ed5, 0x753059b0, 0xbf7df01f, 0xf946977a, 0x6ae0d39b, + 0x2cdbb4fe, 0xe6961d51, 0xa0ad7a34, 0x81dde548, 0xc7e6822d, + 0x0dab2b82, 0x4b904ce7, 0xd8360806, 0x9e0d6f63, 0x5440c6cc, + 0x127ba1a9, 0x1df0042f, 0x5bcb634a, 0x9186cae5, 0xd7bdad80, + 0x441be961, 0x02208e04, 0xc86d27ab, 0x8e5640ce, 0xaf26dfb2, + 0xe91db8d7, 0x23501178, 0x656b761d, 0xf6cd32fc, 0xb0f65599, + 0x7abbfc36, 0x3c809b53, 0x385bc2cf, 0x7e60a5aa, 0xb42d0c05, + 0xf2166b60, 0x61b02f81, 0x278b48e4, 0xedc6e14b, 0xabfd862e, + 0x8a8d1952, 0xccb67e37, 0x06fbd798, 0x40c0b0fd, 0xd366f41c, + 0x955d9379, 0x5f103ad6, 0x192b5db3, 0x2c40f16b, 0x6a7b960e, + 0xa0363fa1, 0xe60d58c4, 0x75ab1c25, 0x33907b40, 0xf9ddd2ef, + 0xbfe6b58a, 0x9e962af6, 0xd8ad4d93, 0x12e0e43c, 0x54db8359, + 0xc77dc7b8, 0x8146a0dd, 0x4b0b0972, 0x0d306e17, 0x09eb378b, + 0x4fd050ee, 0x859df941, 0xc3a69e24, 0x5000dac5, 0x163bbda0, + 0xdc76140f, 0x9a4d736a, 0xbb3dec16, 0xfd068b73, 0x374b22dc, + 0x717045b9, 0xe2d60158, 0xa4ed663d, 0x6ea0cf92, 0x289ba8f7, + 0x27100d71, 0x612b6a14, 0xab66c3bb, 0xed5da4de, 0x7efbe03f, + 0x38c0875a, 0xf28d2ef5, 0xb4b64990, 0x95c6d6ec, 0xd3fdb189, + 0x19b01826, 0x5f8b7f43, 0xcc2d3ba2, 0x8a165cc7, 0x405bf568, + 0x0660920d, 0x02bbcb91, 0x4480acf4, 0x8ecd055b, 0xc8f6623e, + 0x5b5026df, 0x1d6b41ba, 0xd726e815, 0x911d8f70, 0xb06d100c, + 0xf6567769, 0x3c1bdec6, 0x7a20b9a3, 0xe986fd42, 0xafbd9a27, + 0x65f03388, 0x23cb54ed, 0x3ae0095e, 0x7cdb6e3b, 0xb696c794, + 0xf0ada0f1, 0x630be410, 0x25308375, 0xef7d2ada, 0xa9464dbf, + 0x8836d2c3, 0xce0db5a6, 0x04401c09, 0x427b7b6c, 0xd1dd3f8d, + 0x97e658e8, 0x5dabf147, 0x1b909622, 0x1f4bcfbe, 0x5970a8db, + 0x933d0174, 0xd5066611, 0x46a022f0, 0x009b4595, 0xcad6ec3a, + 0x8ced8b5f, 0xad9d1423, 0xeba67346, 0x21ebdae9, 0x67d0bd8c, + 0xf476f96d, 0xb24d9e08, 0x780037a7, 0x3e3b50c2, 0x31b0f544, + 0x778b9221, 0xbdc63b8e, 0xfbfd5ceb, 0x685b180a, 0x2e607f6f, + 0xe42dd6c0, 0xa216b1a5, 0x83662ed9, 0xc55d49bc, 0x0f10e013, + 0x492b8776, 0xda8dc397, 0x9cb6a4f2, 0x56fb0d5d, 0x10c06a38, + 0x141b33a4, 0x522054c1, 0x986dfd6e, 0xde569a0b, 0x4df0deea, + 0x0bcbb98f, 0xc1861020, 0x87bd7745, 0xa6cde839, 0xe0f68f5c, + 0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd, + 0x356bacd8}}; + +#endif /* W */ + +#endif /* N == 5 */ +#if N == 6 + +#if W == 8 + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370, + 0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d, + 0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69, + 0x86ebe6b5, 0x6dfcc142, 0x504d2d9e, 0x169f18fa, 0x2b2ef426, + 0x9b3b7232, 0xa68a9eee, 0xe058ab8a, 0xdde94756, 0x5b02a1e3, + 0x66b34d3f, 0x2061785b, 0x1dd09487, 0xadc51293, 0x9074fe4f, + 0xd6a6cb2b, 0xeb1727f7, 0xdbf98284, 0xe6486e58, 0xa09a5b3c, + 0x9d2bb7e0, 0x2d3e31f4, 0x108fdd28, 0x565de84c, 0x6bec0490, + 0xed07e225, 0xd0b60ef9, 0x96643b9d, 0xabd5d741, 0x1bc05155, + 0x2671bd89, 0x60a388ed, 0x5d126431, 0xb60543c6, 0x8bb4af1a, + 0xcd669a7e, 0xf0d776a2, 0x40c2f0b6, 0x7d731c6a, 0x3ba1290e, + 0x0610c5d2, 0x80fb2367, 0xbd4acfbb, 0xfb98fadf, 0xc6291603, + 0x763c9017, 0x4b8d7ccb, 0x0d5f49af, 0x30eea573, 0x6c820349, + 0x5133ef95, 0x17e1daf1, 0x2a50362d, 0x9a45b039, 0xa7f45ce5, + 0xe1266981, 0xdc97855d, 0x5a7c63e8, 0x67cd8f34, 0x211fba50, + 0x1cae568c, 0xacbbd098, 0x910a3c44, 0xd7d80920, 0xea69e5fc, + 0x017ec20b, 0x3ccf2ed7, 0x7a1d1bb3, 0x47acf76f, 0xf7b9717b, + 0xca089da7, 0x8cdaa8c3, 0xb16b441f, 0x3780a2aa, 0x0a314e76, + 0x4ce37b12, 0x715297ce, 0xc14711da, 0xfcf6fd06, 0xba24c862, + 0x879524be, 0xb77b81cd, 0x8aca6d11, 0xcc185875, 0xf1a9b4a9, + 0x41bc32bd, 0x7c0dde61, 0x3adfeb05, 0x076e07d9, 0x8185e16c, + 0xbc340db0, 0xfae638d4, 0xc757d408, 0x7742521c, 0x4af3bec0, + 0x0c218ba4, 0x31906778, 0xda87408f, 0xe736ac53, 0xa1e49937, + 0x9c5575eb, 0x2c40f3ff, 0x11f11f23, 0x57232a47, 0x6a92c69b, + 0xec79202e, 0xd1c8ccf2, 0x971af996, 0xaaab154a, 0x1abe935e, + 0x270f7f82, 0x61dd4ae6, 0x5c6ca63a, 0xd9040692, 0xe4b5ea4e, + 0xa267df2a, 0x9fd633f6, 0x2fc3b5e2, 0x1272593e, 0x54a06c5a, + 0x69118086, 0xeffa6633, 0xd24b8aef, 0x9499bf8b, 0xa9285357, + 0x193dd543, 0x248c399f, 0x625e0cfb, 0x5fefe027, 0xb4f8c7d0, + 0x89492b0c, 0xcf9b1e68, 0xf22af2b4, 0x423f74a0, 0x7f8e987c, + 0x395cad18, 0x04ed41c4, 0x8206a771, 0xbfb74bad, 0xf9657ec9, + 0xc4d49215, 0x74c11401, 0x4970f8dd, 0x0fa2cdb9, 0x32132165, + 0x02fd8416, 0x3f4c68ca, 0x799e5dae, 0x442fb172, 0xf43a3766, + 0xc98bdbba, 0x8f59eede, 0xb2e80202, 0x3403e4b7, 0x09b2086b, + 0x4f603d0f, 0x72d1d1d3, 0xc2c457c7, 0xff75bb1b, 0xb9a78e7f, + 0x841662a3, 0x6f014554, 0x52b0a988, 0x14629cec, 0x29d37030, + 0x99c6f624, 0xa4771af8, 0xe2a52f9c, 0xdf14c340, 0x59ff25f5, + 0x644ec929, 0x229cfc4d, 0x1f2d1091, 0xaf389685, 0x92897a59, + 0xd45b4f3d, 0xe9eaa3e1, 0xb58605db, 0x8837e907, 0xcee5dc63, + 0xf35430bf, 0x4341b6ab, 0x7ef05a77, 0x38226f13, 0x059383cf, + 0x8378657a, 0xbec989a6, 0xf81bbcc2, 0xc5aa501e, 0x75bfd60a, + 0x480e3ad6, 0x0edc0fb2, 0x336de36e, 0xd87ac499, 0xe5cb2845, + 0xa3191d21, 0x9ea8f1fd, 0x2ebd77e9, 0x130c9b35, 0x55deae51, + 0x686f428d, 0xee84a438, 0xd33548e4, 0x95e77d80, 0xa856915c, + 0x18431748, 0x25f2fb94, 0x6320cef0, 0x5e91222c, 0x6e7f875f, + 0x53ce6b83, 0x151c5ee7, 0x28adb23b, 0x98b8342f, 0xa509d8f3, + 0xe3dbed97, 0xde6a014b, 0x5881e7fe, 0x65300b22, 0x23e23e46, + 0x1e53d29a, 0xae46548e, 0x93f7b852, 0xd5258d36, 0xe89461ea, + 0x0383461d, 0x3e32aac1, 0x78e09fa5, 0x45517379, 0xf544f56d, + 0xc8f519b1, 0x8e272cd5, 0xb396c009, 0x357d26bc, 0x08ccca60, + 0x4e1eff04, 0x73af13d8, 0xc3ba95cc, 0xfe0b7910, 0xb8d94c74, + 0x8568a0a8}, + {0x00000000, 0x69790b65, 0xd2f216ca, 0xbb8b1daf, 0x7e952bd5, + 0x17ec20b0, 0xac673d1f, 0xc51e367a, 0xfd2a57aa, 0x94535ccf, + 0x2fd84160, 0x46a14a05, 0x83bf7c7f, 0xeac6771a, 0x514d6ab5, + 0x383461d0, 0x2125a915, 0x485ca270, 0xf3d7bfdf, 0x9aaeb4ba, + 0x5fb082c0, 0x36c989a5, 0x8d42940a, 0xe43b9f6f, 0xdc0ffebf, + 0xb576f5da, 0x0efde875, 0x6784e310, 0xa29ad56a, 0xcbe3de0f, + 0x7068c3a0, 0x1911c8c5, 0x424b522a, 0x2b32594f, 0x90b944e0, + 0xf9c04f85, 0x3cde79ff, 0x55a7729a, 0xee2c6f35, 0x87556450, + 0xbf610580, 0xd6180ee5, 0x6d93134a, 0x04ea182f, 0xc1f42e55, + 0xa88d2530, 0x1306389f, 0x7a7f33fa, 0x636efb3f, 0x0a17f05a, + 0xb19cedf5, 0xd8e5e690, 0x1dfbd0ea, 0x7482db8f, 0xcf09c620, + 0xa670cd45, 0x9e44ac95, 0xf73da7f0, 0x4cb6ba5f, 0x25cfb13a, + 0xe0d18740, 0x89a88c25, 0x3223918a, 0x5b5a9aef, 0x8496a454, + 0xedefaf31, 0x5664b29e, 0x3f1db9fb, 0xfa038f81, 0x937a84e4, + 0x28f1994b, 0x4188922e, 0x79bcf3fe, 0x10c5f89b, 0xab4ee534, + 0xc237ee51, 0x0729d82b, 0x6e50d34e, 0xd5dbcee1, 0xbca2c584, + 0xa5b30d41, 0xccca0624, 0x77411b8b, 0x1e3810ee, 0xdb262694, + 0xb25f2df1, 0x09d4305e, 0x60ad3b3b, 0x58995aeb, 0x31e0518e, + 0x8a6b4c21, 0xe3124744, 0x260c713e, 0x4f757a5b, 0xf4fe67f4, + 0x9d876c91, 0xc6ddf67e, 0xafa4fd1b, 0x142fe0b4, 0x7d56ebd1, + 0xb848ddab, 0xd131d6ce, 0x6abacb61, 0x03c3c004, 0x3bf7a1d4, + 0x528eaab1, 0xe905b71e, 0x807cbc7b, 0x45628a01, 0x2c1b8164, + 0x97909ccb, 0xfee997ae, 0xe7f85f6b, 0x8e81540e, 0x350a49a1, + 0x5c7342c4, 0x996d74be, 0xf0147fdb, 0x4b9f6274, 0x22e66911, + 0x1ad208c1, 0x73ab03a4, 0xc8201e0b, 0xa159156e, 0x64472314, + 0x0d3e2871, 0xb6b535de, 0xdfcc3ebb, 0xd25c4ee9, 0xbb25458c, + 0x00ae5823, 0x69d75346, 0xacc9653c, 0xc5b06e59, 0x7e3b73f6, + 0x17427893, 0x2f761943, 0x460f1226, 0xfd840f89, 0x94fd04ec, + 0x51e33296, 0x389a39f3, 0x8311245c, 0xea682f39, 0xf379e7fc, + 0x9a00ec99, 0x218bf136, 0x48f2fa53, 0x8deccc29, 0xe495c74c, + 0x5f1edae3, 0x3667d186, 0x0e53b056, 0x672abb33, 0xdca1a69c, + 0xb5d8adf9, 0x70c69b83, 0x19bf90e6, 0xa2348d49, 0xcb4d862c, + 0x90171cc3, 0xf96e17a6, 0x42e50a09, 0x2b9c016c, 0xee823716, + 0x87fb3c73, 0x3c7021dc, 0x55092ab9, 0x6d3d4b69, 0x0444400c, + 0xbfcf5da3, 0xd6b656c6, 0x13a860bc, 0x7ad16bd9, 0xc15a7676, + 0xa8237d13, 0xb132b5d6, 0xd84bbeb3, 0x63c0a31c, 0x0ab9a879, + 0xcfa79e03, 0xa6de9566, 0x1d5588c9, 0x742c83ac, 0x4c18e27c, + 0x2561e919, 0x9eeaf4b6, 0xf793ffd3, 0x328dc9a9, 0x5bf4c2cc, + 0xe07fdf63, 0x8906d406, 0x56caeabd, 0x3fb3e1d8, 0x8438fc77, + 0xed41f712, 0x285fc168, 0x4126ca0d, 0xfaadd7a2, 0x93d4dcc7, + 0xabe0bd17, 0xc299b672, 0x7912abdd, 0x106ba0b8, 0xd57596c2, + 0xbc0c9da7, 0x07878008, 0x6efe8b6d, 0x77ef43a8, 0x1e9648cd, + 0xa51d5562, 0xcc645e07, 0x097a687d, 0x60036318, 0xdb887eb7, + 0xb2f175d2, 0x8ac51402, 0xe3bc1f67, 0x583702c8, 0x314e09ad, + 0xf4503fd7, 0x9d2934b2, 0x26a2291d, 0x4fdb2278, 0x1481b897, + 0x7df8b3f2, 0xc673ae5d, 0xaf0aa538, 0x6a149342, 0x036d9827, + 0xb8e68588, 0xd19f8eed, 0xe9abef3d, 0x80d2e458, 0x3b59f9f7, + 0x5220f292, 0x973ec4e8, 0xfe47cf8d, 0x45ccd222, 0x2cb5d947, + 0x35a41182, 0x5cdd1ae7, 0xe7560748, 0x8e2f0c2d, 0x4b313a57, + 0x22483132, 0x99c32c9d, 0xf0ba27f8, 0xc88e4628, 0xa1f74d4d, + 0x1a7c50e2, 0x73055b87, 0xb61b6dfd, 0xdf626698, 0x64e97b37, + 0x0d907052}, + {0x00000000, 0x7fc99b93, 0xff933726, 0x805aacb5, 0x2457680d, + 0x5b9ef39e, 0xdbc45f2b, 0xa40dc4b8, 0x48aed01a, 0x37674b89, + 0xb73de73c, 0xc8f47caf, 0x6cf9b817, 0x13302384, 0x936a8f31, + 0xeca314a2, 0x915da034, 0xee943ba7, 0x6ece9712, 0x11070c81, + 0xb50ac839, 0xcac353aa, 0x4a99ff1f, 0x3550648c, 0xd9f3702e, + 0xa63aebbd, 0x26604708, 0x59a9dc9b, 0xfda41823, 0x826d83b0, + 0x02372f05, 0x7dfeb496, 0xf9ca4629, 0x8603ddba, 0x0659710f, + 0x7990ea9c, 0xdd9d2e24, 0xa254b5b7, 0x220e1902, 0x5dc78291, + 0xb1649633, 0xcead0da0, 0x4ef7a115, 0x313e3a86, 0x9533fe3e, + 0xeafa65ad, 0x6aa0c918, 0x1569528b, 0x6897e61d, 0x175e7d8e, + 0x9704d13b, 0xe8cd4aa8, 0x4cc08e10, 0x33091583, 0xb353b936, + 0xcc9a22a5, 0x20393607, 0x5ff0ad94, 0xdfaa0121, 0xa0639ab2, + 0x046e5e0a, 0x7ba7c599, 0xfbfd692c, 0x8434f2bf, 0x28e58a13, + 0x572c1180, 0xd776bd35, 0xa8bf26a6, 0x0cb2e21e, 0x737b798d, + 0xf321d538, 0x8ce84eab, 0x604b5a09, 0x1f82c19a, 0x9fd86d2f, + 0xe011f6bc, 0x441c3204, 0x3bd5a997, 0xbb8f0522, 0xc4469eb1, + 0xb9b82a27, 0xc671b1b4, 0x462b1d01, 0x39e28692, 0x9def422a, + 0xe226d9b9, 0x627c750c, 0x1db5ee9f, 0xf116fa3d, 0x8edf61ae, + 0x0e85cd1b, 0x714c5688, 0xd5419230, 0xaa8809a3, 0x2ad2a516, + 0x551b3e85, 0xd12fcc3a, 0xaee657a9, 0x2ebcfb1c, 0x5175608f, + 0xf578a437, 0x8ab13fa4, 0x0aeb9311, 0x75220882, 0x99811c20, + 0xe64887b3, 0x66122b06, 0x19dbb095, 0xbdd6742d, 0xc21fefbe, + 0x4245430b, 0x3d8cd898, 0x40726c0e, 0x3fbbf79d, 0xbfe15b28, + 0xc028c0bb, 0x64250403, 0x1bec9f90, 0x9bb63325, 0xe47fa8b6, + 0x08dcbc14, 0x77152787, 0xf74f8b32, 0x888610a1, 0x2c8bd419, + 0x53424f8a, 0xd318e33f, 0xacd178ac, 0x51cb1426, 0x2e028fb5, + 0xae582300, 0xd191b893, 0x759c7c2b, 0x0a55e7b8, 0x8a0f4b0d, + 0xf5c6d09e, 0x1965c43c, 0x66ac5faf, 0xe6f6f31a, 0x993f6889, + 0x3d32ac31, 0x42fb37a2, 0xc2a19b17, 0xbd680084, 0xc096b412, + 0xbf5f2f81, 0x3f058334, 0x40cc18a7, 0xe4c1dc1f, 0x9b08478c, + 0x1b52eb39, 0x649b70aa, 0x88386408, 0xf7f1ff9b, 0x77ab532e, + 0x0862c8bd, 0xac6f0c05, 0xd3a69796, 0x53fc3b23, 0x2c35a0b0, + 0xa801520f, 0xd7c8c99c, 0x57926529, 0x285bfeba, 0x8c563a02, + 0xf39fa191, 0x73c50d24, 0x0c0c96b7, 0xe0af8215, 0x9f661986, + 0x1f3cb533, 0x60f52ea0, 0xc4f8ea18, 0xbb31718b, 0x3b6bdd3e, + 0x44a246ad, 0x395cf23b, 0x469569a8, 0xc6cfc51d, 0xb9065e8e, + 0x1d0b9a36, 0x62c201a5, 0xe298ad10, 0x9d513683, 0x71f22221, + 0x0e3bb9b2, 0x8e611507, 0xf1a88e94, 0x55a54a2c, 0x2a6cd1bf, + 0xaa367d0a, 0xd5ffe699, 0x792e9e35, 0x06e705a6, 0x86bda913, + 0xf9743280, 0x5d79f638, 0x22b06dab, 0xa2eac11e, 0xdd235a8d, + 0x31804e2f, 0x4e49d5bc, 0xce137909, 0xb1dae29a, 0x15d72622, + 0x6a1ebdb1, 0xea441104, 0x958d8a97, 0xe8733e01, 0x97baa592, + 0x17e00927, 0x682992b4, 0xcc24560c, 0xb3edcd9f, 0x33b7612a, + 0x4c7efab9, 0xa0ddee1b, 0xdf147588, 0x5f4ed93d, 0x208742ae, + 0x848a8616, 0xfb431d85, 0x7b19b130, 0x04d02aa3, 0x80e4d81c, + 0xff2d438f, 0x7f77ef3a, 0x00be74a9, 0xa4b3b011, 0xdb7a2b82, + 0x5b208737, 0x24e91ca4, 0xc84a0806, 0xb7839395, 0x37d93f20, + 0x4810a4b3, 0xec1d600b, 0x93d4fb98, 0x138e572d, 0x6c47ccbe, + 0x11b97828, 0x6e70e3bb, 0xee2a4f0e, 0x91e3d49d, 0x35ee1025, + 0x4a278bb6, 0xca7d2703, 0xb5b4bc90, 0x5917a832, 0x26de33a1, + 0xa6849f14, 0xd94d0487, 0x7d40c03f, 0x02895bac, 0x82d3f719, + 0xfd1a6c8a}, + {0x00000000, 0xa396284c, 0x9c5d56d9, 0x3fcb7e95, 0xe3cbabf3, + 0x405d83bf, 0x7f96fd2a, 0xdc00d566, 0x1ce651a7, 0xbf7079eb, + 0x80bb077e, 0x232d2f32, 0xff2dfa54, 0x5cbbd218, 0x6370ac8d, + 0xc0e684c1, 0x39cca34e, 0x9a5a8b02, 0xa591f597, 0x0607dddb, + 0xda0708bd, 0x799120f1, 0x465a5e64, 0xe5cc7628, 0x252af2e9, + 0x86bcdaa5, 0xb977a430, 0x1ae18c7c, 0xc6e1591a, 0x65777156, + 0x5abc0fc3, 0xf92a278f, 0x7399469c, 0xd00f6ed0, 0xefc41045, + 0x4c523809, 0x9052ed6f, 0x33c4c523, 0x0c0fbbb6, 0xaf9993fa, + 0x6f7f173b, 0xcce93f77, 0xf32241e2, 0x50b469ae, 0x8cb4bcc8, + 0x2f229484, 0x10e9ea11, 0xb37fc25d, 0x4a55e5d2, 0xe9c3cd9e, + 0xd608b30b, 0x759e9b47, 0xa99e4e21, 0x0a08666d, 0x35c318f8, + 0x965530b4, 0x56b3b475, 0xf5259c39, 0xcaeee2ac, 0x6978cae0, + 0xb5781f86, 0x16ee37ca, 0x2925495f, 0x8ab36113, 0xe7328d38, + 0x44a4a574, 0x7b6fdbe1, 0xd8f9f3ad, 0x04f926cb, 0xa76f0e87, + 0x98a47012, 0x3b32585e, 0xfbd4dc9f, 0x5842f4d3, 0x67898a46, + 0xc41fa20a, 0x181f776c, 0xbb895f20, 0x844221b5, 0x27d409f9, + 0xdefe2e76, 0x7d68063a, 0x42a378af, 0xe13550e3, 0x3d358585, + 0x9ea3adc9, 0xa168d35c, 0x02fefb10, 0xc2187fd1, 0x618e579d, + 0x5e452908, 0xfdd30144, 0x21d3d422, 0x8245fc6e, 0xbd8e82fb, + 0x1e18aab7, 0x94abcba4, 0x373de3e8, 0x08f69d7d, 0xab60b531, + 0x77606057, 0xd4f6481b, 0xeb3d368e, 0x48ab1ec2, 0x884d9a03, + 0x2bdbb24f, 0x1410ccda, 0xb786e496, 0x6b8631f0, 0xc81019bc, + 0xf7db6729, 0x544d4f65, 0xad6768ea, 0x0ef140a6, 0x313a3e33, + 0x92ac167f, 0x4eacc319, 0xed3aeb55, 0xd2f195c0, 0x7167bd8c, + 0xb181394d, 0x12171101, 0x2ddc6f94, 0x8e4a47d8, 0x524a92be, + 0xf1dcbaf2, 0xce17c467, 0x6d81ec2b, 0x15141c31, 0xb682347d, + 0x89494ae8, 0x2adf62a4, 0xf6dfb7c2, 0x55499f8e, 0x6a82e11b, + 0xc914c957, 0x09f24d96, 0xaa6465da, 0x95af1b4f, 0x36393303, + 0xea39e665, 0x49afce29, 0x7664b0bc, 0xd5f298f0, 0x2cd8bf7f, + 0x8f4e9733, 0xb085e9a6, 0x1313c1ea, 0xcf13148c, 0x6c853cc0, + 0x534e4255, 0xf0d86a19, 0x303eeed8, 0x93a8c694, 0xac63b801, + 0x0ff5904d, 0xd3f5452b, 0x70636d67, 0x4fa813f2, 0xec3e3bbe, + 0x668d5aad, 0xc51b72e1, 0xfad00c74, 0x59462438, 0x8546f15e, + 0x26d0d912, 0x191ba787, 0xba8d8fcb, 0x7a6b0b0a, 0xd9fd2346, + 0xe6365dd3, 0x45a0759f, 0x99a0a0f9, 0x3a3688b5, 0x05fdf620, + 0xa66bde6c, 0x5f41f9e3, 0xfcd7d1af, 0xc31caf3a, 0x608a8776, + 0xbc8a5210, 0x1f1c7a5c, 0x20d704c9, 0x83412c85, 0x43a7a844, + 0xe0318008, 0xdffafe9d, 0x7c6cd6d1, 0xa06c03b7, 0x03fa2bfb, + 0x3c31556e, 0x9fa77d22, 0xf2269109, 0x51b0b945, 0x6e7bc7d0, + 0xcdedef9c, 0x11ed3afa, 0xb27b12b6, 0x8db06c23, 0x2e26446f, + 0xeec0c0ae, 0x4d56e8e2, 0x729d9677, 0xd10bbe3b, 0x0d0b6b5d, + 0xae9d4311, 0x91563d84, 0x32c015c8, 0xcbea3247, 0x687c1a0b, + 0x57b7649e, 0xf4214cd2, 0x282199b4, 0x8bb7b1f8, 0xb47ccf6d, + 0x17eae721, 0xd70c63e0, 0x749a4bac, 0x4b513539, 0xe8c71d75, + 0x34c7c813, 0x9751e05f, 0xa89a9eca, 0x0b0cb686, 0x81bfd795, + 0x2229ffd9, 0x1de2814c, 0xbe74a900, 0x62747c66, 0xc1e2542a, + 0xfe292abf, 0x5dbf02f3, 0x9d598632, 0x3ecfae7e, 0x0104d0eb, + 0xa292f8a7, 0x7e922dc1, 0xdd04058d, 0xe2cf7b18, 0x41595354, + 0xb87374db, 0x1be55c97, 0x242e2202, 0x87b80a4e, 0x5bb8df28, + 0xf82ef764, 0xc7e589f1, 0x6473a1bd, 0xa495257c, 0x07030d30, + 0x38c873a5, 0x9b5e5be9, 0x475e8e8f, 0xe4c8a6c3, 0xdb03d856, + 0x7895f01a}, + {0x00000000, 0x2a283862, 0x545070c4, 0x7e7848a6, 0xa8a0e188, + 0x8288d9ea, 0xfcf0914c, 0xd6d8a92e, 0x8a30c551, 0xa018fd33, + 0xde60b595, 0xf4488df7, 0x229024d9, 0x08b81cbb, 0x76c0541d, + 0x5ce86c7f, 0xcf108ce3, 0xe538b481, 0x9b40fc27, 0xb168c445, + 0x67b06d6b, 0x4d985509, 0x33e01daf, 0x19c825cd, 0x452049b2, + 0x6f0871d0, 0x11703976, 0x3b580114, 0xed80a83a, 0xc7a89058, + 0xb9d0d8fe, 0x93f8e09c, 0x45501f87, 0x6f7827e5, 0x11006f43, + 0x3b285721, 0xedf0fe0f, 0xc7d8c66d, 0xb9a08ecb, 0x9388b6a9, + 0xcf60dad6, 0xe548e2b4, 0x9b30aa12, 0xb1189270, 0x67c03b5e, + 0x4de8033c, 0x33904b9a, 0x19b873f8, 0x8a409364, 0xa068ab06, + 0xde10e3a0, 0xf438dbc2, 0x22e072ec, 0x08c84a8e, 0x76b00228, + 0x5c983a4a, 0x00705635, 0x2a586e57, 0x542026f1, 0x7e081e93, + 0xa8d0b7bd, 0x82f88fdf, 0xfc80c779, 0xd6a8ff1b, 0x8aa03f0e, + 0xa088076c, 0xdef04fca, 0xf4d877a8, 0x2200de86, 0x0828e6e4, + 0x7650ae42, 0x5c789620, 0x0090fa5f, 0x2ab8c23d, 0x54c08a9b, + 0x7ee8b2f9, 0xa8301bd7, 0x821823b5, 0xfc606b13, 0xd6485371, + 0x45b0b3ed, 0x6f988b8f, 0x11e0c329, 0x3bc8fb4b, 0xed105265, + 0xc7386a07, 0xb94022a1, 0x93681ac3, 0xcf8076bc, 0xe5a84ede, + 0x9bd00678, 0xb1f83e1a, 0x67209734, 0x4d08af56, 0x3370e7f0, + 0x1958df92, 0xcff02089, 0xe5d818eb, 0x9ba0504d, 0xb188682f, + 0x6750c101, 0x4d78f963, 0x3300b1c5, 0x192889a7, 0x45c0e5d8, + 0x6fe8ddba, 0x1190951c, 0x3bb8ad7e, 0xed600450, 0xc7483c32, + 0xb9307494, 0x93184cf6, 0x00e0ac6a, 0x2ac89408, 0x54b0dcae, + 0x7e98e4cc, 0xa8404de2, 0x82687580, 0xfc103d26, 0xd6380544, + 0x8ad0693b, 0xa0f85159, 0xde8019ff, 0xf4a8219d, 0x227088b3, + 0x0858b0d1, 0x7620f877, 0x5c08c015, 0xce31785d, 0xe419403f, + 0x9a610899, 0xb04930fb, 0x669199d5, 0x4cb9a1b7, 0x32c1e911, + 0x18e9d173, 0x4401bd0c, 0x6e29856e, 0x1051cdc8, 0x3a79f5aa, + 0xeca15c84, 0xc68964e6, 0xb8f12c40, 0x92d91422, 0x0121f4be, + 0x2b09ccdc, 0x5571847a, 0x7f59bc18, 0xa9811536, 0x83a92d54, + 0xfdd165f2, 0xd7f95d90, 0x8b1131ef, 0xa139098d, 0xdf41412b, + 0xf5697949, 0x23b1d067, 0x0999e805, 0x77e1a0a3, 0x5dc998c1, + 0x8b6167da, 0xa1495fb8, 0xdf31171e, 0xf5192f7c, 0x23c18652, + 0x09e9be30, 0x7791f696, 0x5db9cef4, 0x0151a28b, 0x2b799ae9, + 0x5501d24f, 0x7f29ea2d, 0xa9f14303, 0x83d97b61, 0xfda133c7, + 0xd7890ba5, 0x4471eb39, 0x6e59d35b, 0x10219bfd, 0x3a09a39f, + 0xecd10ab1, 0xc6f932d3, 0xb8817a75, 0x92a94217, 0xce412e68, + 0xe469160a, 0x9a115eac, 0xb03966ce, 0x66e1cfe0, 0x4cc9f782, + 0x32b1bf24, 0x18998746, 0x44914753, 0x6eb97f31, 0x10c13797, + 0x3ae90ff5, 0xec31a6db, 0xc6199eb9, 0xb861d61f, 0x9249ee7d, + 0xcea18202, 0xe489ba60, 0x9af1f2c6, 0xb0d9caa4, 0x6601638a, + 0x4c295be8, 0x3251134e, 0x18792b2c, 0x8b81cbb0, 0xa1a9f3d2, + 0xdfd1bb74, 0xf5f98316, 0x23212a38, 0x0909125a, 0x77715afc, + 0x5d59629e, 0x01b10ee1, 0x2b993683, 0x55e17e25, 0x7fc94647, + 0xa911ef69, 0x8339d70b, 0xfd419fad, 0xd769a7cf, 0x01c158d4, + 0x2be960b6, 0x55912810, 0x7fb91072, 0xa961b95c, 0x8349813e, + 0xfd31c998, 0xd719f1fa, 0x8bf19d85, 0xa1d9a5e7, 0xdfa1ed41, + 0xf589d523, 0x23517c0d, 0x0979446f, 0x77010cc9, 0x5d2934ab, + 0xced1d437, 0xe4f9ec55, 0x9a81a4f3, 0xb0a99c91, 0x667135bf, + 0x4c590ddd, 0x3221457b, 0x18097d19, 0x44e11166, 0x6ec92904, + 0x10b161a2, 0x3a9959c0, 0xec41f0ee, 0xc669c88c, 0xb811802a, + 0x9239b848}, + {0x00000000, 0x4713f6fb, 0x8e27edf6, 0xc9341b0d, 0xc73eddad, + 0x802d2b56, 0x4919305b, 0x0e0ac6a0, 0x550cbd1b, 0x121f4be0, + 0xdb2b50ed, 0x9c38a616, 0x923260b6, 0xd521964d, 0x1c158d40, + 0x5b067bbb, 0xaa197a36, 0xed0a8ccd, 0x243e97c0, 0x632d613b, + 0x6d27a79b, 0x2a345160, 0xe3004a6d, 0xa413bc96, 0xff15c72d, + 0xb80631d6, 0x71322adb, 0x3621dc20, 0x382b1a80, 0x7f38ec7b, + 0xb60cf776, 0xf11f018d, 0x8f43f22d, 0xc85004d6, 0x01641fdb, + 0x4677e920, 0x487d2f80, 0x0f6ed97b, 0xc65ac276, 0x8149348d, + 0xda4f4f36, 0x9d5cb9cd, 0x5468a2c0, 0x137b543b, 0x1d71929b, + 0x5a626460, 0x93567f6d, 0xd4458996, 0x255a881b, 0x62497ee0, + 0xab7d65ed, 0xec6e9316, 0xe26455b6, 0xa577a34d, 0x6c43b840, + 0x2b504ebb, 0x70563500, 0x3745c3fb, 0xfe71d8f6, 0xb9622e0d, + 0xb768e8ad, 0xf07b1e56, 0x394f055b, 0x7e5cf3a0, 0xc5f6e21b, + 0x82e514e0, 0x4bd10fed, 0x0cc2f916, 0x02c83fb6, 0x45dbc94d, + 0x8cefd240, 0xcbfc24bb, 0x90fa5f00, 0xd7e9a9fb, 0x1eddb2f6, + 0x59ce440d, 0x57c482ad, 0x10d77456, 0xd9e36f5b, 0x9ef099a0, + 0x6fef982d, 0x28fc6ed6, 0xe1c875db, 0xa6db8320, 0xa8d14580, + 0xefc2b37b, 0x26f6a876, 0x61e55e8d, 0x3ae32536, 0x7df0d3cd, + 0xb4c4c8c0, 0xf3d73e3b, 0xfdddf89b, 0xbace0e60, 0x73fa156d, + 0x34e9e396, 0x4ab51036, 0x0da6e6cd, 0xc492fdc0, 0x83810b3b, + 0x8d8bcd9b, 0xca983b60, 0x03ac206d, 0x44bfd696, 0x1fb9ad2d, + 0x58aa5bd6, 0x919e40db, 0xd68db620, 0xd8877080, 0x9f94867b, + 0x56a09d76, 0x11b36b8d, 0xe0ac6a00, 0xa7bf9cfb, 0x6e8b87f6, + 0x2998710d, 0x2792b7ad, 0x60814156, 0xa9b55a5b, 0xeea6aca0, + 0xb5a0d71b, 0xf2b321e0, 0x3b873aed, 0x7c94cc16, 0x729e0ab6, + 0x358dfc4d, 0xfcb9e740, 0xbbaa11bb, 0x509cc277, 0x178f348c, + 0xdebb2f81, 0x99a8d97a, 0x97a21fda, 0xd0b1e921, 0x1985f22c, + 0x5e9604d7, 0x05907f6c, 0x42838997, 0x8bb7929a, 0xcca46461, + 0xc2aea2c1, 0x85bd543a, 0x4c894f37, 0x0b9ab9cc, 0xfa85b841, + 0xbd964eba, 0x74a255b7, 0x33b1a34c, 0x3dbb65ec, 0x7aa89317, + 0xb39c881a, 0xf48f7ee1, 0xaf89055a, 0xe89af3a1, 0x21aee8ac, + 0x66bd1e57, 0x68b7d8f7, 0x2fa42e0c, 0xe6903501, 0xa183c3fa, + 0xdfdf305a, 0x98ccc6a1, 0x51f8ddac, 0x16eb2b57, 0x18e1edf7, + 0x5ff21b0c, 0x96c60001, 0xd1d5f6fa, 0x8ad38d41, 0xcdc07bba, + 0x04f460b7, 0x43e7964c, 0x4ded50ec, 0x0afea617, 0xc3cabd1a, + 0x84d94be1, 0x75c64a6c, 0x32d5bc97, 0xfbe1a79a, 0xbcf25161, + 0xb2f897c1, 0xf5eb613a, 0x3cdf7a37, 0x7bcc8ccc, 0x20caf777, + 0x67d9018c, 0xaeed1a81, 0xe9feec7a, 0xe7f42ada, 0xa0e7dc21, + 0x69d3c72c, 0x2ec031d7, 0x956a206c, 0xd279d697, 0x1b4dcd9a, + 0x5c5e3b61, 0x5254fdc1, 0x15470b3a, 0xdc731037, 0x9b60e6cc, + 0xc0669d77, 0x87756b8c, 0x4e417081, 0x0952867a, 0x075840da, + 0x404bb621, 0x897fad2c, 0xce6c5bd7, 0x3f735a5a, 0x7860aca1, + 0xb154b7ac, 0xf6474157, 0xf84d87f7, 0xbf5e710c, 0x766a6a01, + 0x31799cfa, 0x6a7fe741, 0x2d6c11ba, 0xe4580ab7, 0xa34bfc4c, + 0xad413aec, 0xea52cc17, 0x2366d71a, 0x647521e1, 0x1a29d241, + 0x5d3a24ba, 0x940e3fb7, 0xd31dc94c, 0xdd170fec, 0x9a04f917, + 0x5330e21a, 0x142314e1, 0x4f256f5a, 0x083699a1, 0xc10282ac, + 0x86117457, 0x881bb2f7, 0xcf08440c, 0x063c5f01, 0x412fa9fa, + 0xb030a877, 0xf7235e8c, 0x3e174581, 0x7904b37a, 0x770e75da, + 0x301d8321, 0xf929982c, 0xbe3a6ed7, 0xe53c156c, 0xa22fe397, + 0x6b1bf89a, 0x2c080e61, 0x2202c8c1, 0x65113e3a, 0xac252537, + 0xeb36d3cc}, + {0x00000000, 0xa13984ee, 0x99020f9d, 0x383b8b73, 0xe975197b, + 0x484c9d95, 0x707716e6, 0xd14e9208, 0x099b34b7, 0xa8a2b059, + 0x90993b2a, 0x31a0bfc4, 0xe0ee2dcc, 0x41d7a922, 0x79ec2251, + 0xd8d5a6bf, 0x1336696e, 0xb20fed80, 0x8a3466f3, 0x2b0de21d, + 0xfa437015, 0x5b7af4fb, 0x63417f88, 0xc278fb66, 0x1aad5dd9, + 0xbb94d937, 0x83af5244, 0x2296d6aa, 0xf3d844a2, 0x52e1c04c, + 0x6ada4b3f, 0xcbe3cfd1, 0x266cd2dc, 0x87555632, 0xbf6edd41, + 0x1e5759af, 0xcf19cba7, 0x6e204f49, 0x561bc43a, 0xf72240d4, + 0x2ff7e66b, 0x8ece6285, 0xb6f5e9f6, 0x17cc6d18, 0xc682ff10, + 0x67bb7bfe, 0x5f80f08d, 0xfeb97463, 0x355abbb2, 0x94633f5c, + 0xac58b42f, 0x0d6130c1, 0xdc2fa2c9, 0x7d162627, 0x452dad54, + 0xe41429ba, 0x3cc18f05, 0x9df80beb, 0xa5c38098, 0x04fa0476, + 0xd5b4967e, 0x748d1290, 0x4cb699e3, 0xed8f1d0d, 0x4cd9a5b8, + 0xede02156, 0xd5dbaa25, 0x74e22ecb, 0xa5acbcc3, 0x0495382d, + 0x3caeb35e, 0x9d9737b0, 0x4542910f, 0xe47b15e1, 0xdc409e92, + 0x7d791a7c, 0xac378874, 0x0d0e0c9a, 0x353587e9, 0x940c0307, + 0x5fefccd6, 0xfed64838, 0xc6edc34b, 0x67d447a5, 0xb69ad5ad, + 0x17a35143, 0x2f98da30, 0x8ea15ede, 0x5674f861, 0xf74d7c8f, + 0xcf76f7fc, 0x6e4f7312, 0xbf01e11a, 0x1e3865f4, 0x2603ee87, + 0x873a6a69, 0x6ab57764, 0xcb8cf38a, 0xf3b778f9, 0x528efc17, + 0x83c06e1f, 0x22f9eaf1, 0x1ac26182, 0xbbfbe56c, 0x632e43d3, + 0xc217c73d, 0xfa2c4c4e, 0x5b15c8a0, 0x8a5b5aa8, 0x2b62de46, + 0x13595535, 0xb260d1db, 0x79831e0a, 0xd8ba9ae4, 0xe0811197, + 0x41b89579, 0x90f60771, 0x31cf839f, 0x09f408ec, 0xa8cd8c02, + 0x70182abd, 0xd121ae53, 0xe91a2520, 0x4823a1ce, 0x996d33c6, + 0x3854b728, 0x006f3c5b, 0xa156b8b5, 0x99b34b70, 0x388acf9e, + 0x00b144ed, 0xa188c003, 0x70c6520b, 0xd1ffd6e5, 0xe9c45d96, + 0x48fdd978, 0x90287fc7, 0x3111fb29, 0x092a705a, 0xa813f4b4, + 0x795d66bc, 0xd864e252, 0xe05f6921, 0x4166edcf, 0x8a85221e, + 0x2bbca6f0, 0x13872d83, 0xb2bea96d, 0x63f03b65, 0xc2c9bf8b, + 0xfaf234f8, 0x5bcbb016, 0x831e16a9, 0x22279247, 0x1a1c1934, + 0xbb259dda, 0x6a6b0fd2, 0xcb528b3c, 0xf369004f, 0x525084a1, + 0xbfdf99ac, 0x1ee61d42, 0x26dd9631, 0x87e412df, 0x56aa80d7, + 0xf7930439, 0xcfa88f4a, 0x6e910ba4, 0xb644ad1b, 0x177d29f5, + 0x2f46a286, 0x8e7f2668, 0x5f31b460, 0xfe08308e, 0xc633bbfd, + 0x670a3f13, 0xace9f0c2, 0x0dd0742c, 0x35ebff5f, 0x94d27bb1, + 0x459ce9b9, 0xe4a56d57, 0xdc9ee624, 0x7da762ca, 0xa572c475, + 0x044b409b, 0x3c70cbe8, 0x9d494f06, 0x4c07dd0e, 0xed3e59e0, + 0xd505d293, 0x743c567d, 0xd56aeec8, 0x74536a26, 0x4c68e155, + 0xed5165bb, 0x3c1ff7b3, 0x9d26735d, 0xa51df82e, 0x04247cc0, + 0xdcf1da7f, 0x7dc85e91, 0x45f3d5e2, 0xe4ca510c, 0x3584c304, + 0x94bd47ea, 0xac86cc99, 0x0dbf4877, 0xc65c87a6, 0x67650348, + 0x5f5e883b, 0xfe670cd5, 0x2f299edd, 0x8e101a33, 0xb62b9140, + 0x171215ae, 0xcfc7b311, 0x6efe37ff, 0x56c5bc8c, 0xf7fc3862, + 0x26b2aa6a, 0x878b2e84, 0xbfb0a5f7, 0x1e892119, 0xf3063c14, + 0x523fb8fa, 0x6a043389, 0xcb3db767, 0x1a73256f, 0xbb4aa181, + 0x83712af2, 0x2248ae1c, 0xfa9d08a3, 0x5ba48c4d, 0x639f073e, + 0xc2a683d0, 0x13e811d8, 0xb2d19536, 0x8aea1e45, 0x2bd39aab, + 0xe030557a, 0x4109d194, 0x79325ae7, 0xd80bde09, 0x09454c01, + 0xa87cc8ef, 0x9047439c, 0x317ec772, 0xe9ab61cd, 0x4892e523, + 0x70a96e50, 0xd190eabe, 0x00de78b6, 0xa1e7fc58, 0x99dc772b, + 0x38e5f3c5}, + {0x00000000, 0xe81790a1, 0x0b5e2703, 0xe349b7a2, 0x16bc4e06, + 0xfeabdea7, 0x1de26905, 0xf5f5f9a4, 0x2d789c0c, 0xc56f0cad, + 0x2626bb0f, 0xce312bae, 0x3bc4d20a, 0xd3d342ab, 0x309af509, + 0xd88d65a8, 0x5af13818, 0xb2e6a8b9, 0x51af1f1b, 0xb9b88fba, + 0x4c4d761e, 0xa45ae6bf, 0x4713511d, 0xaf04c1bc, 0x7789a414, + 0x9f9e34b5, 0x7cd78317, 0x94c013b6, 0x6135ea12, 0x89227ab3, + 0x6a6bcd11, 0x827c5db0, 0xb5e27030, 0x5df5e091, 0xbebc5733, + 0x56abc792, 0xa35e3e36, 0x4b49ae97, 0xa8001935, 0x40178994, + 0x989aec3c, 0x708d7c9d, 0x93c4cb3f, 0x7bd35b9e, 0x8e26a23a, + 0x6631329b, 0x85788539, 0x6d6f1598, 0xef134828, 0x0704d889, + 0xe44d6f2b, 0x0c5aff8a, 0xf9af062e, 0x11b8968f, 0xf2f1212d, + 0x1ae6b18c, 0xc26bd424, 0x2a7c4485, 0xc935f327, 0x21226386, + 0xd4d79a22, 0x3cc00a83, 0xdf89bd21, 0x379e2d80, 0xb0b5e621, + 0x58a27680, 0xbbebc122, 0x53fc5183, 0xa609a827, 0x4e1e3886, + 0xad578f24, 0x45401f85, 0x9dcd7a2d, 0x75daea8c, 0x96935d2e, + 0x7e84cd8f, 0x8b71342b, 0x6366a48a, 0x802f1328, 0x68388389, + 0xea44de39, 0x02534e98, 0xe11af93a, 0x090d699b, 0xfcf8903f, + 0x14ef009e, 0xf7a6b73c, 0x1fb1279d, 0xc73c4235, 0x2f2bd294, + 0xcc626536, 0x2475f597, 0xd1800c33, 0x39979c92, 0xdade2b30, + 0x32c9bb91, 0x05579611, 0xed4006b0, 0x0e09b112, 0xe61e21b3, + 0x13ebd817, 0xfbfc48b6, 0x18b5ff14, 0xf0a26fb5, 0x282f0a1d, + 0xc0389abc, 0x23712d1e, 0xcb66bdbf, 0x3e93441b, 0xd684d4ba, + 0x35cd6318, 0xdddaf3b9, 0x5fa6ae09, 0xb7b13ea8, 0x54f8890a, + 0xbcef19ab, 0x491ae00f, 0xa10d70ae, 0x4244c70c, 0xaa5357ad, + 0x72de3205, 0x9ac9a2a4, 0x79801506, 0x919785a7, 0x64627c03, + 0x8c75eca2, 0x6f3c5b00, 0x872bcba1, 0xba1aca03, 0x520d5aa2, + 0xb144ed00, 0x59537da1, 0xaca68405, 0x44b114a4, 0xa7f8a306, + 0x4fef33a7, 0x9762560f, 0x7f75c6ae, 0x9c3c710c, 0x742be1ad, + 0x81de1809, 0x69c988a8, 0x8a803f0a, 0x6297afab, 0xe0ebf21b, + 0x08fc62ba, 0xebb5d518, 0x03a245b9, 0xf657bc1d, 0x1e402cbc, + 0xfd099b1e, 0x151e0bbf, 0xcd936e17, 0x2584feb6, 0xc6cd4914, + 0x2edad9b5, 0xdb2f2011, 0x3338b0b0, 0xd0710712, 0x386697b3, + 0x0ff8ba33, 0xe7ef2a92, 0x04a69d30, 0xecb10d91, 0x1944f435, + 0xf1536494, 0x121ad336, 0xfa0d4397, 0x2280263f, 0xca97b69e, + 0x29de013c, 0xc1c9919d, 0x343c6839, 0xdc2bf898, 0x3f624f3a, + 0xd775df9b, 0x5509822b, 0xbd1e128a, 0x5e57a528, 0xb6403589, + 0x43b5cc2d, 0xaba25c8c, 0x48ebeb2e, 0xa0fc7b8f, 0x78711e27, + 0x90668e86, 0x732f3924, 0x9b38a985, 0x6ecd5021, 0x86dac080, + 0x65937722, 0x8d84e783, 0x0aaf2c22, 0xe2b8bc83, 0x01f10b21, + 0xe9e69b80, 0x1c136224, 0xf404f285, 0x174d4527, 0xff5ad586, + 0x27d7b02e, 0xcfc0208f, 0x2c89972d, 0xc49e078c, 0x316bfe28, + 0xd97c6e89, 0x3a35d92b, 0xd222498a, 0x505e143a, 0xb849849b, + 0x5b003339, 0xb317a398, 0x46e25a3c, 0xaef5ca9d, 0x4dbc7d3f, + 0xa5abed9e, 0x7d268836, 0x95311897, 0x7678af35, 0x9e6f3f94, + 0x6b9ac630, 0x838d5691, 0x60c4e133, 0x88d37192, 0xbf4d5c12, + 0x575accb3, 0xb4137b11, 0x5c04ebb0, 0xa9f11214, 0x41e682b5, + 0xa2af3517, 0x4ab8a5b6, 0x9235c01e, 0x7a2250bf, 0x996be71d, + 0x717c77bc, 0x84898e18, 0x6c9e1eb9, 0x8fd7a91b, 0x67c039ba, + 0xe5bc640a, 0x0dabf4ab, 0xeee24309, 0x06f5d3a8, 0xf3002a0c, + 0x1b17baad, 0xf85e0d0f, 0x10499dae, 0xc8c4f806, 0x20d368a7, + 0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103, + 0x3d3101a2}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000, + 0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000, + 0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000, + 0xad0c6fc500000000, 0x0fbb262600000000, 0xae2b31ce00000000, + 0x0ad2c43b00000000, 0xab42d3d300000000, 0x09f59a3000000000, + 0xa8658dd800000000, 0x1838f15a00000000, 0xb9a8e6b200000000, + 0x1b1faf5100000000, 0xba8fb8b900000000, 0x1e764d4c00000000, + 0xbfe65aa400000000, 0x1d51134700000000, 0xbcc104af00000000, + 0x14a4897700000000, 0xb5349e9f00000000, 0x1783d77c00000000, + 0xb613c09400000000, 0x12ea356100000000, 0xb37a228900000000, + 0x11cd6b6a00000000, 0xb05d7c8200000000, 0x3070e2b500000000, + 0x91e0f55d00000000, 0x3357bcbe00000000, 0x92c7ab5600000000, + 0x363e5ea300000000, 0x97ae494b00000000, 0x351900a800000000, + 0x9489174000000000, 0x3cec9a9800000000, 0x9d7c8d7000000000, + 0x3fcbc49300000000, 0x9e5bd37b00000000, 0x3aa2268e00000000, + 0x9b32316600000000, 0x3985788500000000, 0x98156f6d00000000, + 0x284813ef00000000, 0x89d8040700000000, 0x2b6f4de400000000, + 0x8aff5a0c00000000, 0x2e06aff900000000, 0x8f96b81100000000, + 0x2d21f1f200000000, 0x8cb1e61a00000000, 0x24d46bc200000000, + 0x85447c2a00000000, 0x27f335c900000000, 0x8663222100000000, + 0x229ad7d400000000, 0x830ac03c00000000, 0x21bd89df00000000, + 0x802d9e3700000000, 0x21e6b5b000000000, 0x8076a25800000000, + 0x22c1ebbb00000000, 0x8351fc5300000000, 0x27a809a600000000, + 0x86381e4e00000000, 0x248f57ad00000000, 0x851f404500000000, + 0x2d7acd9d00000000, 0x8ceada7500000000, 0x2e5d939600000000, + 0x8fcd847e00000000, 0x2b34718b00000000, 0x8aa4666300000000, + 0x28132f8000000000, 0x8983386800000000, 0x39de44ea00000000, + 0x984e530200000000, 0x3af91ae100000000, 0x9b690d0900000000, + 0x3f90f8fc00000000, 0x9e00ef1400000000, 0x3cb7a6f700000000, + 0x9d27b11f00000000, 0x35423cc700000000, 0x94d22b2f00000000, + 0x366562cc00000000, 0x97f5752400000000, 0x330c80d100000000, + 0x929c973900000000, 0x302bdeda00000000, 0x91bbc93200000000, + 0x1196570500000000, 0xb00640ed00000000, 0x12b1090e00000000, + 0xb3211ee600000000, 0x17d8eb1300000000, 0xb648fcfb00000000, + 0x14ffb51800000000, 0xb56fa2f000000000, 0x1d0a2f2800000000, + 0xbc9a38c000000000, 0x1e2d712300000000, 0xbfbd66cb00000000, + 0x1b44933e00000000, 0xbad484d600000000, 0x1863cd3500000000, + 0xb9f3dadd00000000, 0x09aea65f00000000, 0xa83eb1b700000000, + 0x0a89f85400000000, 0xab19efbc00000000, 0x0fe01a4900000000, + 0xae700da100000000, 0x0cc7444200000000, 0xad5753aa00000000, + 0x0532de7200000000, 0xa4a2c99a00000000, 0x0615807900000000, + 0xa785979100000000, 0x037c626400000000, 0xa2ec758c00000000, + 0x005b3c6f00000000, 0xa1cb2b8700000000, 0x03ca1aba00000000, + 0xa25a0d5200000000, 0x00ed44b100000000, 0xa17d535900000000, + 0x0584a6ac00000000, 0xa414b14400000000, 0x06a3f8a700000000, + 0xa733ef4f00000000, 0x0f56629700000000, 0xaec6757f00000000, + 0x0c713c9c00000000, 0xade12b7400000000, 0x0918de8100000000, + 0xa888c96900000000, 0x0a3f808a00000000, 0xabaf976200000000, + 0x1bf2ebe000000000, 0xba62fc0800000000, 0x18d5b5eb00000000, + 0xb945a20300000000, 0x1dbc57f600000000, 0xbc2c401e00000000, + 0x1e9b09fd00000000, 0xbf0b1e1500000000, 0x176e93cd00000000, + 0xb6fe842500000000, 0x1449cdc600000000, 0xb5d9da2e00000000, + 0x11202fdb00000000, 0xb0b0383300000000, 0x120771d000000000, + 0xb397663800000000, 0x33baf80f00000000, 0x922aefe700000000, + 0x309da60400000000, 0x910db1ec00000000, 0x35f4441900000000, + 0x946453f100000000, 0x36d31a1200000000, 0x97430dfa00000000, + 0x3f26802200000000, 0x9eb697ca00000000, 0x3c01de2900000000, + 0x9d91c9c100000000, 0x39683c3400000000, 0x98f82bdc00000000, + 0x3a4f623f00000000, 0x9bdf75d700000000, 0x2b82095500000000, + 0x8a121ebd00000000, 0x28a5575e00000000, 0x893540b600000000, + 0x2dccb54300000000, 0x8c5ca2ab00000000, 0x2eebeb4800000000, + 0x8f7bfca000000000, 0x271e717800000000, 0x868e669000000000, + 0x24392f7300000000, 0x85a9389b00000000, 0x2150cd6e00000000, + 0x80c0da8600000000, 0x2277936500000000, 0x83e7848d00000000, + 0x222caf0a00000000, 0x83bcb8e200000000, 0x210bf10100000000, + 0x809be6e900000000, 0x2462131c00000000, 0x85f204f400000000, + 0x27454d1700000000, 0x86d55aff00000000, 0x2eb0d72700000000, + 0x8f20c0cf00000000, 0x2d97892c00000000, 0x8c079ec400000000, + 0x28fe6b3100000000, 0x896e7cd900000000, 0x2bd9353a00000000, + 0x8a4922d200000000, 0x3a145e5000000000, 0x9b8449b800000000, + 0x3933005b00000000, 0x98a317b300000000, 0x3c5ae24600000000, + 0x9dcaf5ae00000000, 0x3f7dbc4d00000000, 0x9eedaba500000000, + 0x3688267d00000000, 0x9718319500000000, 0x35af787600000000, + 0x943f6f9e00000000, 0x30c69a6b00000000, 0x91568d8300000000, + 0x33e1c46000000000, 0x9271d38800000000, 0x125c4dbf00000000, + 0xb3cc5a5700000000, 0x117b13b400000000, 0xb0eb045c00000000, + 0x1412f1a900000000, 0xb582e64100000000, 0x1735afa200000000, + 0xb6a5b84a00000000, 0x1ec0359200000000, 0xbf50227a00000000, + 0x1de76b9900000000, 0xbc777c7100000000, 0x188e898400000000, + 0xb91e9e6c00000000, 0x1ba9d78f00000000, 0xba39c06700000000, + 0x0a64bce500000000, 0xabf4ab0d00000000, 0x0943e2ee00000000, + 0xa8d3f50600000000, 0x0c2a00f300000000, 0xadba171b00000000, + 0x0f0d5ef800000000, 0xae9d491000000000, 0x06f8c4c800000000, + 0xa768d32000000000, 0x05df9ac300000000, 0xa44f8d2b00000000, + 0x00b678de00000000, 0xa1266f3600000000, 0x039126d500000000, + 0xa201313d00000000}, + {0x0000000000000000, 0xee8439a100000000, 0x9d0f029900000000, + 0x738b3b3800000000, 0x7b1975e900000000, 0x959d4c4800000000, + 0xe616777000000000, 0x08924ed100000000, 0xb7349b0900000000, + 0x59b0a2a800000000, 0x2a3b999000000000, 0xc4bfa03100000000, + 0xcc2deee000000000, 0x22a9d74100000000, 0x5122ec7900000000, + 0xbfa6d5d800000000, 0x6e69361300000000, 0x80ed0fb200000000, + 0xf366348a00000000, 0x1de20d2b00000000, 0x157043fa00000000, + 0xfbf47a5b00000000, 0x887f416300000000, 0x66fb78c200000000, + 0xd95dad1a00000000, 0x37d994bb00000000, 0x4452af8300000000, + 0xaad6962200000000, 0xa244d8f300000000, 0x4cc0e15200000000, + 0x3f4bda6a00000000, 0xd1cfe3cb00000000, 0xdcd26c2600000000, + 0x3256558700000000, 0x41dd6ebf00000000, 0xaf59571e00000000, + 0xa7cb19cf00000000, 0x494f206e00000000, 0x3ac41b5600000000, + 0xd44022f700000000, 0x6be6f72f00000000, 0x8562ce8e00000000, + 0xf6e9f5b600000000, 0x186dcc1700000000, 0x10ff82c600000000, + 0xfe7bbb6700000000, 0x8df0805f00000000, 0x6374b9fe00000000, + 0xb2bb5a3500000000, 0x5c3f639400000000, 0x2fb458ac00000000, + 0xc130610d00000000, 0xc9a22fdc00000000, 0x2726167d00000000, + 0x54ad2d4500000000, 0xba2914e400000000, 0x058fc13c00000000, + 0xeb0bf89d00000000, 0x9880c3a500000000, 0x7604fa0400000000, + 0x7e96b4d500000000, 0x90128d7400000000, 0xe399b64c00000000, + 0x0d1d8fed00000000, 0xb8a5d94c00000000, 0x5621e0ed00000000, + 0x25aadbd500000000, 0xcb2ee27400000000, 0xc3bcaca500000000, + 0x2d38950400000000, 0x5eb3ae3c00000000, 0xb037979d00000000, + 0x0f91424500000000, 0xe1157be400000000, 0x929e40dc00000000, + 0x7c1a797d00000000, 0x748837ac00000000, 0x9a0c0e0d00000000, + 0xe987353500000000, 0x07030c9400000000, 0xd6ccef5f00000000, + 0x3848d6fe00000000, 0x4bc3edc600000000, 0xa547d46700000000, + 0xadd59ab600000000, 0x4351a31700000000, 0x30da982f00000000, + 0xde5ea18e00000000, 0x61f8745600000000, 0x8f7c4df700000000, + 0xfcf776cf00000000, 0x12734f6e00000000, 0x1ae101bf00000000, + 0xf465381e00000000, 0x87ee032600000000, 0x696a3a8700000000, + 0x6477b56a00000000, 0x8af38ccb00000000, 0xf978b7f300000000, + 0x17fc8e5200000000, 0x1f6ec08300000000, 0xf1eaf92200000000, + 0x8261c21a00000000, 0x6ce5fbbb00000000, 0xd3432e6300000000, + 0x3dc717c200000000, 0x4e4c2cfa00000000, 0xa0c8155b00000000, + 0xa85a5b8a00000000, 0x46de622b00000000, 0x3555591300000000, + 0xdbd160b200000000, 0x0a1e837900000000, 0xe49abad800000000, + 0x971181e000000000, 0x7995b84100000000, 0x7107f69000000000, + 0x9f83cf3100000000, 0xec08f40900000000, 0x028ccda800000000, + 0xbd2a187000000000, 0x53ae21d100000000, 0x20251ae900000000, + 0xcea1234800000000, 0xc6336d9900000000, 0x28b7543800000000, + 0x5b3c6f0000000000, 0xb5b856a100000000, 0x704bb39900000000, + 0x9ecf8a3800000000, 0xed44b10000000000, 0x03c088a100000000, + 0x0b52c67000000000, 0xe5d6ffd100000000, 0x965dc4e900000000, + 0x78d9fd4800000000, 0xc77f289000000000, 0x29fb113100000000, + 0x5a702a0900000000, 0xb4f413a800000000, 0xbc665d7900000000, + 0x52e264d800000000, 0x21695fe000000000, 0xcfed664100000000, + 0x1e22858a00000000, 0xf0a6bc2b00000000, 0x832d871300000000, + 0x6da9beb200000000, 0x653bf06300000000, 0x8bbfc9c200000000, + 0xf834f2fa00000000, 0x16b0cb5b00000000, 0xa9161e8300000000, + 0x4792272200000000, 0x34191c1a00000000, 0xda9d25bb00000000, + 0xd20f6b6a00000000, 0x3c8b52cb00000000, 0x4f0069f300000000, + 0xa184505200000000, 0xac99dfbf00000000, 0x421de61e00000000, + 0x3196dd2600000000, 0xdf12e48700000000, 0xd780aa5600000000, + 0x390493f700000000, 0x4a8fa8cf00000000, 0xa40b916e00000000, + 0x1bad44b600000000, 0xf5297d1700000000, 0x86a2462f00000000, + 0x68267f8e00000000, 0x60b4315f00000000, 0x8e3008fe00000000, + 0xfdbb33c600000000, 0x133f0a6700000000, 0xc2f0e9ac00000000, + 0x2c74d00d00000000, 0x5fffeb3500000000, 0xb17bd29400000000, + 0xb9e99c4500000000, 0x576da5e400000000, 0x24e69edc00000000, + 0xca62a77d00000000, 0x75c472a500000000, 0x9b404b0400000000, + 0xe8cb703c00000000, 0x064f499d00000000, 0x0edd074c00000000, + 0xe0593eed00000000, 0x93d205d500000000, 0x7d563c7400000000, + 0xc8ee6ad500000000, 0x266a537400000000, 0x55e1684c00000000, + 0xbb6551ed00000000, 0xb3f71f3c00000000, 0x5d73269d00000000, + 0x2ef81da500000000, 0xc07c240400000000, 0x7fdaf1dc00000000, + 0x915ec87d00000000, 0xe2d5f34500000000, 0x0c51cae400000000, + 0x04c3843500000000, 0xea47bd9400000000, 0x99cc86ac00000000, + 0x7748bf0d00000000, 0xa6875cc600000000, 0x4803656700000000, + 0x3b885e5f00000000, 0xd50c67fe00000000, 0xdd9e292f00000000, + 0x331a108e00000000, 0x40912bb600000000, 0xae15121700000000, + 0x11b3c7cf00000000, 0xff37fe6e00000000, 0x8cbcc55600000000, + 0x6238fcf700000000, 0x6aaab22600000000, 0x842e8b8700000000, + 0xf7a5b0bf00000000, 0x1921891e00000000, 0x143c06f300000000, + 0xfab83f5200000000, 0x8933046a00000000, 0x67b73dcb00000000, + 0x6f25731a00000000, 0x81a14abb00000000, 0xf22a718300000000, + 0x1cae482200000000, 0xa3089dfa00000000, 0x4d8ca45b00000000, + 0x3e079f6300000000, 0xd083a6c200000000, 0xd811e81300000000, + 0x3695d1b200000000, 0x451eea8a00000000, 0xab9ad32b00000000, + 0x7a5530e000000000, 0x94d1094100000000, 0xe75a327900000000, + 0x09de0bd800000000, 0x014c450900000000, 0xefc87ca800000000, + 0x9c43479000000000, 0x72c77e3100000000, 0xcd61abe900000000, + 0x23e5924800000000, 0x506ea97000000000, 0xbeea90d100000000, + 0xb678de0000000000, 0x58fce7a100000000, 0x2b77dc9900000000, + 0xc5f3e53800000000}, + {0x0000000000000000, 0xfbf6134700000000, 0xf6ed278e00000000, + 0x0d1b34c900000000, 0xaddd3ec700000000, 0x562b2d8000000000, + 0x5b30194900000000, 0xa0c60a0e00000000, 0x1bbd0c5500000000, + 0xe04b1f1200000000, 0xed502bdb00000000, 0x16a6389c00000000, + 0xb660329200000000, 0x4d9621d500000000, 0x408d151c00000000, + 0xbb7b065b00000000, 0x367a19aa00000000, 0xcd8c0aed00000000, + 0xc0973e2400000000, 0x3b612d6300000000, 0x9ba7276d00000000, + 0x6051342a00000000, 0x6d4a00e300000000, 0x96bc13a400000000, + 0x2dc715ff00000000, 0xd63106b800000000, 0xdb2a327100000000, + 0x20dc213600000000, 0x801a2b3800000000, 0x7bec387f00000000, + 0x76f70cb600000000, 0x8d011ff100000000, 0x2df2438f00000000, + 0xd60450c800000000, 0xdb1f640100000000, 0x20e9774600000000, + 0x802f7d4800000000, 0x7bd96e0f00000000, 0x76c25ac600000000, + 0x8d34498100000000, 0x364f4fda00000000, 0xcdb95c9d00000000, + 0xc0a2685400000000, 0x3b547b1300000000, 0x9b92711d00000000, + 0x6064625a00000000, 0x6d7f569300000000, 0x968945d400000000, + 0x1b885a2500000000, 0xe07e496200000000, 0xed657dab00000000, + 0x16936eec00000000, 0xb65564e200000000, 0x4da377a500000000, + 0x40b8436c00000000, 0xbb4e502b00000000, 0x0035567000000000, + 0xfbc3453700000000, 0xf6d871fe00000000, 0x0d2e62b900000000, + 0xade868b700000000, 0x561e7bf000000000, 0x5b054f3900000000, + 0xa0f35c7e00000000, 0x1be2f6c500000000, 0xe014e58200000000, + 0xed0fd14b00000000, 0x16f9c20c00000000, 0xb63fc80200000000, + 0x4dc9db4500000000, 0x40d2ef8c00000000, 0xbb24fccb00000000, + 0x005ffa9000000000, 0xfba9e9d700000000, 0xf6b2dd1e00000000, + 0x0d44ce5900000000, 0xad82c45700000000, 0x5674d71000000000, + 0x5b6fe3d900000000, 0xa099f09e00000000, 0x2d98ef6f00000000, + 0xd66efc2800000000, 0xdb75c8e100000000, 0x2083dba600000000, + 0x8045d1a800000000, 0x7bb3c2ef00000000, 0x76a8f62600000000, + 0x8d5ee56100000000, 0x3625e33a00000000, 0xcdd3f07d00000000, + 0xc0c8c4b400000000, 0x3b3ed7f300000000, 0x9bf8ddfd00000000, + 0x600eceba00000000, 0x6d15fa7300000000, 0x96e3e93400000000, + 0x3610b54a00000000, 0xcde6a60d00000000, 0xc0fd92c400000000, + 0x3b0b818300000000, 0x9bcd8b8d00000000, 0x603b98ca00000000, + 0x6d20ac0300000000, 0x96d6bf4400000000, 0x2dadb91f00000000, + 0xd65baa5800000000, 0xdb409e9100000000, 0x20b68dd600000000, + 0x807087d800000000, 0x7b86949f00000000, 0x769da05600000000, + 0x8d6bb31100000000, 0x006aace000000000, 0xfb9cbfa700000000, + 0xf6878b6e00000000, 0x0d71982900000000, 0xadb7922700000000, + 0x5641816000000000, 0x5b5ab5a900000000, 0xa0aca6ee00000000, + 0x1bd7a0b500000000, 0xe021b3f200000000, 0xed3a873b00000000, + 0x16cc947c00000000, 0xb60a9e7200000000, 0x4dfc8d3500000000, + 0x40e7b9fc00000000, 0xbb11aabb00000000, 0x77c29c5000000000, + 0x8c348f1700000000, 0x812fbbde00000000, 0x7ad9a89900000000, + 0xda1fa29700000000, 0x21e9b1d000000000, 0x2cf2851900000000, + 0xd704965e00000000, 0x6c7f900500000000, 0x9789834200000000, + 0x9a92b78b00000000, 0x6164a4cc00000000, 0xc1a2aec200000000, + 0x3a54bd8500000000, 0x374f894c00000000, 0xccb99a0b00000000, + 0x41b885fa00000000, 0xba4e96bd00000000, 0xb755a27400000000, + 0x4ca3b13300000000, 0xec65bb3d00000000, 0x1793a87a00000000, + 0x1a889cb300000000, 0xe17e8ff400000000, 0x5a0589af00000000, + 0xa1f39ae800000000, 0xace8ae2100000000, 0x571ebd6600000000, + 0xf7d8b76800000000, 0x0c2ea42f00000000, 0x013590e600000000, + 0xfac383a100000000, 0x5a30dfdf00000000, 0xa1c6cc9800000000, + 0xacddf85100000000, 0x572beb1600000000, 0xf7ede11800000000, + 0x0c1bf25f00000000, 0x0100c69600000000, 0xfaf6d5d100000000, + 0x418dd38a00000000, 0xba7bc0cd00000000, 0xb760f40400000000, + 0x4c96e74300000000, 0xec50ed4d00000000, 0x17a6fe0a00000000, + 0x1abdcac300000000, 0xe14bd98400000000, 0x6c4ac67500000000, + 0x97bcd53200000000, 0x9aa7e1fb00000000, 0x6151f2bc00000000, + 0xc197f8b200000000, 0x3a61ebf500000000, 0x377adf3c00000000, + 0xcc8ccc7b00000000, 0x77f7ca2000000000, 0x8c01d96700000000, + 0x811aedae00000000, 0x7aecfee900000000, 0xda2af4e700000000, + 0x21dce7a000000000, 0x2cc7d36900000000, 0xd731c02e00000000, + 0x6c206a9500000000, 0x97d679d200000000, 0x9acd4d1b00000000, + 0x613b5e5c00000000, 0xc1fd545200000000, 0x3a0b471500000000, + 0x371073dc00000000, 0xcce6609b00000000, 0x779d66c000000000, + 0x8c6b758700000000, 0x8170414e00000000, 0x7a86520900000000, + 0xda40580700000000, 0x21b64b4000000000, 0x2cad7f8900000000, + 0xd75b6cce00000000, 0x5a5a733f00000000, 0xa1ac607800000000, + 0xacb754b100000000, 0x574147f600000000, 0xf7874df800000000, + 0x0c715ebf00000000, 0x016a6a7600000000, 0xfa9c793100000000, + 0x41e77f6a00000000, 0xba116c2d00000000, 0xb70a58e400000000, + 0x4cfc4ba300000000, 0xec3a41ad00000000, 0x17cc52ea00000000, + 0x1ad7662300000000, 0xe121756400000000, 0x41d2291a00000000, + 0xba243a5d00000000, 0xb73f0e9400000000, 0x4cc91dd300000000, + 0xec0f17dd00000000, 0x17f9049a00000000, 0x1ae2305300000000, + 0xe114231400000000, 0x5a6f254f00000000, 0xa199360800000000, + 0xac8202c100000000, 0x5774118600000000, 0xf7b21b8800000000, + 0x0c4408cf00000000, 0x015f3c0600000000, 0xfaa92f4100000000, + 0x77a830b000000000, 0x8c5e23f700000000, 0x8145173e00000000, + 0x7ab3047900000000, 0xda750e7700000000, 0x21831d3000000000, + 0x2c9829f900000000, 0xd76e3abe00000000, 0x6c153ce500000000, + 0x97e32fa200000000, 0x9af81b6b00000000, 0x610e082c00000000, + 0xc1c8022200000000, 0x3a3e116500000000, 0x372525ac00000000, + 0xccd336eb00000000}, + {0x0000000000000000, 0x6238282a00000000, 0xc470505400000000, + 0xa648787e00000000, 0x88e1a0a800000000, 0xead9888200000000, + 0x4c91f0fc00000000, 0x2ea9d8d600000000, 0x51c5308a00000000, + 0x33fd18a000000000, 0x95b560de00000000, 0xf78d48f400000000, + 0xd924902200000000, 0xbb1cb80800000000, 0x1d54c07600000000, + 0x7f6ce85c00000000, 0xe38c10cf00000000, 0x81b438e500000000, + 0x27fc409b00000000, 0x45c468b100000000, 0x6b6db06700000000, + 0x0955984d00000000, 0xaf1de03300000000, 0xcd25c81900000000, + 0xb249204500000000, 0xd071086f00000000, 0x7639701100000000, + 0x1401583b00000000, 0x3aa880ed00000000, 0x5890a8c700000000, + 0xfed8d0b900000000, 0x9ce0f89300000000, 0x871f504500000000, + 0xe527786f00000000, 0x436f001100000000, 0x2157283b00000000, + 0x0ffef0ed00000000, 0x6dc6d8c700000000, 0xcb8ea0b900000000, + 0xa9b6889300000000, 0xd6da60cf00000000, 0xb4e248e500000000, + 0x12aa309b00000000, 0x709218b100000000, 0x5e3bc06700000000, + 0x3c03e84d00000000, 0x9a4b903300000000, 0xf873b81900000000, + 0x6493408a00000000, 0x06ab68a000000000, 0xa0e310de00000000, + 0xc2db38f400000000, 0xec72e02200000000, 0x8e4ac80800000000, + 0x2802b07600000000, 0x4a3a985c00000000, 0x3556700000000000, + 0x576e582a00000000, 0xf126205400000000, 0x931e087e00000000, + 0xbdb7d0a800000000, 0xdf8ff88200000000, 0x79c780fc00000000, + 0x1bffa8d600000000, 0x0e3fa08a00000000, 0x6c0788a000000000, + 0xca4ff0de00000000, 0xa877d8f400000000, 0x86de002200000000, + 0xe4e6280800000000, 0x42ae507600000000, 0x2096785c00000000, + 0x5ffa900000000000, 0x3dc2b82a00000000, 0x9b8ac05400000000, + 0xf9b2e87e00000000, 0xd71b30a800000000, 0xb523188200000000, + 0x136b60fc00000000, 0x715348d600000000, 0xedb3b04500000000, + 0x8f8b986f00000000, 0x29c3e01100000000, 0x4bfbc83b00000000, + 0x655210ed00000000, 0x076a38c700000000, 0xa12240b900000000, + 0xc31a689300000000, 0xbc7680cf00000000, 0xde4ea8e500000000, + 0x7806d09b00000000, 0x1a3ef8b100000000, 0x3497206700000000, + 0x56af084d00000000, 0xf0e7703300000000, 0x92df581900000000, + 0x8920f0cf00000000, 0xeb18d8e500000000, 0x4d50a09b00000000, + 0x2f6888b100000000, 0x01c1506700000000, 0x63f9784d00000000, + 0xc5b1003300000000, 0xa789281900000000, 0xd8e5c04500000000, + 0xbadde86f00000000, 0x1c95901100000000, 0x7eadb83b00000000, + 0x500460ed00000000, 0x323c48c700000000, 0x947430b900000000, + 0xf64c189300000000, 0x6aace00000000000, 0x0894c82a00000000, + 0xaedcb05400000000, 0xcce4987e00000000, 0xe24d40a800000000, + 0x8075688200000000, 0x263d10fc00000000, 0x440538d600000000, + 0x3b69d08a00000000, 0x5951f8a000000000, 0xff1980de00000000, + 0x9d21a8f400000000, 0xb388702200000000, 0xd1b0580800000000, + 0x77f8207600000000, 0x15c0085c00000000, 0x5d7831ce00000000, + 0x3f4019e400000000, 0x9908619a00000000, 0xfb3049b000000000, + 0xd599916600000000, 0xb7a1b94c00000000, 0x11e9c13200000000, + 0x73d1e91800000000, 0x0cbd014400000000, 0x6e85296e00000000, + 0xc8cd511000000000, 0xaaf5793a00000000, 0x845ca1ec00000000, + 0xe66489c600000000, 0x402cf1b800000000, 0x2214d99200000000, + 0xbef4210100000000, 0xdccc092b00000000, 0x7a84715500000000, + 0x18bc597f00000000, 0x361581a900000000, 0x542da98300000000, + 0xf265d1fd00000000, 0x905df9d700000000, 0xef31118b00000000, + 0x8d0939a100000000, 0x2b4141df00000000, 0x497969f500000000, + 0x67d0b12300000000, 0x05e8990900000000, 0xa3a0e17700000000, + 0xc198c95d00000000, 0xda67618b00000000, 0xb85f49a100000000, + 0x1e1731df00000000, 0x7c2f19f500000000, 0x5286c12300000000, + 0x30bee90900000000, 0x96f6917700000000, 0xf4ceb95d00000000, + 0x8ba2510100000000, 0xe99a792b00000000, 0x4fd2015500000000, + 0x2dea297f00000000, 0x0343f1a900000000, 0x617bd98300000000, + 0xc733a1fd00000000, 0xa50b89d700000000, 0x39eb714400000000, + 0x5bd3596e00000000, 0xfd9b211000000000, 0x9fa3093a00000000, + 0xb10ad1ec00000000, 0xd332f9c600000000, 0x757a81b800000000, + 0x1742a99200000000, 0x682e41ce00000000, 0x0a1669e400000000, + 0xac5e119a00000000, 0xce6639b000000000, 0xe0cfe16600000000, + 0x82f7c94c00000000, 0x24bfb13200000000, 0x4687991800000000, + 0x5347914400000000, 0x317fb96e00000000, 0x9737c11000000000, + 0xf50fe93a00000000, 0xdba631ec00000000, 0xb99e19c600000000, + 0x1fd661b800000000, 0x7dee499200000000, 0x0282a1ce00000000, + 0x60ba89e400000000, 0xc6f2f19a00000000, 0xa4cad9b000000000, + 0x8a63016600000000, 0xe85b294c00000000, 0x4e13513200000000, + 0x2c2b791800000000, 0xb0cb818b00000000, 0xd2f3a9a100000000, + 0x74bbd1df00000000, 0x1683f9f500000000, 0x382a212300000000, + 0x5a12090900000000, 0xfc5a717700000000, 0x9e62595d00000000, + 0xe10eb10100000000, 0x8336992b00000000, 0x257ee15500000000, + 0x4746c97f00000000, 0x69ef11a900000000, 0x0bd7398300000000, + 0xad9f41fd00000000, 0xcfa769d700000000, 0xd458c10100000000, + 0xb660e92b00000000, 0x1028915500000000, 0x7210b97f00000000, + 0x5cb961a900000000, 0x3e81498300000000, 0x98c931fd00000000, + 0xfaf119d700000000, 0x859df18b00000000, 0xe7a5d9a100000000, + 0x41eda1df00000000, 0x23d589f500000000, 0x0d7c512300000000, + 0x6f44790900000000, 0xc90c017700000000, 0xab34295d00000000, + 0x37d4d1ce00000000, 0x55ecf9e400000000, 0xf3a4819a00000000, + 0x919ca9b000000000, 0xbf35716600000000, 0xdd0d594c00000000, + 0x7b45213200000000, 0x197d091800000000, 0x6611e14400000000, + 0x0429c96e00000000, 0xa261b11000000000, 0xc059993a00000000, + 0xeef041ec00000000, 0x8cc869c600000000, 0x2a8011b800000000, + 0x48b8399200000000}, + {0x0000000000000000, 0x4c2896a300000000, 0xd9565d9c00000000, + 0x957ecb3f00000000, 0xf3abcbe300000000, 0xbf835d4000000000, + 0x2afd967f00000000, 0x66d500dc00000000, 0xa751e61c00000000, + 0xeb7970bf00000000, 0x7e07bb8000000000, 0x322f2d2300000000, + 0x54fa2dff00000000, 0x18d2bb5c00000000, 0x8dac706300000000, + 0xc184e6c000000000, 0x4ea3cc3900000000, 0x028b5a9a00000000, + 0x97f591a500000000, 0xdbdd070600000000, 0xbd0807da00000000, + 0xf120917900000000, 0x645e5a4600000000, 0x2876cce500000000, + 0xe9f22a2500000000, 0xa5dabc8600000000, 0x30a477b900000000, + 0x7c8ce11a00000000, 0x1a59e1c600000000, 0x5671776500000000, + 0xc30fbc5a00000000, 0x8f272af900000000, 0x9c46997300000000, + 0xd06e0fd000000000, 0x4510c4ef00000000, 0x0938524c00000000, + 0x6fed529000000000, 0x23c5c43300000000, 0xb6bb0f0c00000000, + 0xfa9399af00000000, 0x3b177f6f00000000, 0x773fe9cc00000000, + 0xe24122f300000000, 0xae69b45000000000, 0xc8bcb48c00000000, + 0x8494222f00000000, 0x11eae91000000000, 0x5dc27fb300000000, + 0xd2e5554a00000000, 0x9ecdc3e900000000, 0x0bb308d600000000, + 0x479b9e7500000000, 0x214e9ea900000000, 0x6d66080a00000000, + 0xf818c33500000000, 0xb430559600000000, 0x75b4b35600000000, + 0x399c25f500000000, 0xace2eeca00000000, 0xe0ca786900000000, + 0x861f78b500000000, 0xca37ee1600000000, 0x5f49252900000000, + 0x1361b38a00000000, 0x388d32e700000000, 0x74a5a44400000000, + 0xe1db6f7b00000000, 0xadf3f9d800000000, 0xcb26f90400000000, + 0x870e6fa700000000, 0x1270a49800000000, 0x5e58323b00000000, + 0x9fdcd4fb00000000, 0xd3f4425800000000, 0x468a896700000000, + 0x0aa21fc400000000, 0x6c771f1800000000, 0x205f89bb00000000, + 0xb521428400000000, 0xf909d42700000000, 0x762efede00000000, + 0x3a06687d00000000, 0xaf78a34200000000, 0xe35035e100000000, + 0x8585353d00000000, 0xc9ada39e00000000, 0x5cd368a100000000, + 0x10fbfe0200000000, 0xd17f18c200000000, 0x9d578e6100000000, + 0x0829455e00000000, 0x4401d3fd00000000, 0x22d4d32100000000, + 0x6efc458200000000, 0xfb828ebd00000000, 0xb7aa181e00000000, + 0xa4cbab9400000000, 0xe8e33d3700000000, 0x7d9df60800000000, + 0x31b560ab00000000, 0x5760607700000000, 0x1b48f6d400000000, + 0x8e363deb00000000, 0xc21eab4800000000, 0x039a4d8800000000, + 0x4fb2db2b00000000, 0xdacc101400000000, 0x96e486b700000000, + 0xf031866b00000000, 0xbc1910c800000000, 0x2967dbf700000000, + 0x654f4d5400000000, 0xea6867ad00000000, 0xa640f10e00000000, + 0x333e3a3100000000, 0x7f16ac9200000000, 0x19c3ac4e00000000, + 0x55eb3aed00000000, 0xc095f1d200000000, 0x8cbd677100000000, + 0x4d3981b100000000, 0x0111171200000000, 0x946fdc2d00000000, + 0xd8474a8e00000000, 0xbe924a5200000000, 0xf2badcf100000000, + 0x67c417ce00000000, 0x2bec816d00000000, 0x311c141500000000, + 0x7d3482b600000000, 0xe84a498900000000, 0xa462df2a00000000, + 0xc2b7dff600000000, 0x8e9f495500000000, 0x1be1826a00000000, + 0x57c914c900000000, 0x964df20900000000, 0xda6564aa00000000, + 0x4f1baf9500000000, 0x0333393600000000, 0x65e639ea00000000, + 0x29ceaf4900000000, 0xbcb0647600000000, 0xf098f2d500000000, + 0x7fbfd82c00000000, 0x33974e8f00000000, 0xa6e985b000000000, + 0xeac1131300000000, 0x8c1413cf00000000, 0xc03c856c00000000, + 0x55424e5300000000, 0x196ad8f000000000, 0xd8ee3e3000000000, + 0x94c6a89300000000, 0x01b863ac00000000, 0x4d90f50f00000000, + 0x2b45f5d300000000, 0x676d637000000000, 0xf213a84f00000000, + 0xbe3b3eec00000000, 0xad5a8d6600000000, 0xe1721bc500000000, + 0x740cd0fa00000000, 0x3824465900000000, 0x5ef1468500000000, + 0x12d9d02600000000, 0x87a71b1900000000, 0xcb8f8dba00000000, + 0x0a0b6b7a00000000, 0x4623fdd900000000, 0xd35d36e600000000, + 0x9f75a04500000000, 0xf9a0a09900000000, 0xb588363a00000000, + 0x20f6fd0500000000, 0x6cde6ba600000000, 0xe3f9415f00000000, + 0xafd1d7fc00000000, 0x3aaf1cc300000000, 0x76878a6000000000, + 0x10528abc00000000, 0x5c7a1c1f00000000, 0xc904d72000000000, + 0x852c418300000000, 0x44a8a74300000000, 0x088031e000000000, + 0x9dfefadf00000000, 0xd1d66c7c00000000, 0xb7036ca000000000, + 0xfb2bfa0300000000, 0x6e55313c00000000, 0x227da79f00000000, + 0x099126f200000000, 0x45b9b05100000000, 0xd0c77b6e00000000, + 0x9cefedcd00000000, 0xfa3aed1100000000, 0xb6127bb200000000, + 0x236cb08d00000000, 0x6f44262e00000000, 0xaec0c0ee00000000, + 0xe2e8564d00000000, 0x77969d7200000000, 0x3bbe0bd100000000, + 0x5d6b0b0d00000000, 0x11439dae00000000, 0x843d569100000000, + 0xc815c03200000000, 0x4732eacb00000000, 0x0b1a7c6800000000, + 0x9e64b75700000000, 0xd24c21f400000000, 0xb499212800000000, + 0xf8b1b78b00000000, 0x6dcf7cb400000000, 0x21e7ea1700000000, + 0xe0630cd700000000, 0xac4b9a7400000000, 0x3935514b00000000, + 0x751dc7e800000000, 0x13c8c73400000000, 0x5fe0519700000000, + 0xca9e9aa800000000, 0x86b60c0b00000000, 0x95d7bf8100000000, + 0xd9ff292200000000, 0x4c81e21d00000000, 0x00a974be00000000, + 0x667c746200000000, 0x2a54e2c100000000, 0xbf2a29fe00000000, + 0xf302bf5d00000000, 0x3286599d00000000, 0x7eaecf3e00000000, + 0xebd0040100000000, 0xa7f892a200000000, 0xc12d927e00000000, + 0x8d0504dd00000000, 0x187bcfe200000000, 0x5453594100000000, + 0xdb7473b800000000, 0x975ce51b00000000, 0x02222e2400000000, + 0x4e0ab88700000000, 0x28dfb85b00000000, 0x64f72ef800000000, + 0xf189e5c700000000, 0xbda1736400000000, 0x7c2595a400000000, + 0x300d030700000000, 0xa573c83800000000, 0xe95b5e9b00000000, + 0x8f8e5e4700000000, 0xc3a6c8e400000000, 0x56d803db00000000, + 0x1af0957800000000}, + {0x0000000000000000, 0x939bc97f00000000, 0x263793ff00000000, + 0xb5ac5a8000000000, 0x0d68572400000000, 0x9ef39e5b00000000, + 0x2b5fc4db00000000, 0xb8c40da400000000, 0x1ad0ae4800000000, + 0x894b673700000000, 0x3ce73db700000000, 0xaf7cf4c800000000, + 0x17b8f96c00000000, 0x8423301300000000, 0x318f6a9300000000, + 0xa214a3ec00000000, 0x34a05d9100000000, 0xa73b94ee00000000, + 0x1297ce6e00000000, 0x810c071100000000, 0x39c80ab500000000, + 0xaa53c3ca00000000, 0x1fff994a00000000, 0x8c64503500000000, + 0x2e70f3d900000000, 0xbdeb3aa600000000, 0x0847602600000000, + 0x9bdca95900000000, 0x2318a4fd00000000, 0xb0836d8200000000, + 0x052f370200000000, 0x96b4fe7d00000000, 0x2946caf900000000, + 0xbadd038600000000, 0x0f71590600000000, 0x9cea907900000000, + 0x242e9ddd00000000, 0xb7b554a200000000, 0x02190e2200000000, + 0x9182c75d00000000, 0x339664b100000000, 0xa00dadce00000000, + 0x15a1f74e00000000, 0x863a3e3100000000, 0x3efe339500000000, + 0xad65faea00000000, 0x18c9a06a00000000, 0x8b52691500000000, + 0x1de6976800000000, 0x8e7d5e1700000000, 0x3bd1049700000000, + 0xa84acde800000000, 0x108ec04c00000000, 0x8315093300000000, + 0x36b953b300000000, 0xa5229acc00000000, 0x0736392000000000, + 0x94adf05f00000000, 0x2101aadf00000000, 0xb29a63a000000000, + 0x0a5e6e0400000000, 0x99c5a77b00000000, 0x2c69fdfb00000000, + 0xbff2348400000000, 0x138ae52800000000, 0x80112c5700000000, + 0x35bd76d700000000, 0xa626bfa800000000, 0x1ee2b20c00000000, + 0x8d797b7300000000, 0x38d521f300000000, 0xab4ee88c00000000, + 0x095a4b6000000000, 0x9ac1821f00000000, 0x2f6dd89f00000000, + 0xbcf611e000000000, 0x04321c4400000000, 0x97a9d53b00000000, + 0x22058fbb00000000, 0xb19e46c400000000, 0x272ab8b900000000, + 0xb4b171c600000000, 0x011d2b4600000000, 0x9286e23900000000, + 0x2a42ef9d00000000, 0xb9d926e200000000, 0x0c757c6200000000, + 0x9feeb51d00000000, 0x3dfa16f100000000, 0xae61df8e00000000, + 0x1bcd850e00000000, 0x88564c7100000000, 0x309241d500000000, + 0xa30988aa00000000, 0x16a5d22a00000000, 0x853e1b5500000000, + 0x3acc2fd100000000, 0xa957e6ae00000000, 0x1cfbbc2e00000000, + 0x8f60755100000000, 0x37a478f500000000, 0xa43fb18a00000000, + 0x1193eb0a00000000, 0x8208227500000000, 0x201c819900000000, + 0xb38748e600000000, 0x062b126600000000, 0x95b0db1900000000, + 0x2d74d6bd00000000, 0xbeef1fc200000000, 0x0b43454200000000, + 0x98d88c3d00000000, 0x0e6c724000000000, 0x9df7bb3f00000000, + 0x285be1bf00000000, 0xbbc028c000000000, 0x0304256400000000, + 0x909fec1b00000000, 0x2533b69b00000000, 0xb6a87fe400000000, + 0x14bcdc0800000000, 0x8727157700000000, 0x328b4ff700000000, + 0xa110868800000000, 0x19d48b2c00000000, 0x8a4f425300000000, + 0x3fe318d300000000, 0xac78d1ac00000000, 0x2614cb5100000000, + 0xb58f022e00000000, 0x002358ae00000000, 0x93b891d100000000, + 0x2b7c9c7500000000, 0xb8e7550a00000000, 0x0d4b0f8a00000000, + 0x9ed0c6f500000000, 0x3cc4651900000000, 0xaf5fac6600000000, + 0x1af3f6e600000000, 0x89683f9900000000, 0x31ac323d00000000, + 0xa237fb4200000000, 0x179ba1c200000000, 0x840068bd00000000, + 0x12b496c000000000, 0x812f5fbf00000000, 0x3483053f00000000, + 0xa718cc4000000000, 0x1fdcc1e400000000, 0x8c47089b00000000, + 0x39eb521b00000000, 0xaa709b6400000000, 0x0864388800000000, + 0x9bfff1f700000000, 0x2e53ab7700000000, 0xbdc8620800000000, + 0x050c6fac00000000, 0x9697a6d300000000, 0x233bfc5300000000, + 0xb0a0352c00000000, 0x0f5201a800000000, 0x9cc9c8d700000000, + 0x2965925700000000, 0xbafe5b2800000000, 0x023a568c00000000, + 0x91a19ff300000000, 0x240dc57300000000, 0xb7960c0c00000000, + 0x1582afe000000000, 0x8619669f00000000, 0x33b53c1f00000000, + 0xa02ef56000000000, 0x18eaf8c400000000, 0x8b7131bb00000000, + 0x3edd6b3b00000000, 0xad46a24400000000, 0x3bf25c3900000000, + 0xa869954600000000, 0x1dc5cfc600000000, 0x8e5e06b900000000, + 0x369a0b1d00000000, 0xa501c26200000000, 0x10ad98e200000000, + 0x8336519d00000000, 0x2122f27100000000, 0xb2b93b0e00000000, + 0x0715618e00000000, 0x948ea8f100000000, 0x2c4aa55500000000, + 0xbfd16c2a00000000, 0x0a7d36aa00000000, 0x99e6ffd500000000, + 0x359e2e7900000000, 0xa605e70600000000, 0x13a9bd8600000000, + 0x803274f900000000, 0x38f6795d00000000, 0xab6db02200000000, + 0x1ec1eaa200000000, 0x8d5a23dd00000000, 0x2f4e803100000000, + 0xbcd5494e00000000, 0x097913ce00000000, 0x9ae2dab100000000, + 0x2226d71500000000, 0xb1bd1e6a00000000, 0x041144ea00000000, + 0x978a8d9500000000, 0x013e73e800000000, 0x92a5ba9700000000, + 0x2709e01700000000, 0xb492296800000000, 0x0c5624cc00000000, + 0x9fcdedb300000000, 0x2a61b73300000000, 0xb9fa7e4c00000000, + 0x1beedda000000000, 0x887514df00000000, 0x3dd94e5f00000000, + 0xae42872000000000, 0x16868a8400000000, 0x851d43fb00000000, + 0x30b1197b00000000, 0xa32ad00400000000, 0x1cd8e48000000000, + 0x8f432dff00000000, 0x3aef777f00000000, 0xa974be0000000000, + 0x11b0b3a400000000, 0x822b7adb00000000, 0x3787205b00000000, + 0xa41ce92400000000, 0x06084ac800000000, 0x959383b700000000, + 0x203fd93700000000, 0xb3a4104800000000, 0x0b601dec00000000, + 0x98fbd49300000000, 0x2d578e1300000000, 0xbecc476c00000000, + 0x2878b91100000000, 0xbbe3706e00000000, 0x0e4f2aee00000000, + 0x9dd4e39100000000, 0x2510ee3500000000, 0xb68b274a00000000, + 0x03277dca00000000, 0x90bcb4b500000000, 0x32a8175900000000, + 0xa133de2600000000, 0x149f84a600000000, 0x87044dd900000000, + 0x3fc0407d00000000, 0xac5b890200000000, 0x19f7d38200000000, + 0x8a6c1afd00000000}, + {0x0000000000000000, 0x650b796900000000, 0xca16f2d200000000, + 0xaf1d8bbb00000000, 0xd52b957e00000000, 0xb020ec1700000000, + 0x1f3d67ac00000000, 0x7a361ec500000000, 0xaa572afd00000000, + 0xcf5c539400000000, 0x6041d82f00000000, 0x054aa14600000000, + 0x7f7cbf8300000000, 0x1a77c6ea00000000, 0xb56a4d5100000000, + 0xd061343800000000, 0x15a9252100000000, 0x70a25c4800000000, + 0xdfbfd7f300000000, 0xbab4ae9a00000000, 0xc082b05f00000000, + 0xa589c93600000000, 0x0a94428d00000000, 0x6f9f3be400000000, + 0xbffe0fdc00000000, 0xdaf576b500000000, 0x75e8fd0e00000000, + 0x10e3846700000000, 0x6ad59aa200000000, 0x0fdee3cb00000000, + 0xa0c3687000000000, 0xc5c8111900000000, 0x2a524b4200000000, + 0x4f59322b00000000, 0xe044b99000000000, 0x854fc0f900000000, + 0xff79de3c00000000, 0x9a72a75500000000, 0x356f2cee00000000, + 0x5064558700000000, 0x800561bf00000000, 0xe50e18d600000000, + 0x4a13936d00000000, 0x2f18ea0400000000, 0x552ef4c100000000, + 0x30258da800000000, 0x9f38061300000000, 0xfa337f7a00000000, + 0x3ffb6e6300000000, 0x5af0170a00000000, 0xf5ed9cb100000000, + 0x90e6e5d800000000, 0xead0fb1d00000000, 0x8fdb827400000000, + 0x20c609cf00000000, 0x45cd70a600000000, 0x95ac449e00000000, + 0xf0a73df700000000, 0x5fbab64c00000000, 0x3ab1cf2500000000, + 0x4087d1e000000000, 0x258ca88900000000, 0x8a91233200000000, + 0xef9a5a5b00000000, 0x54a4968400000000, 0x31afefed00000000, + 0x9eb2645600000000, 0xfbb91d3f00000000, 0x818f03fa00000000, + 0xe4847a9300000000, 0x4b99f12800000000, 0x2e92884100000000, + 0xfef3bc7900000000, 0x9bf8c51000000000, 0x34e54eab00000000, + 0x51ee37c200000000, 0x2bd8290700000000, 0x4ed3506e00000000, + 0xe1cedbd500000000, 0x84c5a2bc00000000, 0x410db3a500000000, + 0x2406cacc00000000, 0x8b1b417700000000, 0xee10381e00000000, + 0x942626db00000000, 0xf12d5fb200000000, 0x5e30d40900000000, + 0x3b3bad6000000000, 0xeb5a995800000000, 0x8e51e03100000000, + 0x214c6b8a00000000, 0x444712e300000000, 0x3e710c2600000000, + 0x5b7a754f00000000, 0xf467fef400000000, 0x916c879d00000000, + 0x7ef6ddc600000000, 0x1bfda4af00000000, 0xb4e02f1400000000, + 0xd1eb567d00000000, 0xabdd48b800000000, 0xced631d100000000, + 0x61cbba6a00000000, 0x04c0c30300000000, 0xd4a1f73b00000000, + 0xb1aa8e5200000000, 0x1eb705e900000000, 0x7bbc7c8000000000, + 0x018a624500000000, 0x64811b2c00000000, 0xcb9c909700000000, + 0xae97e9fe00000000, 0x6b5ff8e700000000, 0x0e54818e00000000, + 0xa1490a3500000000, 0xc442735c00000000, 0xbe746d9900000000, + 0xdb7f14f000000000, 0x74629f4b00000000, 0x1169e62200000000, + 0xc108d21a00000000, 0xa403ab7300000000, 0x0b1e20c800000000, + 0x6e1559a100000000, 0x1423476400000000, 0x71283e0d00000000, + 0xde35b5b600000000, 0xbb3eccdf00000000, 0xe94e5cd200000000, + 0x8c4525bb00000000, 0x2358ae0000000000, 0x4653d76900000000, + 0x3c65c9ac00000000, 0x596eb0c500000000, 0xf6733b7e00000000, + 0x9378421700000000, 0x4319762f00000000, 0x26120f4600000000, + 0x890f84fd00000000, 0xec04fd9400000000, 0x9632e35100000000, + 0xf3399a3800000000, 0x5c24118300000000, 0x392f68ea00000000, + 0xfce779f300000000, 0x99ec009a00000000, 0x36f18b2100000000, + 0x53faf24800000000, 0x29ccec8d00000000, 0x4cc795e400000000, + 0xe3da1e5f00000000, 0x86d1673600000000, 0x56b0530e00000000, + 0x33bb2a6700000000, 0x9ca6a1dc00000000, 0xf9add8b500000000, + 0x839bc67000000000, 0xe690bf1900000000, 0x498d34a200000000, + 0x2c864dcb00000000, 0xc31c179000000000, 0xa6176ef900000000, + 0x090ae54200000000, 0x6c019c2b00000000, 0x163782ee00000000, + 0x733cfb8700000000, 0xdc21703c00000000, 0xb92a095500000000, + 0x694b3d6d00000000, 0x0c40440400000000, 0xa35dcfbf00000000, + 0xc656b6d600000000, 0xbc60a81300000000, 0xd96bd17a00000000, + 0x76765ac100000000, 0x137d23a800000000, 0xd6b532b100000000, + 0xb3be4bd800000000, 0x1ca3c06300000000, 0x79a8b90a00000000, + 0x039ea7cf00000000, 0x6695dea600000000, 0xc988551d00000000, + 0xac832c7400000000, 0x7ce2184c00000000, 0x19e9612500000000, + 0xb6f4ea9e00000000, 0xd3ff93f700000000, 0xa9c98d3200000000, + 0xccc2f45b00000000, 0x63df7fe000000000, 0x06d4068900000000, + 0xbdeaca5600000000, 0xd8e1b33f00000000, 0x77fc388400000000, + 0x12f741ed00000000, 0x68c15f2800000000, 0x0dca264100000000, + 0xa2d7adfa00000000, 0xc7dcd49300000000, 0x17bde0ab00000000, + 0x72b699c200000000, 0xddab127900000000, 0xb8a06b1000000000, + 0xc29675d500000000, 0xa79d0cbc00000000, 0x0880870700000000, + 0x6d8bfe6e00000000, 0xa843ef7700000000, 0xcd48961e00000000, + 0x62551da500000000, 0x075e64cc00000000, 0x7d687a0900000000, + 0x1863036000000000, 0xb77e88db00000000, 0xd275f1b200000000, + 0x0214c58a00000000, 0x671fbce300000000, 0xc802375800000000, + 0xad094e3100000000, 0xd73f50f400000000, 0xb234299d00000000, + 0x1d29a22600000000, 0x7822db4f00000000, 0x97b8811400000000, + 0xf2b3f87d00000000, 0x5dae73c600000000, 0x38a50aaf00000000, + 0x4293146a00000000, 0x27986d0300000000, 0x8885e6b800000000, + 0xed8e9fd100000000, 0x3defabe900000000, 0x58e4d28000000000, + 0xf7f9593b00000000, 0x92f2205200000000, 0xe8c43e9700000000, + 0x8dcf47fe00000000, 0x22d2cc4500000000, 0x47d9b52c00000000, + 0x8211a43500000000, 0xe71add5c00000000, 0x480756e700000000, + 0x2d0c2f8e00000000, 0x573a314b00000000, 0x3231482200000000, + 0x9d2cc39900000000, 0xf827baf000000000, 0x28468ec800000000, + 0x4d4df7a100000000, 0xe2507c1a00000000, 0x875b057300000000, + 0xfd6d1bb600000000, 0x986662df00000000, 0x377be96400000000, + 0x5270900d00000000}, + {0x0000000000000000, 0xdcecb13d00000000, 0xb8d9637b00000000, + 0x6435d24600000000, 0x70b3c7f600000000, 0xac5f76cb00000000, + 0xc86aa48d00000000, 0x148615b000000000, 0xa160fe3600000000, + 0x7d8c4f0b00000000, 0x19b99d4d00000000, 0xc5552c7000000000, + 0xd1d339c000000000, 0x0d3f88fd00000000, 0x690a5abb00000000, + 0xb5e6eb8600000000, 0x42c1fc6d00000000, 0x9e2d4d5000000000, + 0xfa189f1600000000, 0x26f42e2b00000000, 0x32723b9b00000000, + 0xee9e8aa600000000, 0x8aab58e000000000, 0x5647e9dd00000000, + 0xe3a1025b00000000, 0x3f4db36600000000, 0x5b78612000000000, + 0x8794d01d00000000, 0x9312c5ad00000000, 0x4ffe749000000000, + 0x2bcba6d600000000, 0xf72717eb00000000, 0x8482f9db00000000, + 0x586e48e600000000, 0x3c5b9aa000000000, 0xe0b72b9d00000000, + 0xf4313e2d00000000, 0x28dd8f1000000000, 0x4ce85d5600000000, + 0x9004ec6b00000000, 0x25e207ed00000000, 0xf90eb6d000000000, + 0x9d3b649600000000, 0x41d7d5ab00000000, 0x5551c01b00000000, + 0x89bd712600000000, 0xed88a36000000000, 0x3164125d00000000, + 0xc64305b600000000, 0x1aafb48b00000000, 0x7e9a66cd00000000, + 0xa276d7f000000000, 0xb6f0c24000000000, 0x6a1c737d00000000, + 0x0e29a13b00000000, 0xd2c5100600000000, 0x6723fb8000000000, + 0xbbcf4abd00000000, 0xdffa98fb00000000, 0x031629c600000000, + 0x17903c7600000000, 0xcb7c8d4b00000000, 0xaf495f0d00000000, + 0x73a5ee3000000000, 0x4903826c00000000, 0x95ef335100000000, + 0xf1dae11700000000, 0x2d36502a00000000, 0x39b0459a00000000, + 0xe55cf4a700000000, 0x816926e100000000, 0x5d8597dc00000000, + 0xe8637c5a00000000, 0x348fcd6700000000, 0x50ba1f2100000000, + 0x8c56ae1c00000000, 0x98d0bbac00000000, 0x443c0a9100000000, + 0x2009d8d700000000, 0xfce569ea00000000, 0x0bc27e0100000000, + 0xd72ecf3c00000000, 0xb31b1d7a00000000, 0x6ff7ac4700000000, + 0x7b71b9f700000000, 0xa79d08ca00000000, 0xc3a8da8c00000000, + 0x1f446bb100000000, 0xaaa2803700000000, 0x764e310a00000000, + 0x127be34c00000000, 0xce97527100000000, 0xda1147c100000000, + 0x06fdf6fc00000000, 0x62c824ba00000000, 0xbe24958700000000, + 0xcd817bb700000000, 0x116dca8a00000000, 0x755818cc00000000, + 0xa9b4a9f100000000, 0xbd32bc4100000000, 0x61de0d7c00000000, + 0x05ebdf3a00000000, 0xd9076e0700000000, 0x6ce1858100000000, + 0xb00d34bc00000000, 0xd438e6fa00000000, 0x08d457c700000000, + 0x1c52427700000000, 0xc0bef34a00000000, 0xa48b210c00000000, + 0x7867903100000000, 0x8f4087da00000000, 0x53ac36e700000000, + 0x3799e4a100000000, 0xeb75559c00000000, 0xfff3402c00000000, + 0x231ff11100000000, 0x472a235700000000, 0x9bc6926a00000000, + 0x2e2079ec00000000, 0xf2ccc8d100000000, 0x96f91a9700000000, + 0x4a15abaa00000000, 0x5e93be1a00000000, 0x827f0f2700000000, + 0xe64add6100000000, 0x3aa66c5c00000000, 0x920604d900000000, + 0x4eeab5e400000000, 0x2adf67a200000000, 0xf633d69f00000000, + 0xe2b5c32f00000000, 0x3e59721200000000, 0x5a6ca05400000000, + 0x8680116900000000, 0x3366faef00000000, 0xef8a4bd200000000, + 0x8bbf999400000000, 0x575328a900000000, 0x43d53d1900000000, + 0x9f398c2400000000, 0xfb0c5e6200000000, 0x27e0ef5f00000000, + 0xd0c7f8b400000000, 0x0c2b498900000000, 0x681e9bcf00000000, + 0xb4f22af200000000, 0xa0743f4200000000, 0x7c988e7f00000000, + 0x18ad5c3900000000, 0xc441ed0400000000, 0x71a7068200000000, + 0xad4bb7bf00000000, 0xc97e65f900000000, 0x1592d4c400000000, + 0x0114c17400000000, 0xddf8704900000000, 0xb9cda20f00000000, + 0x6521133200000000, 0x1684fd0200000000, 0xca684c3f00000000, + 0xae5d9e7900000000, 0x72b12f4400000000, 0x66373af400000000, + 0xbadb8bc900000000, 0xdeee598f00000000, 0x0202e8b200000000, + 0xb7e4033400000000, 0x6b08b20900000000, 0x0f3d604f00000000, + 0xd3d1d17200000000, 0xc757c4c200000000, 0x1bbb75ff00000000, + 0x7f8ea7b900000000, 0xa362168400000000, 0x5445016f00000000, + 0x88a9b05200000000, 0xec9c621400000000, 0x3070d32900000000, + 0x24f6c69900000000, 0xf81a77a400000000, 0x9c2fa5e200000000, + 0x40c314df00000000, 0xf525ff5900000000, 0x29c94e6400000000, + 0x4dfc9c2200000000, 0x91102d1f00000000, 0x859638af00000000, + 0x597a899200000000, 0x3d4f5bd400000000, 0xe1a3eae900000000, + 0xdb0586b500000000, 0x07e9378800000000, 0x63dce5ce00000000, + 0xbf3054f300000000, 0xabb6414300000000, 0x775af07e00000000, + 0x136f223800000000, 0xcf83930500000000, 0x7a65788300000000, + 0xa689c9be00000000, 0xc2bc1bf800000000, 0x1e50aac500000000, + 0x0ad6bf7500000000, 0xd63a0e4800000000, 0xb20fdc0e00000000, + 0x6ee36d3300000000, 0x99c47ad800000000, 0x4528cbe500000000, + 0x211d19a300000000, 0xfdf1a89e00000000, 0xe977bd2e00000000, + 0x359b0c1300000000, 0x51aede5500000000, 0x8d426f6800000000, + 0x38a484ee00000000, 0xe44835d300000000, 0x807de79500000000, + 0x5c9156a800000000, 0x4817431800000000, 0x94fbf22500000000, + 0xf0ce206300000000, 0x2c22915e00000000, 0x5f877f6e00000000, + 0x836bce5300000000, 0xe75e1c1500000000, 0x3bb2ad2800000000, + 0x2f34b89800000000, 0xf3d809a500000000, 0x97eddbe300000000, + 0x4b016ade00000000, 0xfee7815800000000, 0x220b306500000000, + 0x463ee22300000000, 0x9ad2531e00000000, 0x8e5446ae00000000, + 0x52b8f79300000000, 0x368d25d500000000, 0xea6194e800000000, + 0x1d46830300000000, 0xc1aa323e00000000, 0xa59fe07800000000, + 0x7973514500000000, 0x6df544f500000000, 0xb119f5c800000000, + 0xd52c278e00000000, 0x09c096b300000000, 0xbc267d3500000000, + 0x60cacc0800000000, 0x04ff1e4e00000000, 0xd813af7300000000, + 0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000, + 0xa8a0688500000000}}; + +#else /* W == 4 */ + +static const uint32_t crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}}; + +static const z_word_t crc_braid_big_table[][256] = { + {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912, + 0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba, + 0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3, + 0x2e8f154c, 0xec12e44b, 0x72913ed4, 0x911320af, 0x0f90fa30, + 0x57161d59, 0xc995c7c6, 0x2a17d9bd, 0xb4940322, 0x9a1b166e, + 0x0498ccf1, 0xe71ad28a, 0x79990815, 0x211fef7c, 0xbf9c35e3, + 0x5c1e2b98, 0xc29df107, 0xd825c897, 0x46a61208, 0xa5240c73, + 0x3ba7d6ec, 0x63213185, 0xfda2eb1a, 0x1e20f561, 0x80a32ffe, + 0xae2c3ab2, 0x30afe02d, 0xd32dfe56, 0x4dae24c9, 0x1528c3a0, + 0x8bab193f, 0x68290744, 0xf6aadddb, 0x34372cdc, 0xaab4f643, + 0x4936e838, 0xd7b532a7, 0x8f33d5ce, 0x11b00f51, 0xf232112a, + 0x6cb1cbb5, 0x423edef9, 0xdcbd0466, 0x3f3f1a1d, 0xa1bcc082, + 0xf93a27eb, 0x67b9fd74, 0x843be30f, 0x1ab83990, 0xf14de1f4, + 0x6fce3b6b, 0x8c4c2510, 0x12cfff8f, 0x4a4918e6, 0xd4cac279, + 0x3748dc02, 0xa9cb069d, 0x874413d1, 0x19c7c94e, 0xfa45d735, + 0x64c60daa, 0x3c40eac3, 0xa2c3305c, 0x41412e27, 0xdfc2f4b8, + 0x1d5f05bf, 0x83dcdf20, 0x605ec15b, 0xfedd1bc4, 0xa65bfcad, + 0x38d82632, 0xdb5a3849, 0x45d9e2d6, 0x6b56f79a, 0xf5d52d05, + 0x1657337e, 0x88d4e9e1, 0xd0520e88, 0x4ed1d417, 0xad53ca6c, + 0x33d010f3, 0x29682963, 0xb7ebf3fc, 0x5469ed87, 0xcaea3718, + 0x926cd071, 0x0cef0aee, 0xef6d1495, 0x71eece0a, 0x5f61db46, + 0xc1e201d9, 0x22601fa2, 0xbce3c53d, 0xe4652254, 0x7ae6f8cb, + 0x9964e6b0, 0x07e73c2f, 0xc57acd28, 0x5bf917b7, 0xb87b09cc, + 0x26f8d353, 0x7e7e343a, 0xe0fdeea5, 0x037ff0de, 0x9dfc2a41, + 0xb3733f0d, 0x2df0e592, 0xce72fbe9, 0x50f12176, 0x0877c61f, + 0x96f41c80, 0x757602fb, 0xebf5d864, 0xa39db332, 0x3d1e69ad, + 0xde9c77d6, 0x401fad49, 0x18994a20, 0x861a90bf, 0x65988ec4, + 0xfb1b545b, 0xd5944117, 0x4b179b88, 0xa89585f3, 0x36165f6c, + 0x6e90b805, 0xf013629a, 0x13917ce1, 0x8d12a67e, 0x4f8f5779, + 0xd10c8de6, 0x328e939d, 0xac0d4902, 0xf48bae6b, 0x6a0874f4, + 0x898a6a8f, 0x1709b010, 0x3986a55c, 0xa7057fc3, 0x448761b8, + 0xda04bb27, 0x82825c4e, 0x1c0186d1, 0xff8398aa, 0x61004235, + 0x7bb87ba5, 0xe53ba13a, 0x06b9bf41, 0x983a65de, 0xc0bc82b7, + 0x5e3f5828, 0xbdbd4653, 0x233e9ccc, 0x0db18980, 0x9332531f, + 0x70b04d64, 0xee3397fb, 0xb6b57092, 0x2836aa0d, 0xcbb4b476, + 0x55376ee9, 0x97aa9fee, 0x09294571, 0xeaab5b0a, 0x74288195, + 0x2cae66fc, 0xb22dbc63, 0x51afa218, 0xcf2c7887, 0xe1a36dcb, + 0x7f20b754, 0x9ca2a92f, 0x022173b0, 0x5aa794d9, 0xc4244e46, + 0x27a6503d, 0xb9258aa2, 0x52d052c6, 0xcc538859, 0x2fd19622, + 0xb1524cbd, 0xe9d4abd4, 0x7757714b, 0x94d56f30, 0x0a56b5af, + 0x24d9a0e3, 0xba5a7a7c, 0x59d86407, 0xc75bbe98, 0x9fdd59f1, + 0x015e836e, 0xe2dc9d15, 0x7c5f478a, 0xbec2b68d, 0x20416c12, + 0xc3c37269, 0x5d40a8f6, 0x05c64f9f, 0x9b459500, 0x78c78b7b, + 0xe64451e4, 0xc8cb44a8, 0x56489e37, 0xb5ca804c, 0x2b495ad3, + 0x73cfbdba, 0xed4c6725, 0x0ece795e, 0x904da3c1, 0x8af59a51, + 0x147640ce, 0xf7f45eb5, 0x6977842a, 0x31f16343, 0xaf72b9dc, + 0x4cf0a7a7, 0xd2737d38, 0xfcfc6874, 0x627fb2eb, 0x81fdac90, + 0x1f7e760f, 0x47f89166, 0xd97b4bf9, 0x3af95582, 0xa47a8f1d, + 0x66e77e1a, 0xf864a485, 0x1be6bafe, 0x85656061, 0xdde38708, + 0x43605d97, 0xa0e243ec, 0x3e619973, 0x10ee8c3f, 0x8e6d56a0, + 0x6def48db, 0xf36c9244, 0xabea752d, 0x3569afb2, 0xd6ebb1c9, + 0x48686b56}, + {0x00000000, 0xc0642817, 0x80c9502e, 0x40ad7839, 0x0093a15c, + 0xc0f7894b, 0x805af172, 0x403ed965, 0x002643b9, 0xc0426bae, + 0x80ef1397, 0x408b3b80, 0x00b5e2e5, 0xc0d1caf2, 0x807cb2cb, + 0x40189adc, 0x414af7a9, 0x812edfbe, 0xc183a787, 0x01e78f90, + 0x41d956f5, 0x81bd7ee2, 0xc11006db, 0x01742ecc, 0x416cb410, + 0x81089c07, 0xc1a5e43e, 0x01c1cc29, 0x41ff154c, 0x819b3d5b, + 0xc1364562, 0x01526d75, 0xc3929f88, 0x03f6b79f, 0x435bcfa6, + 0x833fe7b1, 0xc3013ed4, 0x036516c3, 0x43c86efa, 0x83ac46ed, + 0xc3b4dc31, 0x03d0f426, 0x437d8c1f, 0x8319a408, 0xc3277d6d, + 0x0343557a, 0x43ee2d43, 0x838a0554, 0x82d86821, 0x42bc4036, + 0x0211380f, 0xc2751018, 0x824bc97d, 0x422fe16a, 0x02829953, + 0xc2e6b144, 0x82fe2b98, 0x429a038f, 0x02377bb6, 0xc25353a1, + 0x826d8ac4, 0x4209a2d3, 0x02a4daea, 0xc2c0f2fd, 0xc7234eca, + 0x074766dd, 0x47ea1ee4, 0x878e36f3, 0xc7b0ef96, 0x07d4c781, + 0x4779bfb8, 0x871d97af, 0xc7050d73, 0x07612564, 0x47cc5d5d, + 0x87a8754a, 0xc796ac2f, 0x07f28438, 0x475ffc01, 0x873bd416, + 0x8669b963, 0x460d9174, 0x06a0e94d, 0xc6c4c15a, 0x86fa183f, + 0x469e3028, 0x06334811, 0xc6576006, 0x864ffada, 0x462bd2cd, + 0x0686aaf4, 0xc6e282e3, 0x86dc5b86, 0x46b87391, 0x06150ba8, + 0xc67123bf, 0x04b1d142, 0xc4d5f955, 0x8478816c, 0x441ca97b, + 0x0422701e, 0xc4465809, 0x84eb2030, 0x448f0827, 0x049792fb, + 0xc4f3baec, 0x845ec2d5, 0x443aeac2, 0x040433a7, 0xc4601bb0, + 0x84cd6389, 0x44a94b9e, 0x45fb26eb, 0x859f0efc, 0xc53276c5, + 0x05565ed2, 0x456887b7, 0x850cafa0, 0xc5a1d799, 0x05c5ff8e, + 0x45dd6552, 0x85b94d45, 0xc514357c, 0x05701d6b, 0x454ec40e, + 0x852aec19, 0xc5879420, 0x05e3bc37, 0xcf41ed4f, 0x0f25c558, + 0x4f88bd61, 0x8fec9576, 0xcfd24c13, 0x0fb66404, 0x4f1b1c3d, + 0x8f7f342a, 0xcf67aef6, 0x0f0386e1, 0x4faefed8, 0x8fcad6cf, + 0xcff40faa, 0x0f9027bd, 0x4f3d5f84, 0x8f597793, 0x8e0b1ae6, + 0x4e6f32f1, 0x0ec24ac8, 0xcea662df, 0x8e98bbba, 0x4efc93ad, + 0x0e51eb94, 0xce35c383, 0x8e2d595f, 0x4e497148, 0x0ee40971, + 0xce802166, 0x8ebef803, 0x4edad014, 0x0e77a82d, 0xce13803a, + 0x0cd372c7, 0xccb75ad0, 0x8c1a22e9, 0x4c7e0afe, 0x0c40d39b, + 0xcc24fb8c, 0x8c8983b5, 0x4cedaba2, 0x0cf5317e, 0xcc911969, + 0x8c3c6150, 0x4c584947, 0x0c669022, 0xcc02b835, 0x8cafc00c, + 0x4ccbe81b, 0x4d99856e, 0x8dfdad79, 0xcd50d540, 0x0d34fd57, + 0x4d0a2432, 0x8d6e0c25, 0xcdc3741c, 0x0da75c0b, 0x4dbfc6d7, + 0x8ddbeec0, 0xcd7696f9, 0x0d12beee, 0x4d2c678b, 0x8d484f9c, + 0xcde537a5, 0x0d811fb2, 0x0862a385, 0xc8068b92, 0x88abf3ab, + 0x48cfdbbc, 0x08f102d9, 0xc8952ace, 0x883852f7, 0x485c7ae0, + 0x0844e03c, 0xc820c82b, 0x888db012, 0x48e99805, 0x08d74160, + 0xc8b36977, 0x881e114e, 0x487a3959, 0x4928542c, 0x894c7c3b, + 0xc9e10402, 0x09852c15, 0x49bbf570, 0x89dfdd67, 0xc972a55e, + 0x09168d49, 0x490e1795, 0x896a3f82, 0xc9c747bb, 0x09a36fac, + 0x499db6c9, 0x89f99ede, 0xc954e6e7, 0x0930cef0, 0xcbf03c0d, + 0x0b94141a, 0x4b396c23, 0x8b5d4434, 0xcb639d51, 0x0b07b546, + 0x4baacd7f, 0x8bcee568, 0xcbd67fb4, 0x0bb257a3, 0x4b1f2f9a, + 0x8b7b078d, 0xcb45dee8, 0x0b21f6ff, 0x4b8c8ec6, 0x8be8a6d1, + 0x8abacba4, 0x4adee3b3, 0x0a739b8a, 0xca17b39d, 0x8a296af8, + 0x4a4d42ef, 0x0ae03ad6, 0xca8412c1, 0x8a9c881d, 0x4af8a00a, + 0x0a55d833, 0xca31f024, 0x8a0f2941, 0x4a6b0156, 0x0ac6796f, + 0xcaa25178}, + {0x00000000, 0xd4ea739b, 0xe9d396ed, 0x3d39e576, 0x93a15c00, + 0x474b2f9b, 0x7a72caed, 0xae98b976, 0x2643b900, 0xf2a9ca9b, + 0xcf902fed, 0x1b7a5c76, 0xb5e2e500, 0x6108969b, 0x5c3173ed, + 0x88db0076, 0x4c867201, 0x986c019a, 0xa555e4ec, 0x71bf9777, + 0xdf272e01, 0x0bcd5d9a, 0x36f4b8ec, 0xe21ecb77, 0x6ac5cb01, + 0xbe2fb89a, 0x83165dec, 0x57fc2e77, 0xf9649701, 0x2d8ee49a, + 0x10b701ec, 0xc45d7277, 0x980ce502, 0x4ce69699, 0x71df73ef, + 0xa5350074, 0x0badb902, 0xdf47ca99, 0xe27e2fef, 0x36945c74, + 0xbe4f5c02, 0x6aa52f99, 0x579ccaef, 0x8376b974, 0x2dee0002, + 0xf9047399, 0xc43d96ef, 0x10d7e574, 0xd48a9703, 0x0060e498, + 0x3d5901ee, 0xe9b37275, 0x472bcb03, 0x93c1b898, 0xaef85dee, + 0x7a122e75, 0xf2c92e03, 0x26235d98, 0x1b1ab8ee, 0xcff0cb75, + 0x61687203, 0xb5820198, 0x88bbe4ee, 0x5c519775, 0x3019ca05, + 0xe4f3b99e, 0xd9ca5ce8, 0x0d202f73, 0xa3b89605, 0x7752e59e, + 0x4a6b00e8, 0x9e817373, 0x165a7305, 0xc2b0009e, 0xff89e5e8, + 0x2b639673, 0x85fb2f05, 0x51115c9e, 0x6c28b9e8, 0xb8c2ca73, + 0x7c9fb804, 0xa875cb9f, 0x954c2ee9, 0x41a65d72, 0xef3ee404, + 0x3bd4979f, 0x06ed72e9, 0xd2070172, 0x5adc0104, 0x8e36729f, + 0xb30f97e9, 0x67e5e472, 0xc97d5d04, 0x1d972e9f, 0x20aecbe9, + 0xf444b872, 0xa8152f07, 0x7cff5c9c, 0x41c6b9ea, 0x952cca71, + 0x3bb47307, 0xef5e009c, 0xd267e5ea, 0x068d9671, 0x8e569607, + 0x5abce59c, 0x678500ea, 0xb36f7371, 0x1df7ca07, 0xc91db99c, + 0xf4245cea, 0x20ce2f71, 0xe4935d06, 0x30792e9d, 0x0d40cbeb, + 0xd9aab870, 0x77320106, 0xa3d8729d, 0x9ee197eb, 0x4a0be470, + 0xc2d0e406, 0x163a979d, 0x2b0372eb, 0xffe90170, 0x5171b806, + 0x859bcb9d, 0xb8a22eeb, 0x6c485d70, 0x6032940b, 0xb4d8e790, + 0x89e102e6, 0x5d0b717d, 0xf393c80b, 0x2779bb90, 0x1a405ee6, + 0xceaa2d7d, 0x46712d0b, 0x929b5e90, 0xafa2bbe6, 0x7b48c87d, + 0xd5d0710b, 0x013a0290, 0x3c03e7e6, 0xe8e9947d, 0x2cb4e60a, + 0xf85e9591, 0xc56770e7, 0x118d037c, 0xbf15ba0a, 0x6bffc991, + 0x56c62ce7, 0x822c5f7c, 0x0af75f0a, 0xde1d2c91, 0xe324c9e7, + 0x37ceba7c, 0x9956030a, 0x4dbc7091, 0x708595e7, 0xa46fe67c, + 0xf83e7109, 0x2cd40292, 0x11ede7e4, 0xc507947f, 0x6b9f2d09, + 0xbf755e92, 0x824cbbe4, 0x56a6c87f, 0xde7dc809, 0x0a97bb92, + 0x37ae5ee4, 0xe3442d7f, 0x4ddc9409, 0x9936e792, 0xa40f02e4, + 0x70e5717f, 0xb4b80308, 0x60527093, 0x5d6b95e5, 0x8981e67e, + 0x27195f08, 0xf3f32c93, 0xcecac9e5, 0x1a20ba7e, 0x92fbba08, + 0x4611c993, 0x7b282ce5, 0xafc25f7e, 0x015ae608, 0xd5b09593, + 0xe88970e5, 0x3c63037e, 0x502b5e0e, 0x84c12d95, 0xb9f8c8e3, + 0x6d12bb78, 0xc38a020e, 0x17607195, 0x2a5994e3, 0xfeb3e778, + 0x7668e70e, 0xa2829495, 0x9fbb71e3, 0x4b510278, 0xe5c9bb0e, + 0x3123c895, 0x0c1a2de3, 0xd8f05e78, 0x1cad2c0f, 0xc8475f94, + 0xf57ebae2, 0x2194c979, 0x8f0c700f, 0x5be60394, 0x66dfe6e2, + 0xb2359579, 0x3aee950f, 0xee04e694, 0xd33d03e2, 0x07d77079, + 0xa94fc90f, 0x7da5ba94, 0x409c5fe2, 0x94762c79, 0xc827bb0c, + 0x1ccdc897, 0x21f42de1, 0xf51e5e7a, 0x5b86e70c, 0x8f6c9497, + 0xb25571e1, 0x66bf027a, 0xee64020c, 0x3a8e7197, 0x07b794e1, + 0xd35de77a, 0x7dc55e0c, 0xa92f2d97, 0x9416c8e1, 0x40fcbb7a, + 0x84a1c90d, 0x504bba96, 0x6d725fe0, 0xb9982c7b, 0x1700950d, + 0xc3eae696, 0xfed303e0, 0x2a39707b, 0xa2e2700d, 0x76080396, + 0x4b31e6e0, 0x9fdb957b, 0x31432c0d, 0xe5a95f96, 0xd890bae0, + 0x0c7ac97b}, + {0x00000000, 0x27652581, 0x0fcc3bd9, 0x28a91e58, 0x5f9e0669, + 0x78fb23e8, 0x50523db0, 0x77371831, 0xbe3c0dd2, 0x99592853, + 0xb1f0360b, 0x9695138a, 0xe1a20bbb, 0xc6c72e3a, 0xee6e3062, + 0xc90b15e3, 0x3d7f6b7f, 0x1a1a4efe, 0x32b350a6, 0x15d67527, + 0x62e16d16, 0x45844897, 0x6d2d56cf, 0x4a48734e, 0x834366ad, + 0xa426432c, 0x8c8f5d74, 0xabea78f5, 0xdcdd60c4, 0xfbb84545, + 0xd3115b1d, 0xf4747e9c, 0x7afed6fe, 0x5d9bf37f, 0x7532ed27, + 0x5257c8a6, 0x2560d097, 0x0205f516, 0x2aaceb4e, 0x0dc9cecf, + 0xc4c2db2c, 0xe3a7fead, 0xcb0ee0f5, 0xec6bc574, 0x9b5cdd45, + 0xbc39f8c4, 0x9490e69c, 0xb3f5c31d, 0x4781bd81, 0x60e49800, + 0x484d8658, 0x6f28a3d9, 0x181fbbe8, 0x3f7a9e69, 0x17d38031, + 0x30b6a5b0, 0xf9bdb053, 0xded895d2, 0xf6718b8a, 0xd114ae0b, + 0xa623b63a, 0x814693bb, 0xa9ef8de3, 0x8e8aa862, 0xb5fadc26, + 0x929ff9a7, 0xba36e7ff, 0x9d53c27e, 0xea64da4f, 0xcd01ffce, + 0xe5a8e196, 0xc2cdc417, 0x0bc6d1f4, 0x2ca3f475, 0x040aea2d, + 0x236fcfac, 0x5458d79d, 0x733df21c, 0x5b94ec44, 0x7cf1c9c5, + 0x8885b759, 0xafe092d8, 0x87498c80, 0xa02ca901, 0xd71bb130, + 0xf07e94b1, 0xd8d78ae9, 0xffb2af68, 0x36b9ba8b, 0x11dc9f0a, + 0x39758152, 0x1e10a4d3, 0x6927bce2, 0x4e429963, 0x66eb873b, + 0x418ea2ba, 0xcf040ad8, 0xe8612f59, 0xc0c83101, 0xe7ad1480, + 0x909a0cb1, 0xb7ff2930, 0x9f563768, 0xb83312e9, 0x7138070a, + 0x565d228b, 0x7ef43cd3, 0x59911952, 0x2ea60163, 0x09c324e2, + 0x216a3aba, 0x060f1f3b, 0xf27b61a7, 0xd51e4426, 0xfdb75a7e, + 0xdad27fff, 0xade567ce, 0x8a80424f, 0xa2295c17, 0x854c7996, + 0x4c476c75, 0x6b2249f4, 0x438b57ac, 0x64ee722d, 0x13d96a1c, + 0x34bc4f9d, 0x1c1551c5, 0x3b707444, 0x6af5b94d, 0x4d909ccc, + 0x65398294, 0x425ca715, 0x356bbf24, 0x120e9aa5, 0x3aa784fd, + 0x1dc2a17c, 0xd4c9b49f, 0xf3ac911e, 0xdb058f46, 0xfc60aac7, + 0x8b57b2f6, 0xac329777, 0x849b892f, 0xa3feacae, 0x578ad232, + 0x70eff7b3, 0x5846e9eb, 0x7f23cc6a, 0x0814d45b, 0x2f71f1da, + 0x07d8ef82, 0x20bdca03, 0xe9b6dfe0, 0xced3fa61, 0xe67ae439, + 0xc11fc1b8, 0xb628d989, 0x914dfc08, 0xb9e4e250, 0x9e81c7d1, + 0x100b6fb3, 0x376e4a32, 0x1fc7546a, 0x38a271eb, 0x4f9569da, + 0x68f04c5b, 0x40595203, 0x673c7782, 0xae376261, 0x895247e0, + 0xa1fb59b8, 0x869e7c39, 0xf1a96408, 0xd6cc4189, 0xfe655fd1, + 0xd9007a50, 0x2d7404cc, 0x0a11214d, 0x22b83f15, 0x05dd1a94, + 0x72ea02a5, 0x558f2724, 0x7d26397c, 0x5a431cfd, 0x9348091e, + 0xb42d2c9f, 0x9c8432c7, 0xbbe11746, 0xccd60f77, 0xebb32af6, + 0xc31a34ae, 0xe47f112f, 0xdf0f656b, 0xf86a40ea, 0xd0c35eb2, + 0xf7a67b33, 0x80916302, 0xa7f44683, 0x8f5d58db, 0xa8387d5a, + 0x613368b9, 0x46564d38, 0x6eff5360, 0x499a76e1, 0x3ead6ed0, + 0x19c84b51, 0x31615509, 0x16047088, 0xe2700e14, 0xc5152b95, + 0xedbc35cd, 0xcad9104c, 0xbdee087d, 0x9a8b2dfc, 0xb22233a4, + 0x95471625, 0x5c4c03c6, 0x7b292647, 0x5380381f, 0x74e51d9e, + 0x03d205af, 0x24b7202e, 0x0c1e3e76, 0x2b7b1bf7, 0xa5f1b395, + 0x82949614, 0xaa3d884c, 0x8d58adcd, 0xfa6fb5fc, 0xdd0a907d, + 0xf5a38e25, 0xd2c6aba4, 0x1bcdbe47, 0x3ca89bc6, 0x1401859e, + 0x3364a01f, 0x4453b82e, 0x63369daf, 0x4b9f83f7, 0x6cfaa676, + 0x988ed8ea, 0xbfebfd6b, 0x9742e333, 0xb027c6b2, 0xc710de83, + 0xe075fb02, 0xc8dce55a, 0xefb9c0db, 0x26b2d538, 0x01d7f0b9, + 0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888, + 0x5185cd09}}; + +#endif /* W */ + +#endif /* N == 6 */ + +static const uint32_t x2n_table[] = { + 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, + 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, + 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, + 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, + 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, + 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, + 0xc40ba6d0, 0xc4e22c3c}; + +#endif /* CRC32_BRAID_TBL_H_ */ diff --git a/deflate.c b/deflate.c new file mode 100644 index 0000000000..630cce2553 --- /dev/null +++ b/deflate.c @@ -0,0 +1,1513 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in https://tools.ietf.org/html/rfc1951 + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +#include "zbuild.h" +#include "deflate.h" +#include "deflate_p.h" +#include "functable.h" + +/* Avoid conflicts with zlib.h macros */ +#ifdef ZLIB_COMPAT +# undef deflateInit +# undef deflateInit2 +#endif + +const char PREFIX(deflate_copyright)[] = " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Architecture-specific hooks. + */ +#ifdef S390_DFLTCC_DEFLATE +# include "arch/s390/dfltcc_deflate.h" +/* DFLTCC instructions require window to be page-aligned */ +# define PAD_WINDOW PAD_4096 +# define WINDOW_PAD_SIZE 4096 +# define HINT_ALIGNED_WINDOW HINT_ALIGNED_4096 +#else +# define PAD_WINDOW PAD_64 +# define WINDOW_PAD_SIZE 64 +# define HINT_ALIGNED_WINDOW HINT_ALIGNED_64 +/* Adjust the window size for the arch-specific deflate code. */ +# define DEFLATE_ADJUST_WINDOW_SIZE(n) (n) +/* Invoked at the beginning of deflateSetDictionary(). Useful for checking arch-specific window data. */ +# define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) +/* Invoked at the beginning of deflateGetDictionary(). Useful for adjusting arch-specific window data. */ +# define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) +/* Invoked at the end of deflateResetKeep(). Useful for initializing arch-specific extension blocks. */ +# define DEFLATE_RESET_KEEP_HOOK(strm) do {} while (0) +/* Invoked at the beginning of deflateParams(). Useful for updating arch-specific compression parameters. */ +# define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) do {} while (0) +/* Returns whether the last deflate(flush) operation did everything it's supposed to do. */ +# define DEFLATE_DONE(strm, flush) 1 +/* Adjusts the upper bound on compressed data length based on compression parameters and uncompressed data length. + * Useful when arch-specific deflation code behaves differently than regular zlib-ng algorithms. */ +# define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen) do {} while (0) +/* Returns whether an optimistic upper bound on compressed data length should *not* be used. + * Useful when arch-specific deflation code behaves differently than regular zlib-ng algorithms. */ +# define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) 0 +/* Invoked for each deflate() call. Useful for plugging arch-specific deflation code. */ +# define DEFLATE_HOOK(strm, flush, bstate) 0 +/* Returns whether zlib-ng should compute a checksum. Set to 0 if arch-specific deflation code already does that. */ +# define DEFLATE_NEED_CHECKSUM(strm) 1 +/* Returns whether reproducibility parameter can be set to a given value. */ +# define DEFLATE_CAN_SET_REPRODUCIBLE(strm, reproducible) 1 +#endif + +/* =========================================================================== + * Function prototypes. + */ +static int deflateStateCheck (PREFIX3(stream) *strm); +Z_INTERNAL block_state deflate_stored(deflate_state *s, int flush); +Z_INTERNAL block_state deflate_fast (deflate_state *s, int flush); +Z_INTERNAL block_state deflate_quick (deflate_state *s, int flush); +#ifndef NO_MEDIUM_STRATEGY +Z_INTERNAL block_state deflate_medium(deflate_state *s, int flush); +#endif +Z_INTERNAL block_state deflate_slow (deflate_state *s, int flush); +Z_INTERNAL block_state deflate_rle (deflate_state *s, int flush); +Z_INTERNAL block_state deflate_huff (deflate_state *s, int flush); +static void lm_set_level (deflate_state *s, int level); +static void lm_init (deflate_state *s); +Z_INTERNAL unsigned read_buf (PREFIX3(stream) *strm, unsigned char *buf, unsigned size); + +/* =========================================================================== + * Local data + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + uint16_t good_length; /* reduce lazy search above this match length */ + uint16_t max_lazy; /* do not perform lazy search above this match length */ + uint16_t nice_length; /* quit search above this match length */ + uint16_t max_chain; + compress_func func; +} config; + +static const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ + +#ifdef NO_QUICK_STRATEGY +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +#else +/* 1 */ {0, 0, 0, 0, deflate_quick}, +/* 2 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +#endif + +#ifdef NO_MEDIUM_STRATEGY +/* 3 */ {4, 6, 32, 32, deflate_fast}, +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +#else +/* 3 */ {4, 6, 16, 6, deflate_medium}, +/* 4 */ {4, 12, 32, 24, deflate_medium}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_medium}, +/* 6 */ {8, 16, 128, 128, deflate_medium}, +#endif + +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ + +/* Note: the deflate() code requires max_lazy >= STD_MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ +#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) + + +/* =========================================================================== + * Initialize the hash table. prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) do { \ + memset((unsigned char *)s->head, 0, HASH_SIZE * sizeof(*s->head)); \ + } while (0) + + +#ifdef DEF_ALLOC_DEBUG +# include +# define LOGSZ(name,size) fprintf(stderr, "%s is %d bytes\n", name, size) +# define LOGSZP(name,size,loc,pad) fprintf(stderr, "%s is %d bytes, offset %d, padded %d\n", name, size, loc, pad) +# define LOGSZPL(name,size,loc,pad) fprintf(stderr, "%s is %d bytes, offset %ld, padded %d\n", name, size, loc, pad) +#else +# define LOGSZ(name,size) +# define LOGSZP(name,size,loc,pad) +# define LOGSZPL(name,size,loc,pad) +#endif + +/* =========================================================================== + * Allocate a big buffer and divide it up into the various buffers deflate needs. + * Handles alignment of allocated buffer and alignment of individual buffers. + */ +Z_INTERNAL deflate_allocs* alloc_deflate(PREFIX3(stream) *strm, int windowBits, int lit_bufsize) { + int curr_size = 0; + + /* Define sizes */ + int window_size = DEFLATE_ADJUST_WINDOW_SIZE((1 << windowBits) * 2); + int prev_size = (1 << windowBits) * (int)sizeof(Pos); + int head_size = HASH_SIZE * sizeof(Pos); + int pending_size = lit_bufsize * LIT_BUFS; + int state_size = sizeof(deflate_state); + int alloc_size = sizeof(deflate_allocs); + + /* Calculate relative buffer positions and paddings */ + LOGSZP("window", window_size, PAD_WINDOW(curr_size), PADSZ(curr_size,WINDOW_PAD_SIZE)); + int window_pos = PAD_WINDOW(curr_size); + curr_size = window_pos + window_size; + + LOGSZP("prev", prev_size, PAD_64(curr_size), PADSZ(curr_size,64)); + int prev_pos = PAD_64(curr_size); + curr_size = prev_pos + prev_size; + + LOGSZP("head", head_size, PAD_64(curr_size), PADSZ(curr_size,64)); + int head_pos = PAD_64(curr_size); + curr_size = head_pos + head_size; + + LOGSZP("pending", pending_size, PAD_64(curr_size), PADSZ(curr_size,64)); + int pending_pos = PAD_64(curr_size); + curr_size = pending_pos + pending_size; + + LOGSZP("state", state_size, PAD_64(curr_size), PADSZ(curr_size,64)); + int state_pos = PAD_64(curr_size); + curr_size = state_pos + state_size; + + LOGSZP("alloc", alloc_size, PAD_16(curr_size), PADSZ(curr_size,16)); + int alloc_pos = PAD_16(curr_size); + curr_size = alloc_pos + alloc_size; + + /* Add 64-1 or 4096-1 to allow window alignment, and round size of buffer up to multiple of 64 */ + int total_size = PAD_64(curr_size + (WINDOW_PAD_SIZE - 1)); + + /* Allocate buffer, align to 64-byte cacheline, and zerofill the resulting buffer */ + char *original_buf = (char *)strm->zalloc(strm->opaque, 1, total_size); + if (original_buf == NULL) + return NULL; + + char *buff = (char *)HINT_ALIGNED_WINDOW((char *)PAD_WINDOW(original_buf)); + LOGSZPL("Buffer alloc", total_size, PADSZ((uintptr_t)original_buf,WINDOW_PAD_SIZE), PADSZ(curr_size,WINDOW_PAD_SIZE)); + + /* Initialize alloc_bufs */ + deflate_allocs *alloc_bufs = (struct deflate_allocs_s *)(buff + alloc_pos); + alloc_bufs->buf_start = original_buf; + alloc_bufs->zfree = strm->zfree; + + /* Assign buffers */ + alloc_bufs->window = (unsigned char *)HINT_ALIGNED_WINDOW(buff + window_pos); + alloc_bufs->prev = (Pos *)HINT_ALIGNED_64(buff + prev_pos); + alloc_bufs->head = (Pos *)HINT_ALIGNED_64(buff + head_pos); + alloc_bufs->pending_buf = (unsigned char *)HINT_ALIGNED_64(buff + pending_pos); + alloc_bufs->state = (deflate_state *)HINT_ALIGNED_16(buff + state_pos); + + memset((char *)alloc_bufs->prev, 0, prev_size); + + return alloc_bufs; +} + +/* =========================================================================== + * Free all allocated deflate buffers + */ +static inline void free_deflate(PREFIX3(stream) *strm) { + deflate_state *state = (deflate_state *)strm->state; + + if (state->alloc_bufs != NULL) { + deflate_allocs *alloc_bufs = state->alloc_bufs; + alloc_bufs->zfree(strm->opaque, alloc_bufs->buf_start); + strm->state = NULL; + } +} + +/* =========================================================================== + * Initialize deflate state and buffers. + * This function is hidden in ZLIB_COMPAT builds. + */ +int32_t ZNG_CONDEXPORT PREFIX(deflateInit2)(PREFIX3(stream) *strm, int32_t level, int32_t method, int32_t windowBits, + int32_t memLevel, int32_t strategy) { + /* Todo: ignore strm->next_in if we use it as window */ + deflate_state *s; + int wrap = 1; + + /* Initialize functable */ + FUNCTABLE_INIT; + + if (strm == NULL) + return Z_STREAM_ERROR; + + strm->msg = NULL; + if (strm->zalloc == NULL) { + strm->zalloc = PREFIX(zcalloc); + strm->opaque = NULL; + } + if (strm->zfree == NULL) + strm->zfree = PREFIX(zcfree); + + if (level == Z_DEFAULT_COMPRESSION) + level = 6; + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + if (windowBits < -MAX_WBITS) + return Z_STREAM_ERROR; + windowBits = -windowBits; +#ifdef GZIP + } else if (windowBits > MAX_WBITS) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; +#endif + } + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < MIN_WBITS || + windowBits > MAX_WBITS || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED || + (windowBits == 8 && wrap != 1)) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) + windowBits = 9; /* until 256-byte window bug fixed */ + + /* Allocate buffers */ + int lit_bufsize = 1 << (memLevel + 6); + deflate_allocs *alloc_bufs = alloc_deflate(strm, windowBits, lit_bufsize); + if (alloc_bufs == NULL) + return Z_MEM_ERROR; + + s = alloc_bufs->state; + s->alloc_bufs = alloc_bufs; + s->window = alloc_bufs->window; + s->prev = alloc_bufs->prev; + s->head = alloc_bufs->head; + s->pending_buf = alloc_bufs->pending_buf; + + strm->state = (struct internal_state *)s; + s->strm = strm; + s->status = INIT_STATE; /* to pass state test in deflateReset() */ + + s->wrap = wrap; + s->gzhead = NULL; + s->w_bits = (unsigned int)windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->high_water = 0; /* nothing written to s->window yet */ + + s->lit_bufsize = lit_bufsize; /* 16K elements by default */ + + /* We overlay pending_buf and sym_buf. This works since the average size + * for length/distance pairs over any compressed block is assured to be 31 + * bits or less. + * + * Analysis: The longest fixed codes are a length code of 8 bits plus 5 + * extra bits, for lengths 131 to 257. The longest fixed distance codes are + * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest + * possible fixed-codes length/distance pair is then 31 bits total. + * + * sym_buf starts one-fourth of the way into pending_buf. So there are + * three bytes in sym_buf for every four bytes in pending_buf. Each symbol + * in sym_buf is three bytes -- two for the distance and one for the + * literal/length. As each symbol is consumed, the pointer to the next + * sym_buf value to read moves forward three bytes. From that symbol, up to + * 31 bits are written to pending_buf. The closest the written pending_buf + * bits gets to the next sym_buf symbol to read is just before the last + * code is written. At that time, 31*(n-2) bits have been written, just + * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1 + * symbols are written.) The closest the writing gets to what is unread is + * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and + * can range from 128 to 32768. + * + * Therefore, at a minimum, there are 142 bits of space between what is + * written and what is read in the overlain buffers, so the symbols cannot + * be overwritten by the compressed data. That space is actually 139 bits, + * due to the three-bit fixed-code block header. + * + * That covers the case where either Z_FIXED is specified, forcing fixed + * codes, or when the use of fixed codes is chosen, because that choice + * results in a smaller compressed block than dynamic codes. That latter + * condition then assures that the above analysis also covers all dynamic + * blocks. A dynamic-code block will only be chosen to be emitted if it has + * fewer bits than a fixed-code block would for the same set of symbols. + * Therefore its average symbol length is assured to be less than 31. So + * the compressed data for a dynamic block also cannot overwrite the + * symbols from which it is being constructed. + */ + + s->pending_buf_size = s->lit_bufsize * 4; + + if (s->window == NULL || s->prev == NULL || s->head == NULL || s->pending_buf == NULL) { + s->status = FINISH_STATE; + strm->msg = ERR_MSG(Z_MEM_ERROR); + PREFIX(deflateEnd)(strm); + return Z_MEM_ERROR; + } + +#ifdef LIT_MEM + s->d_buf = (uint16_t *)(s->pending_buf + (s->lit_bufsize << 1)); + s->l_buf = s->pending_buf + (s->lit_bufsize << 2); + s->sym_end = s->lit_bufsize - 1; +#else + s->sym_buf = s->pending_buf + s->lit_bufsize; + s->sym_end = (s->lit_bufsize - 1) * 3; +#endif + /* We avoid equality with lit_bufsize*3 because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ + + s->level = level; + s->strategy = strategy; + s->block_open = 0; + s->reproducible = 0; + + return PREFIX(deflateReset)(strm); +} + +#ifndef ZLIB_COMPAT +int32_t Z_EXPORT PREFIX(deflateInit)(PREFIX3(stream) *strm, int32_t level) { + return PREFIX(deflateInit2)(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); +} +#endif + +/* Function used by zlib.h and zlib-ng version 2.0 macros */ +int32_t Z_EXPORT PREFIX(deflateInit_)(PREFIX3(stream) *strm, int32_t level, const char *version, int32_t stream_size) { + if (CHECK_VER_STSIZE(version, stream_size)) + return Z_VERSION_ERROR; + return PREFIX(deflateInit2)(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); +} + +/* Function used by zlib.h and zlib-ng version 2.0 macros */ +int32_t Z_EXPORT PREFIX(deflateInit2_)(PREFIX3(stream) *strm, int32_t level, int32_t method, int32_t windowBits, + int32_t memLevel, int32_t strategy, const char *version, int32_t stream_size) { + if (CHECK_VER_STSIZE(version, stream_size)) + return Z_VERSION_ERROR; + return PREFIX(deflateInit2)(strm, level, method, windowBits, memLevel, strategy); +} + +/* ========================================================================= + * Check for a valid deflate stream state. Return 0 if ok, 1 if not. + */ +static int deflateStateCheck(PREFIX3(stream) *strm) { + deflate_state *s; + if (strm == NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + s = strm->state; + if (s == NULL || s->alloc_bufs == NULL || s->strm != strm || (s->status < INIT_STATE || s->status > MAX_STATE)) + return 1; + return 0; +} + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflateSetDictionary)(PREFIX3(stream) *strm, const uint8_t *dictionary, uint32_t dictLength) { + deflate_state *s; + unsigned int str, n; + int wrap; + uint32_t avail; + const unsigned char *next; + + if (deflateStateCheck(strm) || dictionary == NULL) + return Z_STREAM_ERROR; + s = strm->state; + wrap = s->wrap; + if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) + return Z_STREAM_ERROR; + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap == 1) + strm->adler = FUNCTABLE_CALL(adler32)(strm->adler, dictionary, dictLength); + DEFLATE_SET_DICTIONARY_HOOK(strm, dictionary, dictLength); /* hook for IBM Z DFLTCC */ + s->wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s->w_size) { + if (wrap == 0) { /* already empty otherwise */ + CLEAR_HASH(s); + s->strstart = 0; + s->block_start = 0; + s->insert = 0; + } + dictionary += dictLength - s->w_size; /* use the tail */ + dictLength = s->w_size; + } + + /* insert dictionary into window and hash */ + avail = strm->avail_in; + next = strm->next_in; + strm->avail_in = dictLength; + strm->next_in = (z_const unsigned char *)dictionary; + PREFIX(fill_window)(s); + while (s->lookahead >= STD_MIN_MATCH) { + str = s->strstart; + n = s->lookahead - (STD_MIN_MATCH - 1); + s->insert_string(s, str, n); + s->strstart = str + n; + s->lookahead = STD_MIN_MATCH - 1; + PREFIX(fill_window)(s); + } + s->strstart += s->lookahead; + s->block_start = (int)s->strstart; + s->insert = s->lookahead; + s->lookahead = 0; + s->prev_length = 0; + s->match_available = 0; + strm->next_in = (z_const unsigned char *)next; + strm->avail_in = avail; + s->wrap = wrap; + return Z_OK; +} + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflateGetDictionary)(PREFIX3(stream) *strm, uint8_t *dictionary, uint32_t *dictLength) { + deflate_state *s; + unsigned int len; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + DEFLATE_GET_DICTIONARY_HOOK(strm, dictionary, dictLength); /* hook for IBM Z DFLTCC */ + s = strm->state; + len = s->strstart + s->lookahead; + if (len > s->w_size) + len = s->w_size; + if (dictionary != NULL && len) + memcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); + if (dictLength != NULL) + *dictLength = len; + return Z_OK; +} + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflateResetKeep)(PREFIX3(stream) *strm) { + deflate_state *s; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + + strm->total_in = strm->total_out = 0; + strm->msg = NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + + s->status = +#ifdef GZIP + s->wrap == 2 ? GZIP_STATE : +#endif + INIT_STATE; + +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = FUNCTABLE_CALL(crc32_fold_reset)(&s->crc_fold); + } else +#endif + strm->adler = ADLER32_INITIAL_VALUE; + s->last_flush = -2; + + zng_tr_init(s); + + DEFLATE_RESET_KEEP_HOOK(strm); /* hook for IBM Z DFLTCC */ + + return Z_OK; +} + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflateReset)(PREFIX3(stream) *strm) { + int ret = PREFIX(deflateResetKeep)(strm); + if (ret == Z_OK) + lm_init(strm->state); + return ret; +} + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflateSetHeader)(PREFIX3(stream) *strm, PREFIX(gz_headerp) head) { + if (deflateStateCheck(strm) || strm->state->wrap != 2) + return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflatePending)(PREFIX3(stream) *strm, uint32_t *pending, int32_t *bits) { + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + if (pending != NULL) + *pending = strm->state->pending; + if (bits != NULL) + *bits = strm->state->bi_valid; + return Z_OK; +} + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflatePrime)(PREFIX3(stream) *strm, int32_t bits, int32_t value) { + deflate_state *s; + uint64_t value64 = (uint64_t)value; + int32_t put; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + +#ifdef LIT_MEM + if (bits < 0 || bits > BIT_BUF_SIZE || + (unsigned char *)s->d_buf < s->pending_out + ((BIT_BUF_SIZE + 7) >> 3)) + return Z_BUF_ERROR; +#else + if (bits < 0 || bits > BIT_BUF_SIZE || bits > (int32_t)(sizeof(value) << 3) || + s->sym_buf < s->pending_out + ((BIT_BUF_SIZE + 7) >> 3)) + return Z_BUF_ERROR; +#endif + + do { + put = BIT_BUF_SIZE - s->bi_valid; + put = MIN(put, bits); + + if (s->bi_valid == 0) + s->bi_buf = value64; + else + s->bi_buf |= (value64 & ((UINT64_C(1) << put) - 1)) << s->bi_valid; + s->bi_valid += put; + zng_tr_flush_bits(s); + value64 >>= put; + bits -= put; + } while (bits); + return Z_OK; +} + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflateParams)(PREFIX3(stream) *strm, int32_t level, int32_t strategy) { + deflate_state *s; + compress_func func; + int hook_flush = Z_NO_FLUSH; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + + if (level == Z_DEFAULT_COMPRESSION) + level = 6; + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) + return Z_STREAM_ERROR; + DEFLATE_PARAMS_HOOK(strm, level, strategy, &hook_flush); /* hook for IBM Z DFLTCC */ + func = configuration_table[s->level].func; + + if (((strategy != s->strategy || func != configuration_table[level].func) && s->last_flush != -2) + || hook_flush != Z_NO_FLUSH) { + /* Flush the last buffer. Use Z_BLOCK mode, unless the hook requests a "stronger" one. */ + int flush = RANK(hook_flush) > RANK(Z_BLOCK) ? hook_flush : Z_BLOCK; + int err = PREFIX(deflate)(strm, flush); + if (err == Z_STREAM_ERROR) + return err; + if (strm->avail_in || ((int)s->strstart - s->block_start) + s->lookahead || !DEFLATE_DONE(strm, flush)) + return Z_BUF_ERROR; + } + if (s->level != level) { + if (s->level == 0 && s->matches != 0) { + if (s->matches == 1) { + FUNCTABLE_CALL(slide_hash)(s); + } else { + CLEAR_HASH(s); + } + s->matches = 0; + } + + lm_set_level(s, level); + } + s->strategy = strategy; + return Z_OK; +} + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflateTune)(PREFIX3(stream) *strm, int32_t good_length, int32_t max_lazy, int32_t nice_length, int32_t max_chain) { + deflate_state *s; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + s->good_match = (unsigned int)good_length; + s->max_lazy_match = (unsigned int)max_lazy; + s->nice_match = nice_length; + s->max_chain_length = (unsigned int)max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds for + * every combination of windowBits and memLevel. But even the conservative + * upper bound of about 14% expansion does not seem onerous for output buffer + * allocation. + */ +unsigned long Z_EXPORT PREFIX(deflateBound)(PREFIX3(stream) *strm, unsigned long sourceLen) { + deflate_state *s; + unsigned long complen, wraplen; + + /* conservative upper bound for compressed data */ + complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen); /* hook for IBM Z DFLTCC */ + + /* if can't get parameters, return conservative bound plus zlib wrapper */ + if (deflateStateCheck(strm)) + return complen + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = ZLIB_WRAPLEN + (s->strstart ? 4 : 0); + break; +#ifdef GZIP + case 2: /* gzip wrapper */ + wraplen = GZIP_WRAPLEN; + if (s->gzhead != NULL) { /* user-supplied gzip header */ + unsigned char *str; + if (s->gzhead->extra != NULL) { + wraplen += 2 + s->gzhead->extra_len; + } + str = s->gzhead->name; + if (str != NULL) { + do { + wraplen++; + } while (*str++); + } + str = s->gzhead->comment; + if (str != NULL) { + do { + wraplen++; + } while (*str++); + } + if (s->gzhead->hcrc) + wraplen += 2; + } + break; +#endif + default: /* for compiler happiness */ + wraplen = ZLIB_WRAPLEN; + } + + /* if not default parameters, return conservative bound */ + if (DEFLATE_NEED_CONSERVATIVE_BOUND(strm) || /* hook for IBM Z DFLTCC */ + s->w_bits != MAX_WBITS || HASH_BITS < 15) { + if (s->level == 0) { + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + complen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + (sourceLen >> 11) + 7; + } + + return complen + wraplen; + } + +#ifndef NO_QUICK_STRATEGY + return sourceLen /* The source size itself */ + + (sourceLen == 0 ? 1 : 0) /* Always at least one byte for any input */ + + (sourceLen < 9 ? 1 : 0) /* One extra byte for lengths less than 9 */ + + DEFLATE_QUICK_OVERHEAD(sourceLen) /* Source encoding overhead, padded to next full byte */ + + DEFLATE_BLOCK_OVERHEAD /* Deflate block overhead bytes */ + + wraplen; /* none, zlib or gzip wrapper */ +#else + return sourceLen + (sourceLen >> 4) + 7 + wraplen; +#endif +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output, except for + * some deflate_stored() output, goes through this function so some + * applications may wish to modify it to avoid allocating a large + * strm->next_out buffer and copying into it. (See also read_buf()). + */ +Z_INTERNAL void PREFIX(flush_pending)(PREFIX3(stream) *strm) { + uint32_t len; + deflate_state *s = strm->state; + + zng_tr_flush_bits(s); + len = MIN(s->pending, strm->avail_out); + if (len == 0) + return; + + Tracev((stderr, "[FLUSH]")); + memcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) + s->pending_out = s->pending_buf; +} + +/* =========================================================================== + * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. + */ +#define HCRC_UPDATE(beg) \ + do { \ + if (s->gzhead->hcrc && s->pending > (beg)) \ + strm->adler = PREFIX(crc32)(strm->adler, s->pending_buf + (beg), s->pending - (beg)); \ + } while (0) + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { + int32_t old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) + return Z_STREAM_ERROR; + s = strm->state; + + if (strm->next_out == NULL || (strm->avail_in != 0 && strm->next_in == NULL) + || (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + old_flush = s->last_flush; + s->last_flush = flush; + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + PREFIX(flush_pending)(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Write the header */ + if (s->status == INIT_STATE && s->wrap == 0) + s->status = BUSY_STATE; + if (s->status == INIT_STATE) { + /* zlib header */ + unsigned int header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + unsigned int level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) + header |= PRESET_DICT; + header += 31 - (header % 31); + + put_short_msb(s, (uint16_t)header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) + put_uint32_msb(s, strm->adler); + strm->adler = ADLER32_INITIAL_VALUE; + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + PREFIX(flush_pending)(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#ifdef GZIP + if (s->status == GZIP_STATE) { + /* gzip header */ + FUNCTABLE_CALL(crc32_fold_reset)(&s->crc_fold); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_uint32(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + PREFIX(flush_pending)(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == NULL ? 0 : 4) + + (s->gzhead->name == NULL ? 0 : 8) + + (s->gzhead->comment == NULL ? 0 : 16) + ); + put_uint32(s, s->gzhead->time); + put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) + put_short(s, (uint16_t)s->gzhead->extra_len); + if (s->gzhead->hcrc) + strm->adler = PREFIX(crc32)(strm->adler, s->pending_buf, s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uint32_t beg = s->pending; /* start of bytes to update crc */ + uint32_t left = (s->gzhead->extra_len & 0xffff) - s->gzindex; + + while (s->pending + left > s->pending_buf_size) { + uint32_t copy = s->pending_buf_size - s->pending; + memcpy(s->pending_buf + s->pending, s->gzhead->extra + s->gzindex, copy); + s->pending = s->pending_buf_size; + HCRC_UPDATE(beg); + s->gzindex += copy; + PREFIX(flush_pending)(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + left -= copy; + } + memcpy(s->pending_buf + s->pending, s->gzhead->extra + s->gzindex, left); + s->pending += left; + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uint32_t beg = s->pending; /* start of bytes to update crc */ + unsigned char val; + + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + PREFIX(flush_pending)(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uint32_t beg = s->pending; /* start of bytes to update crc */ + unsigned char val; + + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + PREFIX(flush_pending)(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + } + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) { + PREFIX(flush_pending)(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + put_short(s, (uint16_t)strm->adler); + FUNCTABLE_CALL(crc32_fold_reset)(&s->crc_fold); + } + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + PREFIX(flush_pending)(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#endif + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = DEFLATE_HOOK(strm, flush, &bstate) ? bstate : /* hook for IBM Z DFLTCC */ + s->level == 0 ? deflate_stored(s, flush) : + s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + zng_tr_align(s); + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + zng_tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0; + s->insert = 0; + } + } + } + PREFIX(flush_pending)(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + + if (flush != Z_FINISH) + return Z_OK; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = FUNCTABLE_CALL(crc32_fold_final)(&s->crc_fold); + + put_uint32(s, strm->adler); + put_uint32(s, (uint32_t)strm->total_in); + } else +#endif + { + if (s->wrap == 1) + put_uint32_msb(s, strm->adler); + } + PREFIX(flush_pending)(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) + s->wrap = -s->wrap; /* write the trailer only once! */ + if (s->pending == 0) { + Assert(s->bi_valid == 0, "bi_buf not flushed"); + return Z_STREAM_END; + } + return Z_OK; +} + +/* ========================================================================= */ +int32_t Z_EXPORT PREFIX(deflateEnd)(PREFIX3(stream) *strm) { + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + + int32_t status = strm->state->status; + + /* Free allocated buffers */ + free_deflate(strm); + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + */ +int32_t Z_EXPORT PREFIX(deflateCopy)(PREFIX3(stream) *dest, PREFIX3(stream) *source) { + deflate_state *ds; + deflate_state *ss; + + if (deflateStateCheck(source) || dest == NULL) + return Z_STREAM_ERROR; + + ss = source->state; + + memcpy((void *)dest, (void *)source, sizeof(PREFIX3(stream))); + + deflate_allocs *alloc_bufs = alloc_deflate(dest, ss->w_bits, ss->lit_bufsize); + if (alloc_bufs == NULL) + return Z_MEM_ERROR; + + ds = alloc_bufs->state; + + dest->state = (struct internal_state *) ds; + memcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->alloc_bufs = alloc_bufs; + ds->window = alloc_bufs->window; + ds->prev = alloc_bufs->prev; + ds->head = alloc_bufs->head; + ds->pending_buf = alloc_bufs->pending_buf; + + if (ds->window == NULL || ds->prev == NULL || ds->head == NULL || ds->pending_buf == NULL) { + PREFIX(deflateEnd)(dest); + return Z_MEM_ERROR; + } + + memcpy(ds->window, ss->window, DEFLATE_ADJUST_WINDOW_SIZE(ds->w_size * 2 * sizeof(unsigned char))); + memcpy((void *)ds->prev, (void *)ss->prev, ds->w_size * sizeof(Pos)); + memcpy((void *)ds->head, (void *)ss->head, HASH_SIZE * sizeof(Pos)); + memcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); +#ifdef LIT_MEM + ds->d_buf = (uint16_t *)(ds->pending_buf + (ds->lit_bufsize << 1)); + ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2); +#else + ds->sym_buf = ds->pending_buf + ds->lit_bufsize; +#endif + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +Z_INTERNAL unsigned PREFIX(read_buf)(PREFIX3(stream) *strm, unsigned char *buf, unsigned size) { + uint32_t len = MIN(strm->avail_in, size); + if (len == 0) + return 0; + + strm->avail_in -= len; + + if (!DEFLATE_NEED_CHECKSUM(strm)) { + memcpy(buf, strm->next_in, len); +#ifdef GZIP + } else if (strm->state->wrap == 2) { + FUNCTABLE_CALL(crc32_fold_copy)(&strm->state->crc_fold, buf, strm->next_in, len); +#endif + } else if (strm->state->wrap == 1) { + strm->adler = FUNCTABLE_CALL(adler32_fold_copy)(strm->adler, buf, strm->next_in, len); + } else { + memcpy(buf, strm->next_in, len); + } + strm->next_in += len; + strm->total_in += len; + + return len; +} + +/* =========================================================================== + * Set longest match variables based on level configuration + */ +static void lm_set_level(deflate_state *s, int level) { + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + + /* Use rolling hash for deflate_slow algorithm with level 9. It allows us to + * properly lookup different hash chains to speed up longest_match search. Since hashing + * method changes depending on the level we cannot put this into functable. */ + if (s->max_chain_length > 1024) { + s->update_hash = &update_hash_roll; + s->insert_string = &insert_string_roll; + s->quick_insert_string = &quick_insert_string_roll; + } else { + s->update_hash = update_hash; + s->insert_string = insert_string; + s->quick_insert_string = quick_insert_string; + } + + s->level = level; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +static void lm_init(deflate_state *s) { + s->window_size = 2 * s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + lm_set_level(s, s->level); + + s->strstart = 0; + s->block_start = 0; + s->lookahead = 0; + s->insert = 0; + s->prev_length = 0; + s->match_available = 0; + s->match_start = 0; + s->ins_h = 0; +} + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ + +void Z_INTERNAL PREFIX(fill_window)(deflate_state *s) { + unsigned n; + unsigned int more; /* Amount of free space at the end of the window. */ + unsigned int wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = s->window_size - s->lookahead - s->strstart; + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + memcpy(s->window, s->window+wsize, (unsigned)wsize); + if (s->match_start >= wsize) { + s->match_start -= wsize; + } else { + s->match_start = 0; + s->prev_length = 0; + } + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (int)wsize; + if (s->insert > s->strstart) + s->insert = s->strstart; + FUNCTABLE_CALL(slide_hash)(s); + more += wsize; + } + if (s->strm->avail_in == 0) + break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = PREFIX(read_buf)(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= STD_MIN_MATCH) { + unsigned int str = s->strstart - s->insert; + if (UNLIKELY(s->max_chain_length > 1024)) { + s->ins_h = s->update_hash(s->window[str], s->window[str+1]); + } else if (str >= 1) { + s->quick_insert_string(s, str + 2 - STD_MIN_MATCH); + } + unsigned int count = s->insert; + if (UNLIKELY(s->lookahead == 1)) { + count -= 1; + } + if (count > 0) { + s->insert_string(s, str, count); + s->insert -= count; + } + } + /* If the whole input has less than STD_MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to STD_MAX_MATCH since the longest match + * routines allow scanning to strstart + STD_MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + unsigned int curr = s->strstart + s->lookahead; + unsigned int init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + memset(s->window + curr, 0, init); + s->high_water = curr + init; + } else if (s->high_water < curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + memset(s->window + s->high_water, 0, init); + s->high_water += init; + } + } + + Assert((unsigned long)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + +#ifndef ZLIB_COMPAT +/* ========================================================================= + * Checks whether buffer size is sufficient and whether this parameter is a duplicate. + */ +static int32_t deflateSetParamPre(zng_deflate_param_value **out, size_t min_size, zng_deflate_param_value *param) { + int32_t buf_error = param->size < min_size; + + if (*out != NULL) { + (*out)->status = Z_BUF_ERROR; + buf_error = 1; + } + *out = param; + return buf_error; +} + +/* ========================================================================= */ +int32_t Z_EXPORT zng_deflateSetParams(zng_stream *strm, zng_deflate_param_value *params, size_t count) { + size_t i; + deflate_state *s; + zng_deflate_param_value *new_level = NULL; + zng_deflate_param_value *new_strategy = NULL; + zng_deflate_param_value *new_reproducible = NULL; + int param_buf_error; + int version_error = 0; + int buf_error = 0; + int stream_error = 0; + + /* Initialize the statuses. */ + for (i = 0; i < count; i++) + params[i].status = Z_OK; + + /* Check whether the stream state is consistent. */ + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + + /* Check buffer sizes and detect duplicates. */ + for (i = 0; i < count; i++) { + switch (params[i].param) { + case Z_DEFLATE_LEVEL: + param_buf_error = deflateSetParamPre(&new_level, sizeof(int), ¶ms[i]); + break; + case Z_DEFLATE_STRATEGY: + param_buf_error = deflateSetParamPre(&new_strategy, sizeof(int), ¶ms[i]); + break; + case Z_DEFLATE_REPRODUCIBLE: + param_buf_error = deflateSetParamPre(&new_reproducible, sizeof(int), ¶ms[i]); + break; + default: + params[i].status = Z_VERSION_ERROR; + version_error = 1; + param_buf_error = 0; + break; + } + if (param_buf_error) { + params[i].status = Z_BUF_ERROR; + buf_error = 1; + } + } + /* Exit early if small buffers or duplicates are detected. */ + if (buf_error) + return Z_BUF_ERROR; + + /* Apply changes, remember if there were errors. */ + if (new_level != NULL || new_strategy != NULL) { + int ret = PREFIX(deflateParams)(strm, new_level == NULL ? s->level : *(int *)new_level->buf, + new_strategy == NULL ? s->strategy : *(int *)new_strategy->buf); + if (ret != Z_OK) { + if (new_level != NULL) + new_level->status = Z_STREAM_ERROR; + if (new_strategy != NULL) + new_strategy->status = Z_STREAM_ERROR; + stream_error = 1; + } + } + if (new_reproducible != NULL) { + int val = *(int *)new_reproducible->buf; + if (DEFLATE_CAN_SET_REPRODUCIBLE(strm, val)) { + s->reproducible = val; + } else { + new_reproducible->status = Z_STREAM_ERROR; + stream_error = 1; + } + } + + /* Report version errors only if there are no real errors. */ + return stream_error ? Z_STREAM_ERROR : (version_error ? Z_VERSION_ERROR : Z_OK); +} + +/* ========================================================================= */ +int32_t Z_EXPORT zng_deflateGetParams(zng_stream *strm, zng_deflate_param_value *params, size_t count) { + deflate_state *s; + size_t i; + int32_t buf_error = 0; + int32_t version_error = 0; + + /* Initialize the statuses. */ + for (i = 0; i < count; i++) + params[i].status = Z_OK; + + /* Check whether the stream state is consistent. */ + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + + for (i = 0; i < count; i++) { + switch (params[i].param) { + case Z_DEFLATE_LEVEL: + if (params[i].size < sizeof(int)) + params[i].status = Z_BUF_ERROR; + else + *(int *)params[i].buf = s->level; + break; + case Z_DEFLATE_STRATEGY: + if (params[i].size < sizeof(int)) + params[i].status = Z_BUF_ERROR; + else + *(int *)params[i].buf = s->strategy; + break; + case Z_DEFLATE_REPRODUCIBLE: + if (params[i].size < sizeof(int)) + params[i].status = Z_BUF_ERROR; + else + *(int *)params[i].buf = s->reproducible; + break; + default: + params[i].status = Z_VERSION_ERROR; + version_error = 1; + break; + } + if (params[i].status == Z_BUF_ERROR) + buf_error = 1; + } + return buf_error ? Z_BUF_ERROR : (version_error ? Z_VERSION_ERROR : Z_OK); +} +#endif diff --git a/deflate.h b/deflate.h new file mode 100644 index 0000000000..4b79f8f43b --- /dev/null +++ b/deflate.h @@ -0,0 +1,456 @@ +#ifndef DEFLATE_H_ +#define DEFLATE_H_ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2016 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#include "zutil.h" +#include "zendian.h" +#include "zmemory.h" +#include "crc32.h" + +#ifdef S390_DFLTCC_DEFLATE +# include "arch/s390/dfltcc_common.h" +# define HAVE_ARCH_DEFLATE_STATE +#endif + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at + the cost of a larger memory footprint */ +#ifndef NO_LIT_MEM +# define LIT_MEM +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define BIT_BUF_SIZE 64 +/* size of bit buffer in bi_buf */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define INIT_STATE 1 /* zlib header -> BUSY_STATE */ +#ifdef GZIP +# define GZIP_STATE 4 /* gzip header -> BUSY_STATE | EXTRA_STATE */ +# define EXTRA_STATE 5 /* gzip extra block -> NAME_STATE */ +# define NAME_STATE 6 /* gzip file name -> COMMENT_STATE */ +# define COMMENT_STATE 7 /* gzip comment -> HCRC_STATE */ +# define HCRC_STATE 8 /* gzip header CRC -> BUSY_STATE */ +#endif +#define BUSY_STATE 2 /* deflate -> FINISH_STATE */ +#define FINISH_STATE 3 /* stream complete */ +#ifdef GZIP +# define MAX_STATE HCRC_STATE +#else +# define MAX_STATE FINISH_STATE +#endif +/* Stream status */ + +#define HASH_BITS 16u /* log2(HASH_SIZE) */ +#ifndef HASH_SIZE +# define HASH_SIZE 65536u /* number of elements in hash table */ +#endif +#define HASH_MASK (HASH_SIZE - 1u) /* HASH_SIZE-1 */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + uint16_t freq; /* frequency count */ + uint16_t code; /* bit string */ + } fc; + union { + uint16_t dad; /* father node in Huffman tree */ + uint16_t len; /* length of bit string */ + } dl; +} ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + const static_tree_desc *stat_desc; /* the corresponding static tree */ +} tree_desc; + +typedef uint16_t Pos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. + */ +/* Type definitions for hash callbacks */ +typedef struct internal_state deflate_state; + +typedef uint32_t (* update_hash_cb) (uint32_t h, uint32_t val); +typedef void (* insert_string_cb) (deflate_state *const s, uint32_t str, uint32_t count); +typedef Pos (* quick_insert_string_cb)(deflate_state *const s, uint32_t str); + +uint32_t update_hash (uint32_t h, uint32_t val); +void insert_string (deflate_state *const s, uint32_t str, uint32_t count); +Pos quick_insert_string (deflate_state *const s, uint32_t str); + +uint32_t update_hash_roll (uint32_t h, uint32_t val); +void insert_string_roll (deflate_state *const s, uint32_t str, uint32_t count); +Pos quick_insert_string_roll(deflate_state *const s, uint32_t str); + +/* Struct for memory allocation handling */ +typedef struct deflate_allocs_s { + char *buf_start; + free_func zfree; + deflate_state *state; + unsigned char *window; + unsigned char *pending_buf; + Pos *prev; + Pos *head; +} deflate_allocs; + +struct ALIGNED_(64) internal_state { + PREFIX3(stream) *strm; /* pointer back to this zlib stream */ + unsigned char *pending_buf; /* output still pending */ + unsigned char *pending_out; /* next pending byte to output to the stream */ + uint32_t pending_buf_size; /* size of pending_buf */ + uint32_t pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + uint32_t gzindex; /* where in extra, name, or comment */ + PREFIX(gz_headerp) gzhead; /* gzip header information to write */ + int status; /* as the name implies */ + int last_flush; /* value of flush param for previous deflate call */ + int reproducible; /* Whether reproducible compression results are required. */ + + int block_open; + /* Whether or not a block is currently open for the QUICK deflation scheme. + * This is set to 1 if there is an active block, or 0 if the block was just closed. + */ + + /* used by deflate.c: */ + + unsigned int w_size; /* LZ77 window size (32K by default) */ + unsigned int w_bits; /* log2(w_size) (8..16) */ + unsigned int w_mask; /* w_size - 1 */ + unsigned int lookahead; /* number of valid bytes ahead in window */ + + unsigned int high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + + unsigned int window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + unsigned char *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-STD_MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + Pos *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Pos *head; /* Heads of the hash chains or 0. */ + + uint32_t ins_h; /* hash index of string to be inserted */ + + int block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + unsigned int match_length; /* length of best match */ + Pos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + unsigned int strstart; /* start of string to insert */ + unsigned int match_start; /* start of matching string */ + + unsigned int prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + unsigned int max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this length. + * A higher limit improves compression ratio but degrades the speed. + */ + + unsigned int max_lazy_match; + /* Attempt to find a better match only when the current match is strictly smaller + * than this value. This mechanism is used only for compression levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + update_hash_cb update_hash; + insert_string_cb insert_string; + quick_insert_string_cb quick_insert_string; + /* Hash function callbacks that can be configured depending on the deflate + * algorithm being used */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + unsigned int good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + +#if defined(_M_IX86) || defined(_M_ARM) + int padding[2]; +#endif + + struct crc32_fold_s ALIGNED_(16) crc_fold; + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to suppress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + uint16_t bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + unsigned char depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + unsigned int lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + +#ifdef LIT_MEM +# define LIT_BUFS 5 + uint16_t *d_buf; /* buffer for distances */ + unsigned char *l_buf; /* buffer for literals/lengths */ +#else +# define LIT_BUFS 4 + unsigned char *sym_buf; /* buffer for distances and literals/lengths */ +#endif + + unsigned int sym_next; /* running index in symbol buffer */ + unsigned int sym_end; /* symbol table full when sym_next reaches this */ + + unsigned long opt_len; /* bit length of current block with optimal trees */ + unsigned long static_len; /* bit length of current block with static trees */ + unsigned int matches; /* number of string matches in current block */ + unsigned int insert; /* bytes at end of window left to insert */ + + /* compressed_len and bits_sent are only used if ZLIB_DEBUG is defined */ + unsigned long compressed_len; /* total bit length of compressed file mod 2^32 */ + unsigned long bits_sent; /* bit length of compressed data sent mod 2^32 */ + + deflate_allocs *alloc_bufs; + +#ifdef HAVE_ARCH_DEFLATE_STATE + arch_deflate_state arch; /* architecture-specific extensions */ +#endif + + uint64_t bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least significant bits). */ + + int32_t bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit are always zero. */ + + /* Reserved for future use and alignment purposes */ + int32_t reserved[19]; +#if defined(_M_IX86) || defined(_M_ARM) + int32_t padding2[4]; +#endif +}; + +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) { \ + s->pending_buf[s->pending++] = (unsigned char)(c); \ +} + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pending_buf. + */ +static inline void put_short(deflate_state *s, uint16_t w) { +#if BYTE_ORDER == BIG_ENDIAN + w = ZSWAP16(w); +#endif + zng_memwrite_2(&s->pending_buf[s->pending], w); + s->pending += 2; +} + +/* =========================================================================== + * Output a short MSB first on the stream. + * IN assertion: there is enough room in pending_buf. + */ +static inline void put_short_msb(deflate_state *s, uint16_t w) { +#if BYTE_ORDER == LITTLE_ENDIAN + w = ZSWAP16(w); +#endif + zng_memwrite_2(&s->pending_buf[s->pending], w); + s->pending += 2; +} + +/* =========================================================================== + * Output a 32-bit unsigned int LSB first on the stream. + * IN assertion: there is enough room in pending_buf. + */ +static inline void put_uint32(deflate_state *s, uint32_t dw) { +#if BYTE_ORDER == BIG_ENDIAN + dw = ZSWAP32(dw); +#endif + zng_memwrite_4(&s->pending_buf[s->pending], dw); + s->pending += 4; +} + +/* =========================================================================== + * Output a 32-bit unsigned int MSB first on the stream. + * IN assertion: there is enough room in pending_buf. + */ +static inline void put_uint32_msb(deflate_state *s, uint32_t dw) { +#if BYTE_ORDER == LITTLE_ENDIAN + dw = ZSWAP32(dw); +#endif + zng_memwrite_4(&s->pending_buf[s->pending], dw); + s->pending += 4; +} + +/* =========================================================================== + * Output a 64-bit unsigned int LSB first on the stream. + * IN assertion: there is enough room in pending_buf. + */ +static inline void put_uint64(deflate_state *s, uint64_t lld) { +#if BYTE_ORDER == BIG_ENDIAN + lld = ZSWAP64(lld); +#endif + zng_memwrite_8(&s->pending_buf[s->pending], lld); + s->pending += 8; +} + +#define MIN_LOOKAHEAD (STD_MAX_MATCH + STD_MIN_MATCH + 1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the STD_MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size - MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT STD_MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + +void Z_INTERNAL PREFIX(fill_window)(deflate_state *s); +void Z_INTERNAL slide_hash_c(deflate_state *s); + + /* in trees.c */ +void Z_INTERNAL zng_tr_init(deflate_state *s); +void Z_INTERNAL zng_tr_flush_block(deflate_state *s, char *buf, uint32_t stored_len, int last); +void Z_INTERNAL zng_tr_flush_bits(deflate_state *s); +void Z_INTERNAL zng_tr_align(deflate_state *s); +void Z_INTERNAL zng_tr_stored_block(deflate_state *s, char *buf, uint32_t stored_len, int last); +uint16_t Z_INTERNAL PREFIX(bi_reverse)(unsigned code, int len); +void Z_INTERNAL PREFIX(flush_pending)(PREFIX3(streamp) strm); +#define d_code(dist) ((dist) < 256 ? zng_dist_code[dist] : zng_dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. zng_dist_code[256] and zng_dist_code[257] are never + * used. + */ + +/* Bit buffer and compress bits calculation debugging */ +#ifdef ZLIB_DEBUG +# define cmpr_bits_add(s, len) s->compressed_len += (len) +# define cmpr_bits_align(s) s->compressed_len = (s->compressed_len + 7) & ~7L +# define sent_bits_add(s, bits) s->bits_sent += (bits) +# define sent_bits_align(s) s->bits_sent = (s->bits_sent + 7) & ~7L +#else +# define cmpr_bits_add(s, len) Z_UNUSED(len) +# define cmpr_bits_align(s) +# define sent_bits_add(s, bits) Z_UNUSED(bits) +# define sent_bits_align(s) +#endif + +#endif /* DEFLATE_H_ */ diff --git a/deflate_fast.c b/deflate_fast.c new file mode 100644 index 0000000000..e682697d5c --- /dev/null +++ b/deflate_fast.c @@ -0,0 +1,104 @@ +/* deflate_fast.c -- compress data using the fast strategy of deflation algorithm + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "deflate.h" +#include "deflate_p.h" +#include "functable.h" + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +Z_INTERNAL block_state deflate_fast(deflate_state *s, int flush) { + Pos hash_head; /* head of the hash chain */ + int bflush = 0; /* set if current block must be flushed */ + int64_t dist; + uint32_t match_len = 0; + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need STD_MAX_MATCH bytes + * for the next match, plus WANT_MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + PREFIX(fill_window)(s); + if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) { + return need_more; + } + if (UNLIKELY(s->lookahead == 0)) + break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= WANT_MIN_MATCH) { + hash_head = quick_insert_string(s, s->strstart); + dist = (int64_t)s->strstart - hash_head; + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match length < WANT_MIN_MATCH + */ + if (dist <= MAX_DIST(s) && dist > 0 && hash_head != 0) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + match_len = FUNCTABLE_CALL(longest_match)(s, hash_head); + /* longest_match() sets match_start */ + } + } + + if (match_len >= WANT_MIN_MATCH) { + Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); + Assert(s->match_start <= UINT16_MAX, "match_start should fit in uint16_t"); + check_match(s, (Pos)s->strstart, (Pos)s->match_start, match_len); + + bflush = zng_tr_tally_dist(s, s->strstart - s->match_start, match_len - STD_MIN_MATCH); + + s->lookahead -= match_len; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (match_len <= s->max_insert_length && s->lookahead >= WANT_MIN_MATCH) { + match_len--; /* string at strstart already in table */ + s->strstart++; + + insert_string(s, s->strstart, match_len); + s->strstart += match_len; + } else { + s->strstart += match_len; + quick_insert_string(s, s->strstart + 2 - STD_MIN_MATCH); + + /* If lookahead < STD_MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + match_len = 0; + } else { + /* No match, output a literal byte */ + bflush = zng_tr_tally_lit(s, s->window[s->strstart]); + s->lookahead--; + s->strstart++; + } + if (UNLIKELY(bflush)) + FLUSH_BLOCK(s, 0); + } + s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); + if (UNLIKELY(flush == Z_FINISH)) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (UNLIKELY(s->sym_next)) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/deflate_huff.c b/deflate_huff.c new file mode 100644 index 0000000000..d5a234b114 --- /dev/null +++ b/deflate_huff.c @@ -0,0 +1,45 @@ +/* deflate_huff.c -- compress data using huffman encoding only strategy + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "deflate.h" +#include "deflate_p.h" +#include "functable.h" + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +Z_INTERNAL block_state deflate_huff(deflate_state *s, int flush) { + int bflush = 0; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + PREFIX(fill_window)(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + bflush = zng_tr_tally_lit(s, s->window[s->strstart]); + s->lookahead--; + s->strstart++; + if (bflush) + FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/deflate_medium.c b/deflate_medium.c new file mode 100644 index 0000000000..2aeebe2026 --- /dev/null +++ b/deflate_medium.c @@ -0,0 +1,278 @@ +/* deflate_medium.c -- The deflate_medium deflate strategy + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * Authors: + * Arjan van de Ven + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#ifndef NO_MEDIUM_STRATEGY +#include "zbuild.h" +#include "deflate.h" +#include "deflate_p.h" +#include "functable.h" + +struct match { + uint16_t match_start; + uint16_t match_length; + uint16_t strstart; + uint16_t orgstart; +}; + +static int emit_match(deflate_state *s, struct match match) { + int bflush = 0; + + /* matches that are not long enough we need to emit as literals */ + if (match.match_length < WANT_MIN_MATCH) { + while (match.match_length) { + bflush += zng_tr_tally_lit(s, s->window[match.strstart]); + s->lookahead--; + match.strstart++; + match.match_length--; + } + return bflush; + } + + check_match(s, match.strstart, match.match_start, match.match_length); + + bflush += zng_tr_tally_dist(s, match.strstart - match.match_start, match.match_length - STD_MIN_MATCH); + + s->lookahead -= match.match_length; + return bflush; +} + +static void insert_match(deflate_state *s, struct match match) { + if (UNLIKELY(s->lookahead <= (unsigned int)(match.match_length + WANT_MIN_MATCH))) + return; + + /* string at strstart already in table */ + match.strstart++; + match.match_length--; + + /* matches that are not long enough we need to emit as literals */ + if (LIKELY(match.match_length < WANT_MIN_MATCH - 1)) { + if (UNLIKELY(match.match_length > 0)) { + if (match.strstart >= match.orgstart) { + if (match.strstart + match.match_length - 1 >= match.orgstart) { + insert_string(s, match.strstart, match.match_length); + } else { + insert_string(s, match.strstart, match.orgstart - match.strstart + 1); + } + match.strstart += match.match_length; + match.match_length = 0; + } + } + return; + } + + /* Insert into hash table. */ + if (LIKELY(match.strstart >= match.orgstart)) { + if (LIKELY(match.strstart + match.match_length - 1 >= match.orgstart)) { + insert_string(s, match.strstart, match.match_length); + } else { + insert_string(s, match.strstart, match.orgstart - match.strstart + 1); + } + } else if (match.orgstart < match.strstart + match.match_length) { + insert_string(s, match.orgstart, match.strstart + match.match_length - match.orgstart); + } + match.strstart += match.match_length; + match.match_length = 0; +} + +static void fizzle_matches(deflate_state *s, struct match *current, struct match *next) { + Pos limit; + unsigned char *match, *orig; + int changed = 0; + struct match c, n; + /* step zero: sanity checks */ + + if (current->match_length <= 1) + return; + + if (UNLIKELY(current->match_length > 1 + next->match_start)) + return; + + if (UNLIKELY(current->match_length > 1 + next->strstart)) + return; + + match = s->window - current->match_length + 1 + next->match_start; + orig = s->window - current->match_length + 1 + next->strstart; + + /* quick exit check.. if this fails then don't bother with anything else */ + if (LIKELY(*match != *orig)) + return; + + c = *current; + n = *next; + + /* step one: try to move the "next" match to the left as much as possible */ + limit = next->strstart > MAX_DIST(s) ? next->strstart - (Pos)MAX_DIST(s) : 0; + + match = s->window + n.match_start - 1; + orig = s->window + n.strstart - 1; + + while (*match == *orig) { + if (UNLIKELY(c.match_length < 1)) + break; + if (UNLIKELY(n.strstart <= limit)) + break; + if (UNLIKELY(n.match_length >= 256)) + break; + if (UNLIKELY(n.match_start <= 1)) + break; + + n.strstart--; + n.match_start--; + n.match_length++; + c.match_length--; + match--; + orig--; + changed++; + } + + if (!changed) + return; + + if (c.match_length <= 1 && n.match_length != 2) { + n.orgstart++; + *current = c; + *next = n; + } else { + return; + } +} + +Z_INTERNAL block_state deflate_medium(deflate_state *s, int flush) { + /* Align the first struct to start on a new cacheline, this allows us to fit both structs in one cacheline */ + ALIGNED_(16) struct match current_match; + struct match next_match; + + /* For levels below 5, don't check the next position for a better match */ + int early_exit = s->level < 5; + + memset(¤t_match, 0, sizeof(struct match)); + memset(&next_match, 0, sizeof(struct match)); + + for (;;) { + Pos hash_head = 0; /* head of the hash chain */ + int bflush = 0; /* set if current block must be flushed */ + int64_t dist; + + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need STD_MAX_MATCH bytes + * for the next match, plus WANT_MIN_MATCH bytes to insert the + * string following the next current_match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + PREFIX(fill_window)(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (UNLIKELY(s->lookahead == 0)) + break; /* flush the current block */ + next_match.match_length = 0; + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + + /* If we already have a future match from a previous round, just use that */ + if (!early_exit && next_match.match_length > 0) { + current_match = next_match; + next_match.match_length = 0; + } else { + hash_head = 0; + if (s->lookahead >= WANT_MIN_MATCH) { + hash_head = quick_insert_string(s, s->strstart); + } + + current_match.strstart = (uint16_t)s->strstart; + current_match.orgstart = current_match.strstart; + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < WANT_MIN_MATCH + */ + + dist = (int64_t)s->strstart - hash_head; + if (dist <= MAX_DIST(s) && dist > 0 && hash_head != 0) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + current_match.match_length = (uint16_t)FUNCTABLE_CALL(longest_match)(s, hash_head); + current_match.match_start = (uint16_t)s->match_start; + if (UNLIKELY(current_match.match_length < WANT_MIN_MATCH)) + current_match.match_length = 1; + if (UNLIKELY(current_match.match_start >= current_match.strstart)) { + /* this can happen due to some restarts */ + current_match.match_length = 1; + } + } else { + /* Set up the match to be a 1 byte literal */ + current_match.match_start = 0; + current_match.match_length = 1; + } + } + + insert_match(s, current_match); + + /* now, look ahead one */ + if (LIKELY(!early_exit && s->lookahead > MIN_LOOKAHEAD && (uint32_t)(current_match.strstart + current_match.match_length) < (s->window_size - MIN_LOOKAHEAD))) { + s->strstart = current_match.strstart + current_match.match_length; + hash_head = quick_insert_string(s, s->strstart); + + next_match.strstart = (uint16_t)s->strstart; + next_match.orgstart = next_match.strstart; + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < WANT_MIN_MATCH + */ + + dist = (int64_t)s->strstart - hash_head; + if (dist <= MAX_DIST(s) && dist > 0 && hash_head != 0) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + next_match.match_length = (uint16_t)FUNCTABLE_CALL(longest_match)(s, hash_head); + next_match.match_start = (uint16_t)s->match_start; + if (UNLIKELY(next_match.match_start >= next_match.strstart)) { + /* this can happen due to some restarts */ + next_match.match_length = 1; + } + if (next_match.match_length < WANT_MIN_MATCH) + next_match.match_length = 1; + else + fizzle_matches(s, ¤t_match, &next_match); + } else { + /* Set up the match to be a 1 byte literal */ + next_match.match_start = 0; + next_match.match_length = 1; + } + + s->strstart = current_match.strstart; + } else { + next_match.match_length = 0; + } + + /* now emit the current match */ + bflush = emit_match(s, current_match); + + /* move the "cursor" forward */ + s->strstart += current_match.match_length; + + if (UNLIKELY(bflush)) + FLUSH_BLOCK(s, 0); + } + s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (UNLIKELY(s->sym_next)) + FLUSH_BLOCK(s, 0); + + return block_done; +} +#endif diff --git a/deflate_p.h b/deflate_p.h new file mode 100644 index 0000000000..abcc8b1c7c --- /dev/null +++ b/deflate_p.h @@ -0,0 +1,128 @@ +/* deflate_p.h -- Private inline functions and macros shared with more than + * one deflate method + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + */ + +#ifndef DEFLATE_P_H +#define DEFLATE_P_H + +/* Forward declare common non-inlined functions declared in deflate.c */ + +#ifdef ZLIB_DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +static inline void check_match(deflate_state *s, Pos start, Pos match, int length) { + /* check that the match length is valid*/ + if (length < STD_MIN_MATCH || length > STD_MAX_MATCH) { + fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); + z_error("invalid match length"); + } + /* check that the match isn't at the same position as the start string */ + if (match == start) { + fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); + z_error("invalid match position"); + } + /* check that the match is indeed a match */ + if (memcmp(s->window + match, s->window + start, length) != 0) { + int32_t i = 0; + fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); + do { + fprintf(stderr, " %03d: match [%02x] start [%02x]\n", i++, + s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr, "\\[%u,%d]", start-match, length); + do { + putc(s->window[start++], stderr); + } while (--length != 0); + } +} +#else +#define check_match(s, start, match, length) +#endif + +Z_INTERNAL void PREFIX(flush_pending)(PREFIX3(stream) *strm); +Z_INTERNAL unsigned PREFIX(read_buf)(PREFIX3(stream) *strm, unsigned char *buf, unsigned size); + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ + +extern const unsigned char Z_INTERNAL zng_length_code[]; +extern const unsigned char Z_INTERNAL zng_dist_code[]; + +static inline int zng_tr_tally_lit(deflate_state *s, unsigned char c) { + /* c is the unmatched char */ +#ifdef LIT_MEM + s->d_buf[s->sym_next] = 0; + s->l_buf[s->sym_next++] = c; +#else + s->sym_buf[s->sym_next++] = 0; + s->sym_buf[s->sym_next++] = 0; + s->sym_buf[s->sym_next++] = c; +#endif + s->dyn_ltree[c].Freq++; + Tracevv((stderr, "%c", c)); + Assert(c <= (STD_MAX_MATCH-STD_MIN_MATCH), "zng_tr_tally: bad literal"); + return (s->sym_next == s->sym_end); +} + +static inline int zng_tr_tally_dist(deflate_state* s, uint32_t dist, uint32_t len) { + /* dist: distance of matched string */ + /* len: match length-STD_MIN_MATCH */ +#ifdef LIT_MEM + Assert(dist <= UINT16_MAX, "dist should fit in uint16_t"); + Assert(len <= UINT8_MAX, "len should fit in uint8_t"); + s->d_buf[s->sym_next] = (uint16_t)dist; + s->l_buf[s->sym_next++] = (uint8_t)len; +#else + s->sym_buf[s->sym_next++] = (uint8_t)(dist); + s->sym_buf[s->sym_next++] = (uint8_t)(dist >> 8); + s->sym_buf[s->sym_next++] = (uint8_t)len; +#endif + s->matches++; + dist--; + Assert(dist < MAX_DIST(s) && (uint16_t)d_code(dist) < (uint16_t)D_CODES, + "zng_tr_tally: bad match"); + + s->dyn_ltree[zng_length_code[len] + LITERALS + 1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + return (s->sym_next == s->sym_end); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, last) { \ + zng_tr_flush_block(s, (s->block_start >= 0 ? \ + (char *)&s->window[(unsigned)s->block_start] : \ + NULL), \ + (uint32_t)((int)s->strstart - s->block_start), \ + (last)); \ + s->block_start = (int)s->strstart; \ + PREFIX(flush_pending)(s->strm); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* Maximum stored block length in deflate format (not including header). */ +#define MAX_STORED 65535 + +/* Compression function. Returns the block state after the call. */ +typedef block_state (*compress_func) (deflate_state *s, int flush); +/* Match function. Returns the longest match. */ +typedef uint32_t (*match_func) (deflate_state *const s, Pos cur_match); + +#endif diff --git a/deflate_quick.c b/deflate_quick.c new file mode 100644 index 0000000000..d5fd986d7a --- /dev/null +++ b/deflate_quick.c @@ -0,0 +1,130 @@ +/* + * The deflate_quick deflate strategy, designed to be used when cycles are + * at a premium. + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * Authors: + * Wajdi Feghali + * Jim Guilford + * Vinodh Gopal + * Erdinc Ozturk + * Jim Kukunas + * + * Portions are Copyright (C) 2016 12Sided Technology, LLC. + * Author: + * Phil Vachon + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zmemory.h" +#include "deflate.h" +#include "deflate_p.h" +#include "functable.h" +#include "trees_emit.h" + +extern const ct_data static_ltree[L_CODES+2]; +extern const ct_data static_dtree[D_CODES]; + +#define QUICK_START_BLOCK(s, last) { \ + zng_tr_emit_tree(s, STATIC_TREES, last); \ + s->block_open = 1 + (int)last; \ + s->block_start = (int)s->strstart; \ +} + +#define QUICK_END_BLOCK(s, last) { \ + if (s->block_open) { \ + zng_tr_emit_end_block(s, static_ltree, last); \ + s->block_open = 0; \ + s->block_start = (int)s->strstart; \ + PREFIX(flush_pending)(s->strm); \ + if (s->strm->avail_out == 0) \ + return (last) ? finish_started : need_more; \ + } \ +} + +Z_INTERNAL block_state deflate_quick(deflate_state *s, int flush) { + Pos hash_head; + int64_t dist; + unsigned match_len, last; + + + last = (flush == Z_FINISH) ? 1 : 0; + if (UNLIKELY(last && s->block_open != 2)) { + /* Emit end of previous block */ + QUICK_END_BLOCK(s, 0); + /* Emit start of last block */ + QUICK_START_BLOCK(s, last); + } else if (UNLIKELY(s->block_open == 0 && s->lookahead > 0)) { + /* Start new block only when we have lookahead data, so that if no + input data is given an empty block will not be written */ + QUICK_START_BLOCK(s, last); + } + + for (;;) { + if (UNLIKELY(s->pending + ((BIT_BUF_SIZE + 7) >> 3) >= s->pending_buf_size)) { + PREFIX(flush_pending)(s->strm); + if (s->strm->avail_out == 0) { + return (last && s->strm->avail_in == 0 && s->bi_valid == 0 && s->block_open == 0) ? finish_started : need_more; + } + } + + if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD)) { + PREFIX(fill_window)(s); + if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) { + return need_more; + } + if (UNLIKELY(s->lookahead == 0)) + break; + + if (UNLIKELY(s->block_open == 0)) { + /* Start new block when we have lookahead data, so that if no + input data is given an empty block will not be written */ + QUICK_START_BLOCK(s, last); + } + } + + if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) { + hash_head = quick_insert_string(s, s->strstart); + dist = (int64_t)s->strstart - hash_head; + + if (dist <= MAX_DIST(s) && dist > 0) { + const uint8_t *str_start = s->window + s->strstart; + const uint8_t *match_start = s->window + hash_head; + + if (zng_memcmp_2(str_start, match_start) == 0) { + match_len = FUNCTABLE_CALL(compare256)(str_start+2, match_start+2) + 2; + + if (match_len >= WANT_MIN_MATCH) { + if (UNLIKELY(match_len > s->lookahead)) + match_len = s->lookahead; + if (UNLIKELY(match_len > STD_MAX_MATCH)) + match_len = STD_MAX_MATCH; + + Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); + check_match(s, (Pos)s->strstart, hash_head, match_len); + + zng_tr_emit_dist(s, static_ltree, static_dtree, match_len - STD_MIN_MATCH, (uint32_t)dist); + s->lookahead -= match_len; + s->strstart += match_len; + continue; + } + } + } + } + + zng_tr_emit_lit(s, static_ltree, s->window[s->strstart]); + s->strstart++; + s->lookahead--; + } + + s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); + if (UNLIKELY(last)) { + QUICK_END_BLOCK(s, 1); + return finish_done; + } + + QUICK_END_BLOCK(s, 0); + return block_done; +} diff --git a/deflate_rle.c b/deflate_rle.c new file mode 100644 index 0000000000..9e39810483 --- /dev/null +++ b/deflate_rle.c @@ -0,0 +1,84 @@ +/* deflate_rle.c -- compress data using RLE strategy of deflation algorithm + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "deflate.h" +#include "deflate_p.h" +#include "functable.h" +#include "compare256_rle.h" + +#if OPTIMAL_CMP == 8 +# define compare256_rle compare256_rle_8 +#elif defined(HAVE_BUILTIN_CTZLL) +# define compare256_rle compare256_rle_64 +#elif defined(HAVE_BUILTIN_CTZ) +# define compare256_rle compare256_rle_32 +#else +# define compare256_rle compare256_rle_16 +#endif + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +Z_INTERNAL block_state deflate_rle(deflate_state *s, int flush) { + int bflush = 0; /* set if current block must be flushed */ + unsigned char *scan; /* scan goes up to strend for length of run */ + uint32_t match_len = 0; + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need STD_MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s->lookahead <= STD_MAX_MATCH) { + PREFIX(fill_window)(s); + if (s->lookahead <= STD_MAX_MATCH && flush == Z_NO_FLUSH) + return need_more; + if (s->lookahead == 0) + break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + if (s->lookahead >= STD_MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + if (scan[0] == scan[1] && scan[1] == scan[2]) { + match_len = compare256_rle(scan, scan+3)+2; + match_len = MIN(match_len, s->lookahead); + match_len = MIN(match_len, STD_MAX_MATCH); + } + Assert(scan+match_len <= s->window + s->window_size - 1, "wild scan"); + } + + /* Emit match if have run of STD_MIN_MATCH or longer, else emit literal */ + if (match_len >= STD_MIN_MATCH) { + Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); + check_match(s, (Pos)s->strstart, (Pos)(s->strstart - 1), match_len); + + bflush = zng_tr_tally_dist(s, 1, match_len - STD_MIN_MATCH); + + s->lookahead -= match_len; + s->strstart += match_len; + match_len = 0; + } else { + /* No match, output a literal byte */ + bflush = zng_tr_tally_lit(s, s->window[s->strstart]); + s->lookahead--; + s->strstart++; + } + if (bflush) + FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/deflate_slow.c b/deflate_slow.c new file mode 100644 index 0000000000..4165eea2af --- /dev/null +++ b/deflate_slow.c @@ -0,0 +1,144 @@ +/* deflate_slow.c -- compress data using the slow strategy of deflation algorithm + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "deflate.h" +#include "deflate_p.h" +#include "functable.h" + +/* =========================================================================== + * Same as deflate_medium, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +Z_INTERNAL block_state deflate_slow(deflate_state *s, int flush) { + Pos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + int64_t dist; + uint32_t match_len; + match_func longest_match; + + if (s->max_chain_length <= 1024) + longest_match = FUNCTABLE_FPTR(longest_match); + else + longest_match = FUNCTABLE_FPTR(longest_match_slow); + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need STD_MAX_MATCH bytes + * for the next match, plus WANT_MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + PREFIX(fill_window)(s); + if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) { + return need_more; + } + if (UNLIKELY(s->lookahead == 0)) + break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0; + if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) { + hash_head = s->quick_insert_string(s, s->strstart); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_match = (Pos)s->match_start; + match_len = STD_MIN_MATCH - 1; + dist = (int64_t)s->strstart - hash_head; + + if (dist <= MAX_DIST(s) && dist > 0 && s->prev_length < s->max_lazy_match && hash_head != 0) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + match_len = longest_match(s, hash_head); + /* longest_match() sets match_start */ + + if (match_len <= 5 && (s->strategy == Z_FILTERED)) { + /* If prev_match is also WANT_MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + match_len = STD_MIN_MATCH - 1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= STD_MIN_MATCH && match_len <= s->prev_length) { + unsigned int max_insert = s->strstart + s->lookahead - STD_MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + Assert((s->strstart-1) <= UINT16_MAX, "strstart-1 should fit in uint16_t"); + check_match(s, (Pos)(s->strstart - 1), s->prev_match, s->prev_length); + + bflush = zng_tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - STD_MIN_MATCH); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->prev_length -= 1; + s->lookahead -= s->prev_length; + + unsigned int mov_fwd = s->prev_length - 1; + if (max_insert > s->strstart) { + unsigned int insert_cnt = mov_fwd; + if (UNLIKELY(insert_cnt > max_insert - s->strstart)) + insert_cnt = max_insert - s->strstart; + s->insert_string(s, s->strstart + 1, insert_cnt); + } + s->prev_length = 0; + s->match_available = 0; + s->strstart += mov_fwd + 1; + + if (UNLIKELY(bflush)) + FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + bflush = zng_tr_tally_lit(s, s->window[s->strstart-1]); + if (UNLIKELY(bflush)) + FLUSH_BLOCK_ONLY(s, 0); + s->prev_length = match_len; + s->strstart++; + s->lookahead--; + if (UNLIKELY(s->strm->avail_out == 0)) + return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->prev_length = match_len; + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert(flush != Z_NO_FLUSH, "no flush?"); + if (UNLIKELY(s->match_available)) { + Z_UNUSED(zng_tr_tally_lit(s, s->window[s->strstart-1])); + s->match_available = 0; + } + s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); + if (UNLIKELY(flush == Z_FINISH)) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (UNLIKELY(s->sym_next)) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/deflate_stored.c b/deflate_stored.c new file mode 100644 index 0000000000..9e5acfbf96 --- /dev/null +++ b/deflate_stored.c @@ -0,0 +1,186 @@ +/* deflate_stored.c -- store data without compression using deflation algorithm + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "deflate.h" +#include "deflate_p.h" +#include "functable.h" + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * + * In case deflateParams() is used to later switch to a non-zero compression + * level, s->matches (otherwise unused when storing) keeps track of the number + * of hash table slides to perform. If s->matches is 1, then one hash table + * slide will be done when switching. If s->matches is 2, the maximum value + * allowed here, then the hash table will be cleared, since two or more slides + * is the same as a clear. + * + * deflate_stored() is written to minimize the number of times an input byte is + * copied. It is most efficient with large input and output buffers, which + * maximizes the opportunities to have a single copy from next_in to next_out. + */ +Z_INTERNAL block_state deflate_stored(deflate_state *s, int flush) { + /* Smallest worthy block size when not flushing or finishing. By default + * this is 32K. This can be as small as 507 bytes for memLevel == 1. For + * large input and output buffers, the stored block size will be larger. + */ + unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); + + /* Copy as many min_block or larger stored blocks directly to next_out as + * possible. If flushing, copy the remaining available input to next_out as + * stored blocks, if there is enough space. + */ + unsigned len, left, have, last = 0; + unsigned used = s->strm->avail_in; + do { + /* Set len to the maximum size block that we can copy directly with the + * available input data and output space. Set left to how much of that + * would be copied from what's left in the window. + */ + len = MAX_STORED; /* maximum deflate stored block length */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + if (s->strm->avail_out < have) /* need room for header */ + break; + /* maximum stored block length that will fit in avail_out: */ + have = s->strm->avail_out - have; + left = (int)s->strstart - s->block_start; /* bytes left in window */ + if (len > (unsigned long)left + s->strm->avail_in) + len = left + s->strm->avail_in; /* limit len to the input */ + len = MIN(len, have); /* limit len to the output */ + + /* If the stored block would be less than min_block in length, or if + * unable to copy all of the available input when flushing, then try + * copying to the window and the pending buffer instead. Also don't + * write an empty block when flushing -- deflate() does that. + */ + if (len < min_block && ((len == 0 && flush != Z_FINISH) || flush == Z_NO_FLUSH || len != left + s->strm->avail_in)) + break; + + /* Make a dummy stored block in pending to get the header bytes, + * including any pending bits. This also updates the debugging counts. + */ + last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; + zng_tr_stored_block(s, (char *)0, 0L, last); + + /* Replace the lengths in the dummy stored block with len. */ + s->pending -= 4; + put_short(s, (uint16_t)len); + put_short(s, (uint16_t)~len); + + /* Write the stored block header bytes. */ + PREFIX(flush_pending)(s->strm); + + /* Update debugging counts for the data about to be copied. */ + cmpr_bits_add(s, len << 3); + sent_bits_add(s, len << 3); + + /* Copy uncompressed bytes from the window to next_out. */ + if (left) { + left = MIN(left, len); + memcpy(s->strm->next_out, s->window + s->block_start, left); + s->strm->next_out += left; + s->strm->avail_out -= left; + s->strm->total_out += left; + s->block_start += (int)left; + len -= left; + } + + /* Copy uncompressed bytes directly from next_in to next_out, updating + * the check value. + */ + if (len) { + PREFIX(read_buf)(s->strm, s->strm->next_out, len); + s->strm->next_out += len; + s->strm->avail_out -= len; + s->strm->total_out += len; + } + } while (last == 0); + + /* Update the sliding window with the last s->w_size bytes of the copied + * data, or append all of the copied data to the existing window if less + * than s->w_size bytes were copied. Also update the number of bytes to + * insert in the hash tables, in the event that deflateParams() switches to + * a non-zero compression level. + */ + used -= s->strm->avail_in; /* number of input bytes directly copied */ + if (used) { + /* If any input was used, then no unused input remains in the window, + * therefore s->block_start == s->strstart. + */ + if (used >= s->w_size) { /* supplant the previous history */ + s->matches = 2; /* clear hash */ + memcpy(s->window, s->strm->next_in - s->w_size, s->w_size); + s->strstart = s->w_size; + s->insert = s->strstart; + } else { + if (s->window_size - s->strstart <= used) { + /* Slide the window down. */ + s->strstart -= s->w_size; + memcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + s->insert = MIN(s->insert, s->strstart); + } + memcpy(s->window + s->strstart, s->strm->next_in - used, used); + s->strstart += used; + s->insert += MIN(used, s->w_size - s->insert); + } + s->block_start = (int)s->strstart; + } + s->high_water = MAX(s->high_water, s->strstart); + + /* If the last block was written to next_out, then done. */ + if (last) + return finish_done; + + /* If flushing and all input has been consumed, then done. */ + if (flush != Z_NO_FLUSH && flush != Z_FINISH && s->strm->avail_in == 0 && (int)s->strstart == s->block_start) + return block_done; + + /* Fill the window with any remaining input. */ + have = s->window_size - s->strstart; + if (s->strm->avail_in > have && s->block_start >= (int)s->w_size) { + /* Slide the window down. */ + s->block_start -= (int)s->w_size; + s->strstart -= s->w_size; + memcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + have += s->w_size; /* more space now */ + s->insert = MIN(s->insert, s->strstart); + } + + have = MIN(have, s->strm->avail_in); + if (have) { + PREFIX(read_buf)(s->strm, s->window + s->strstart, have); + s->strstart += have; + s->insert += MIN(have, s->w_size - s->insert); + } + s->high_water = MAX(s->high_water, s->strstart); + + /* There was not enough avail_out to write a complete worthy or flushed + * stored block to next_out. Write a stored block to pending instead, if we + * have enough input for a worthy block, or if flushing and there is enough + * room for the remaining input as a stored block in the pending buffer. + */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + /* maximum stored block length that will fit in pending: */ + have = MIN(s->pending_buf_size - have, MAX_STORED); + min_block = MIN(have, s->w_size); + left = (int)s->strstart - s->block_start; + if (left >= min_block || ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && s->strm->avail_in == 0 && left <= have)) { + len = MIN(left, have); + last = flush == Z_FINISH && s->strm->avail_in == 0 && len == left ? 1 : 0; + zng_tr_stored_block(s, (char *)s->window + s->block_start, len, last); + s->block_start += (int)len; + PREFIX(flush_pending)(s->strm); + } + + /* We've done all we can with the available input and output. */ + return last ? finish_started : need_more; +} diff --git a/doc/algorithm.txt b/doc/algorithm.txt new file mode 100644 index 0000000000..acd099c9ae --- /dev/null +++ b/doc/algorithm.txt @@ -0,0 +1,209 @@ +1. Compression algorithm (deflate) + +The deflation algorithm used by gzip (also zip and zlib) is a variation of +LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in +the input data. The second occurrence of a string is replaced by a +pointer to the previous string, in the form of a pair (distance, +length). Distances are limited to 32K bytes, and lengths are limited +to 258 bytes. When a string does not occur anywhere in the previous +32K bytes, it is emitted as a sequence of literal bytes. (In this +description, `string' must be taken as an arbitrary sequence of bytes, +and is not restricted to printable characters.) + +Literals or match lengths are compressed with one Huffman tree, and +match distances are compressed with another tree. The trees are stored +in a compact form at the start of each block. The blocks can have any +size (except that the compressed data for one block must fit in +available memory). A block is terminated when deflate() determines that +it would be useful to start another block with fresh trees. (This is +somewhat similar to the behavior of LZW-based _compress_.) + +Duplicated strings are found using a hash table. All input strings of +length 3 are inserted in the hash table. A hash index is computed for +the next 3 bytes. If the hash chain for this index is not empty, all +strings in the chain are compared with the current input string, and +the longest match is selected. + +The hash chains are searched starting with the most recent strings, to +favor small distances and thus take advantage of the Huffman encoding. +The hash chains are singly linked. There are no deletions from the +hash chains, the algorithm simply discards matches that are too old. + +To avoid a worst-case situation, very long hash chains are arbitrarily +truncated at a certain length, determined by a runtime option (level +parameter of deflateInit). So deflate() does not always find the longest +possible match but generally finds a match which is long enough. + +deflate() also defers the selection of matches with a lazy evaluation +mechanism. After a match of length N has been found, deflate() searches for +a longer match at the next input byte. If a longer match is found, the +previous match is truncated to a length of one (thus producing a single +literal byte) and the process of lazy evaluation begins again. Otherwise, +the original match is kept, and the next match search is attempted only N +steps later. + +The lazy match evaluation is also subject to a runtime parameter. If +the current match is long enough, deflate() reduces the search for a longer +match, thus speeding up the whole process. If compression ratio is more +important than speed, deflate() attempts a complete second search even if +the first match is already long enough. + +The lazy match evaluation is not performed for the fastest compression +modes (level parameter 1 to 3). For these fast modes, new strings +are inserted in the hash table only when no match was found, or +when the match is not too long. This degrades the compression ratio +but saves time since there are both fewer insertions and fewer searches. + + +2. Decompression algorithm (inflate) + +2.1 Introduction + +The key question is how to represent a Huffman code (or any prefix code) so +that you can decode fast. The most important characteristic is that shorter +codes are much more common than longer codes, so pay attention to decoding the +short codes fast, and let the long codes take longer to decode. + +inflate() sets up a first level table that covers some number of bits of +input less than the length of longest code. It gets that many bits from the +stream, and looks it up in the table. The table will tell if the next +code is that many bits or less and how many, and if it is, it will tell +the value, else it will point to the next level table for which inflate() +grabs more bits and tries to decode a longer code. + +How many bits to make the first lookup is a tradeoff between the time it +takes to decode and the time it takes to build the table. If building the +table took no time (and if you had infinite memory), then there would only +be a first level table to cover all the way to the longest code. However, +building the table ends up taking a lot longer for more bits since short +codes are replicated many times in such a table. What inflate() does is +simply to make the number of bits in the first table a variable, and then +to set that variable for the maximum speed. + +For inflate, which has 286 possible codes for the literal/length tree, the size +of the first table is nine bits. Also the distance trees have 30 possible +values, and the size of the first table is six bits. Note that for each of +those cases, the table ended up one bit longer than the ``average'' code +length, i.e. the code length of an approximately flat code which would be a +little more than eight bits for 286 symbols and a little less than five bits +for 30 symbols. + + +2.2 More details on the inflate table lookup + +Ok, you want to know what this cleverly obfuscated inflate tree actually +looks like. You are correct that it's not a Huffman tree. It is simply a +lookup table for the first, let's say, nine bits of a Huffman symbol. The +symbol could be as short as one bit or as long as 15 bits. If a particular +symbol is shorter than nine bits, then that symbol's translation is duplicated +in all those entries that start with that symbol's bits. For example, if the +symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a +symbol is nine bits long, it appears in the table once. + +If the symbol is longer than nine bits, then that entry in the table points +to another similar table for the remaining bits. Again, there are duplicated +entries as needed. The idea is that most of the time the symbol will be short +and there will only be one table look up. (That's whole idea behind data +compression in the first place.) For the less frequent long symbols, there +will be two lookups. If you had a compression method with really long +symbols, you could have as many levels of lookups as is efficient. For +inflate, two is enough. + +So a table entry either points to another table (in which case nine bits in +the above example are gobbled), or it contains the translation for the symbol +and the number of bits to gobble. Then you start again with the next +ungobbled bit. + +You may wonder: why not just have one lookup table for how ever many bits the +longest symbol is? The reason is that if you do that, you end up spending +more time filling in duplicate symbol entries than you do actually decoding. +At least for deflate's output that generates new trees every several 10's of +kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code +would take too long if you're only decoding several thousand symbols. At the +other extreme, you could make a new table for every bit in the code. In fact, +that's essentially a Huffman tree. But then you spend too much time +traversing the tree while decoding, even for short symbols. + +So the number of bits for the first lookup table is a trade of the time to +fill out the table vs. the time spent looking at the second level and above of +the table. + +Here is an example, scaled down: + +The code being decoded, with 10 symbols, from 1 to 6 bits long: + +A: 0 +B: 10 +C: 1100 +D: 11010 +E: 11011 +F: 11100 +G: 11101 +H: 11110 +I: 111110 +J: 111111 + +Let's make the first table three bits long (eight entries): + +000: A,1 +001: A,1 +010: A,1 +011: A,1 +100: B,2 +101: B,2 +110: -> table X (gobble 3 bits) +111: -> table Y (gobble 3 bits) + +Each entry is what the bits decode as and how many bits that is, i.e. how +many bits to gobble. Or the entry points to another table, with the number of +bits to gobble implicit in the size of the table. + +Table X is two bits long since the longest code starting with 110 is five bits +long: + +00: C,1 +01: C,1 +10: D,2 +11: E,2 + +Table Y is three bits long since the longest code starting with 111 is six +bits long: + +000: F,2 +001: F,2 +010: G,2 +011: G,2 +100: H,2 +101: H,2 +110: I,3 +111: J,3 + +So what we have here are three tables with a total of 20 entries that had to +be constructed. That's compared to 64 entries for a single table. Or +compared to 16 entries for a Huffman tree (six two entry tables and one four +entry table). Assuming that the code ideally represents the probability of +the symbols, it takes on the average 1.25 lookups per symbol. That's compared +to one lookup for the single table, or 1.66 lookups per symbol for the +Huffman tree. + +There, I think that gives you a picture of what's going on. For inflate, the +meaning of a particular symbol is often more than just a letter. It can be a +byte (a "literal"), or it can be either a length or a distance which +indicates a base value and a number of bits to fetch after the code that is +added to the base value. Or it might be the special end-of-block code. The +data structures created in inftrees.c try to encode all that information +compactly in the tables. + + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + + +References: + +[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data +Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, +pp. 337-343. + +``DEFLATE Compressed Data Format Specification'' available in +https://tools.ietf.org/html/rfc1951 diff --git a/doc/crc-doc.1.0.pdf b/doc/crc-doc.1.0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d6942ecc09a3f8b2d7e4b6fbecc5955121e8e7cf GIT binary patch literal 776142 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

ha zLaMAf=TJIZFK#&6Va%U0pVsiSVUZh*LkUizvxS8u)Y!TfY|0^ziJ~FxwB}7Vdd7On z8NgP0Yl65ZP(%#h1;sObJ}n@Z#xe45MiBUgigq_(3)!+sV+~$)7?)?tGYc_mnG$d7 zy2!hUhiHD=c=x27VoQ~2f=CDE(5fW|#H^q{`zm&6bGf~ewX8ez&{cQ#mdfWvclH3w zBgTU#xeY&CW?nb@{%CllMYZQHhO+sVY% z8=DjR<~!&7xIenr-d$bQ)mW=~clEC4l?9=RhV$xCQc2d7Uh5~C#de_^3(xHKV4b*d zs;$AW&vc^*nNpmsoyGb5YNM0ambVo$v~nB)Jd?zenVY%)ilahXd(^vX5c8C>ACP&r z`16hCQ-O81I)?_QdZ*8JqI3oEj(Jh`uZ5zzvjxImBQs2ryqycd3Y^z?dMiG(BLm7g zEm*8c!YM-5q#p`8{9gU52{YzJ6e5}e|26CE#FI)PTfFvvV(+yvF9!dM9qxb zT7Ie>V?+v&yUFY=LBHfn=&|NF!w{YQ8zESN~%2!StzD%C{Wp{ zT6>hreBhQn+ShjDTQ9BdZzIbIOk_Q)QV*%i=;9OJoMT!=N;zX@h6dlu`s;g}CE!K1 zNC&n}%;}=fgU)_}_mD72S|sW}&D1 zhkQIUpgW{4XG!~wEIU%VeisWBDveLx2!3@$9_R044RpcIXHIK&gv@cX*_r{*mFsLt z033Op&UT8kg(kPB!#<@HzP1Y)`UcD2s%J@GA4IxT`ecm>t8@`$|-Uk z3zZKQTLLO2@}!y4s-E_66_Re#pe$#}0fd@+26R645}RQWRlQ;2T<0S;m8 z2Lige{^!nlqiTb=Js}F^g@~wW3T5F9#u?><(B}71fxvvXW!N*KIQDbhz%b|vczFt3 zNV|YdVMuOaVJ|Ew$qc@HB0;0I_2Yh32>7gRZ#4c`RiRKP%tGLKz?Z&Y*>=z(^9jQ! z(^C#LpY~*6(Ow6l2?r4bQnYtMG|F2;j2h%uHqgd>kUBdF5lB>Dmx4w-H53KdneZ6f z4kNIvB}%HPs+xPb4M-tb!LA+pd_u7Ujw*`gg=rV~N~gvw(ap=E_6vD5M_K2S%-jm7 z{L-0>2(VVbK!c~9{g622ch|_UaIZjTe9;DKPSmfx+D+mUZMBYIp)+kH`HE`J=1>;y z;~Z)9-$JUs6l!x@s0w89MOyj|#O!=eu*51wY)z0!XRm$-@Lo75Bv_QN?5OxEZW6{ZYq!bfD)#r`jk#BJ9`(Wug08T_6?NAMD% zb-)tT#4Zaz-@qssK!qTe`_nOE4b=Qa4u4_$8Ycor#c`JnSj}v=IxDZQuRM7+HtkGT z5HAT;JVN#R)JTGp4HDJ}sD!)k-T90gN6H>LPOC^C?ZFHV!AQ^ir~PR7P2HxioJ zcc@hp#N#5M$~~vKhS;u{b!^E^$n)P^b(whs=Xa^ZgiB(jaNu23<4jm3rdy8kVWq!_ zlK-?@mAg%$KM z(b#hsDUOBzw>t%4@)+X$3wB@36)csUhZK6U=Jd-dRz;r5vWI+Fii zcTQ%N7~?ws0?SxL8rb;K5)4Wl95brywmZpuc+?zyf|wfbcE|n9I{5P2i;13mK|<|0 zA4-aZAk~{1D`FLRXsAVe1Bl==1PW@V0kNRSwE+2=TKzUQ;-{;<0nLArI|FqbVexEb zUYENo4!WQRoUPe-S$9GH?yb~)fP!F7cR7Ili?1La&7T<8Zu`{-pEN53y{#}3e~|8)|H0ratMi2aiwdU}JK7Li(=r058bg|ha+$O<9aN(;N{&DA#@Izur#@6qExIj zPlf6~^-yCQ@4W2>?k`1}yVsz-ygh$`6WR@1*=@_C;zI2vS~p>;-7sb%S=&u+0u>K) zD}$Rx52IaF`YAfNX0yi0tkVqHSr#qQDQ*Fs{_2zh8@a%VbBNgJUgEMj*UeV&G=(dh zOQJn-0$5CX;Y)&qKa#~nI8?WvJ)NP~d=+*}(%wd&Cd#+%Azf5jGhPjS0 z5NgEl;tPrOG%*yvGBHgKdB@*#iYipaIqb(J*O5+D@d66Z2_+eFN??3Ck_^`7S#|PX zf;=ICSx7p_G@{rVO{bsUiV5gz08pHYmd}i!7Dm(_s_jm&dG1gMVV1e{x6uQC6^$|! zOCHkaVNzP17qL#y-Fe$20>uiBI~SbYltEYk@{(358AMzk3u8+?@gfH;)dyk1FYOlI4KY z#3JiqiBywTVe~Fwb?%%oDU{xS5sYhcUq=PO3&Byob=g<)qJ7RY9L=+Z`!hM+np$J? zlngYR*~qD4?-v)q`D=38l{J93b1}&U*d<(%*Nqge!GGap>cYJ0o)h1g=%4IoQc|w& zOpIS&44~Pu`FGn`PB?(;Utt5C!8&h#tZ{ehJXHWGRiCC4RA+FeP_a*EdgYFk&DC$u zrEu;OTpF$rR235H2gSh#3Y?8s|KNw4Xj?tA6Ql{8icHT$c>0E%!?Da%4;u!2tr}EH zV^&5&sM1jk8`c;~Mw_WZ#~g*?A*k*j59yJcUFO_R3Un{an%_mW3Ax-y;kQrFtI3ce z^gD#4W}L|B?glw+vm$>Ot;&jN6x`XDE#lRNDC*D|edtgHa1<*+hv3rdJ-iFBTZ~d8 z$C~$&G*XUJlrUr(Ov$n6X~P`lYa+JJyCAI9%+36Hg0q+xz%dWHCPABIrxc7Q@45L1 zti|QEVl*6SEz+yKA}ke# z5tj)zt0zNNEMd-?OT1u^X-+}obuH9JXotf{UGkM(4+DYF35}q>j)_vCMbI&5Z9B6# zg68rVX|7fp-IPqZrPIN4q#iX{zo}o^Wyoc3qQ9WAfA<}!v#$5M-*YKLT8q3%{9b+t z+ji-(fA-kB4SLCcIf#ZBRWf%1;g@O{QFjXpy4gF&jEDV&A+V3=Q_@J)#{cZt`&G3q z-cw@inJ9Ybfq#h19TA>buneigY602pf7* z^3U^!O&Z)U0ivCy8pE7JLmU(X$~;k~0qbtGQS2%`^d-qdoI}j=#$i5F5%bFiGCE`X zP9BZ83}PSAIRTRo^<9SnjyuSu;oi!;v1>8;cBDut_8=lf84oZFyeuz=9H~oBx6v!= zJ|SB`j5#F%ulpw=9)|Af^igku1{nNFByaT8;@xB_bC_|LdS@K}iw_y9>5 z@Ky8%oVmm0^uUxokYOAce6R8vyN{?#1{Xc*=yp?pIBHb-#8J>K578${S$G~{&p_PL zh2n2DqZ9^TdqZ#sh`qYii`diaBaRHl@I6MKN}!eB3cq(Jtjeyb3eAoUUX^Oy_|`RR{SFzH57*>FU!lsY^!;E06nJt2NPWUfFqHeuW0A^@g?y-TU0 z?iOuEpCQMm0tHS37@OO;nggK#73W?=yfn$}q`@>B2BH7%oFP~JkuyA*19;K&m``>Q zu0>u~zI+fic`vKhp{F5ICy$}{c)tO3=xM^ z2oWMsW~s_u#Vv66V2`2K#fGZkdkC&h&r%jxE$;VL7;sh4}DS%Jz}_8vV*otJK^3UE0!twP_P;QrLHm zM0jceH2-fC8V%U9RcVYsdw93UQ&<%7IO@S#_=eOi;sux%l$E7bvW0)Gi<2!j;UF#3 zZg9SQ`~aNUm@|-3eOLNApkdQEcVIP_D=()X8|#j5jlzpa=yE= zG7(z?YO9$!(uJ0GGi^Cx*yFZQ1~^hIWofQcLs&n951QrFvwjN;5V`TEE(dRYN;F^| zwh}Ho(s|1*m-SqY9km{0UZ|kca@YbV4$c|f85Ib?nfn1&- z0FAY7!;8NgWB0C-Kc?k3M>0(fS@kJ93iG`@r?t~?8`7grzW3{{j3a}EuN&{09Tcx*bzNZ)wWXNQyG=1xbWu7Qm|-WIHKT6s$Dn^ zR4W+PNrN}-v(!!j=!1?5i&g?-ijq=!iH=rK+#2XAVL7b4W;E|Z811Pd@`AYM>h&ty zVnUC8tGKaAOnS_^3kzZrASE36z6m``W7ocA&#+S=n3}G-hS#bIYs+-{jhQ&IkGakK*e@UtWXzZ0J9% z4bBzJk}x?9d(JA*2+V@GE_<~TT3Yn&m^sn%1sIYvoEP=A!;?bF28s#SRu3#hvf5Bb(tj%z*9ZUM7>=cmXC~f7=s(F! zEfZAZehvVSk9o(F7SHTxCpn4?R48ic**Oj76DK_3Hwkg$*Ph-~edP4xWU|~o7jPC~ z00@~T{Q0M(E(-8tq0aX#Skx={V7p9kfH668q?J0CIkmA$P`%J&8bU`_G%S|R^iZ;h zeU*=Rt1b%c3Q3|x<%oYxuTwNTf?jbp0yx;_fWQPSig+bRNC1e;ibAU~`Ih;Ppw7W( z$=kMt>!G9;sDCXDa4ht1-N^F~B{yd~(**^e6V=s$uS_L^%1iM#{OB5^+ML@To;2-w$%wk2#^XV+=bPs}{BC*yJ;H9`X}{}9*-lZ| zGox6^@ok#7zhl0A@5GPz$(+m=jq%{;#^fJtI!AIr%`H;*6RO_liJwQZU5;@XTRD>; z56a#XoDpw~Skd0d`xIXoveP2qKswh*WluO=1z{m}!za3lBhwa&a%9+%x_6M@rGjP@ zYXWSmrWN=7%oRWaX}E69$^gmfZB04RMCQi@+eyA(z!MWve0*VpyCU|Y0wLQ$^a&@d z_)SH?v0TNfVS)R2UoM!aDw0L+uBAcYE=i~~l&b|Qk{Z}SWzzByYykL|MBI&F3gU@M z53-aMg~IH!Xm0hf4Att?F{x45kfn@N=lw|z!^hBD=H7clVFr0|3zL97U{(Mb&gMGz zJf}y?Zj$jpi`Aw^YFVHu!I3`J$FB&0EASZI+>D1qnEjREQGEwQ_v8Kg=G499+EVGf zE)FP$YD7@Mf{$4za5P`AeKxKjkLUyCWKhTFslA$S`-IPe611|J2Ain|Dob~=`5<|0 zus)0L)YSp2NWJ*FHrs^p5VmZCuYaaVV=zq;FD_13l}Tgv8WT27s0ot*#zZJ{nI=gT zM1<1K2&{zTlGhn%qOn8<4UT7%3`V?AA#7jaQ@&MRr$SY6UeRjl@|_Fec{dhy~Wk(=nn2G&soxoukpvBQ8jD!em{0 zQ91uyVS<(A9+D>^m`jx@a4UI*3#``ysS2zqn7Kn5{U_@c*s|5vgw~;8D{*vz$60o8 ziNH16@VaP{z!|bk8vPI5G}6W>A+eOB#V{4Jxd)$4rnT+f$74 zI+f;os!AIDk3A$zgyo>nrb1z%1(|T$v;fl?Sti9mB)hUeCVXJbEb1t@bm-2)N5pCH zuYI?B#DL$ECjJD5>+O+$*U+X41t-F_Xv7?9AsAFfBnj2-7k`7gfGTw~Spg-gC_iXW zZI}mgC5iw}&_f41u*U_uU+|;|&9OBRpah?Xp)hFCE2%LuqlT-)Xi%-e{`ihoIS(}yn zwxC{wB&5M#(<9t;NbMT0dc*A<2^aHEAYI(>S?e16ZtCr{z=x_&NyJ)cfc48Y%GtS$&aXeRM zF|&V?qR)qGL+1H+o<-pu$Z`D@d0HC{ z3Y+Xt46{-Q7iNQ?0esd9>6q(lD_Tn^!<*ff`J*|Buvjcc?9(Cin!CfBR?RaTk^vS% zW%7yJTlX05@@HfR^0o^tjQqLp7l8{!uy}-VW5-Kjg;_XI8BQ!4<^J);_;fC1u^`{l zz)0L}**QW=2w6Sua?$()Np#od&rb;=E&WIRSdLM|v~z-^%Q@ze92Wz00~_v{wM(?& zJm;UMx_vcT5CaTZkYu4zpyk{nD^Bh_V~mRSyhv7lG!RsmbD5j%;b@ATqxJ>1oDOSI zCR?e$3qUd_TMlIRvJ=g0WkRxx zl_b)!iH-kRn6B*~A*qNAq|a6tMWIKzen;57Vi9xM?+YTynoP{S{CXQ`yl z7B%L8rS4V>`-jOqMV`NkpBLP)vscsPljeEeV)Z(#!{xR=v*8&0&$E3B`49t$B zdGCP}G}4=qO_5*F3@ftaKuJ#O8o{<1(L4tHXki#IQheWC9yYxLhk#gqH|z$l#^Foz z-ne0btdx04{d}r0QAAs;21Da$b~xVr?X{aB1bU}-d=FLf+h5v>Bf6M+TMOjeu_D7i z+hqG;I|U!~B=avdyug$@eN4(}kcs7rD%jLw6@E-i0BhA=!5_{@ht(DOhlQLeVG~o( z##S_@*HpR#qdW2T_NTqsf?5i!j~N-2L!TCuNSuCc<78p0%`r^P9r?R|u2xapK@kCj_ZyOP|>$Uin+5(kJ!t*mA3`frSHIF;!{O=a+Oe&LATSIts>4f(x`DV zL8>u2b%g7X3We;Bnj>d4&&gOgn+oBJnLG0cK0?Jzh#3HyV)wd}2wd$l6$xN@t$0gB z;G*(ArLG=7R{VnZs69bk<8A5}jXJv$Q@_XKiDGFj1V8`5Qh1@9%W4;+`t_K@JoZ3^ z{~0eU@ko%B7&C~Wh~SZAh4V*(X{}qW>fSQR5vn(?jG%exof$=M(xLcWrh2D=I4UL7 zdp*qHNtiJhY(_)g0iSFk(`PR|F~E?xHwW9SK8pL z(fEV|x`&6@(8502oHM!~mE`rGmV`+@u}9dONXbEr#J~B6op?|D+MfQ?{o|1ZCVOAM z29j?%(QKo!w*3)6aRV`5+H-wOFfmuQ(2hor2=T@ov}1>TnQ0Dc!{_d&U{b{H*tjVT z?m}~J=%PA5*M8eJy=$^pTAzGA(l+!JV}hn8Y6YtT&LmG%<#{~?g0x2}JT4xKB{gH}E^UNQo#C07h*ann?!tT?yUT@YQe=Cf6;czW6fV zno%Ype}K~Iu^s9|VbO0Z0yOvMa#`;L1ecv6KQhUKeul;ZVU) zNx4*FpYqfZ8T<~V7v|T03ZCE4v%&(}Xp)3Mg)BP#x8~A(ehlA&j@L!$5w({oQ={%a z`}Mb;GjOVcgIFvQ#4lgUHTfFEH1=Dn!w>y?+P&s zRInGr|8~W=2Sn;XO!r-LGfY%*;JFb7th^bjxMk4s<1fL4)W|3jTR@PmC|`Vr_ys_i z?~@7woX(Pr?#VOKk7Nz^nR$6irG$=$UHS;f5(`Mu^vnDdK@F&S&028N!F)xD zm-vZ%rCfr2wV|0|okq{m$`s9-&(brR(6!XHtJ^^Alb>(ZLo7z-OHE;r$d9im3=B@*5>bVPaGjTSjeD0O3`Rri=!RvQ2A9C|N{SBHlAcghFNpEIeK&L>6Eh zPBRWZ6Q>P&eENaZc3sC19$`IY1XD8$@%;;4>4GM45aX^Fdt7YgQA%8h@VT9iocBa6 zaZ}#a&Q&u5Ou_r1sCi|ul+f*GLQ)S|+j3ZU5T&$WO6bv&j?ORdresWn!F$=7lkgLy)t$%Jkz%XSH{YVw{=aS|n(0ISrKE+7$_RX7!Es)e zx8jDejTmCu^%l02IOC@MK0>H_B2xwigO@O3 zE=A}*!OEa`0ot8Qnw87M3?#;C_OaW@P?ZVt!SR0MeQ93+ocTviW8uLr{UfKKWyncE zV@kR+0h;?s=Mre54+6@hhsU>dGF;a$?=^6pcFP|X z5XVX~jw$-0m2E^on3ThDIci!?AP{FFIv){M7UdTq0-dub%Z9H8!x-suGNRToeDd=p zAQ6yGF>AyB!oguZVN7lHDHIowFzfP(MUYEgzRzMT38I-Q4R9^)8sTdM0b5^_Sz_qF z0b5dvi)(l=34iYO!j#35u*O$75)Ut4xKtI2YLrCRU?9$)tBEz5F`F8>+Ltb&5r>KO zr=umtba%r|4$QxlYsJva-_B8!mxI+ZkXgI*hbT%7Y+0veHpW1tvp|44Ed-%Ae*KH{ zyx0LWT1)r3%H7GHalx_3-4eaO;@Wbf9nQ|JnmDj=J<6@0aj;gI0=dfYK_V2@r^b$0 zL|7;oJCklztkDfr+3C^w^8@%cn?RK}yKQ6i^Ku6z3;i&y(U3cQ*pq=YXPP%c>?o(GYWNj5c62*`@Xh_GVFC#gh?mJgzo3Nf3BgoB4m0$wz|4l} zOy#h|hh_$j|Hl+x)dC(<5;u-+TpazuD|g8Wi9=h6a1{5RdVo)Y14)~#Bh?(K4S!TT z3gB()uTto+wW7{~EW!bZr2SAJfE52iY4 zr--$f(vgt9;nIH#NSxb}yZEs#;-Z;|W??UCj(9i)3AO?Gbu0z?jTTpsgE@T7OiW7~ zoJ57=R4N!wS#XOotvjTO9-ES!Zbxu3#K+!a!XZU2f1crGCw52K$?oR_oa8}So5y)h zeorAeqn;G3Sf#VziwDlAvxf4d5!0T&`@`|-HtFSbd`jMfoV@FZsk$m&4O3@gX`2Iwnv*OkzX==4$Cq zgb5I+<|V?Q+xTFdQ8z;JFC%}s*)D%(%&S624*u#@zOw;Wv~tkdc7L+IJkr2^nX?mF z=PBUgdquATJVZ5<%{Bj`NS$$jf5uc20p8oK%v$BG;?~2YvV9SwqL=PjQQNLAE_{vp z1YEe=me)MU!bl{3j=uA1WOEWBmd2o@}?%G3w+3&+_|j$LhrH-niJbA8Uu> zeP{969fhZ{RyOPK5c1JSfGrK#>EynFLrHKS1z)ZNScF>H z#?mSa%M~Y2{3w0W+hb%&u%$z!cBodu&D}QDVBKGRuXulegQv5+U!YLrQ3fN0w z9B59DB@yhF$Ho<&uCh`_T4X9gr0?us9HSoru>Ck8mMCS&{8Sx>~}C+<>{HG&#YV4E4CGsBGm z-fB=_iK6e(a|=ILEyzMaN)gfxYC+ZIv4V>G9%-@U>A3{@w^1X(& z=kmQcL>k1-R>|itQC5Xsyr!mH_biChR&$^0$G|MrVLtj?_$61Miy3eRgh0hm_g|h* z4sXFz0(Divs6?XqK0xpfXL0x{z6v-{K#IV9VUW@ZeJ{vLhx9YmX!gpO?xnLhcj%jY z=RT;O+ZciVsx-9?Zj)ehz!j}-RRlc6JK}XPK1Mpucs3;Ap{;q_lgQ)b_#3)DsklAc zCS)8`H&omMDogqs&~y3zA?ZHelH3EJ6g!R@fH9F9{3(W;xne#Zb*}JH50hWEck31Q z{SqE5;nL?%G_cKGoyrNy^T_ZEJ9e(r-CF$@Y{+0+Op`oBl%ThZokscHiy1wh7|v4{ z{qb+jUR2ZmWxx}`4A6Hqok_{q~*@Bq3bwSOoSZUTeras#lv0azZJPzcIV<6`-zlV0^vi5Q4{ z+%{k^uf;I}+IAaI$1T~8CgJe9dSHlyDiFmHL^#K-F+d7UKgnYaDw?MmnJ1r(vz^Zx zOj*!#u1gjjB|k==%8=d$Okl$lHvl=44J7}|eGRJAGOYNAke?3oMp9kSla~ha^4~}@ z)jT7XyW&EFSY8?Yyz1r#h1q~9Pn6mGhEhkqc!Bsu8v_P>7W6$Qpw@~stZ;?2OtlK;dP3kg_WP2|D<1^AnkEblI+4mR(eFz102nE&hIr~(mpQh%i% zV#jizQ5|>XQ|~*@hWPujjQ{(L@ax?RR+wB}kH07Fvj^|S&yJ+H%~OTZ&uCn}Z_?he z$1vdg%crpR^K0%0=rOJDPLEi6c(eE9)>*@R8sH;)vgI)KF-tYDOJNP+3 z)AxN0BJQ=|He0`S7h$Q>Hd?sXy>1LD&Gn$rRVox z;&V`aSRmg75)pl1_B~lGy??FQ87h7gU|gXb=Ib)ReCCHD|M zJgQ?a=txdoUNd}g3t#VZi#)l#NvM6*Dc+n&`5;kR=Uu--d1MDc! zefOjMWWM|lOa{B`dQZds>)%kov#Z+MKNnX4G)5HReFH1Y2%L`r0oDu<|2lKhO~G+* z`}+|<0iZgAIS-}EV1BakLxgM2{B_WuA8yDG{8ur6L4d1I8Y~SGC)GduZzLGE!_%+3 z_jfz@-#0fm-FJu@eT065H#a|>3af8V5jSSNRD)j`!XBMvzhCClh^#mL%jq)PXZP~_ zzTbgrne)PU14;bd3ei*3-eT9gZtWLfr95zd1K`(?dj32=gq;F^{&9tfxCjQ<;j>+5 zxjmeqt+-UfzxkN+2~$$Pr178l1GDr%BKg9tZI`8hLIFTE&AZNd1#XQ5toB*g5O3%4 zuchK_{o}6fF*oCU2cLmdKPQ0$2|;(Jo&2f;cE|jIqvm+^IofXd`PG=D{PgEelyO{E z*dZ(ScqKp``T5vS3F6=HIs~8nx8i2uCxM@Ry=~`s``_;x_}$u`4~+b-um67n(er^* z&^7S)=uVgMS;D`$LS=`0SGn3<_#qDJuw7fvuWj57FKMK_CheoXEeCw|%MUQ20cCoy zVR!G1WdM9QnW^(*oEWVhfm=FL>u*FjQtRl*nj27IXj~(G%#(hF!BKUNXjgp-Vg|>- zTWdJ^HLUKO-T#XF=?((~+)w0#5ecBAprRe0_S*d2dWWr$#cTSaHT|$#+{V|_-;UjFy?v=xzm_l%!D};)RbiLfwMcBh=~9jE!KX=; zU(M*Tc`%%5;+djg;pM&;nr&()bkC9E7Pjb?pYb@;;Ac*>dqcQ8)Dl!QW-~M=Z`q|7 zk>SY*m%E$5daCxk=NMV4*q~(#l}c?l)tb5yGKqk#xUjlo*A=Q4PZ(c9#%!L|Z@?tE zv$a0#KL?tvoIF>!7&usFQS1sUX)g-foJT(EU4ruubav=6x%GtXqwUeX+1~mNVdZhG zQI6$DtoS2-Q6B_UZRrSc4=&WIPD1UkVO74=5j~O=;HX`)?aSVZVEbcnb%U)KPHuWp zX9HyGw%lEpZU88rC<<5B1iqA@$aP{(Ln$FgsfM51_J{!?pl7(mmCtpQycFf0uXcf&hiY z8@LX#l=<1x5Q)HlvzCy9FUN&}C#06UZ``xTAOAh-Bi_BH3VIhcxQ0^f^OHT36nxBb zXPjR!e@zLH{c}o4iIy1s+9hF%F+)8Tj`Icb(?a#{+-829ShL;Dc?M$lp}S+t&tlkb z)&fXiRl4899`d+Qr;TPIzlWOxqGti}{eJTQ2|ci4NM$p3*zIqljOrF$MW(uruLtYu zJ{1Um`?QimgsI%=r*_)q?uKYTu&%7}q;niAUq|1cZ|^w6QXJ3|_-|mfp)h$*Gwlh@ zC=IMTtvax8mB#)f1i1vuA+D^sUo-64<2rlmxFH5>HrHy-u!!IdSiRi*&%~miVARZw zbRofjOu*QEzi}{Z6$E!_{0l%v{{U~!Wll|5(Giilk7%L)ykt9Qi*LOe8+V1#2*q$CSLX^U+5a z4$3jQG~WaETt3i$8sPg9uM@Uwb;x-2!_RZaXWF-FT`iyiuqCb*$gEy$U(IC+U2I(` zM0##~B52IWx^W+p$QNxPxR$u3Ttg5Tge6s7NIiQ?r!8?lb8GK~=L7aM--_Sy2l2Jq z{9N1ZEkw+j+g~H{O?ASnUHMoQp+gBe4h+c4bt=4|ez5E)wUKw~>1=<`3VYu1*o((? zd39iV5S&7c&oT1Fn7kUR`>9{*q`q%ghSdBVJ2m^s-9xV5G*`wTuEWpCz0$m=t>0`O zU!6AIXx$43yJ;4)(N{3n8^-PX<$Tj=&6^VKfW91F@C&&kO3%>&&uGhdWl2Y zDe-2GFMFEh`&xayQHo)9oGLr`{2lCeR$H9QU-S821?{ifcYXo)wDZ;ZmdE>>Z=k&# z%Z!@PswC*{nGV9kK54Ua?&q$$Z>T*T9QgLvbiH1}&b}Gnv`T|2;Aa?bz5Aa!%CJ~O zJ$yCKKe|eD{ZWw1i(QXH`XX=GLh4_!62v~PW9qbpQU6i*sg%z$K4px+K`zq{zTOXx>2NEg>5EpSx_c9DY=3H*lVUq>tE5| z`9EMxhzGjH1qMGw$|P}TZ8H|@8+Jy z{q@g2@PyZ zZ_XHvj%FK92mha_MlZ`6Ux-oor-X=YFDWKPlZrWi7IB&W+1v#Gp?~=wNl;~Ns__U0 zuSLwWqrSo4p5)oK*Ljp~yMEcRSJr|taOD1F>+K{OnM)lxxBH`C5s7gqgk`fhfdvbT zaN>>7(KNG6+OynyBa)xYqIo~vuWK%0rO|nfyvO^uH`md95k$1O8{NH$C@{RXvc%c<~Jtx6@I8T^G#4X-sd2IH#*^ij+m^~oxZ2rhU`TQUG zWm>BXZ-vwtu`AWjLTBmd5Bq(eW+A!bgkeQ1SVo~siO)+bR*P8zw{6$KWkyeCQhZY0 zJa`RlGSe9e{0#l|Jdc;q#Rqckk6m9P^JWQgVOfuZ+{b{e`v|$jQE0uhA4=udec~(% zAtL#CN;51;TWQJydhtW>b?~3Ov;Up0b_x0|q&wQ|R5i=<1+*7Vx4|m$2l7b1DDRKB zRJ9R@(LmvZnv@$^+EE$&QnkCFAzRC%@W#Z76rRdSS=uho{LV};@q$_0ww8s*`WBfu zM`U^SJ<`6tC%@9gwZ`BzSlTi_mFrnFEkA43{(rs@)nee6Hj_*{gRdERf`9f3-~lI| zk3Mg{ZZCYi13r0HH}gXal__KO(|nCqUKSP(H;&@P;|7bS!|K!qM&%Ovha>%r{9>mw zvc10^8&DD8FxIii@Gh}7A29+%kJ}~|!a$z9$DX~f=12kP@Ku9-)hO@c^ zcr-V%ICwq&?155Hz?q-HS@I5qj=OUwFAb<{p^?^bHbOeWn+MkqG&pht+J!a&7buG|8KExoi}G5<*cSLzOn~ zqgHqpgRe;4Y=vLoJ@>z9v@*26N$gK>%^-Q2KOkEna*R%MKdoD5J)Y~nt zl*|?VYoY%(1RG0}c{SN)pKk$FSZ*<*JK9m$M`e&;t0%^Ugowk7Q#{tACfAx}i;8UFA0~x_Dc!+TC_UDnG8t<#Ei5*M zrZg6lnn4y2aBrV*NKWSRG+n#Q8{N;-1?lBvWoa85_Su@DH4X2m%TO0CWQbFCre8Ix3P}t{xg^11655P0fWZ6l>oNnbv zN1{e+ENo6Vh%v;xv+k68n~Zno%4JY6waQ@N9;h7y9u(-^Ll@bd%ko2SY*jZAmE(d# z9_DjIZd2Z{-c|S+tJ=921?}gB!R~xpQFts8Eanok^%Y_ol(Ho9h%wQs$K+o3xj9_> z$D)CusPH(BU^CK}Vp;Otwcv008}cRzFb6sXn<(E=4pT3$XV(=9w)fSi{^^=4oTF~h ziO(W#g7;-h4heGu+HzS=q3Z1+%cGg#J#lbP+KjwhqD@*IBiV|)F=z48KB@~lo3teOQ^ltd@>L&vp{;h&Kk=S_7l4>ei* za+eeoopluh(e3{UefZ}ziiw!$pewhEs^U=NpzZ`X{98zQXXqMv>dlozg-2|jL9sD6 z)A0)KTf%6k?NxH3K~`Lu z4+XGZ(anZ)qbhlV<9Q1cS6_d9#Gtt?BmmICz-cN)BC6;FLTh6U)dJ1=++f*^iUtj$zv?{brT#Xg; zRpl4YX*&?HV7>yPkh41N`)VYJpF@*Rn*U~tX2$eC{@~pA`mpMV%Y$BX1Ss5{ySAnw zz$d0|vNU(-CWwPdjDX3=p$B|0O~Ro#J~BxTzn$=8sopt?i_SK@#Ngic=4h~>Biy9& zUWT6wh}P9ZP@Tw@c&2(4%=gP|gi?{|zYO1k;gvlEK6&aRGzR-m$9cA%7ZsYh%o@CW zZr=5N`r?Q6BZw2_-LTZ1?Ym*dHTIWND`8C+*&hzZJ_Uk>>XNvrhdC%r>$-1>Km(@$ zR9aWfIGqKEEQGl)gh`!I312$<;B88A1>Tx zum0Vb_%KIBvKNg@{1+XSDAIhEACEi{uX^T_UhTP5V`9o2(ZK6dv#oN?n=+t5xec+=PNh21WX3wKNjx1;)Z|m zCF$-Ww~4jg=vLd)&`6-szkJ8(=_S{XwLs}!KdL4lb0AWAF1!$i|5JRe==4_Mnl~!; zUFk~5uTf{~nx0cD-PG9XUYHa=(-VQ=N$gT4J*~T{gUvuFbZXX<&do&Oy84n6 ztO=E}jp(y<-QD=NhgmKGVVzt>Ny9f10S8feF zO)8I-cl4-V5#>$8bIT@iy3549P21q->U^ZOg$QLB@v--X7aHhN z>miYnzKb--aJ>d^1)yWaK~d{Cq#Nd(3FJ?CgTs8Jq})(cdcyHBL+cLM{HOcvub6Pm z$694%ty1~*m)COI+O}PtGwh)z96~_0n}`ZK0n{?UFEQhq�rRb`0y|*v1_Y0K2x& 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 z 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%0A!*@!_1l*%gn{T*uEUOk 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

TW z_IDONo{|>HAW1G>TyRtpbmwk{?E;Qe^keeoFsDM3S=2db6)SXNcKE5%&&Ar#_N zpb@o8hS`1wgDDbLa&s+bs8dLKx3^4*zmN|i^7+?GCYx*0-1L2GVTM3%-hPWrrhz0e zbXNHB3HfPmGwCS)c;aGu`*;sb-s8nk=U{GPS59ihrvy=D!4Vx`q}533<6z$ck`Pyq z#Wp|O#O4)elSw*QD!!Er{iJ0~8m2>w=uzx@uM&gU0r$C!=YYmjU1aUBHf`trIflpm zFq{>9Y%Ab4N$mgk2oo{wij86SPzFIw|MoSMh>+=?vK%06Ri5?N6y32 zPWFhl#BhsY+gB&zX;_uy28Xzn@#4NH&UCg_=suUja2QPKb-V!m%U6KxcfYDXI(>KVeZLk1dpU8 zJ(yC4l)g7U9lQo+6a{OuE#k*r-jT#E>0I?o6F>I7yPufUqKPKv}ds~3-?2-x{@=kJ>}nO93O zI3+2XM938mPr#0cVU!2=Wwm_oC}TP=y|_@ywlY%`>@9xa$lSI=tkviJnbecM0g6D; z#gnR7xopbk>jjl(OpGP8cT&dDJ^}*|cYn&W;+mV3&0>yf)w#>nwHu1yokd8ym zQAEeQj_R{r_lrFHT8M}S83BAw2~OKeB5i}Q1uX)2R?d&}r0rzF4H>KEf;v|b}({Pj53@@LXZ!rbM&_B91^_?a$7^_jgH z_D&VwOkJ-?ckMq0-)0KKW|}6YyN3ro2heX%gbj1Kpnk|b734y1tAZb=i8QY5bMHOC zbUYV^l|Rp`f6{L!GWTHZr zoJeOTZ>=xYHk|0I*rr{Y?@X3*1y^kuJ3YGuir-S?3uMz24JJ&d@LXC^AIqx2430Mw zxhP8Ewks}5ddx7a%H&Pkvbe{q+$Hm?zRF9aZnQP@uchGsl#Cc}$!-uw4xA^8 zJTo>TdPw1Sw;2$~;fGv{;q(+?rngoV%qxM9sMp!{!D53t zHYX@;Z65KdeOE|7NY41K;ryCh*ITJZc-|E5k=47tbg`vkV>v}>cYd6|SMWCm>(jj> z(Y-IP3MMF`@7?wsDi;HW<_vO~T(l=k={JY>LsPax4pbFHZ{$NzksGQkw&_C{BRM

?-Y#xg4rj7}S3taUTj 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

{LABC35aZ+t^w!fb%kfniC0^^)fHUEz8(f& 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 Cetk@ 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

  • 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 z. + +Abstract + + This specification defines a lossless compressed data format. The + data can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a priori + bounded amount of intermediate storage. The format presently uses + the DEFLATE compression method but can be easily extended to use + other compression methods. It can be implemented readily in a manner + not covered by patents. This specification also defines the ADLER-32 + checksum (an extension and improvement of the Fletcher checksum), + used for detection of data corruption, and provides an algorithm for + computing it. + + + + +Deutsch & Gailly Informational [Page 1] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................ 3 + 1.6. Changes from previous versions ............................ 3 + 2. Detailed specification ......................................... 3 + 2.1. Overall conventions ....................................... 3 + 2.2. Data format ............................................... 4 + 2.3. Compliance ................................................ 7 + 3. References ..................................................... 7 + 4. Source code .................................................... 8 + 5. Security Considerations ........................................ 8 + 6. Acknowledgements ............................................... 8 + 7. Authors' Addresses ............................................. 8 + 8. Appendix: Rationale ............................................ 9 + 9. Appendix: Sample code ..........................................10 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + + * Can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a + priori bounded amount of intermediate storage, and hence can + be used in data communications or similar structures such as + Unix filters; + + * Can use a number of different compression methods; + + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely. + + The data format defined by this specification does not attempt to + allow random access to compressed data. + + + + + + + +Deutsch & Gailly Informational [Page 2] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into zlib format and/or decompress data from zlib + format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. + + 1.3. Scope + + The specification specifies a compressed data format that can be + used for in-memory compression of a sequence of arbitrary bytes. + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any data set that conforms to all + the specifications presented here; a compliant compressor must + produce data sets that conform to all the specifications presented + here. + + 1.5. Definitions of terms and conventions used + + byte: 8 bits stored or transmitted as a unit (same as an octet). + (For this specification, a byte is exactly 8 bits, even on + machines which store a character on a number of bits different + from 8.) See below, for the numbering of bits within a byte. + + 1.6. Changes from previous versions + + Version 3.1 was the first public release of this specification. + In version 3.2, some terminology was changed and the Adler-32 + sample code was rewritten for clarity. In version 3.3, the + support for a preset dictionary was introduced, and the + specification was converted to RFC style. + +2. Detailed specification + + 2.1. Overall conventions + + In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + + + +Deutsch & Gailly Informational [Page 3] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the MOST-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00000010|00001000| + +--------+--------+ + ^ ^ + | | + | + less significant byte = 8 + + more significant byte = 2 x 256 + + 2.2. Data format + + A zlib stream has the following structure: + + 0 1 + +---+---+ + |CMF|FLG| (more-->) + +---+---+ + + + + + + + + +Deutsch & Gailly Informational [Page 4] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + (if FLG.FDICT set) + + 0 1 2 3 + +---+---+---+---+ + | DICTID | (more-->) + +---+---+---+---+ + + +=====================+---+---+---+---+ + |...compressed data...| ADLER32 | + +=====================+---+---+---+---+ + + Any data which may appear after ADLER32 are not part of the zlib + stream. + + CMF (Compression Method and flags) + This byte is divided into a 4-bit compression method and a 4- + bit information field depending on the compression method. + + bits 0 to 3 CM Compression method + bits 4 to 7 CINFO Compression info + + CM (Compression method) + This identifies the compression method used in the file. CM = 8 + denotes the "deflate" compression method with a window size up + to 32K. This is the method used by gzip and PNG (see + references [1] and [2] in Chapter 3, below, for the reference + documents). CM = 15 is reserved. It might be used in a future + version of this specification to indicate the presence of an + extra field before the compressed data. + + CINFO (Compression info) + For CM = 8, CINFO is the base-2 logarithm of the LZ77 window + size, minus eight (CINFO=7 indicates a 32K window size). Values + of CINFO above 7 are not allowed in this version of the + specification. CINFO is not defined in this specification for + CM not equal to 8. + + FLG (FLaGs) + This flag byte is divided as follows: + + bits 0 to 4 FCHECK (check bits for CMF and FLG) + bit 5 FDICT (preset dictionary) + bits 6 to 7 FLEVEL (compression level) + + The FCHECK value must be such that CMF and FLG, when viewed as + a 16-bit unsigned integer stored in MSB order (CMF*256 + FLG), + is a multiple of 31. + + + + +Deutsch & Gailly Informational [Page 5] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + FDICT (Preset dictionary) + If FDICT is set, a DICT dictionary identifier is present + immediately after the FLG byte. The dictionary is a sequence of + bytes which are initially fed to the compressor without + producing any compressed output. DICT is the Adler-32 checksum + of this sequence of bytes (see the definition of ADLER32 + below). The decompressor can use this identifier to determine + which dictionary has been used by the compressor. + + FLEVEL (Compression level) + These flags are available for use by specific compression + methods. The "deflate" method (CM = 8) sets these flags as + follows: + + 0 - compressor used fastest algorithm + 1 - compressor used fast algorithm + 2 - compressor used default algorithm + 3 - compressor used maximum compression, slowest algorithm + + The information in FLEVEL is not needed for decompression; it + is there to indicate if recompression might be worthwhile. + + compressed data + For compression method 8, the compressed data is stored in the + deflate compressed data format as described in the document + "DEFLATE Compressed Data Format Specification" by L. Peter + Deutsch. (See reference [3] in Chapter 3, below) + + Other compressed data formats are not specified in this version + of the zlib specification. + + ADLER32 (Adler-32 checksum) + This contains a checksum value of the uncompressed data + (excluding any dictionary data) computed according to Adler-32 + algorithm. This algorithm is a 32-bit extension and improvement + of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073 + standard. See references [4] and [5] in Chapter 3, below) + + Adler-32 is composed of two sums accumulated per byte: s1 is + the sum of all bytes, s2 is the sum of all s1 values. Both sums + are done modulo 65521. s1 is initialized to 1, s2 to zero. The + Adler-32 checksum is stored as s2*65536 + s1 in most- + significant-byte first (network) order. + + + + + + + + +Deutsch & Gailly Informational [Page 6] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + 2.3. Compliance + + A compliant compressor must produce streams with correct CMF, FLG + and ADLER32, but need not support preset dictionaries. When the + zlib data format is used as part of another standard data format, + the compressor may use only preset dictionaries that are specified + by this other data format. If this other format does not use the + preset dictionary feature, the compressor must not set the FDICT + flag. + + A compliant decompressor must check CMF, FLG, and ADLER32, and + provide an error indication if any of these have incorrect values. + A compliant decompressor must give an error indication if CM is + not one of the values defined in this specification (only the + value 8 is permitted in this version), since another value could + indicate the presence of new features that would cause subsequent + data to be interpreted incorrectly. A compliant decompressor must + give an error indication if FDICT is set and DICTID is not the + identifier of a known preset dictionary. A decompressor may + ignore FLEVEL and still be compliant. When the zlib data format + is being used as a part of another standard format, a compliant + decompressor must support all the preset dictionaries specified by + the other format. When the other format does not use the preset + dictionary feature, a compliant decompressor must reject any + stream in which the FDICT flag is set. + +3. References + + [1] Deutsch, L.P.,"GZIP Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [2] Thomas Boutell, "PNG (Portable Network Graphics) specification", + available in ftp://ftp.uu.net/graphics/png/documents/ + + [3] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [4] Fletcher, J. G., "An Arithmetic Checksum for Serial + Transmissions," IEEE Transactions on Communications, Vol. COM-30, + No. 1, January 1982, pp. 247-252. + + [5] ITU-T Recommendation X.224, Annex D, "Checksum Algorithms," + November, 1993, pp. 144, 145. (Available from + gopher://info.itu.ch). ITU-T X.244 is also the same as ISO 8073. + + + + + + + +Deutsch & Gailly Informational [Page 7] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +4. Source code + + Source code for a C language implementation of a "zlib" compliant + library is available at ftp://ftp.uu.net/pub/archiving/zip/zlib/. + +5. Security Considerations + + A decoder that fails to check the ADLER32 checksum value may be + subject to undetected data corruption. + +6. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Jean-Loup Gailly and Mark Adler designed the zlib format and wrote + the related software described in this specification. Glenn + Randers-Pehrson converted this document to RFC and HTML format. + +7. Authors' Addresses + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + + Jean-Loup Gailly + + EMail: + + Questions about the technical content of this specification can be + sent by email to + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + + + + +Deutsch & Gailly Informational [Page 8] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +8. Appendix: Rationale + + 8.1. Preset dictionaries + + A preset dictionary is specially useful to compress short input + sequences. The compressor can take advantage of the dictionary + context to encode the input in a more compact manner. The + decompressor can be initialized with the appropriate context by + virtually decompressing a compressed version of the dictionary + without producing any output. However for certain compression + algorithms such as the deflate algorithm this operation can be + achieved without actually performing any decompression. + + The compressor and the decompressor must use exactly the same + dictionary. The dictionary may be fixed or may be chosen among a + certain number of predefined dictionaries, according to the kind + of input data. The decompressor can determine which dictionary has + been chosen by the compressor by checking the dictionary + identifier. This document does not specify the contents of + predefined dictionaries, since the optimal dictionaries are + application specific. Standard data formats using this feature of + the zlib specification must precisely define the allowed + dictionaries. + + 8.2. The Adler-32 algorithm + + The Adler-32 algorithm is much faster than the CRC32 algorithm yet + still provides an extremely low probability of undetected errors. + + The modulo on unsigned long accumulators can be delayed for 5552 + bytes, so the modulo operation time is negligible. If the bytes + are a, b, c, the second sum is 3a + 2b + c + 3, and so is position + and order sensitive, unlike the first sum, which is just a + checksum. That 65521 is prime is important to avoid a possible + large class of two-byte errors that leave the check unchanged. + (The Fletcher checksum uses 255, which is not prime and which also + makes the Fletcher check insensitive to single byte changes 0 <-> + 255.) + + The sum s1 is initialized to 1 instead of zero to make the length + of the sequence part of s2, so that the length does not have to be + checked separately. (Any sequence of zeroes has a Fletcher + checksum of zero.) + + + + + + + + +Deutsch & Gailly Informational [Page 9] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +9. Appendix: Sample code + + The following C code computes the Adler-32 checksum of a data buffer. + It is written for clarity, not for speed. The sample code is in the + ANSI C programming language. Non C users may find it easier to read + with these hints: + + & Bitwise AND operator. + >> Bitwise right shift operator. When applied to an + unsigned quantity, as here, right shift inserts zero bit(s) + at the left. + << Bitwise left shift operator. Left shift inserts zero + bit(s) at the right. + ++ "n++" increments the variable n. + % modulo operator: a % b is the remainder of a divided by b. + + #define BASE 65521 /* largest prime smaller than 65536 */ + + /* + Update a running Adler-32 checksum with the bytes buf[0..len-1] + and return the updated checksum. The Adler-32 checksum should be + initialized to 1. + + Usage example: + + unsigned long adler = 1L; + + while (read_buffer(buffer, length) != EOF) { + adler = update_adler32(adler, buffer, length); + } + if (adler != original_adler) error(); + */ + unsigned long update_adler32(unsigned long adler, + unsigned char *buf, int len) + { + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int n; + + for (n = 0; n < len; n++) { + s1 = (s1 + buf[n]) % BASE; + s2 = (s2 + s1) % BASE; + } + return (s2 << 16) + s1; + } + + /* Return the adler32 of the bytes buf[0..len-1] */ + + + + +Deutsch & Gailly Informational [Page 10] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + unsigned long adler32(unsigned char *buf, int len) + { + return update_adler32(1L, buf, len); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Deutsch & Gailly Informational [Page 11] + diff --git a/doc/rfc1951.txt b/doc/rfc1951.txt new file mode 100644 index 0000000000..403c8c722f --- /dev/null +++ b/doc/rfc1951.txt @@ -0,0 +1,955 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1951 Aladdin Enterprises +Category: Informational May 1996 + + + DEFLATE Compressed Data Format Specification version 1.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format that + compresses data using a combination of the LZ77 algorithm and Huffman + coding, with efficiency comparable to the best currently available + general-purpose compression methods. The data can be produced or + consumed, even for an arbitrarily long sequentially presented input + data stream, using only an a priori bounded amount of intermediate + storage. The format can be implemented readily in a manner not + covered by patents. + + + + + + + + +Deutsch Informational [Page 1] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................ 3 + 1.6. Changes from previous versions ............................ 4 + 2. Compressed representation overview ............................. 4 + 3. Detailed specification ......................................... 5 + 3.1. Overall conventions ....................................... 5 + 3.1.1. Packing into bytes .................................. 5 + 3.2. Compressed block format ................................... 6 + 3.2.1. Synopsis of prefix and Huffman coding ............... 6 + 3.2.2. Use of Huffman coding in the "deflate" format ....... 7 + 3.2.3. Details of block format ............................. 9 + 3.2.4. Non-compressed blocks (BTYPE=00) ................... 11 + 3.2.5. Compressed blocks (length and distance codes) ...... 11 + 3.2.6. Compression with fixed Huffman codes (BTYPE=01) .... 12 + 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) .. 13 + 3.3. Compliance ............................................... 14 + 4. Compression algorithm details ................................. 14 + 5. References .................................................... 16 + 6. Security Considerations ....................................... 16 + 7. Source code ................................................... 16 + 8. Acknowledgements .............................................. 16 + 9. Author's Address .............................................. 17 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + * Can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a + priori bounded amount of intermediate storage, and hence + can be used in data communications or similar structures + such as Unix filters; + * Compresses data with efficiency comparable to the best + currently available general-purpose compression methods, + and in particular considerably better than the "compress" + program; + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely; + + + +Deutsch Informational [Page 2] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + * Is compatible with the file format produced by the current + widely used gzip utility, in that conforming decompressors + will be able to read data produced by the existing gzip + compressor. + + The data format defined by this specification does not attempt to: + + * Allow random access to compressed data; + * Compress specialized data (e.g., raster graphics) as well + as the best currently available specialized algorithms. + + A simple counting argument shows that no lossless compression + algorithm can compress every possible input data set. For the + format defined here, the worst case expansion is 5 bytes per 32K- + byte block, i.e., a size increase of 0.015% for large data sets. + English text usually compresses by a factor of 2.5 to 3; + executable files usually compress somewhat less; graphical data + such as raster images may compress much more. + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into "deflate" format and/or decompress data from + "deflate" format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. Familiarity with the technique of Huffman coding + is helpful but not required. + + 1.3. Scope + + The specification specifies a method for representing a sequence + of bytes as a (usually shorter) sequence of bits, and a method for + packing the latter bit sequence into bytes. + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any data set that conforms to all + the specifications presented here; a compliant compressor must + produce data sets that conform to all the specifications presented + here. + + 1.5. Definitions of terms and conventions used + + Byte: 8 bits stored or transmitted as a unit (same as an octet). + For this specification, a byte is exactly 8 bits, even on machines + + + +Deutsch Informational [Page 3] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + which store a character on a number of bits different from eight. + See below, for the numbering of bits within a byte. + + String: a sequence of arbitrary bytes. + + 1.6. Changes from previous versions + + There have been no technical changes to the deflate format since + version 1.1 of this specification. In version 1.2, some + terminology was changed. Version 1.3 is a conversion of the + specification to RFC style. + +2. Compressed representation overview + + A compressed data set consists of a series of blocks, corresponding + to successive blocks of input data. The block sizes are arbitrary, + except that non-compressible blocks are limited to 65,535 bytes. + + Each block is compressed using a combination of the LZ77 algorithm + and Huffman coding. The Huffman trees for each block are independent + of those for previous or subsequent blocks; the LZ77 algorithm may + use a reference to a duplicated string occurring in a previous block, + up to 32K input bytes before. + + Each block consists of two parts: a pair of Huffman code trees that + describe the representation of the compressed data part, and a + compressed data part. (The Huffman trees themselves are compressed + using Huffman encoding.) The compressed data consists of a series of + elements of two types: literal bytes (of strings that have not been + detected as duplicated within the previous 32K input bytes), and + pointers to duplicated strings, where a pointer is represented as a + pair . The representation used in the + "deflate" format limits distances to 32K bytes and lengths to 258 + bytes, but does not limit the size of a block, except for + uncompressible blocks, which are limited as noted above. + + Each type of value (literals, distances, and lengths) in the + compressed data is represented using a Huffman code, using one code + tree for literals and lengths and a separate code tree for distances. + The code trees for each block appear in a compact form just before + the compressed data for that block. + + + + + + + + + + +Deutsch Informational [Page 4] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +3. Detailed specification + + 3.1. Overall conventions In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the least-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00001000|00000010| + +--------+--------+ + ^ ^ + | | + | + more significant byte = 2 x 256 + + less significant byte = 8 + + 3.1.1. Packing into bytes + + This document does not address the issue of the order in which + bits of a byte are transmitted on a bit-sequential medium, + since the final data format described here is byte- rather than + + + +Deutsch Informational [Page 5] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + bit-oriented. However, we describe the compressed block format + in below, as a sequence of data elements of various bit + lengths, not a sequence of bytes. We must therefore specify + how to pack these data elements into bytes to form the final + compressed byte sequence: + + * Data elements are packed into bytes in order of + increasing bit number within the byte, i.e., starting + with the least-significant bit of the byte. + * Data elements other than Huffman codes are packed + starting with the least-significant bit of the data + element. + * Huffman codes are packed starting with the most- + significant bit of the code. + + In other words, if one were to print out the compressed data as + a sequence of bytes, starting with the first byte at the + *right* margin and proceeding to the *left*, with the most- + significant bit of each byte on the left as usual, one would be + able to parse the result from right to left, with fixed-width + elements in the correct MSB-to-LSB order and Huffman codes in + bit-reversed order (i.e., with the first bit of the code in the + relative LSB position). + + 3.2. Compressed block format + + 3.2.1. Synopsis of prefix and Huffman coding + + Prefix coding represents symbols from an a priori known + alphabet by bit sequences (codes), one code for each symbol, in + a manner such that different symbols may be represented by bit + sequences of different lengths, but a parser can always parse + an encoded string unambiguously symbol-by-symbol. + + We define a prefix code in terms of a binary tree in which the + two edges descending from each non-leaf node are labeled 0 and + 1 and in which the leaf nodes correspond one-for-one with (are + labeled with) the symbols of the alphabet; then the code for a + symbol is the sequence of 0's and 1's on the edges leading from + the root to the leaf labeled with that symbol. For example: + + + + + + + + + + + +Deutsch Informational [Page 6] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + /\ Symbol Code + 0 1 ------ ---- + / \ A 00 + /\ B B 1 + 0 1 C 011 + / \ D 010 + A /\ + 0 1 + / \ + D C + + A parser can decode the next symbol from an encoded input + stream by walking down the tree from the root, at each step + choosing the edge corresponding to the next input bit. + + Given an alphabet with known symbol frequencies, the Huffman + algorithm allows the construction of an optimal prefix code + (one which represents strings with those symbol frequencies + using the fewest bits of any possible prefix codes for that + alphabet). Such a code is called a Huffman code. (See + reference [1] in Chapter 5, references for additional + information on Huffman codes.) + + Note that in the "deflate" format, the Huffman codes for the + various alphabets must not exceed certain maximum code lengths. + This constraint complicates the algorithm for computing code + lengths from symbol frequencies. Again, see Chapter 5, + references for details. + + 3.2.2. Use of Huffman coding in the "deflate" format + + The Huffman codes used for each alphabet in the "deflate" + format have two additional rules: + + * All codes of a given bit length have lexicographically + consecutive values, in the same order as the symbols + they represent; + + * Shorter codes lexicographically precede longer codes. + + + + + + + + + + + + +Deutsch Informational [Page 7] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + We could recode the example above to follow this rule as + follows, assuming that the order of the alphabet is ABCD: + + Symbol Code + ------ ---- + A 10 + B 0 + C 110 + D 111 + + I.e., 0 precedes 10 which precedes 11x, and 110 and 111 are + lexicographically consecutive. + + Given this rule, we can define the Huffman code for an alphabet + just by giving the bit lengths of the codes for each symbol of + the alphabet in order; this is sufficient to determine the + actual codes. In our example, the code is completely defined + by the sequence of bit lengths (2, 1, 3, 3). The following + algorithm generates the codes as integers, intended to be read + from most- to least-significant bit. The code lengths are + initially in tree[I].Len; the codes are produced in + tree[I].Code. + + 1) Count the number of codes for each code length. Let + bl_count[N] be the number of codes of length N, N >= 1. + + 2) Find the numerical value of the smallest code for each + code length: + + code = 0; + bl_count[0] = 0; + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits-1]) << 1; + next_code[bits] = code; + } + + 3) Assign numerical values to all codes, using consecutive + values for all codes of the same length with the base + values determined at step 2. Codes that are never used + (which have a bit length of zero) must not be assigned a + value. + + for (n = 0; n <= max_code; n++) { + len = tree[n].Len; + if (len != 0) { + tree[n].Code = next_code[len]; + next_code[len]++; + } + + + +Deutsch Informational [Page 8] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + } + + Example: + + Consider the alphabet ABCDEFGH, with bit lengths (3, 3, 3, 3, + 3, 2, 4, 4). After step 1, we have: + + N bl_count[N] + - ----------- + 2 1 + 3 5 + 4 2 + + Step 2 computes the following next_code values: + + N next_code[N] + - ------------ + 1 0 + 2 0 + 3 2 + 4 14 + + Step 3 produces the following code values: + + Symbol Length Code + ------ ------ ---- + A 3 010 + B 3 011 + C 3 100 + D 3 101 + E 3 110 + F 2 00 + G 4 1110 + H 4 1111 + + 3.2.3. Details of block format + + Each block of compressed data begins with 3 header bits + containing the following data: + + first bit BFINAL + next 2 bits BTYPE + + Note that the header bits do not necessarily begin on a byte + boundary, since a block does not necessarily occupy an integral + number of bytes. + + + + + +Deutsch Informational [Page 9] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + BFINAL is set if and only if this is the last block of the data + set. + + BTYPE specifies how the data are compressed, as follows: + + 00 - no compression + 01 - compressed with fixed Huffman codes + 10 - compressed with dynamic Huffman codes + 11 - reserved (error) + + The only difference between the two compressed cases is how the + Huffman codes for the literal/length and distance alphabets are + defined. + + In all cases, the decoding algorithm for the actual data is as + follows: + + do + read block header from input stream. + if stored with no compression + skip any remaining bits in current partially + processed byte + read LEN and NLEN (see next section) + copy LEN bytes of data to output + otherwise + if compressed with dynamic Huffman codes + read representation of code trees (see + subsection below) + loop (until end of block code recognized) + decode literal/length value from input stream + if value < 256 + copy value (literal byte) to output stream + otherwise + if value = end of block (256) + break from loop + otherwise (value = 257..285) + decode distance from input stream + + move backwards distance bytes in the output + stream, and copy length bytes from this + position to the output stream. + end loop + while not last block + + Note that a duplicated string reference may refer to a string + in a previous block; i.e., the backward distance may cross one + or more block boundaries. However a distance cannot refer past + the beginning of the output stream. (An application using a + + + +Deutsch Informational [Page 10] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + preset dictionary might discard part of the output stream; a + distance can refer to that part of the output stream anyway) + Note also that the referenced string may overlap the current + position; for example, if the last 2 bytes decoded have values + X and Y, a string reference with + adds X,Y,X,Y,X to the output stream. + + We now specify each compression method in turn. + + 3.2.4. Non-compressed blocks (BTYPE=00) + + Any bits of input up to the next byte boundary are ignored. + The rest of the block consists of the following information: + + 0 1 2 3 4... + +---+---+---+---+================================+ + | LEN | NLEN |... LEN bytes of literal data...| + +---+---+---+---+================================+ + + LEN is the number of data bytes in the block. NLEN is the + one's complement of LEN. + + 3.2.5. Compressed blocks (length and distance codes) + + As noted above, encoded data blocks in the "deflate" format + consist of sequences of symbols drawn from three conceptually + distinct alphabets: either literal bytes, from the alphabet of + byte values (0..255), or pairs, + where the length is drawn from (3..258) and the distance is + drawn from (1..32,768). In fact, the literal and length + alphabets are merged into a single alphabet (0..285), where + values 0..255 represent literal bytes, the value 256 indicates + end-of-block, and values 257..285 represent length codes + (possibly in conjunction with extra bits following the symbol + code) as follows: + + + + + + + + + + + + + + + + +Deutsch Informational [Page 11] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + Extra Extra Extra + Code Bits Length(s) Code Bits Lengths Code Bits Length(s) + ---- ---- ------ ---- ---- ------- ---- ---- ------- + 257 0 3 267 1 15,16 277 4 67-82 + 258 0 4 268 1 17,18 278 4 83-98 + 259 0 5 269 2 19-22 279 4 99-114 + 260 0 6 270 2 23-26 280 4 115-130 + 261 0 7 271 2 27-30 281 5 131-162 + 262 0 8 272 2 31-34 282 5 163-194 + 263 0 9 273 3 35-42 283 5 195-226 + 264 0 10 274 3 43-50 284 5 227-257 + 265 1 11,12 275 3 51-58 285 0 258 + 266 1 13,14 276 3 59-66 + + The extra bits should be interpreted as a machine integer + stored with the most-significant bit first, e.g., bits 1110 + represent the value 14. + + Extra Extra Extra + Code Bits Dist Code Bits Dist Code Bits Distance + ---- ---- ---- ---- ---- ------ ---- ---- -------- + 0 0 1 10 4 33-48 20 9 1025-1536 + 1 0 2 11 4 49-64 21 9 1537-2048 + 2 0 3 12 5 65-96 22 10 2049-3072 + 3 0 4 13 5 97-128 23 10 3073-4096 + 4 1 5,6 14 6 129-192 24 11 4097-6144 + 5 1 7,8 15 6 193-256 25 11 6145-8192 + 6 2 9-12 16 7 257-384 26 12 8193-12288 + 7 2 13-16 17 7 385-512 27 12 12289-16384 + 8 3 17-24 18 8 513-768 28 13 16385-24576 + 9 3 25-32 19 8 769-1024 29 13 24577-32768 + + 3.2.6. Compression with fixed Huffman codes (BTYPE=01) + + The Huffman codes for the two alphabets are fixed, and are not + represented explicitly in the data. The Huffman code lengths + for the literal/length alphabet are: + + Lit Value Bits Codes + --------- ---- ----- + 0 - 143 8 00110000 through + 10111111 + 144 - 255 9 110010000 through + 111111111 + 256 - 279 7 0000000 through + 0010111 + 280 - 287 8 11000000 through + 11000111 + + + +Deutsch Informational [Page 12] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + The code lengths are sufficient to generate the actual codes, + as described above; we show the codes in the table for added + clarity. Literal/length values 286-287 will never actually + occur in the compressed data, but participate in the code + construction. + + Distance codes 0-31 are represented by (fixed-length) 5-bit + codes, with possible additional bits as shown in the table + shown in Paragraph 3.2.5, above. Note that distance codes 30- + 31 will never actually occur in the compressed data. + + 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) + + The Huffman codes for the two alphabets appear in the block + immediately after the header bits and before the actual + compressed data, first the literal/length code and then the + distance code. Each code is defined by a sequence of code + lengths, as discussed in Paragraph 3.2.2, above. For even + greater compactness, the code length sequences themselves are + compressed using a Huffman code. The alphabet for code lengths + is as follows: + + 0 - 15: Represent code lengths of 0 - 15 + 16: Copy the previous code length 3 - 6 times. + The next 2 bits indicate repeat length + (0 = 3, ... , 3 = 6) + Example: Codes 8, 16 (+2 bits 11), + 16 (+2 bits 10) will expand to + 12 code lengths of 8 (1 + 6 + 5) + 17: Repeat a code length of 0 for 3 - 10 times. + (3 bits of length) + 18: Repeat a code length of 0 for 11 - 138 times + (7 bits of length) + + A code length of 0 indicates that the corresponding symbol in + the literal/length or distance alphabet will not occur in the + block, and should not participate in the Huffman code + construction algorithm given earlier. If only one distance + code is used, it is encoded using one bit, not zero bits; in + this case there is a single code length of one, with one unused + code. One distance code of zero bits means that there are no + distance codes used at all (the data is all literals). + + We can now define the format of the block: + + 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286) + 5 Bits: HDIST, # of Distance codes - 1 (1 - 32) + 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19) + + + +Deutsch Informational [Page 13] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + (HCLEN + 4) x 3 bits: code lengths for the code length + alphabet given just above, in the order: 16, 17, 18, + 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + + These code lengths are interpreted as 3-bit integers + (0-7); as above, a code length of 0 means the + corresponding symbol (literal/length or distance code + length) is not used. + + HLIT + 257 code lengths for the literal/length alphabet, + encoded using the code length Huffman code + + HDIST + 1 code lengths for the distance alphabet, + encoded using the code length Huffman code + + The actual compressed data of the block, + encoded using the literal/length and distance Huffman + codes + + The literal/length symbol 256 (end of data), + encoded using the literal/length Huffman code + + The code length repeat codes can cross from HLIT + 257 to the + HDIST + 1 code lengths. In other words, all code lengths form + a single sequence of HLIT + HDIST + 258 values. + + 3.3. Compliance + + A compressor may limit further the ranges of values specified in + the previous section and still be compliant; for example, it may + limit the range of backward pointers to some value smaller than + 32K. Similarly, a compressor may limit the size of blocks so that + a compressible block fits in memory. + + A compliant decompressor must accept the full range of possible + values defined in the previous section, and must accept blocks of + arbitrary size. + +4. Compression algorithm details + + While it is the intent of this document to define the "deflate" + compressed data format without reference to any particular + compression algorithm, the format is related to the compressed + formats produced by LZ77 (Lempel-Ziv 1977, see reference [2] below); + since many variations of LZ77 are patented, it is strongly + recommended that the implementor of a compressor follow the general + algorithm presented here, which is known not to be patented per se. + The material in this section is not part of the definition of the + + + +Deutsch Informational [Page 14] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + specification per se, and a compressor need not follow it in order to + be compliant. + + The compressor terminates a block when it determines that starting a + new block with fresh trees would be useful, or when the block size + fills up the compressor's block buffer. + + The compressor uses a chained hash table to find duplicated strings, + using a hash function that operates on 3-byte sequences. At any + given point during compression, let XYZ be the next 3 input bytes to + be examined (not necessarily all different, of course). First, the + compressor examines the hash chain for XYZ. If the chain is empty, + the compressor simply writes out X as a literal byte and advances one + byte in the input. If the hash chain is not empty, indicating that + the sequence XYZ (or, if we are unlucky, some other 3 bytes with the + same hash function value) has occurred recently, the compressor + compares all strings on the XYZ hash chain with the actual input data + sequence starting at the current point, and selects the longest + match. + + The compressor searches the hash chains starting with the most recent + strings, to favor small distances and thus take advantage of the + Huffman encoding. The hash chains are singly linked. There are no + deletions from the hash chains; the algorithm simply discards matches + that are too old. To avoid a worst-case situation, very long hash + chains are arbitrarily truncated at a certain length, determined by a + run-time parameter. + + To improve overall compression, the compressor optionally defers the + selection of matches ("lazy matching"): after a match of length N has + been found, the compressor searches for a longer match starting at + the next input byte. If it finds a longer match, it truncates the + previous match to a length of one (thus producing a single literal + byte) and then emits the longer match. Otherwise, it emits the + original match, and, as described above, advances N bytes before + continuing. + + Run-time parameters also control this "lazy match" procedure. If + compression ratio is most important, the compressor attempts a + complete second search regardless of the length of the first match. + In the normal case, if the current match is "long enough", the + compressor reduces the search for a longer match, thus speeding up + the process. If speed is most important, the compressor inserts new + strings in the hash table only when no match was found, or when the + match is not "too long". This degrades the compression ratio but + saves time since there are both fewer insertions and fewer searches. + + + + + +Deutsch Informational [Page 15] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +5. References + + [1] Huffman, D. A., "A Method for the Construction of Minimum + Redundancy Codes", Proceedings of the Institute of Radio + Engineers, September 1952, Volume 40, Number 9, pp. 1098-1101. + + [2] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data + Compression", IEEE Transactions on Information Theory, Vol. 23, + No. 3, pp. 337-343. + + [3] Gailly, J.-L., and Adler, M., ZLIB documentation and sources, + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [4] Gailly, J.-L., and Adler, M., GZIP documentation and sources, + available as gzip-*.tar in ftp://prep.ai.mit.edu/pub/gnu/ + + [5] Schwartz, E. S., and Kallick, B. "Generating a canonical prefix + encoding." Comm. ACM, 7,3 (Mar. 1964), pp. 166-169. + + [6] Hirschberg and Lelewer, "Efficient decoding of prefix codes," + Comm. ACM, 33,4, April 1990, pp. 449-459. + +6. Security Considerations + + Any data compression method involves the reduction of redundancy in + the data. Consequently, any corruption of the data is likely to have + severe effects and be difficult to correct. Uncompressed text, on + the other hand, will probably still be readable despite the presence + of some corrupted bytes. + + It is recommended that systems using this data format provide some + means of validating the integrity of the compressed data. See + reference [3], for example. + +7. Source code + + Source code for a C language implementation of a "deflate" compliant + compressor and decompressor is available within the zlib package at + ftp://ftp.uu.net/pub/archiving/zip/zlib/. + +8. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Phil Katz designed the deflate format. Jean-Loup Gailly and Mark + Adler wrote the related software described in this specification. + Glenn Randers-Pehrson converted this document to RFC and HTML format. + + + +Deutsch Informational [Page 16] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +9. Author's Address + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + Questions about the technical content of this specification can be + sent by email to: + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to: + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Deutsch Informational [Page 17] + diff --git a/doc/rfc1952.txt b/doc/rfc1952.txt new file mode 100644 index 0000000000..14c0c72eb2 --- /dev/null +++ b/doc/rfc1952.txt @@ -0,0 +1,675 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1952 Aladdin Enterprises +Category: Informational May 1996 + + + GZIP file format specification version 4.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format that is + compatible with the widely used GZIP utility. The format includes a + cyclic redundancy check value for detecting data corruption. The + format presently uses the DEFLATE method of compression but can be + easily extended to use other compression methods. The format can be + implemented readily in a manner not covered by patents. + + + + + + + + + + +Deutsch Informational [Page 1] + +RFC 1952 GZIP File Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................. 3 + 1.6. Changes from previous versions ............................ 3 + 2. Detailed specification ......................................... 4 + 2.1. Overall conventions ....................................... 4 + 2.2. File format ............................................... 5 + 2.3. Member format ............................................. 5 + 2.3.1. Member header and trailer ........................... 6 + 2.3.1.1. Extra field ................................... 8 + 2.3.1.2. Compliance .................................... 9 + 3. References .................................................. 9 + 4. Security Considerations .................................... 10 + 5. Acknowledgements ........................................... 10 + 6. Author's Address ........................................... 10 + 7. Appendix: Jean-Loup Gailly's gzip utility .................. 11 + 8. Appendix: Sample CRC Code .................................. 11 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + * Can compress or decompress a data stream (as opposed to a + randomly accessible file) to produce another data stream, + using only an a priori bounded amount of intermediate + storage, and hence can be used in data communications or + similar structures such as Unix filters; + * Compresses data with efficiency comparable to the best + currently available general-purpose compression methods, + and in particular considerably better than the "compress" + program; + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely; + * Is compatible with the file format produced by the current + widely used gzip utility, in that conforming decompressors + will be able to read data produced by the existing gzip + compressor. + + + + +Deutsch Informational [Page 2] + +RFC 1952 GZIP File Format Specification May 1996 + + + The data format defined by this specification does not attempt to: + + * Provide random access to compressed data; + * Compress specialized data (e.g., raster graphics) as well as + the best currently available specialized algorithms. + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into gzip format and/or decompress data from gzip + format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. + + 1.3. Scope + + The specification specifies a compression method and a file format + (the latter assuming only that a file can store a sequence of + arbitrary bytes). It does not specify any particular interface to + a file system or anything about character sets or encodings + (except for file names and comments, which are optional). + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any file that conforms to all the + specifications presented here; a compliant compressor must produce + files that conform to all the specifications presented here. The + material in the appendices is not part of the specification per se + and is not relevant to compliance. + + 1.5. Definitions of terms and conventions used + + byte: 8 bits stored or transmitted as a unit (same as an octet). + (For this specification, a byte is exactly 8 bits, even on + machines which store a character on a number of bits different + from 8.) See below for the numbering of bits within a byte. + + 1.6. Changes from previous versions + + There have been no technical changes to the gzip format since + version 4.1 of this specification. In version 4.2, some + terminology was changed, and the sample CRC code was rewritten for + clarity and to eliminate the requirement for the caller to do pre- + and post-conditioning. Version 4.3 is a conversion of the + specification to RFC style. + + + +Deutsch Informational [Page 3] + +RFC 1952 GZIP File Format Specification May 1996 + + +2. Detailed specification + + 2.1. Overall conventions + + In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + This document does not address the issue of the order in which + bits of a byte are transmitted on a bit-sequential medium, since + the data format described here is byte- rather than bit-oriented. + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the least-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00001000|00000010| + +--------+--------+ + ^ ^ + | | + | + more significant byte = 2 x 256 + + less significant byte = 8 + + + +Deutsch Informational [Page 4] + +RFC 1952 GZIP File Format Specification May 1996 + + + 2.2. File format + + A gzip file consists of a series of "members" (compressed data + sets). The format of each member is specified in the following + section. The members simply appear one after another in the file, + with no additional information before, between, or after them. + + 2.3. Member format + + Each member has the following structure: + + +---+---+---+---+---+---+---+---+---+---+ + |ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->) + +---+---+---+---+---+---+---+---+---+---+ + + (if FLG.FEXTRA set) + + +---+---+=================================+ + | XLEN |...XLEN bytes of "extra field"...| (more-->) + +---+---+=================================+ + + (if FLG.FNAME set) + + +=========================================+ + |...original file name, zero-terminated...| (more-->) + +=========================================+ + + (if FLG.FCOMMENT set) + + +===================================+ + |...file comment, zero-terminated...| (more-->) + +===================================+ + + (if FLG.FHCRC set) + + +---+---+ + | CRC16 | + +---+---+ + + +=======================+ + |...compressed blocks...| (more-->) + +=======================+ + + 0 1 2 3 4 5 6 7 + +---+---+---+---+---+---+---+---+ + | CRC32 | ISIZE | + +---+---+---+---+---+---+---+---+ + + + + +Deutsch Informational [Page 5] + +RFC 1952 GZIP File Format Specification May 1996 + + + 2.3.1. Member header and trailer + + ID1 (IDentification 1) + ID2 (IDentification 2) + These have the fixed values ID1 = 31 (0x1f, \037), ID2 = 139 + (0x8b, \213), to identify the file as being in gzip format. + + CM (Compression Method) + This identifies the compression method used in the file. CM + = 0-7 are reserved. CM = 8 denotes the "deflate" + compression method, which is the one customarily used by + gzip and which is documented elsewhere. + + FLG (FLaGs) + This flag byte is divided into individual bits as follows: + + bit 0 FTEXT + bit 1 FHCRC + bit 2 FEXTRA + bit 3 FNAME + bit 4 FCOMMENT + bit 5 reserved + bit 6 reserved + bit 7 reserved + + If FTEXT is set, the file is probably ASCII text. This is + an optional indication, which the compressor may set by + checking a small amount of the input data to see whether any + non-ASCII characters are present. In case of doubt, FTEXT + is cleared, indicating binary data. For systems which have + different file formats for ascii text and binary data, the + decompressor can use FTEXT to choose the appropriate format. + We deliberately do not specify the algorithm used to set + this bit, since a compressor always has the option of + leaving it cleared and a decompressor always has the option + of ignoring it and letting some other program handle issues + of data conversion. + + If FHCRC is set, a CRC16 for the gzip header is present, + immediately before the compressed data. The CRC16 consists + of the two least significant bytes of the CRC32 for all + bytes of the gzip header up to and not including the CRC16. + [The FHCRC bit was never set by versions of gzip up to + 1.2.4, even though it was documented with a different + meaning in gzip 1.2.4.] + + If FEXTRA is set, optional extra fields are present, as + described in a following section. + + + +Deutsch Informational [Page 6] + +RFC 1952 GZIP File Format Specification May 1996 + + + If FNAME is set, an original file name is present, + terminated by a zero byte. The name must consist of ISO + 8859-1 (LATIN-1) characters; on operating systems using + EBCDIC or any other character set for file names, the name + must be translated to the ISO LATIN-1 character set. This + is the original name of the file being compressed, with any + directory components removed, and, if the file being + compressed is on a file system with case insensitive names, + forced to lower case. There is no original file name if the + data was compressed from a source other than a named file; + for example, if the source was stdin on a Unix system, there + is no file name. + + If FCOMMENT is set, a zero-terminated file comment is + present. This comment is not interpreted; it is only + intended for human consumption. The comment must consist of + ISO 8859-1 (LATIN-1) characters. Line breaks should be + denoted by a single line feed character (10 decimal). + + Reserved FLG bits must be zero. + + MTIME (Modification TIME) + This gives the most recent modification time of the original + file being compressed. The time is in Unix format, i.e., + seconds since 00:00:00 GMT, Jan. 1, 1970. (Note that this + may cause problems for MS-DOS and other systems that use + local rather than Universal time.) If the compressed data + did not come from a file, MTIME is set to the time at which + compression started. MTIME = 0 means no time stamp is + available. + + XFL (eXtra FLags) + These flags are available for use by specific compression + methods. The "deflate" method (CM = 8) sets these flags as + follows: + + XFL = 2 - compressor used maximum compression, + slowest algorithm + XFL = 4 - compressor used fastest algorithm + + OS (Operating System) + This identifies the type of file system on which compression + took place. This may be useful in determining end-of-line + convention for text files. The currently defined values are + as follows: + + + + + + +Deutsch Informational [Page 7] + +RFC 1952 GZIP File Format Specification May 1996 + + + 0 - FAT filesystem (MS-DOS, OS/2, NT/Win32) + 1 - Amiga + 2 - VMS (or OpenVMS) + 3 - Unix + 4 - VM/CMS + 5 - Atari TOS + 6 - HPFS filesystem (OS/2, NT) + 7 - Macintosh + 8 - Z-System + 9 - CP/M + 10 - TOPS-20 + 11 - NTFS filesystem (NT) + 12 - QDOS + 13 - Acorn RISCOS + 255 - unknown + + XLEN (eXtra LENgth) + If FLG.FEXTRA is set, this gives the length of the optional + extra field. See below for details. + + CRC32 (CRC-32) + This contains a Cyclic Redundancy Check value of the + uncompressed data computed according to CRC-32 algorithm + used in the ISO 3309 standard and in section 8.1.1.6.2 of + ITU-T recommendation V.42. (See https://www.iso.org/ for + ordering ISO documents. See gopher://info.itu.ch for an + online version of ITU-T V.42.) + + ISIZE (Input SIZE) + This contains the size of the original (uncompressed) input + data modulo 2^32. + + 2.3.1.1. Extra field + + If the FLG.FEXTRA bit is set, an "extra field" is present in + the header, with total length XLEN bytes. It consists of a + series of subfields, each of the form: + + +---+---+---+---+==================================+ + |SI1|SI2| LEN |... LEN bytes of subfield data ...| + +---+---+---+---+==================================+ + + SI1 and SI2 provide a subfield ID, typically two ASCII letters + with some mnemonic value. Jean-Loup Gailly + is maintaining a registry of subfield + IDs; please send him any subfield ID you wish to use. Subfield + IDs with SI2 = 0 are reserved for future use. The following + IDs are currently defined: + + + +Deutsch Informational [Page 8] + +RFC 1952 GZIP File Format Specification May 1996 + + + SI1 SI2 Data + ---------- ---------- ---- + 0x41 ('A') 0x70 ('P') Apollo file type information + + LEN gives the length of the subfield data, excluding the 4 + initial bytes. + + 2.3.1.2. Compliance + + A compliant compressor must produce files with correct ID1, + ID2, CM, CRC32, and ISIZE, but may set all the other fields in + the fixed-length part of the header to default values (255 for + OS, 0 for all others). The compressor must set all reserved + bits to zero. + + A compliant decompressor must check ID1, ID2, and CM, and + provide an error indication if any of these have incorrect + values. It must examine FEXTRA/XLEN, FNAME, FCOMMENT and FHCRC + at least so it can skip over the optional fields if they are + present. It need not examine any other part of the header or + trailer; in particular, a decompressor may ignore FTEXT and OS + and always produce binary output, and still be compliant. A + compliant decompressor must give an error indication if any + reserved bit is non-zero, since such a bit could indicate the + presence of a new field that would cause subsequent data to be + interpreted incorrectly. + +3. References + + [1] "Information Processing - 8-bit single-byte coded graphic + character sets - Part 1: Latin alphabet No.1" (ISO 8859-1:1987). + The ISO 8859-1 (Latin-1) character set is a superset of 7-bit + ASCII. Files defining this character set are available as + iso_8859-1.* in ftp://ftp.uu.net/graphics/png/documents/ + + [2] ISO 3309 + + [3] ITU-T recommendation V.42 + + [4] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [5] Gailly, J.-L., GZIP documentation, available as gzip-*.tar in + ftp://prep.ai.mit.edu/pub/gnu/ + + [6] Sarwate, D.V., "Computation of Cyclic Redundancy Checks via Table + Look-Up", Communications of the ACM, 31(8), pp.1008-1013. + + + + +Deutsch Informational [Page 9] + +RFC 1952 GZIP File Format Specification May 1996 + + + [7] Schwaderer, W.D., "CRC Calculation", April 85 PC Tech Journal, + pp.118-133. + + [8] ftp://ftp.adelaide.edu.au/pub/rocksoft/papers/crc_v3.txt, + describing the CRC concept. + +4. Security Considerations + + Any data compression method involves the reduction of redundancy in + the data. Consequently, any corruption of the data is likely to have + severe effects and be difficult to correct. Uncompressed text, on + the other hand, will probably still be readable despite the presence + of some corrupted bytes. + + It is recommended that systems using this data format provide some + means of validating the integrity of the compressed data, such as by + setting and checking the CRC-32 check value. + +5. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Jean-Loup Gailly designed the gzip format and wrote, with Mark Adler, + the related software described in this specification. Glenn + Randers-Pehrson converted this document to RFC and HTML format. + +6. Author's Address + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + Questions about the technical content of this specification can be + sent by email to: + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to: + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + +Deutsch Informational [Page 10] + +RFC 1952 GZIP File Format Specification May 1996 + + +7. Appendix: Jean-Loup Gailly's gzip utility + + The most widely used implementation of gzip compression, and the + original documentation on which this specification is based, were + created by Jean-Loup Gailly . Since this + implementation is a de facto standard, we mention some more of its + features here. Again, the material in this section is not part of + the specification per se, and implementations need not follow it to + be compliant. + + When compressing or decompressing a file, gzip preserves the + protection, ownership, and modification time attributes on the local + file system, since there is no provision for representing protection + attributes in the gzip file format itself. Since the file format + includes a modification time, the gzip decompressor provides a + command line switch that assigns the modification time from the file, + rather than the local modification time of the compressed input, to + the decompressed output. + +8. Appendix: Sample CRC Code + + The following sample code represents a practical implementation of + the CRC (Cyclic Redundancy Check). (See also ISO 3309 and ITU-T V.42 + for a formal specification.) + + The sample code is in the ANSI C programming language. Non C users + may find it easier to read with these hints: + + & Bitwise AND operator. + ^ Bitwise exclusive-OR operator. + >> Bitwise right shift operator. When applied to an + unsigned quantity, as here, right shift inserts zero + bit(s) at the left. + ! Logical NOT operator. + ++ "n++" increments the variable n. + 0xNNN 0x introduces a hexadecimal (base 16) constant. + Suffix L indicates a long value (at least 32 bits). + + /* Table of CRCs of all 8-bit messages. */ + unsigned long crc_table[256]; + + /* Flag: has the table been computed? Initially false. */ + int crc_table_computed = 0; + + /* Make the table for a fast CRC. */ + void make_crc_table(void) + { + unsigned long c; + + + +Deutsch Informational [Page 11] + +RFC 1952 GZIP File Format Specification May 1996 + + + int n, k; + for (n = 0; n < 256; n++) { + c = (unsigned long) n; + for (k = 0; k < 8; k++) { + if (c & 1) { + c = 0xedb88320L ^ (c >> 1); + } else { + c = c >> 1; + } + } + crc_table[n] = c; + } + crc_table_computed = 1; + } + + /* + Update a running crc with the bytes buf[0..len-1] and return + the updated crc. The crc should be initialized to zero. Pre- and + post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the caller. Usage example: + + unsigned long crc = 0L; + + while (read_buffer(buffer, length) != EOF) { + crc = update_crc(crc, buffer, length); + } + if (crc != original_crc) error(); + */ + unsigned long update_crc(unsigned long crc, + unsigned char *buf, int len) + { + unsigned long c = crc ^ 0xffffffffL; + int n; + + if (!crc_table_computed) + make_crc_table(); + for (n = 0; n < len; n++) { + c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c ^ 0xffffffffL; + } + + /* Return the CRC of the bytes buf[0..len-1]. */ + unsigned long crc(unsigned char *buf, int len) + { + return update_crc(0L, buf, len); + } + + + + +Deutsch Informational [Page 12] + diff --git a/doc/txtvsbin.txt b/doc/txtvsbin.txt new file mode 100644 index 0000000000..3d0f0634f7 --- /dev/null +++ b/doc/txtvsbin.txt @@ -0,0 +1,107 @@ +A Fast Method for Identifying Plain Text Files +============================================== + + +Introduction +------------ + +Given a file coming from an unknown source, it is sometimes desirable +to find out whether the format of that file is plain text. Although +this may appear like a simple task, a fully accurate detection of the +file type requires heavy-duty semantic analysis on the file contents. +It is, however, possible to obtain satisfactory results by employing +various heuristics. + +Previous versions of PKZip and other zip-compatible compression tools +were using a crude detection scheme: if more than 80% (4/5) of the bytes +found in a certain buffer are within the range [7..127], the file is +labeled as plain text, otherwise it is labeled as binary. A prominent +limitation of this scheme is the restriction to Latin-based alphabets. +Other alphabets, like Greek, Cyrillic or Asian, make extensive use of +the bytes within the range [128..255], and texts using these alphabets +are most often misidentified by this scheme; in other words, the rate +of false negatives is sometimes too high, which means that the recall +is low. Another weakness of this scheme is a reduced precision, due to +the false positives that may occur when binary files containing large +amounts of textual characters are misidentified as plain text. + +In this article we propose a new, simple detection scheme that features +a much increased precision and a near-100% recall. This scheme is +designed to work on ASCII, Unicode and other ASCII-derived alphabets, +and it handles single-byte encodings (ISO-8859, MacRoman, KOI8, etc.) +and variable-sized encodings (ISO-2022, UTF-8, etc.). Wider encodings +(UCS-2/UTF-16 and UCS-4/UTF-32) are not handled, however. + + +The Algorithm +------------- + +The algorithm works by dividing the set of bytecodes [0..255] into three +categories: +- The white list of textual bytecodes: + 9 (TAB), 10 (LF), 13 (CR), 32 (SPACE) to 255. +- The gray list of tolerated bytecodes: + 7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB), 27 (ESC). +- The black list of undesired, non-textual bytecodes: + 0 (NUL) to 6, 14 to 31. + +If a file contains at least one byte that belongs to the white list and +no byte that belongs to the black list, then the file is categorized as +plain text; otherwise, it is categorized as binary. (The boundary case, +when the file is empty, automatically falls into the latter category.) + + +Rationale +--------- + +The idea behind this algorithm relies on two observations. + +The first observation is that, although the full range of 7-bit codes +[0..127] is properly specified by the ASCII standard, most control +characters in the range [0..31] are not used in practice. The only +widely-used, almost universally-portable control codes are 9 (TAB), +10 (LF) and 13 (CR). There are a few more control codes that are +recognized on a reduced range of platforms and text viewers/editors: +7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB) and 27 (ESC); but these +codes are rarely (if ever) used alone, without being accompanied by +some printable text. Even the newer, portable text formats such as +XML avoid using control characters outside the list mentioned here. + +The second observation is that most of the binary files tend to contain +control characters, especially 0 (NUL). Even though the older text +detection schemes observe the presence of non-ASCII codes from the range +[128..255], the precision rarely has to suffer if this upper range is +labeled as textual, because the files that are genuinely binary tend to +contain both control characters and codes from the upper range. On the +other hand, the upper range needs to be labeled as textual, because it +is used by virtually all ASCII extensions. In particular, this range is +used for encoding non-Latin scripts. + +Since there is no counting involved, other than simply observing the +presence or the absence of some byte values, the algorithm produces +consistent results, regardless what alphabet encoding is being used. +(If counting were involved, it could be possible to obtain different +results on a text encoded, say, using ISO-8859-16 versus UTF-8.) + +There is an extra category of plain text files that are "polluted" with +one or more black-listed codes, either by mistake or by peculiar design +considerations. In such cases, a scheme that tolerates a small fraction +of black-listed codes would provide an increased recall (i.e. more true +positives). This, however, incurs a reduced precision overall, since +false positives are more likely to appear in binary files that contain +large chunks of textual data. Furthermore, "polluted" plain text should +be regarded as binary by general-purpose text detection schemes, because +general-purpose text processing algorithms might not be applicable. +Under this premise, it is safe to say that our detection method provides +a near-100% recall. + +Experiments have been run on many files coming from various platforms +and applications. We tried plain text files, system logs, source code, +formatted office documents, compiled object code, etc. The results +confirm the optimistic assumptions about the capabilities of this +algorithm. + + +-- +Cosmin Truta +Last updated: 2006-May-28 diff --git a/fallback_builtins.h b/fallback_builtins.h new file mode 100644 index 0000000000..8303508fa1 --- /dev/null +++ b/fallback_builtins.h @@ -0,0 +1,47 @@ +#ifndef FALLBACK_BUILTINS_H +#define FALLBACK_BUILTINS_H + +#if defined(_MSC_VER) && !defined(__clang__) +#if defined(_M_IX86) || defined(_M_AMD64) || defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) + +#include + +/* This is not a general purpose replacement for __builtin_ctz. The function expects that value is != 0. + * Because of that assumption trailing_zero is not initialized and the return value is not checked. + * Tzcnt and bsf give identical results except when input value is 0, therefore this can not be allowed. + * If tzcnt instruction is not supported, the cpu will itself execute bsf instead. + * Performance tzcnt/bsf is identical on Intel cpu, tzcnt is faster than bsf on AMD cpu. + */ +static __forceinline int __builtin_ctz(unsigned int value) { + Assert(value != 0, "Invalid input value: 0"); +# if defined(X86_FEATURES) && !(_MSC_VER < 1700) + return (int)_tzcnt_u32(value); +# else + unsigned long trailing_zero; + _BitScanForward(&trailing_zero, value); + return (int)trailing_zero; +# endif +} +#define HAVE_BUILTIN_CTZ + +#ifdef _M_AMD64 +/* This is not a general purpose replacement for __builtin_ctzll. The function expects that value is != 0. + * Because of that assumption trailing_zero is not initialized and the return value is not checked. + */ +static __forceinline int __builtin_ctzll(unsigned long long value) { + Assert(value != 0, "Invalid input value: 0"); +# if defined(X86_FEATURES) && !(_MSC_VER < 1700) + return (int)_tzcnt_u64(value); +# else + unsigned long trailing_zero; + _BitScanForward64(&trailing_zero, value); + return (int)trailing_zero; +# endif +} +#define HAVE_BUILTIN_CTZLL +#endif // Microsoft AMD64 + +#endif // Microsoft AMD64/IA64/x86/ARM/ARM64 test +#endif // _MSC_VER & !clang + +#endif // include guard FALLBACK_BUILTINS_H diff --git a/functable.c b/functable.c new file mode 100644 index 0000000000..3cee95bff1 --- /dev/null +++ b/functable.c @@ -0,0 +1,362 @@ +/* functable.c -- Choose relevant optimized functions at runtime + * Copyright (C) 2017 Hans Kristian Rosbach + * For conditions of distribution and use, see copyright notice in zlib.h + */ +#ifndef DISABLE_RUNTIME_CPU_DETECTION + +#include "zbuild.h" + +#if defined(_MSC_VER) +# include +#endif + +#include "functable.h" +#include "cpu_features.h" +#include "arch_functions.h" + +/* Platform has pointer size atomic store */ +#if defined(__GNUC__) || defined(__clang__) +# define FUNCTABLE_ASSIGN(VAR, FUNC_NAME) \ + __atomic_store(&(functable.FUNC_NAME), &(VAR.FUNC_NAME), __ATOMIC_SEQ_CST) +# define FUNCTABLE_BARRIER() __atomic_thread_fence(__ATOMIC_SEQ_CST) +#elif defined(_MSC_VER) +# define FUNCTABLE_ASSIGN(VAR, FUNC_NAME) \ + _InterlockedExchangePointer((void * volatile *)&(functable.FUNC_NAME), (void *)(VAR.FUNC_NAME)) +# if defined(_M_ARM) || defined(_M_ARM64) +# define FUNCTABLE_BARRIER() do { \ + _ReadWriteBarrier(); \ + __dmb(0xB); /* _ARM_BARRIER_ISH */ \ + _ReadWriteBarrier(); \ +} while (0) +# else +# define FUNCTABLE_BARRIER() _ReadWriteBarrier() +# endif +#else +# warning Unable to detect atomic intrinsic support. +# define FUNCTABLE_ASSIGN(VAR, FUNC_NAME) \ + *((void * volatile *)&(functable.FUNC_NAME)) = (void *)(VAR.FUNC_NAME) +# define FUNCTABLE_BARRIER() do { /* Empty */ } while (0) +#endif + +static void force_init_empty(void) { + // empty +} + +static void init_functable(void) { + struct functable_s ft; + struct cpu_features cf; + + cpu_check_features(&cf); + + // Generic code + ft.force_init = &force_init_empty; + ft.adler32 = &adler32_c; + ft.adler32_fold_copy = &adler32_fold_copy_c; + ft.chunkmemset_safe = &chunkmemset_safe_c; + ft.chunksize = &chunksize_c; + ft.crc32 = &PREFIX(crc32_braid); + ft.crc32_fold = &crc32_fold_c; + ft.crc32_fold_copy = &crc32_fold_copy_c; + ft.crc32_fold_final = &crc32_fold_final_c; + ft.crc32_fold_reset = &crc32_fold_reset_c; + ft.inflate_fast = &inflate_fast_c; + ft.slide_hash = &slide_hash_c; + ft.longest_match = &longest_match_c; + ft.longest_match_slow = &longest_match_slow_c; + ft.compare256 = &compare256_c; + + // Select arch-optimized functions + + // X86 - SSE2 +#ifdef X86_SSE2 +# if !defined(__x86_64__) && !defined(_M_X64) && !defined(X86_NOCHECK_SSE2) + if (cf.x86.has_sse2) +# endif + { + ft.chunkmemset_safe = &chunkmemset_safe_sse2; + ft.chunksize = &chunksize_sse2; + ft.inflate_fast = &inflate_fast_sse2; + ft.slide_hash = &slide_hash_sse2; +# ifdef HAVE_BUILTIN_CTZ + ft.compare256 = &compare256_sse2; + ft.longest_match = &longest_match_sse2; + ft.longest_match_slow = &longest_match_slow_sse2; +# endif + } +#endif + // X86 - SSSE3 +#ifdef X86_SSSE3 + if (cf.x86.has_ssse3) { + ft.adler32 = &adler32_ssse3; + ft.chunkmemset_safe = &chunkmemset_safe_ssse3; + ft.inflate_fast = &inflate_fast_ssse3; + } +#endif + // X86 - SSE4.2 +#ifdef X86_SSE42 + if (cf.x86.has_sse42) { + ft.adler32_fold_copy = &adler32_fold_copy_sse42; + } +#endif + // X86 - PCLMUL +#ifdef X86_PCLMULQDQ_CRC + if (cf.x86.has_pclmulqdq) { + ft.crc32 = &crc32_pclmulqdq; + ft.crc32_fold = &crc32_fold_pclmulqdq; + ft.crc32_fold_copy = &crc32_fold_pclmulqdq_copy; + ft.crc32_fold_final = &crc32_fold_pclmulqdq_final; + ft.crc32_fold_reset = &crc32_fold_pclmulqdq_reset; + } +#endif + // X86 - AVX +#ifdef X86_AVX2 + /* BMI2 support is all but implicit with AVX2 but let's sanity check this just in case. Enabling BMI2 allows for + * flagless shifts, resulting in fewer flag stalls for the pipeline, and allows us to set destination registers + * for the shift results as an operand, eliminating several register-register moves when the original value needs + * to remain intact. They also allow for a count operand that isn't the CL register, avoiding contention there */ + if (cf.x86.has_avx2 && cf.x86.has_bmi2) { + ft.adler32 = &adler32_avx2; + ft.adler32_fold_copy = &adler32_fold_copy_avx2; + ft.chunkmemset_safe = &chunkmemset_safe_avx2; + ft.chunksize = &chunksize_avx2; + ft.inflate_fast = &inflate_fast_avx2; + ft.slide_hash = &slide_hash_avx2; +# ifdef HAVE_BUILTIN_CTZ + ft.compare256 = &compare256_avx2; + ft.longest_match = &longest_match_avx2; + ft.longest_match_slow = &longest_match_slow_avx2; +# endif + } +#endif + // X86 - AVX512 (F,DQ,BW,Vl) +#ifdef X86_AVX512 + if (cf.x86.has_avx512_common) { + ft.adler32 = &adler32_avx512; + ft.adler32_fold_copy = &adler32_fold_copy_avx512; + ft.chunkmemset_safe = &chunkmemset_safe_avx512; + ft.chunksize = &chunksize_avx512; + ft.inflate_fast = &inflate_fast_avx512; + } +#endif +#ifdef X86_AVX512VNNI + if (cf.x86.has_avx512vnni) { + ft.adler32 = &adler32_avx512_vnni; + ft.adler32_fold_copy = &adler32_fold_copy_avx512_vnni; + } +#endif + // X86 - VPCLMULQDQ +#ifdef X86_VPCLMULQDQ_CRC + if (cf.x86.has_pclmulqdq && cf.x86.has_avx512_common && cf.x86.has_vpclmulqdq) { + ft.crc32 = &crc32_vpclmulqdq; + ft.crc32_fold = &crc32_fold_vpclmulqdq; + ft.crc32_fold_copy = &crc32_fold_vpclmulqdq_copy; + ft.crc32_fold_final = &crc32_fold_vpclmulqdq_final; + ft.crc32_fold_reset = &crc32_fold_vpclmulqdq_reset; + } +#endif + + + // ARM - SIMD +#ifdef ARM_SIMD +# ifndef ARM_NOCHECK_SIMD + if (cf.arm.has_simd) +# endif + { + ft.slide_hash = &slide_hash_armv6; + } +#endif + // ARM - NEON +#ifdef ARM_NEON +# ifndef ARM_NOCHECK_NEON + if (cf.arm.has_neon) +# endif + { + ft.adler32 = &adler32_neon; + ft.chunkmemset_safe = &chunkmemset_safe_neon; + ft.chunksize = &chunksize_neon; + ft.inflate_fast = &inflate_fast_neon; + ft.slide_hash = &slide_hash_neon; +# ifdef HAVE_BUILTIN_CTZLL + ft.compare256 = &compare256_neon; + ft.longest_match = &longest_match_neon; + ft.longest_match_slow = &longest_match_slow_neon; +# endif + } +#endif + // ARM - ACLE +#ifdef ARM_ACLE + if (cf.arm.has_crc32) { + ft.crc32 = &crc32_acle; + } +#endif + + + // Power - VMX +#ifdef PPC_VMX + if (cf.power.has_altivec) { + ft.adler32 = &adler32_vmx; + ft.slide_hash = &slide_hash_vmx; + } +#endif + // Power8 - VSX +#ifdef POWER8_VSX + if (cf.power.has_arch_2_07) { + ft.adler32 = &adler32_power8; + ft.chunkmemset_safe = &chunkmemset_safe_power8; + ft.chunksize = &chunksize_power8; + ft.inflate_fast = &inflate_fast_power8; + ft.slide_hash = &slide_hash_power8; + } +#endif +#ifdef POWER8_VSX_CRC32 + if (cf.power.has_arch_2_07) + ft.crc32 = &crc32_power8; +#endif + // Power9 +#ifdef POWER9 + if (cf.power.has_arch_3_00) { + ft.compare256 = &compare256_power9; + ft.longest_match = &longest_match_power9; + ft.longest_match_slow = &longest_match_slow_power9; + } +#endif + + + // RISCV - RVV +#ifdef RISCV_RVV + if (cf.riscv.has_rvv) { + ft.adler32 = &adler32_rvv; + ft.adler32_fold_copy = &adler32_fold_copy_rvv; + ft.chunkmemset_safe = &chunkmemset_safe_rvv; + ft.chunksize = &chunksize_rvv; + ft.compare256 = &compare256_rvv; + ft.inflate_fast = &inflate_fast_rvv; + ft.longest_match = &longest_match_rvv; + ft.longest_match_slow = &longest_match_slow_rvv; + ft.slide_hash = &slide_hash_rvv; + } +#endif + + + // S390 +#ifdef S390_CRC32_VX + if (cf.s390.has_vx) + ft.crc32 = crc32_s390_vx; +#endif + + // Assign function pointers individually for atomic operation + FUNCTABLE_ASSIGN(ft, force_init); + FUNCTABLE_ASSIGN(ft, adler32); + FUNCTABLE_ASSIGN(ft, adler32_fold_copy); + FUNCTABLE_ASSIGN(ft, chunkmemset_safe); + FUNCTABLE_ASSIGN(ft, chunksize); + FUNCTABLE_ASSIGN(ft, compare256); + FUNCTABLE_ASSIGN(ft, crc32); + FUNCTABLE_ASSIGN(ft, crc32_fold); + FUNCTABLE_ASSIGN(ft, crc32_fold_copy); + FUNCTABLE_ASSIGN(ft, crc32_fold_final); + FUNCTABLE_ASSIGN(ft, crc32_fold_reset); + FUNCTABLE_ASSIGN(ft, inflate_fast); + FUNCTABLE_ASSIGN(ft, longest_match); + FUNCTABLE_ASSIGN(ft, longest_match_slow); + FUNCTABLE_ASSIGN(ft, slide_hash); + + // Memory barrier for weak memory order CPUs + FUNCTABLE_BARRIER(); +} + +/* stub functions */ +static void force_init_stub(void) { + init_functable(); +} + +static uint32_t adler32_stub(uint32_t adler, const uint8_t* buf, size_t len) { + init_functable(); + return functable.adler32(adler, buf, len); +} + +static uint32_t adler32_fold_copy_stub(uint32_t adler, uint8_t* dst, const uint8_t* src, size_t len) { + init_functable(); + return functable.adler32_fold_copy(adler, dst, src, len); +} + +static uint8_t* chunkmemset_safe_stub(uint8_t* out, uint8_t *from, unsigned len, unsigned left) { + init_functable(); + return functable.chunkmemset_safe(out, from, len, left); +} + +static uint32_t chunksize_stub(void) { + init_functable(); + return functable.chunksize(); +} + +static uint32_t compare256_stub(const uint8_t* src0, const uint8_t* src1) { + init_functable(); + return functable.compare256(src0, src1); +} + +static uint32_t crc32_stub(uint32_t crc, const uint8_t* buf, size_t len) { + init_functable(); + return functable.crc32(crc, buf, len); +} + +static void crc32_fold_stub(crc32_fold* crc, const uint8_t* src, size_t len, uint32_t init_crc) { + init_functable(); + functable.crc32_fold(crc, src, len, init_crc); +} + +static void crc32_fold_copy_stub(crc32_fold* crc, uint8_t* dst, const uint8_t* src, size_t len) { + init_functable(); + functable.crc32_fold_copy(crc, dst, src, len); +} + +static uint32_t crc32_fold_final_stub(crc32_fold* crc) { + init_functable(); + return functable.crc32_fold_final(crc); +} + +static uint32_t crc32_fold_reset_stub(crc32_fold* crc) { + init_functable(); + return functable.crc32_fold_reset(crc); +} + +static void inflate_fast_stub(PREFIX3(stream) *strm, uint32_t start) { + init_functable(); + functable.inflate_fast(strm, start); +} + +static uint32_t longest_match_stub(deflate_state* const s, Pos cur_match) { + init_functable(); + return functable.longest_match(s, cur_match); +} + +static uint32_t longest_match_slow_stub(deflate_state* const s, Pos cur_match) { + init_functable(); + return functable.longest_match_slow(s, cur_match); +} + +static void slide_hash_stub(deflate_state* s) { + init_functable(); + functable.slide_hash(s); +} + +/* functable init */ +Z_INTERNAL struct functable_s functable = { + force_init_stub, + adler32_stub, + adler32_fold_copy_stub, + chunkmemset_safe_stub, + chunksize_stub, + compare256_stub, + crc32_stub, + crc32_fold_stub, + crc32_fold_copy_stub, + crc32_fold_final_stub, + crc32_fold_reset_stub, + inflate_fast_stub, + longest_match_stub, + longest_match_slow_stub, + slide_hash_stub, +}; + +#endif diff --git a/functable.h b/functable.h new file mode 100644 index 0000000000..83dda88088 --- /dev/null +++ b/functable.h @@ -0,0 +1,55 @@ +/* functable.h -- Struct containing function pointers to optimized functions + * Copyright (C) 2017 Hans Kristian Rosbach + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef FUNCTABLE_H_ +#define FUNCTABLE_H_ + +#include "deflate.h" +#include "crc32.h" + +#ifdef DISABLE_RUNTIME_CPU_DETECTION + +# include "arch_functions.h" + +/* When compiling with native instructions it is not necessary to use functable. + * Instead we use native_ macro indicating the best available variant of arch-specific + * functions for the current platform. + */ +# define FUNCTABLE_INIT ((void)0) +# define FUNCTABLE_CALL(name) native_ ## name +# define FUNCTABLE_FPTR(name) &native_ ## name + +#else + +struct functable_s { + void (* force_init) (void); + uint32_t (* adler32) (uint32_t adler, const uint8_t *buf, size_t len); + uint32_t (* adler32_fold_copy) (uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); + uint8_t* (* chunkmemset_safe) (uint8_t *out, uint8_t *from, unsigned len, unsigned left); + uint32_t (* chunksize) (void); + uint32_t (* compare256) (const uint8_t *src0, const uint8_t *src1); + uint32_t (* crc32) (uint32_t crc, const uint8_t *buf, size_t len); + void (* crc32_fold) (struct crc32_fold_s *crc, const uint8_t *src, size_t len, uint32_t init_crc); + void (* crc32_fold_copy) (struct crc32_fold_s *crc, uint8_t *dst, const uint8_t *src, size_t len); + uint32_t (* crc32_fold_final) (struct crc32_fold_s *crc); + uint32_t (* crc32_fold_reset) (struct crc32_fold_s *crc); + void (* inflate_fast) (PREFIX3(stream) *strm, uint32_t start); + uint32_t (* longest_match) (deflate_state *const s, Pos cur_match); + uint32_t (* longest_match_slow) (deflate_state *const s, Pos cur_match); + void (* slide_hash) (deflate_state *s); +}; + +Z_INTERNAL extern struct functable_s functable; + + +/* Explicitly indicate functions are conditionally dispatched. + */ +# define FUNCTABLE_INIT functable.force_init() +# define FUNCTABLE_CALL(name) functable.name +# define FUNCTABLE_FPTR(name) functable.name + +#endif + +#endif diff --git a/gzguts.h b/gzguts.h new file mode 100644 index 0000000000..14f2391152 --- /dev/null +++ b/gzguts.h @@ -0,0 +1,146 @@ +#ifndef GZGUTS_H_ +#define GZGUTS_H_ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# undef _FILE_OFFSET_BITS +# undef _TIME_BITS +#endif + +#if defined(HAVE_VISIBILITY_INTERNAL) +# define Z_INTERNAL __attribute__((visibility ("internal"))) +#elif defined(HAVE_VISIBILITY_HIDDEN) +# define Z_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define Z_INTERNAL +#endif + +#include +#include +#include +#include +#include + +#if defined(ZLIB_COMPAT) +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#ifdef _WIN32 +# include +#endif + +#if defined(_WIN32) +# include +# define WIDECHAR +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +#if !defined(STDC99) && !defined(__CYGWIN__) && !defined(__MINGW__) && defined(_WIN32) +# if !defined(vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +#endif + +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c + where the result is assured to fit in the space provided */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +/* get errno and strerror definition */ +#ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +#else +# define zstrerror() "stdio error (consult errno)" +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#ifndef GZBUFSIZE +# define GZBUFSIZE 131072 +#endif + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer (double-sized when writing) */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + int reset; /* true if a reset is pending after a Z_FINISH */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + PREFIX3(stream) strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state *gz_statep; + +/* shared functions */ +void Z_INTERNAL gz_error(gz_state *, int, const char *); +#ifdef ZLIB_COMPAT +unsigned Z_INTERNAL gz_intmax(void); +#endif +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) + +#endif /* GZGUTS_H_ */ diff --git a/gzlib.c b/gzlib.c new file mode 100644 index 0000000000..b8a506b6a5 --- /dev/null +++ b/gzlib.c @@ -0,0 +1,531 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zutil_p.h" +#include "gzguts.h" + +#if defined(_WIN32) +# define LSEEK _lseeki64 +#else +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif +#endif + +/* Local functions */ +static void gz_reset(gz_state *); +static gzFile gz_open(const void *, int, const char *); + +/* Reset gzip file state */ +static void gz_reset(gz_state *state) { + state->x.have = 0; /* no output data available */ + if (state->mode == GZ_READ) { /* for reading ... */ + state->eof = 0; /* not at end of file */ + state->past = 0; /* have not read past end yet */ + state->how = LOOK; /* look for gzip header */ + } + else /* for writing ... */ + state->reset = 0; /* no deflateReset pending */ + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->x.pos = 0; /* no uncompressed data yet */ + state->strm.avail_in = 0; /* no input data yet */ +} + +/* Open a gzip file either by name or file descriptor. */ +static gzFile gz_open(const void *path, int fd, const char *mode) { + gz_state *state; + size_t len; + int oflag; +#ifdef O_CLOEXEC + int cloexec = 0; +#endif +#ifdef O_EXCL + int exclusive = 0; +#endif + + /* check input */ + if (path == NULL) + return NULL; + + /* allocate gzFile structure to return */ + state = (gz_state *)zng_alloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ + + /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + state->direct = 0; + while (*mode) { + if (*mode >= '0' && *mode <= '9') { + state->level = *mode - '0'; + } else { + switch (*mode) { + case 'r': + state->mode = GZ_READ; + break; +#ifndef NO_GZCOMPRESS + case 'w': + state->mode = GZ_WRITE; + break; + case 'a': + state->mode = GZ_APPEND; + break; +#endif + case '+': /* can't read and write at the same time */ + zng_free(state); + return NULL; + case 'b': /* ignore -- will request binary anyway */ + break; +#ifdef O_CLOEXEC + case 'e': + cloexec = 1; + break; +#endif +#ifdef O_EXCL + case 'x': + exclusive = 1; + break; +#endif + case 'f': + state->strategy = Z_FILTERED; + break; + case 'h': + state->strategy = Z_HUFFMAN_ONLY; + break; + case 'R': + state->strategy = Z_RLE; + break; + case 'F': + state->strategy = Z_FIXED; + break; + case 'T': + state->direct = 1; + break; + default: /* could consider as an error, but just ignore */ + {} + } + } + mode++; + } + + /* must provide an "r", "w", or "a" */ + if (state->mode == GZ_NONE) { + zng_free(state); + return NULL; + } + + /* can't force transparent read */ + if (state->mode == GZ_READ) { + if (state->direct) { + zng_free(state); + return NULL; + } + state->direct = 1; /* for empty file */ + } + + /* save the path name for error messages */ +#ifdef WIDECHAR + if (fd == -2) { + len = wcstombs(NULL, (const wchar_t *)path, 0); + if (len == (size_t)-1) + len = 0; + } else +#endif + len = strlen((const char *)path); + state->path = (char *)malloc(len + 1); + if (state->path == NULL) { + zng_free(state); + return NULL; + } +#ifdef WIDECHAR + if (fd == -2) + if (len) { + wcstombs(state->path, (const wchar_t *)path, len + 1); + } else { + *(state->path) = 0; + } + else +#endif + (void)snprintf(state->path, len + 1, "%s", (const char *)path); + + /* compute the flags for open() */ + oflag = +#ifdef O_LARGEFILE + O_LARGEFILE | +#endif +#ifdef O_BINARY + O_BINARY | +#endif +#ifdef O_CLOEXEC + (cloexec ? O_CLOEXEC : 0) | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | +#ifdef O_EXCL + (exclusive ? O_EXCL : 0) | +#endif + (state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))); + + /* open the file with the appropriate flags (or just use fd) */ + state->fd = fd > -1 ? fd : ( +#if defined(_WIN32) + fd == -2 ? _wopen((const wchar_t *)path, oflag, 0666) : +#elif __CYGWIN__ + fd == -2 ? open(state->path, oflag, 0666) : +#endif + open((const char *)path, oflag, 0666)); + if (state->fd == -1) { + free(state->path); + zng_free(state); + return NULL; + } + if (state->mode == GZ_APPEND) { + LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ + state->mode = GZ_WRITE; /* simplify later checks */ + } + + /* save the current position for rewinding (only if reading) */ + if (state->mode == GZ_READ) { + state->start = LSEEK(state->fd, 0, SEEK_CUR); + if (state->start == -1) state->start = 0; + } + + /* initialize stream */ + gz_reset(state); + + /* return stream */ + return (gzFile)state; +} + +/* -- see zlib.h -- */ +gzFile Z_EXPORT PREFIX(gzopen)(const char *path, const char *mode) { + return gz_open(path, -1, mode); +} + +#ifdef ZLIB_COMPAT +gzFile Z_EXPORT PREFIX4(gzopen)(const char *path, const char *mode) { + return gz_open(path, -1, mode); +} +#endif + +/* -- see zlib.h -- */ +gzFile Z_EXPORT PREFIX(gzdopen)(int fd, const char *mode) { + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) + return NULL; + (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); /* for debugging */ + gz = gz_open(path, fd, mode); + free(path); + return gz; +} + +/* -- see zlib.h -- */ +#ifdef WIDECHAR +gzFile Z_EXPORT PREFIX(gzopen_w)(const wchar_t *path, const char *mode) { + return gz_open(path, -2, mode); +} +#endif + +int Z_EXPORT PREFIX(gzclose)(gzFile file) { +#ifndef NO_GZCOMPRESS + gz_state *state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_state *)file; + + return state->mode == GZ_READ ? PREFIX(gzclose_r)(file) : PREFIX(gzclose_w)(file); +#else + return PREFIX(gzclose_r)(file); +#endif +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzbuffer)(gzFile file, unsigned size) { + gz_state *state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_state *)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* make sure we haven't already allocated memory */ + if (state->size != 0) + return -1; + + /* check and set requested size */ + if ((size << 1) < size) + return -1; /* need to be able to double it */ + if (size < 8) + size = 8; /* needed to behave well with flushing */ + state->want = size; + return 0; +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzrewind)(gzFile file) { + gz_state *state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_state *)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* back up and start over */ + if (LSEEK(state->fd, state->start, SEEK_SET) == -1) + return -1; + gz_reset(state); + return 0; +} + +/* -- see zlib.h -- */ +z_off64_t Z_EXPORT PREFIX4(gzseek)(gzFile file, z_off64_t offset, int whence) { + unsigned n; + z_off64_t ret; + gz_state *state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_state *)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* check that there's no error */ + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* can only seek from start or relative to current position */ + if (whence != SEEK_SET && whence != SEEK_CUR) + return -1; + + /* normalize offset to a SEEK_CUR specification */ + if (whence == SEEK_SET) + offset -= state->x.pos; + else if (state->seek) + offset += state->skip; + state->seek = 0; + + /* if within raw area while reading, just go there */ + if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { + ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); + if (ret == -1) + return -1; + state->x.have = 0; + state->eof = 0; + state->past = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->x.pos += offset; + return state->x.pos; + } + + /* calculate skip amount, rewinding if needed for back seek when reading */ + if (offset < 0) { + if (state->mode != GZ_READ) /* writing -- can't go backwards */ + return -1; + offset += state->x.pos; + if (offset < 0) /* before start of file! */ + return -1; + if (PREFIX(gzrewind)(file) == -1) /* rewind, then skip to offset */ + return -1; + } + + /* if reading, skip what's in output buffer (one less gzgetc() check) */ + if (state->mode == GZ_READ) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->x.pos + offset; +} + +/* -- see zlib.h -- */ +#ifdef ZLIB_COMPAT +z_off_t Z_EXPORT PREFIX(gzseek)(gzFile file, z_off_t offset, int whence) { + z_off64_t ret; + + ret = PREFIX4(gzseek)(file, (z_off64_t)offset, whence); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} +#endif + +/* -- see zlib.h -- */ +z_off64_t Z_EXPORT PREFIX4(gztell)(gzFile file) { + gz_state *state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_state *)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* return position */ + return state->x.pos + (state->seek ? state->skip : 0); +} + +/* -- see zlib.h -- */ +#ifdef ZLIB_COMPAT +z_off_t Z_EXPORT PREFIX(gztell)(gzFile file) { + + z_off64_t ret; + + ret = PREFIX4(gztell)(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} +#endif + +/* -- see zlib.h -- */ +z_off64_t Z_EXPORT PREFIX4(gzoffset)(gzFile file) { + z_off64_t offset; + gz_state *state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_state *)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* compute and return effective offset in file */ + offset = LSEEK(state->fd, 0, SEEK_CUR); + if (offset == -1) + return -1; + if (state->mode == GZ_READ) /* reading */ + offset -= state->strm.avail_in; /* don't count buffered input */ + return offset; +} + +/* -- see zlib.h -- */ +#ifdef ZLIB_COMPAT +z_off_t Z_EXPORT PREFIX(gzoffset)(gzFile file) { + z_off64_t ret; + + ret = PREFIX4(gzoffset)(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} +#endif + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzeof)(gzFile file) { + gz_state *state; + + /* get internal structure and check integrity */ + if (file == NULL) + return 0; + state = (gz_state *)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return 0; + + /* return end-of-file state */ + return state->mode == GZ_READ ? state->past : 0; +} + +/* -- see zlib.h -- */ +const char * Z_EXPORT PREFIX(gzerror)(gzFile file, int *errnum) { + gz_state *state; + + /* get internal structure and check integrity */ + if (file == NULL) + return NULL; + state = (gz_state *)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return NULL; + + /* return error information */ + if (errnum != NULL) + *errnum = state->err; + return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg); +} + +/* -- see zlib.h -- */ +void Z_EXPORT PREFIX(gzclearerr)(gzFile file) { + gz_state *state; + + /* get internal structure and check integrity */ + if (file == NULL) + return; + state = (gz_state *)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return; + + /* clear error and end-of-file */ + if (state->mode == GZ_READ) { + state->eof = 0; + state->past = 0; + } + gz_error(state, Z_OK, NULL); +} + +/* Create an error message in allocated memory and set state->err and + state->msg accordingly. Free any previous error message already there. Do + not try to free or allocate space if the error is Z_MEM_ERROR (out of + memory). Simply save the error message as a static string. If there is an + allocation failure constructing the error message, then convert the error to + out of memory. */ +void Z_INTERNAL gz_error(gz_state *state, int err, const char *msg) { + /* free previously allocated message and clear */ + if (state->msg != NULL) { + if (state->err != Z_MEM_ERROR) + free(state->msg); + state->msg = NULL; + } + + /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ + if (err != Z_OK && err != Z_BUF_ERROR) + state->x.have = 0; + + /* set error code, and if no message, then done */ + state->err = err; + if (msg == NULL) + return; + + /* for an out of memory error, return literal string when requested */ + if (err == Z_MEM_ERROR) + return; + + /* construct error message with path */ + if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { + state->err = Z_MEM_ERROR; + return; + } + (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg); +} + +#ifdef ZLIB_COMPAT +unsigned Z_INTERNAL gz_intmax(void) { + return INT_MAX; +} +#endif diff --git a/gzread.c.in b/gzread.c.in new file mode 100644 index 0000000000..1fc7b370fd --- /dev/null +++ b/gzread.c.in @@ -0,0 +1,606 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zutil_p.h" +#include "gzguts.h" + +/* Local functions */ +static int gz_load(gz_state *, unsigned char *, unsigned, unsigned *); +static int gz_avail(gz_state *); +static int gz_look(gz_state *); +static int gz_decomp(gz_state *); +static int gz_fetch(gz_state *); +static int gz_skip(gz_state *, z_off64_t); +static size_t gz_read(gz_state *, void *, size_t); + +/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from + state->fd, and update state->eof, state->err, and state->msg as appropriate. + This function needs to loop on read(), since read() is not guaranteed to + read the number of bytes requested, depending on the type of descriptor. */ +static int gz_load(gz_state *state, unsigned char *buf, unsigned len, unsigned *have) { + ssize_t ret; + + *have = 0; + do { + ret = read(state->fd, buf + *have, len - *have); + if (ret <= 0) + break; + *have += (unsigned)ret; + } while (*have < len); + if (ret < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (ret == 0) + state->eof = 1; + return 0; +} + +/* Load up input buffer and set eof flag if last data loaded -- return -1 on + error, 0 otherwise. Note that the eof flag is set when the end of the input + file is reached, even though there may be unused data in the buffer. Once + that data has been used, no more attempts will be made to read the file. + If strm->avail_in != 0, then the current data is moved to the beginning of + the input buffer, and then the remainder of the buffer is loaded with the + available data from the input file. */ +static int gz_avail(gz_state *state) { + unsigned got; + PREFIX3(stream) *strm = &(state->strm); + + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + if (state->eof == 0) { + if (strm->avail_in) { /* copy what's there to the start */ + unsigned char *p = state->in; + unsigned const char *q = strm->next_in; + unsigned n = strm->avail_in; + do { + *p++ = *q++; + } while (--n); + } + if (gz_load(state, state->in + strm->avail_in, state->size - strm->avail_in, &got) == -1) + return -1; + strm->avail_in += got; + strm->next_in = state->in; + } + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. + If this is the first time in, allocate required memory. state->how will be + left unchanged if there is no more input data available, will be set to COPY + if there is no gzip header and direct copying will be performed, or it will + be set to GZIP for decompression. If direct copying, then leftover input + data from the input buffer will be copied to the output buffer. In that + case, all further file reads will be directly to either the output buffer or + a user buffer. If decompressing, the inflate state will be initialized. + gz_look() will return 0 on success or -1 on failure. */ +static int gz_look(gz_state *state) { + PREFIX3(stream) *strm = &(state->strm); + + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = (unsigned char *)zng_alloc(state->want); + state->out = (unsigned char *)zng_alloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + zng_free(state->out); + zng_free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = NULL; + state->strm.zfree = NULL; + state->strm.opaque = NULL; + state->strm.avail_in = 0; + state->strm.next_in = NULL; + if (PREFIX(inflateInit2)(&(state->strm), MAX_WBITS + 16) != Z_OK) { /* gunzip */ + zng_free(state->out); + zng_free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get at least the magic bytes in the input buffer */ + if (strm->avail_in < 2) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for gzip magic bytes -- if there, do gzip decoding (note: there is + a logical dilemma here when considering the case of a partially written + gzip file, to wit, if a single 31 byte is written, then we cannot tell + whether this is a single-byte file, or just a partially written gzip + file -- for here we assume that if a gzip file is being written, then + the header will be written in a single operation, so that reading a + single byte is sufficient indication that it is not a gzip file) */ + if (strm->avail_in > 1 && + strm->next_in[0] == 31 && strm->next_in[1] == 139) { + PREFIX(inflateReset)(strm); + state->how = GZIP; + state->direct = 0; + return 0; + } + + /* no gzip header -- if we were decoding gzip before, then this is trailing + garbage. Ignore the trailing garbage and finish. */ + if (state->direct == 0) { + strm->avail_in = 0; + state->eof = 1; + state->x.have = 0; + return 0; + } + + /* doing raw i/o, copy any leftover input to output -- this assumes that + the output buffer is larger than the input buffer, which also assures + space for gzungetc() */ + state->x.next = state->out; + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; + strm->avail_in = 0; + state->how = COPY; + state->direct = 1; + return 0; +} + +/* Decompress from input to the provided next_out and avail_out in the state. + On return, state->x.have and state->x.next point to the just decompressed + data. If the gzip stream completes, state->how is reset to LOOK to look for + the next gzip stream or raw data, once state->x.have is depleted. Returns 0 + on success, -1 on failure. */ +static int gz_decomp(gz_state *state) { + int ret = Z_OK; + unsigned had; + PREFIX3(stream) *strm = &(state->strm); + + /* fill output buffer up to end of deflate stream */ + had = strm->avail_out; + do { + /* get more input for inflate() */ + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) { + gz_error(state, Z_BUF_ERROR, "unexpected end of file"); + break; + } + + /* decompress and handle errors */ + ret = PREFIX(inflate)(strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { + gz_error(state, Z_STREAM_ERROR, "internal error: inflate stream corrupt"); + return -1; + } + if (ret == Z_MEM_ERROR) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ + gz_error(state, Z_DATA_ERROR, strm->msg == NULL ? "compressed data error" : strm->msg); + return -1; + } + } while (strm->avail_out && ret != Z_STREAM_END); + + /* update available output */ + state->x.have = had - strm->avail_out; + state->x.next = strm->next_out - state->x.have; + + /* if the gzip stream completed successfully, look for another */ + if (ret == Z_STREAM_END) + state->how = LOOK; + + /* good decompression */ + return 0; +} + +/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. + Data is either copied from the input file or decompressed from the input + file depending on state->how. If state->how is LOOK, then a gzip header is + looked for to determine whether to copy or decompress. Returns -1 on error, + otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the + end of the input file has been reached and all data has been processed. */ +static int gz_fetch(gz_state *state) { + PREFIX3(stream) *strm = &(state->strm); + + do { + switch (state->how) { + case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ + if (gz_look(state) == -1) + return -1; + if (state->how == LOOK) + return 0; + break; + case COPY: /* -> COPY */ + if (gz_load(state, state->out, state->size << 1, &(state->x.have)) + == -1) + return -1; + state->x.next = state->out; + return 0; + case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + } while (state->x.have == 0 && (!state->eof || strm->avail_in)); + return 0; +} + +/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ +static int gz_skip(gz_state *state, z_off64_t len) { + unsigned n; + + /* skip over len bytes or reach end-of-file, whichever comes first */ + while (len) + /* skip over whatever is in output buffer */ + if (state->x.have) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? + (unsigned)len : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + len -= n; + } else if (state->eof && state->strm.avail_in == 0) { + /* output buffer empty -- return if we're at the end of the input */ + break; + } else { + /* need more data to skip -- load up output buffer */ + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return -1; + } + return 0; +} + +/* Read len bytes into buf from file, or less than len up to the end of the + input. Return the number of bytes read. If zero is returned, either the + end of file was reached, or there was an error. state->err must be + consulted in that case to determine which. */ +static size_t gz_read(gz_state *state, void *buf, size_t len) { + size_t got; + unsigned n; + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return 0; + } + + /* get len bytes to buf, or less than len if at the end */ + got = 0; + do { + /* set n to the maximum amount of len that fits in an unsigned int */ + n = (unsigned)-1; + if (n > len) + n = (unsigned)len; + + /* first just try copying data from the output buffer */ + if (state->x.have) { + if (state->x.have < n) + n = state->x.have; + memcpy(buf, state->x.next, n); + state->x.next += n; + state->x.have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) { + state->past = 1; /* tried to read past end */ + break; + } + + /* need output data -- for small len or new stream load up our output + buffer */ + else if (state->how == LOOK || n < (state->size << 1)) { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return 0; + continue; /* no progress yet -- go back to copy above */ + /* the copy above assures that we will leave with space in the + output buffer, allowing at least one gzungetc() to succeed */ + } + + /* large len -- read directly into user buffer */ + else if (state->how == COPY) { /* read directly */ + if (gz_load(state, (unsigned char *)buf, n, &n) == -1) + return 0; + } + + /* large len -- decompress directly into user buffer */ + else { /* state->how == GZIP */ + state->strm.avail_out = n; + state->strm.next_out = (unsigned char *)buf; + if (gz_decomp(state) == -1) + return 0; + n = state->x.have; + state->x.have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->x.pos += n; + } while (len); + + /* return number of bytes read into user buffer */ + return got; +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzread)(gzFile file, void *buf, unsigned len) { + gz_state *state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_state *)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); + return -1; + } + + /* read len or fewer bytes to buf */ + len = (unsigned)gz_read(state, buf, len); + + /* check for an error */ + if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* return the number of bytes read (this is assured to fit in an int) */ + return (int)len; +} + +/* -- see zlib.h -- */ +size_t Z_EXPORT PREFIX(gzfread)(void *buf, size_t size, size_t nitems, gzFile file) { + size_t len; + gz_state *state; + + /* Exit early if size is zero, also prevents potential division by zero */ + if (size == 0) + return 0; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_state *)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return 0; + + /* compute bytes to read -- error on overflow */ + if (size && SIZE_MAX / size < nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + len = nitems * size; + + /* read len or fewer bytes to buf, return the number of full items read */ + return len ? gz_read(state, buf, len) / size : 0; +} + +/* -- see zlib.h -- */ +#undef @ZLIB_SYMBOL_PREFIX@gzgetc +#undef @ZLIB_SYMBOL_PREFIX@zng_gzgetc +int Z_EXPORT PREFIX(gzgetc)(gzFile file) { + unsigned char buf[1]; + gz_state *state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_state *)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->x.have) { + state->x.have--; + state->x.pos++; + return *(state->x.next)++; + } + + /* nothing there -- try gz_read() */ + return gz_read(state, buf, 1) < 1 ? -1 : buf[0]; +} + +#ifdef ZLIB_COMPAT +int Z_EXPORT PREFIX(gzgetc_)(gzFile file) { + return PREFIX(gzgetc)(file); +} +#endif + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzungetc)(int c, gzFile file) { + gz_state *state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_state *)file; + + /* in case this was just opened, set up the input buffer */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* can't push EOF */ + if (c < 0) + return -1; + + /* if output buffer empty, put byte at end (allows more pushing) */ + if (state->x.have == 0) { + state->x.have = 1; + state->x.next = state->out + (state->size << 1) - 1; + state->x.next[0] = (unsigned char)c; + state->x.pos--; + state->past = 0; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->x.have == (state->size << 1)) { + gz_error(state, Z_DATA_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->x.next == state->out) { + unsigned char *src = state->out + state->x.have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->x.next = dest; + } + state->x.have++; + state->x.next--; + state->x.next[0] = (unsigned char)c; + state->x.pos--; + state->past = 0; + return c; +} + +/* -- see zlib.h -- */ +char * Z_EXPORT PREFIX(gzgets)(gzFile file, char *buf, int len) { + unsigned left, n; + char *str; + unsigned char *eol; + gz_state *state; + + /* check parameters and get internal structure */ + if (file == NULL || buf == NULL || len < 1) + return NULL; + state = (gz_state *)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return NULL; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return NULL; + } + + /* copy output bytes up to new line or len - 1, whichever comes first -- + append a terminating zero to the string (we don't check for a zero in + the contents, let the user worry about that) */ + str = buf; + left = (unsigned)len - 1; + if (left) { + do { + /* assure that something is in the output buffer */ + if (state->x.have == 0 && gz_fetch(state) == -1) + return NULL; /* error */ + if (state->x.have == 0) { /* end of file */ + state->past = 1; /* read past end */ + break; /* return what we have */ + } + + /* look for end-of-line in current output buffer */ + n = state->x.have > left ? left : state->x.have; + eol = (unsigned char *)memchr(state->x.next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->x.next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->x.next, n); + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + } + + /* return terminated string, or if nothing, end of file */ + if (buf == str) + return NULL; + buf[0] = 0; + return str; +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzdirect)(gzFile file) { + gz_state *state; + + /* get internal structure */ + if (file == NULL) + return 0; + + state = (gz_state *)file; + + /* if the state is not known, but we can find out, then do so (this is + mainly for right after a gzopen() or gzdopen()) */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* return 1 if transparent, 0 if processing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzclose_r)(gzFile file) { + int ret, err; + gz_state *state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + + state = (gz_state *)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return Z_STREAM_ERROR; + + /* free memory and close file */ + if (state->size) { + PREFIX(inflateEnd)(&(state->strm)); + zng_free(state->out); + zng_free(state->in); + } + err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + zng_free(state); + return ret ? Z_ERRNO : err; +} diff --git a/gzwrite.c b/gzwrite.c new file mode 100644 index 0000000000..08e0ce9aab --- /dev/null +++ b/gzwrite.c @@ -0,0 +1,526 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zutil_p.h" +#include +#include "gzguts.h" + +/* Local functions */ +static int gz_init(gz_state *); +static int gz_comp(gz_state *, int); +static int gz_zero(gz_state *, z_off64_t); +static size_t gz_write(gz_state *, void const *, size_t); + +/* Initialize state for writing a gzip file. Mark initialization by setting + state->size to non-zero. Return -1 on a memory allocation failure, or 0 on + success. */ +static int gz_init(gz_state *state) { + int ret; + PREFIX3(stream) *strm = &(state->strm); + + /* allocate input buffer (double size for gzprintf) */ + state->in = (unsigned char *)zng_alloc(state->want << 1); + if (state->in == NULL) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + memset(state->in, 0, state->want << 1); + + /* only need output buffer and deflate state if compressing */ + if (!state->direct) { + /* allocate output buffer */ + state->out = (unsigned char *)zng_alloc(state->want); + if (state->out == NULL) { + zng_free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = NULL; + strm->zfree = NULL; + strm->opaque = NULL; + ret = PREFIX(deflateInit2)(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); + if (ret != Z_OK) { + zng_free(state->out); + zng_free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + strm->next_in = NULL; + } + + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer if compressing */ + if (!state->direct) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = strm->next_out; + } + return 0; +} + +/* Compress whatever is at avail_in and next_in and write to the output file. + Return -1 if there is an error writing to the output file or if gz_init() + fails to allocate memory, otherwise 0. flush is assumed to be a valid + deflate() flush value. If flush is Z_FINISH, then the deflate() state is + reset to start a new gzip stream. If gz->direct is true, then simply write + to the output file without compressing, and ignore flush. */ +static int gz_comp(gz_state *state, int flush) { + int ret; + ssize_t got; + unsigned have; + PREFIX3(stream) *strm = &(state->strm); + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return -1; + + /* write directly if requested */ + if (state->direct) { + got = write(state->fd, strm->next_in, strm->avail_in); + if (got < 0 || (unsigned)got != strm->avail_in) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in = 0; + return 0; + } + + /* check for a pending reset */ + if (state->reset) { + /* don't start a new gzip member unless there is data to write */ + if (strm->avail_in == 0) + return 0; + PREFIX(deflateReset)(strm); + state->reset = 0; + } + + /* run deflate() on provided input until it produces no more output */ + ret = Z_OK; + do { + /* write out current buffer contents if full, or if flushing, but if + doing Z_FINISH then don't write until we get to Z_STREAM_END */ + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { + have = (unsigned)(strm->next_out - state->x.next); + if (have && ((got = write(state->fd, state->x.next, (unsigned long)have)) < 0 || (unsigned)got != have)) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (strm->avail_out == 0) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = state->out; + } + state->x.next = strm->next_out; + } + + /* compress */ + have = strm->avail_out; + ret = PREFIX(deflate)(strm, flush); + if (ret == Z_STREAM_ERROR) { + gz_error(state, Z_STREAM_ERROR, "internal error: deflate stream corrupt"); + return -1; + } + have -= strm->avail_out; + } while (have); + + /* if that completed a deflate stream, allow another to start */ + if (flush == Z_FINISH) + state->reset = 1; + /* all done, no errors */ + return 0; +} + +/* Compress len zeros to output. Return -1 on a write error or memory + allocation failure by gz_comp(), or 0 on success. */ +static int gz_zero(gz_state *state, z_off64_t len) { + int first; + unsigned n; + PREFIX3(stream) *strm = &(state->strm); + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + + /* compress len zeros (len guaranteed > 0) */ + first = 1; + while (len) { + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? (unsigned)len : state->size; + if (first) { + memset(state->in, 0, n); + first = 0; + } + strm->avail_in = n; + strm->next_in = state->in; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + len -= n; + } + return 0; +} + +/* Write len bytes from buf to file. Return the number of bytes written. If + the returned value is less than len, then there was an error. */ +static size_t gz_write(gz_state *state, void const *buf, size_t len) { + size_t put = len; + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* for small len, copy to input buffer, otherwise compress directly */ + if (len < state->size) { + /* copy to input buffer, compress when full */ + do { + unsigned have, copy; + + if (state->strm.avail_in == 0) + state->strm.next_in = state->in; + have = (unsigned)((state->strm.next_in + state->strm.avail_in) - + state->in); + copy = state->size - have; + if (copy > len) + copy = (unsigned)len; + memcpy(state->in + have, buf, copy); + state->strm.avail_in += copy; + state->x.pos += copy; + buf = (const char *)buf + copy; + len -= copy; + if (len && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } while (len); + } else { + /* consume whatever's left in the input buffer */ + if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* directly compress user buffer to file */ + state->strm.next_in = (z_const unsigned char *) buf; + do { + unsigned n = (unsigned)-1; + if (n > len) + n = (unsigned)len; + state->strm.avail_in = n; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + len -= n; + } while (len); + } + + /* input was all buffered or compressed */ + return put; +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzwrite)(gzFile file, void const *buf, unsigned len) { + gz_state *state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_state *)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return 0; + } + + /* write len bytes from buf (the return value will fit in an int) */ + return (int)gz_write(state, buf, len); +} + +/* -- see zlib.h -- */ +size_t Z_EXPORT PREFIX(gzfwrite)(void const *buf, size_t size, size_t nitems, gzFile file) { + size_t len; + gz_state *state; + + /* Exit early if size is zero, also prevents potential division by zero */ + if (size == 0) + return 0; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_state *)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* write len bytes to buf, return the number of full items written */ + return len ? gz_write(state, buf, len) / size : 0; +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzputc)(gzFile file, int c) { + unsigned have; + unsigned char buf[1]; + gz_state *state; + PREFIX3(stream) *strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_state *)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* try writing to input buffer for speed (state->size == 0 if buffer not + initialized) */ + if (state->size) { + if (strm->avail_in == 0) + strm->next_in = state->in; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + if (have < state->size) { + state->in[have] = (unsigned char)c; + strm->avail_in++; + state->x.pos++; + return c & 0xff; + } + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = (unsigned char)c; + if (gz_write(state, buf, 1) != 1) + return -1; + return c & 0xff; +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzputs)(gzFile file, const char *s) { + size_t len, put; + gz_state *state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_state *)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* write string */ + len = strlen(s); + if ((int)len < 0 || (unsigned)len != len) { + gz_error(state, Z_STREAM_ERROR, "string length does not fit in int"); + return -1; + } + put = gz_write(state, s, len); + return put < len ? -1 : (int)len; +} + +/* -- see zlib.h -- */ +int Z_EXPORTVA PREFIX(gzvprintf)(gzFile file, const char *format, va_list va) { + int len; + unsigned left; + char *next; + gz_state *state; + PREFIX3(stream) *strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_state *)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return state->err; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); + next[state->size - 1] = 0; + len = vsnprintf(next, state->size, format, va); + + /* check that printf() results fit in buffer */ + if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) + return 0; + + /* update buffer and position, compress first half if past that */ + strm->avail_in += (unsigned)len; + state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memmove(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return len; +} + +int Z_EXPORTVA PREFIX(gzprintf)(gzFile file, const char *format, ...) { + va_list va; + int ret; + + va_start(va, format); + ret = PREFIX(gzvprintf)(file, format, va); + va_end(va); + return ret; +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzflush)(gzFile file, int flush) { + gz_state *state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_state *)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* check flush parameter */ + if (flush < 0 || flush > Z_FINISH) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* compress remaining data with requested flush */ + (void)gz_comp(state, flush); + return state->err; +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzsetparams)(gzFile file, int level, int strategy) { + gz_state *state; + PREFIX3(stream) *strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_state *)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct) + return Z_STREAM_ERROR; + + /* if no change is requested, then do nothing */ + if (level == state->level && strategy == state->strategy) + return Z_OK; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* change compression parameters for subsequent input */ + if (state->size) { + /* flush previous input with previous parameters before changing */ + if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) + return state->err; + PREFIX(deflateParams)(strm, level, strategy); + } + state->level = level; + state->strategy = strategy; + return Z_OK; +} + +/* -- see zlib.h -- */ +int Z_EXPORT PREFIX(gzclose_w)(gzFile file) { + int ret = Z_OK; + gz_state *state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_state *)file; + + /* check that we're writing */ + if (state->mode != GZ_WRITE) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + ret = state->err; + } + + /* flush, free memory, and close file */ + if (gz_comp(state, Z_FINISH) == -1) + ret = state->err; + if (state->size) { + if (!state->direct) { + (void)PREFIX(deflateEnd)(&(state->strm)); + zng_free(state->out); + } + zng_free(state->in); + } + gz_error(state, Z_OK, NULL); + free(state->path); + if (close(state->fd) == -1) + ret = Z_ERRNO; + zng_free(state); + return ret; +} diff --git a/infback.c b/infback.c new file mode 100644 index 0000000000..b6d98d4a3f --- /dev/null +++ b/infback.c @@ -0,0 +1,523 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zbuild.h" +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inflate_p.h" +#include "functable.h" + +/* Avoid conflicts with zlib.h macros */ +#ifdef ZLIB_COMPAT +# undef inflateBackInit +#endif + +/* + strm provides memory allocation functions in zalloc and zfree, or + NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + + This function is hidden in ZLIB_COMPAT builds. + */ +int32_t ZNG_CONDEXPORT PREFIX(inflateBackInit)(PREFIX3(stream) *strm, int32_t windowBits, uint8_t *window) { + struct inflate_state *state; + + if (strm == NULL || window == NULL || windowBits < MIN_WBITS || windowBits > MAX_WBITS) + return Z_STREAM_ERROR; + strm->msg = NULL; /* in case we return an error */ + if (strm->zalloc == NULL) { + strm->zalloc = PREFIX(zcalloc); + strm->opaque = NULL; + } + if (strm->zfree == NULL) + strm->zfree = PREFIX(zcfree); + + inflate_allocs *alloc_bufs = alloc_inflate(strm); + if (alloc_bufs == NULL) + return Z_MEM_ERROR; + + state = alloc_bufs->state; + state->alloc_bufs = alloc_bufs; + Tracev((stderr, "inflate: allocated\n")); + + strm->state = (struct internal_state *)state; + state->wbits = (unsigned int)windowBits; + state->wsize = 1U << windowBits; + state->wbufsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + state->chunksize = FUNCTABLE_CALL(chunksize)(); +#ifdef INFLATE_STRICT + state->dmax = 32768U; +#endif +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = 1; +#endif + return Z_OK; +} + +/* Function used by zlib.h and zlib-ng version 2.0 macros */ +int32_t Z_EXPORT PREFIX(inflateBackInit_)(PREFIX3(stream) *strm, int32_t windowBits, uint8_t *window, + const char *version, int32_t stream_size) { + if (CHECK_VER_STSIZE(version, stream_size)) + return Z_VERSION_ERROR; + return PREFIX(inflateBackInit)(strm, windowBits, window); +} + +/* + Private macros for inflateBack() + Look in inflate_p.h for macros shared with inflate() +*/ + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += ((uint64_t)(*next++) << bits); \ + bits += 8; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is NULL or the state was not initialized. + */ +int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in_desc, out_func out, void *out_desc) { + struct inflate_state *state; + z_const unsigned char *next; /* next input */ + unsigned char *put; /* next output */ + unsigned have, left; /* available input and output */ + uint64_t hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int32_t ret; /* return code */ + static const uint16_t order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == NULL || strm->state == NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + + /* Reset the state */ + strm->msg = NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + PREFIX(fixedtables)(state); + Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + SET_BAD("invalid block type"); + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + SET_BAD("invalid stored block lengths"); + break; + } + state->length = (uint16_t)hold; + Tracev((stderr, "inflate: stored length %u\n", state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + copy = MIN(copy, have); + copy = MIN(copy, left); + memcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + SET_BAD("too many length or distance symbols"); + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + + /* get code length code lengths (not a typo) */ + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (uint16_t)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code *)(state->next); + state->lenbits = 7; + ret = zng_inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); + if (ret) { + SET_BAD("invalid code lengths set"); + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + + /* get length and distance code code lengths */ + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if (here.bits <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + SET_BAD("invalid bit length repeat"); + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + SET_BAD("invalid bit length repeat"); + break; + } + while (copy) { + --copy; + state->lens[state->have++] = (uint16_t)len; + } + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) + break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + SET_BAD("invalid code -- missing end-of-block"); + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (10 and 9) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code *)(state->next); + state->lenbits = 10; + ret = zng_inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); + if (ret) { + SET_BAD("invalid literal/lengths set"); + break; + } + state->distcode = (const code *)(state->next); + state->distbits = 9; + ret = zng_inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + SET_BAD("invalid distances set"); + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + Z_FALLTHROUGH; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= INFLATE_FAST_MIN_HAVE && + left >= INFLATE_FAST_MIN_LEFT) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + FUNCTABLE_CALL(inflate_fast)(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if (here.bits <= bits) + break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)last.bits + (unsigned)here.bits <= bits) + break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = here.val; + + /* process literal */ + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + SET_BAD("invalid literal/length code"); + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (here.op & MAX_BITS); + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if (here.bits <= bits) + break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)last.bits + (unsigned)here.bits <= bits) + break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + SET_BAD("invalid distance code"); + break; + } + state->offset = here.val; + state->extra = (here.op & MAX_BITS); + + /* get distance extra bits, if any */ + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->wsize - (state->whave < state->wsize ? left : 0)) { + SET_BAD("invalid distance too far back"); + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } else { + from = put - state->offset; + copy = left; + } + copy = MIN(copy, state->length); + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly */ + ret = Z_STREAM_END; + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Write leftover output and return unused input */ + inf_leave: + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left) && (ret == Z_STREAM_END)) { + ret = Z_BUF_ERROR; + } + } + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int32_t Z_EXPORT PREFIX(inflateBackEnd)(PREFIX3(stream) *strm) { + if (strm == NULL || strm->state == NULL || strm->zfree == NULL) + return Z_STREAM_ERROR; + + /* Free allocated buffers */ + free_inflate(strm); + + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/inffast_tpl.h b/inffast_tpl.h new file mode 100644 index 0000000000..2ec865dbff --- /dev/null +++ b/inffast_tpl.h @@ -0,0 +1,332 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zendian.h" +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inflate_p.h" +#include "functable.h" + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= INFLATE_FAST_MIN_HAVE + strm->avail_out >= INFLATE_FAST_MIN_LEFT + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - On some architectures, it can be significantly faster (e.g. up to 1.2x + faster on x86_64) to load from strm->next_in 64 bits, or 8 bytes, at a + time, so INFLATE_FAST_MIN_HAVE == 8. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void Z_INTERNAL INFLATE_FAST(PREFIX3(stream) *strm, uint32_t start) { + /* start: inflate()'s starting value for strm->avail_out */ + struct inflate_state *state; + z_const unsigned char *in; /* local strm->next_in */ + const unsigned char *last; /* have enough input while in < last */ + unsigned char *out; /* local strm->next_out */ + unsigned char *beg; /* inflate()'s initial strm->next_out */ + unsigned char *end; /* while out < end, enough space available */ + unsigned char *safe; /* can use chunkcopy provided out < safe */ + unsigned char *window; /* allocated sliding window, if wsize != 0 */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + + /* hold is a local copy of strm->hold. By default, hold satisfies the same + invariants that strm->hold does, namely that (hold >> bits) == 0. This + invariant is kept by loading bits into hold one byte at a time, like: + + hold |= next_byte_of_input << bits; in++; bits += 8; + + If we need to ensure that bits >= 15 then this code snippet is simply + repeated. Over one iteration of the outermost do/while loop, this + happens up to six times (48 bits of input), as described in the NOTES + above. + + However, on some little endian architectures, it can be significantly + faster to load 64 bits once instead of 8 bits six times: + + if (bits <= 16) { + hold |= next_8_bytes_of_input << bits; in += 6; bits += 48; + } + + Unlike the simpler one byte load, shifting the next_8_bytes_of_input + by bits will overflow and lose those high bits, up to 2 bytes' worth. + The conservative estimate is therefore that we have read only 6 bytes + (48 bits). Again, as per the NOTES above, 48 bits is sufficient for the + rest of the iteration, and we will not need to load another 8 bytes. + + Inside this function, we no longer satisfy (hold >> bits) == 0, but + this is not problematic, even if that overflow does not land on an 8 bit + byte boundary. Those excess bits will eventually shift down lower as the + Huffman decoder consumes input, and when new input bits need to be loaded + into the bits variable, the same input bits will be or'ed over those + existing bits. A bitwise or is idempotent: (a | b | b) equals (a | b). + Note that we therefore write that load operation as "hold |= etc" and not + "hold += etc". + + Outside that loop, at the end of the function, hold is bitwise and'ed + with (1<hold >> state->bits) == 0. + */ + unsigned bits; /* local strm->bits */ + uint64_t hold; /* local strm->hold */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code const *lcode; /* local strm->lencode */ + code const *dcode; /* local strm->distcode */ + const code *here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned char *from; /* where to copy match from */ + unsigned dist; /* match distance */ + unsigned extra_safe; /* copy chunks safely in all cases */ + + /* copy state to local variables */ + state = (struct inflate_state *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - (INFLATE_FAST_MIN_HAVE - 1)); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - (INFLATE_FAST_MIN_LEFT - 1)); + safe = out + strm->avail_out; + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* Detect if out and window point to the same memory allocation. In this instance it is + necessary to use safe chunk copy functions to prevent overwriting the window. If the + window is overwritten then future matches with far distances will fail to copy correctly. */ + extra_safe = (wsize != 0 && out >= window && out + INFLATE_FAST_MIN_LEFT <= window + state->wbufsize); + +#define REFILL() do { \ + hold |= load_64_bits(in, bits); \ + in += 7; \ + in -= ((bits >> 3) & 7); \ + bits |= 56; \ + } while (0) + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + REFILL(); + here = lcode + (hold & lmask); + if (here->op == 0) { + *out++ = (unsigned char)(here->val); + DROPBITS(here->bits); + here = lcode + (hold & lmask); + if (here->op == 0) { + *out++ = (unsigned char)(here->val); + DROPBITS(here->bits); + here = lcode + (hold & lmask); + } + } + dolen: + DROPBITS(here->bits); + op = here->op; + if (op == 0) { /* literal */ + Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here->val)); + *out++ = (unsigned char)(here->val); + } else if (op & 16) { /* length base */ + len = here->val; + op &= MAX_BITS; /* number of extra bits */ + len += BITS(op); + DROPBITS(op); + Tracevv((stderr, "inflate: length %u\n", len)); + here = dcode + (hold & dmask); + if (bits < MAX_BITS + MAX_DIST_EXTRA_BITS) { + REFILL(); + } + dodist: + DROPBITS(here->bits); + op = here->op; + if (op & 16) { /* distance base */ + dist = here->val; + op &= MAX_BITS; /* number of extra bits */ + dist += BITS(op); +#ifdef INFLATE_STRICT + if (dist > state->dmax) { + SET_BAD("invalid distance too far back"); + break; + } +#endif + DROPBITS(op); + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (state->sane) { + SET_BAD("invalid distance too far back"); + break; + } + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#else + SET_BAD("invalid distance too far back"); + break; +#endif + } + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + } else if (wnext >= op) { /* contiguous in window */ + from += wnext - op; + } else { /* wrap around window */ + op -= wnext; + from += wsize - op; + if (op < len) { /* some from end of window */ + len -= op; + out = CHUNKCOPY_SAFE(out, from, op, safe); + from = window; /* more from start of window */ + op = wnext; + /* This (rare) case can create a situation where + the first chunkcopy below must be checked. + */ + } + } + if (op < len) { /* still need some from output */ + len -= op; + if (!extra_safe) { + out = CHUNKCOPY_SAFE(out, from, op, safe); + out = CHUNKUNROLL(out, &dist, &len); + out = CHUNKCOPY_SAFE(out, out - dist, len, safe); + } else { + out = chunkcopy_safe(out, from, op, safe); + out = chunkcopy_safe(out, out - dist, len, safe); + } + } else { +#ifndef HAVE_MASKED_READWRITE + if (extra_safe) + out = chunkcopy_safe(out, from, len, safe); + else +#endif + out = CHUNKCOPY_SAFE(out, from, len, safe); + } +#ifndef HAVE_MASKED_READWRITE + } else if (extra_safe) { + /* Whole reference is in range of current output. */ + out = chunkcopy_safe(out, out - dist, len, safe); +#endif + } else { + /* Whole reference is in range of current output. No range checks are + necessary because we start with room for at least 258 bytes of output, + so unroll and roundoff operations can write beyond `out+len` so long + as they stay within 258 bytes of `out`. + */ + if (dist >= len || dist >= state->chunksize) + out = CHUNKCOPY(out, out - dist, len); + else + out = CHUNKMEMSET(out, out - dist, len); + } + } else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode + here->val + BITS(op); + goto dodist; + } else { + SET_BAD("invalid distance code"); + break; + } + } else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode + here->val + BITS(op); + goto dolen; + } else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } else { + SET_BAD("invalid literal/length code"); + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (UINT64_C(1) << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? (INFLATE_FAST_MIN_HAVE - 1) + (last - in) + : (INFLATE_FAST_MIN_HAVE - 1) - (in - last)); + strm->avail_out = (unsigned)(out < end ? (INFLATE_FAST_MIN_LEFT - 1) + (end - out) + : (INFLATE_FAST_MIN_LEFT - 1) - (out - end)); + + Assert(bits <= 32, "Remaining bits greater than 32"); + state->hold = (uint32_t)hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ diff --git a/inffixed_tbl.h b/inffixed_tbl.h new file mode 100644 index 0000000000..7292fa06ec --- /dev/null +++ b/inffixed_tbl.h @@ -0,0 +1,94 @@ +/* inffixed_tbl.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + +/* WARNING: this file should *not* be used by applications. + * It is part of the implementation of this library and is + * subject to change. Applications should only use zlib.h. + */ + +static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} +}; + +static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} +}; diff --git a/inflate.c b/inflate.c new file mode 100644 index 0000000000..8c373da69d --- /dev/null +++ b/inflate.c @@ -0,0 +1,1462 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inflate_p.h" +#include "inffixed_tbl.h" +#include "functable.h" + +/* Avoid conflicts with zlib.h macros */ +#ifdef ZLIB_COMPAT +# undef inflateInit +# undef inflateInit2 +#endif + +/* function prototypes */ +static int inflateStateCheck(PREFIX3(stream) *strm); +static void updatewindow(PREFIX3(stream) *strm, const uint8_t *end, uint32_t len, int32_t cksum); +static uint32_t syncsearch(uint32_t *have, const unsigned char *buf, uint32_t len); + +static inline void inf_chksum_cpy(PREFIX3(stream) *strm, uint8_t *dst, + const uint8_t *src, uint32_t copy) { + if (!copy) return; + struct inflate_state *state = (struct inflate_state*)strm->state; +#ifdef GUNZIP + if (state->flags) { + FUNCTABLE_CALL(crc32_fold_copy)(&state->crc_fold, dst, src, copy); + } else +#endif + { + strm->adler = state->check = FUNCTABLE_CALL(adler32_fold_copy)(state->check, dst, src, copy); + } +} + +static inline void inf_chksum(PREFIX3(stream) *strm, const uint8_t *src, uint32_t len) { + struct inflate_state *state = (struct inflate_state*)strm->state; +#ifdef GUNZIP + if (state->flags) { + FUNCTABLE_CALL(crc32_fold)(&state->crc_fold, src, len, 0); + } else +#endif + { + strm->adler = state->check = FUNCTABLE_CALL(adler32)(state->check, src, len); + } +} + +static int inflateStateCheck(PREFIX3(stream) *strm) { + struct inflate_state *state; + if (strm == NULL || strm->zalloc == NULL || strm->zfree == NULL) + return 1; + state = (struct inflate_state *)strm->state; + if (state == NULL || state->alloc_bufs == NULL || state->strm != strm || state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + +int32_t Z_EXPORT PREFIX(inflateResetKeep)(PREFIX3(stream) *strm) { + struct inflate_state *state; + + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->check = ADLER32_INITIAL_VALUE; + state->last = 0; + state->havedict = 0; + state->flags = -1; + state->head = NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->back = -1; +#ifdef INFLATE_STRICT + state->dmax = 32768U; +#endif +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = 1; +#endif + INFLATE_RESET_KEEP_HOOK(strm); /* hook for IBM Z DFLTCC */ + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int32_t Z_EXPORT PREFIX(inflateReset)(PREFIX3(stream) *strm) { + struct inflate_state *state; + + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return PREFIX(inflateResetKeep)(strm); +} + +int32_t Z_EXPORT PREFIX(inflateReset2)(PREFIX3(stream) *strm, int32_t windowBits) { + int wrap; + struct inflate_state *state; + + /* get the state */ + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + if (windowBits < -MAX_WBITS) + return Z_STREAM_ERROR; + windowBits = -windowBits; + } else { + wrap = (windowBits >> 4) + 5; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= MAX_WBITS; +#endif + } + + /* set number of window bits */ + if (windowBits && (windowBits < MIN_WBITS || windowBits > MAX_WBITS)) + return Z_STREAM_ERROR; + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return PREFIX(inflateReset)(strm); +} + +#ifdef INF_ALLOC_DEBUG +# include +# define LOGSZ(name,size) fprintf(stderr, "%s is %d bytes\n", name, size) +# define LOGSZP(name,size,loc,pad) fprintf(stderr, "%s is %d bytes, offset %d, padded %d\n", name, size, loc, pad) +# define LOGSZPL(name,size,loc,pad) fprintf(stderr, "%s is %d bytes, offset %ld, padded %d\n", name, size, loc, pad) +#else +# define LOGSZ(name,size) +# define LOGSZP(name,size,loc,pad) +# define LOGSZPL(name,size,loc,pad) +#endif + +/* =========================================================================== + * Allocate a big buffer and divide it up into the various buffers inflate needs. + * Handles alignment of allocated buffer and alignment of individual buffers. + */ +Z_INTERNAL inflate_allocs* alloc_inflate(PREFIX3(stream) *strm) { + int curr_size = 0; + + /* Define sizes */ + int window_size = INFLATE_ADJUST_WINDOW_SIZE((1 << MAX_WBITS) + 64); /* 64B padding for chunksize */ + int state_size = sizeof(inflate_state); + int alloc_size = sizeof(inflate_allocs); + + /* Calculate relative buffer positions and paddings */ + LOGSZP("window", window_size, PAD_WINDOW(curr_size), PADSZ(curr_size,WINDOW_PAD_SIZE)); + int window_pos = PAD_WINDOW(curr_size); + curr_size = window_pos + window_size; + + LOGSZP("state", state_size, PAD_64(curr_size), PADSZ(curr_size,64)); + int state_pos = PAD_64(curr_size); + curr_size = state_pos + state_size; + + LOGSZP("alloc", alloc_size, PAD_16(curr_size), PADSZ(curr_size,16)); + int alloc_pos = PAD_16(curr_size); + curr_size = alloc_pos + alloc_size; + + /* Add 64-1 or 4096-1 to allow window alignment, and round size of buffer up to multiple of 64 */ + int total_size = PAD_64(curr_size + (WINDOW_PAD_SIZE - 1)); + + /* Allocate buffer, align to 64-byte cacheline, and zerofill the resulting buffer */ + char *original_buf = (char *)strm->zalloc(strm->opaque, 1, total_size); + if (original_buf == NULL) + return NULL; + + char *buff = (char *)HINT_ALIGNED_WINDOW((char *)PAD_WINDOW(original_buf)); + LOGSZPL("Buffer alloc", total_size, PADSZ((uintptr_t)original_buf,WINDOW_PAD_SIZE), PADSZ(curr_size,WINDOW_PAD_SIZE)); + + /* Initialize alloc_bufs */ + inflate_allocs *alloc_bufs = (struct inflate_allocs_s *)(buff + alloc_pos); + alloc_bufs->buf_start = original_buf; + alloc_bufs->zfree = strm->zfree; + + alloc_bufs->window = (unsigned char *)HINT_ALIGNED_WINDOW((buff + window_pos)); + alloc_bufs->state = (inflate_state *)HINT_ALIGNED_64((buff + state_pos)); + +#ifdef Z_MEMORY_SANITIZER + /* This is _not_ to subvert the memory sanitizer but to instead unposion some + data we willingly and purposefully load uninitialized into vector registers + in order to safely read the last < chunksize bytes of the window. */ + __msan_unpoison(alloc_bufs->window + window_size, 64); +#endif + + return alloc_bufs; +} + +/* =========================================================================== + * Free all allocated inflate buffers + */ +Z_INTERNAL void free_inflate(PREFIX3(stream) *strm) { + struct inflate_state *state = (struct inflate_state *)strm->state; + + if (state->alloc_bufs != NULL) { + inflate_allocs *alloc_bufs = state->alloc_bufs; + alloc_bufs->zfree(strm->opaque, alloc_bufs->buf_start); + strm->state = NULL; + } +} + +/* =========================================================================== + * Initialize inflate state and buffers. + * This function is hidden in ZLIB_COMPAT builds. + */ +int32_t ZNG_CONDEXPORT PREFIX(inflateInit2)(PREFIX3(stream) *strm, int32_t windowBits) { + struct inflate_state *state; + int32_t ret; + + /* Initialize functable */ + FUNCTABLE_INIT; + + if (strm == NULL) + return Z_STREAM_ERROR; + strm->msg = NULL; /* in case we return an error */ + if (strm->zalloc == NULL) { + strm->zalloc = PREFIX(zcalloc); + strm->opaque = NULL; + } + if (strm->zfree == NULL) + strm->zfree = PREFIX(zcfree); + + inflate_allocs *alloc_bufs = alloc_inflate(strm); + if (alloc_bufs == NULL) + return Z_MEM_ERROR; + + state = alloc_bufs->state; + state->window = alloc_bufs->window; + state->alloc_bufs = alloc_bufs; + state->wbufsize = INFLATE_ADJUST_WINDOW_SIZE((1 << MAX_WBITS) + 64); + Tracev((stderr, "inflate: allocated\n")); + + strm->state = (struct internal_state *)state; + state->strm = strm; + state->mode = HEAD; /* to pass state test in inflateReset2() */ + state->chunksize = FUNCTABLE_CALL(chunksize)(); + ret = PREFIX(inflateReset2)(strm, windowBits); + if (ret != Z_OK) { + free_inflate(strm); + } + return ret; +} + +#ifndef ZLIB_COMPAT +int32_t Z_EXPORT PREFIX(inflateInit)(PREFIX3(stream) *strm) { + return PREFIX(inflateInit2)(strm, DEF_WBITS); +} +#endif + +/* Function used by zlib.h and zlib-ng version 2.0 macros */ +int32_t Z_EXPORT PREFIX(inflateInit_)(PREFIX3(stream) *strm, const char *version, int32_t stream_size) { + if (CHECK_VER_STSIZE(version, stream_size)) + return Z_VERSION_ERROR; + return PREFIX(inflateInit2)(strm, DEF_WBITS); +} + +/* Function used by zlib.h and zlib-ng version 2.0 macros */ +int32_t Z_EXPORT PREFIX(inflateInit2_)(PREFIX3(stream) *strm, int32_t windowBits, const char *version, int32_t stream_size) { + if (CHECK_VER_STSIZE(version, stream_size)) + return Z_VERSION_ERROR; + return PREFIX(inflateInit2)(strm, windowBits); +} + +int32_t Z_EXPORT PREFIX(inflatePrime)(PREFIX3(stream) *strm, int32_t bits, int32_t value) { + struct inflate_state *state; + + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + if (bits == 0) + return Z_OK; + INFLATE_PRIME_HOOK(strm, bits, value); /* hook for IBM Z DFLTCC */ + state = (struct inflate_state *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + (unsigned int)bits > 32) + return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += (uint64_t)value << state->bits; + state->bits += (unsigned int)bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. This returns fixed tables from inffixed_tbl.h. + */ + +void Z_INTERNAL PREFIX(fixedtables)(struct inflate_state *state) { + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +static void updatewindow(PREFIX3(stream) *strm, const uint8_t *end, uint32_t len, int32_t cksum) { + struct inflate_state *state; + uint32_t dist; + + state = (struct inflate_state *)strm->state; + + /* if window not in use yet, initialize */ + if (state->wsize == 0) + state->wsize = 1U << state->wbits; + + /* len state->wsize or less output bytes into the circular window */ + if (len >= state->wsize) { + /* Only do this if the caller specifies to checksum bytes AND the platform requires + * it (s/390 being the primary exception to this) */ + if (INFLATE_NEED_CHECKSUM(strm) && cksum) { + /* We have to split the checksum over non-copied and copied bytes */ + if (len > state->wsize) + inf_chksum(strm, end - len, len - state->wsize); + inf_chksum_cpy(strm, state->window, end - state->wsize, state->wsize); + } else { + memcpy(state->window, end - state->wsize, state->wsize); + } + + state->wnext = 0; + state->whave = state->wsize; + } else { + dist = state->wsize - state->wnext; + /* Only do this if the caller specifies to checksum bytes AND the platform requires + * We need to maintain the correct order here for the checksum */ + dist = MIN(dist, len); + if (INFLATE_NEED_CHECKSUM(strm) && cksum) { + inf_chksum_cpy(strm, state->window + state->wnext, end - len, dist); + } else { + memcpy(state->window + state->wnext, end - len, dist); + } + len -= dist; + if (len) { + if (INFLATE_NEED_CHECKSUM(strm) && cksum) { + inf_chksum_cpy(strm, state->window, end - len, len); + } else { + memcpy(state->window, end - len, len); + } + + state->wnext = len; + state->whave = state->wsize; + } else { + state->wnext += dist; + if (state->wnext == state->wsize) + state->wnext = 0; + if (state->whave < state->wsize) + state->whave += dist; + } + } +} + +/* + Private macros for inflate() + Look in inflate_p.h for macros shared with inflateBack() +*/ + +/* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += ((uint64_t)(*next++) << bits); \ + bits += 8; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { + struct inflate_state *state; + const unsigned char *next; /* next input */ + unsigned char *put; /* next output */ + unsigned char *from; /* where to copy match bytes from */ + unsigned have, left; /* available input and output */ + uint64_t hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + uint32_t in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int32_t ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const uint16_t order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (inflateStateCheck(strm) || strm->next_out == NULL || + (strm->next_in == NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state *)strm->state; + if (state->mode == TYPE) /* skip check */ + state->mode = TYPEDO; + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = MAX_WBITS; + state->check = CRC32_INITIAL_VALUE; + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + if (state->head != NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + SET_BAD("incorrect header check"); + break; + } + if (BITS(4) != Z_DEFLATED) { + SET_BAD("unknown compression method"); + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + if (len > MAX_WBITS || len > state->wbits) { + SET_BAD("invalid window size"); + break; + } +#ifdef INFLATE_STRICT + state->dmax = 1U << len; +#endif + state->flags = 0; /* indicate zlib header */ + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = ADLER32_INITIAL_VALUE; + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + SET_BAD("unknown compression method"); + break; + } + if (state->flags & 0xe000) { + SET_BAD("unknown header flags set"); + break; + } + if (state->head != NULL) + state->head->text = (int)((hold >> 8) & 1); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + Z_FALLTHROUGH; + + case TIME: + NEEDBITS(32); + if (state->head != NULL) + state->head->time = (unsigned)(hold); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + Z_FALLTHROUGH; + + case OS: + NEEDBITS(16); + if (state->head != NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + Z_FALLTHROUGH; + + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (uint16_t)hold; + if (state->head != NULL) + state->head->extra_len = (uint16_t)hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + } else if (state->head != NULL) { + state->head->extra = NULL; + } + state->mode = EXTRA; + Z_FALLTHROUGH; + + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) + copy = have; + if (copy) { + if (state->head != NULL && state->head->extra != NULL) { + len = state->head->extra_len - state->length; + if (len < state->head->extra_max) { + memcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + } + if ((state->flags & 0x0200) && (state->wrap & 4)) { + state->check = PREFIX(crc32)(state->check, next, copy); + } + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) + goto inf_leave; + } + state->length = 0; + state->mode = NAME; + Z_FALLTHROUGH; + + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != NULL && state->head->name != NULL && state->length < state->head->name_max) + state->head->name[state->length++] = (unsigned char)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = PREFIX(crc32)(state->check, next, copy); + have -= copy; + next += copy; + if (len) + goto inf_leave; + } else if (state->head != NULL) { + state->head->name = NULL; + } + state->length = 0; + state->mode = COMMENT; + Z_FALLTHROUGH; + + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != NULL && state->head->comment != NULL + && state->length < state->head->comm_max) + state->head->comment[state->length++] = (unsigned char)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = PREFIX(crc32)(state->check, next, copy); + have -= copy; + next += copy; + if (len) + goto inf_leave; + } else if (state->head != NULL) { + state->head->comment = NULL; + } + state->mode = HCRC; + Z_FALLTHROUGH; + + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { + SET_BAD("header crc mismatch"); + break; + } + INITBITS(); + } + if (state->head != NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + /* compute crc32 checksum if not in raw mode */ + if ((state->wrap & 4) && state->flags) + strm->adler = state->check = FUNCTABLE_CALL(crc32_fold_reset)(&state->crc_fold); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32((unsigned)hold); + INITBITS(); + state->mode = DICT; + Z_FALLTHROUGH; + + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = ADLER32_INITIAL_VALUE; + state->mode = TYPE; + Z_FALLTHROUGH; + + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) + goto inf_leave; + Z_FALLTHROUGH; + + case TYPEDO: + /* determine and dispatch block type */ + INFLATE_TYPEDO_HOOK(strm, flush); /* hook for IBM Z DFLTCC */ + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + PREFIX(fixedtables)(state); + Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + SET_BAD("invalid block type"); + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + SET_BAD("invalid stored block lengths"); + break; + } + state->length = (uint16_t)hold; + Tracev((stderr, "inflate: stored length %u\n", state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) + goto inf_leave; + Z_FALLTHROUGH; + + case COPY_: + state->mode = COPY; + Z_FALLTHROUGH; + + case COPY: + /* copy stored block from input to output */ + copy = state->length; + if (copy) { + copy = MIN(copy, have); + copy = MIN(copy, left); + if (copy == 0) + goto inf_leave; + memcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + SET_BAD("too many length or distance symbols"); + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + Z_FALLTHROUGH; + + case LENLENS: + /* get code length code lengths (not a typo) */ + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (uint16_t)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code *)(state->next); + state->lenbits = 7; + ret = zng_inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); + if (ret) { + SET_BAD("invalid code lengths set"); + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + Z_FALLTHROUGH; + + case CODELENS: + /* get length and distance code code lengths */ + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if (here.bits <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + SET_BAD("invalid bit length repeat"); + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + SET_BAD("invalid bit length repeat"); + break; + } + while (copy) { + --copy; + state->lens[state->have++] = (uint16_t)len; + } + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) + break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + SET_BAD("invalid code -- missing end-of-block"); + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (10 and 9) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code *)(state->next); + state->lenbits = 10; + ret = zng_inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); + if (ret) { + SET_BAD("invalid literal/lengths set"); + break; + } + state->distcode = (const code *)(state->next); + state->distbits = 9; + ret = zng_inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + SET_BAD("invalid distances set"); + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) + goto inf_leave; + Z_FALLTHROUGH; + + case LEN_: + state->mode = LEN; + Z_FALLTHROUGH; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= INFLATE_FAST_MIN_HAVE && left >= INFLATE_FAST_MIN_LEFT) { + RESTORE(); + FUNCTABLE_CALL(inflate_fast)(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if (here.bits <= bits) + break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)last.bits + (unsigned)here.bits <= bits) + break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = here.val; + + /* process literal */ + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + SET_BAD("invalid literal/length code"); + break; + } + + /* length code */ + state->extra = (here.op & MAX_BITS); + state->mode = LENEXT; + Z_FALLTHROUGH; + + case LENEXT: + /* get extra bits, if any */ + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + Z_FALLTHROUGH; + + case DIST: + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if (here.bits <= bits) + break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)last.bits + (unsigned)here.bits <= bits) + break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + SET_BAD("invalid distance code"); + break; + } + state->offset = here.val; + state->extra = (here.op & MAX_BITS); + state->mode = DISTEXT; + Z_FALLTHROUGH; + + case DISTEXT: + /* get distance extra bits, if any */ + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + SET_BAD("invalid distance too far back"); + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + Z_FALLTHROUGH; + + case MATCH: + /* copy match from window to output */ + if (left == 0) + goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (state->sane) { + SET_BAD("invalid distance too far back"); + break; + } + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + copy = MIN(copy, state->length); + copy = MIN(copy, left); + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) + state->mode = LEN; +#else + SET_BAD("invalid distance too far back"); +#endif + break; + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } else { + from = state->window + (state->wnext - copy); + } + copy = MIN(copy, state->length); + copy = MIN(copy, left); + + put = chunkcopy_safe(put, from, copy, put + left); + } else { + copy = MIN(state->length, left); + + put = FUNCTABLE_CALL(chunkmemset_safe)(put, put - state->offset, copy, left); + } + left -= copy; + state->length -= copy; + if (state->length == 0) + state->mode = LEN; + break; + + case LIT: + if (left == 0) + goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + + /* compute crc32 checksum if not in raw mode */ + if (INFLATE_NEED_CHECKSUM(strm) && state->wrap & 4) { + if (out) { + inf_chksum(strm, put - out, out); + } +#ifdef GUNZIP + if (state->flags) + strm->adler = state->check = FUNCTABLE_CALL(crc32_fold_final)(&state->crc_fold); +#endif + } + out = left; + if ((state->wrap & 4) && ( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32((unsigned)hold)) != state->check) { + SET_BAD("incorrect data check"); + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + Z_FALLTHROUGH; + + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { + SET_BAD("incorrect length check"); + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + Z_FALLTHROUGH; + + case DONE: + /* inflate stream terminated properly */ + ret = Z_STREAM_END; + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + case SYNC: + + default: /* can't happen, but makes compilers happy */ + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + */ + inf_leave: + RESTORE(); + uint32_t check_bytes = out - strm->avail_out; + if (INFLATE_NEED_UPDATEWINDOW(strm) && + (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH)))) { + /* update sliding window with respective checksum if not in "raw" mode */ + updatewindow(strm, strm->next_out, check_bytes, state->wrap & 4); + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) { + /* when no sliding window is used, hash the output bytes if no CHECK state */ + if (INFLATE_NEED_CHECKSUM(strm) && !state->wsize && flush == Z_FINISH) { + inf_chksum(strm, put - check_bytes, check_bytes); + } + ret = Z_BUF_ERROR; + } + return ret; +} + +int32_t Z_EXPORT PREFIX(inflateEnd)(PREFIX3(stream) *strm) { + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + + /* Free allocated buffers */ + free_inflate(strm); + + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int32_t Z_EXPORT PREFIX(inflateGetDictionary)(PREFIX3(stream) *strm, uint8_t *dictionary, uint32_t *dictLength) { + struct inflate_state *state; + + /* check state */ + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + + INFLATE_GET_DICTIONARY_HOOK(strm, dictionary, dictLength); /* hook for IBM Z DFLTCC */ + + /* copy dictionary */ + if (state->whave && dictionary != NULL) { + memcpy(dictionary, state->window + state->wnext, state->whave - state->wnext); + memcpy(dictionary + state->whave - state->wnext, state->window, state->wnext); + } + if (dictLength != NULL) + *dictLength = state->whave; + return Z_OK; +} + +int32_t Z_EXPORT PREFIX(inflateSetDictionary)(PREFIX3(stream) *strm, const uint8_t *dictionary, uint32_t dictLength) { + struct inflate_state *state; + unsigned long dictid; + + /* check state */ + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = FUNCTABLE_CALL(adler32)(ADLER32_INITIAL_VALUE, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + INFLATE_SET_DICTIONARY_HOOK(strm, dictionary, dictLength); /* hook for IBM Z DFLTCC */ + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + updatewindow(strm, dictionary + dictLength, dictLength, 0); + + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int32_t Z_EXPORT PREFIX(inflateGetHeader)(PREFIX3(stream) *strm, PREFIX(gz_headerp) head) { + struct inflate_state *state; + + /* check state */ + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + if ((state->wrap & 2) == 0) + return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +static uint32_t syncsearch(uint32_t *have, const uint8_t *buf, uint32_t len) { + uint32_t got, next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int32_t Z_EXPORT PREFIX(inflateSync)(PREFIX3(stream) *strm) { + struct inflate_state *state; + size_t in, out; /* temporary to save total_in and total_out */ + unsigned len; /* number of bytes to look at or looked at */ + int flags; /* temporary to save header status */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + + /* check parameters */ + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) + return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold >>= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) + return Z_DATA_ERROR; + if (state->flags == -1) + state->wrap = 0; /* if no header yet, treat as raw */ + else + state->wrap &= ~4; /* no point in computing a check value now */ + flags = state->flags; + in = strm->total_in; + out = strm->total_out; + PREFIX(inflateReset)(strm); + strm->total_in = (z_uintmax_t)in; /* Can't use z_size_t here as it will overflow on 64-bit Windows */ + strm->total_out = (z_uintmax_t)out; + state->flags = flags; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int32_t Z_EXPORT PREFIX(inflateSyncPoint)(PREFIX3(stream) *strm) { + struct inflate_state *state; + + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + INFLATE_SYNC_POINT_HOOK(strm); + state = (struct inflate_state *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int32_t Z_EXPORT PREFIX(inflateCopy)(PREFIX3(stream) *dest, PREFIX3(stream) *source) { + struct inflate_state *state; + struct inflate_state *copy; + + /* check input */ + if (inflateStateCheck(source) || dest == NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state *)source->state; + + /* copy stream */ + memcpy((void *)dest, (void *)source, sizeof(PREFIX3(stream))); + + /* allocate space */ + inflate_allocs *alloc_bufs = alloc_inflate(dest); + if (alloc_bufs == NULL) + return Z_MEM_ERROR; + copy = alloc_bufs->state; + + /* copy state */ + memcpy(copy, state, sizeof(struct inflate_state)); + copy->strm = dest; + if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + copy->window = alloc_bufs->window; + copy->alloc_bufs = alloc_bufs; + + /* window */ + memcpy(copy->window, state->window, INFLATE_ADJUST_WINDOW_SIZE((size_t)state->wsize)); + + dest->state = (struct internal_state *)copy; + return Z_OK; +} + +int32_t Z_EXPORT PREFIX(inflateUndermine)(PREFIX3(stream) *strm, int32_t subvert) { +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + struct inflate_state *state; + + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + state->sane = !subvert; + return Z_OK; +#else + Z_UNUSED(strm); + Z_UNUSED(subvert); + return Z_DATA_ERROR; +#endif +} + +int32_t Z_EXPORT PREFIX(inflateValidate)(PREFIX3(stream) *strm, int32_t check) { + struct inflate_state *state; + + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + if (check && state->wrap) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + +long Z_EXPORT PREFIX(inflateMark)(PREFIX3(stream) *strm) { + struct inflate_state *state; + + if (inflateStateCheck(strm)) + return -65536; + INFLATE_MARK_HOOK(strm); /* hook for IBM Z DFLTCC */ + state = (struct inflate_state *)strm->state; + return (long)(((unsigned long)((long)state->back)) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} + +unsigned long Z_EXPORT PREFIX(inflateCodesUsed)(PREFIX3(stream) *strm) { + struct inflate_state *state; + if (strm == NULL || strm->state == NULL) + return (unsigned long)-1; + state = (struct inflate_state *)strm->state; + return (unsigned long)(state->next - state->codes); +} diff --git a/inflate.h b/inflate.h new file mode 100644 index 0000000000..9d5c482707 --- /dev/null +++ b/inflate.h @@ -0,0 +1,172 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef INFLATE_H_ +#define INFLATE_H_ + +#include "crc32.h" + +#ifdef S390_DFLTCC_INFLATE +# include "arch/s390/dfltcc_common.h" +# define HAVE_ARCH_INFLATE_STATE +#endif + +/* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). + NO_GZIP would be used to avoid linking in the crc code when it is not needed. + For shared libraries, gzip decoding should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD = 16180, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ +typedef struct inflate_state inflate_state; + +/* Struct for memory allocation handling */ +typedef struct inflate_allocs_s { + char *buf_start; + free_func zfree; + inflate_state *state; + unsigned char *window; +} inflate_allocs; + +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ +struct ALIGNED_(64) inflate_state { + PREFIX3(stream) *strm; /* pointer back to this zlib stream */ + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags, 0 if zlib, or + -1 if raw or no header yet */ + unsigned was; /* initial length of match, for inflateMark */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + PREFIX(gz_headerp) head; /* where to save gzip header information */ + int back; /* bits back of last unprocessed length/lit */ + + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + uint32_t wsize; /* window size or zero if not using window */ + uint32_t wbufsize; /* real size of the allocated window buffer, including padding */ + uint32_t whave; /* valid bytes in the window */ + uint32_t wnext; /* window write index */ + unsigned char *window; /* allocated sliding window, if needed */ + uint32_t chunksize; /* size of memory copying chunk */ + + /* bit accumulator */ + uint64_t hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* fixed and dynamic code tables */ + unsigned lenbits; /* index bits for lencode */ + code const *lencode; /* starting table for length/literal codes */ + code const *distcode; /* starting table for distance codes */ + unsigned distbits; /* index bits for distcode */ + /* for string and stored block copying */ + uint32_t length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + uint32_t have; /* number of code lengths in lens[] */ + code *next; /* next available space in codes[] */ + +#if defined(_M_IX86) || defined(_M_ARM) + uint32_t padding[1]; +#endif + struct crc32_fold_s ALIGNED_(16) crc_fold; + + uint16_t lens[320]; /* temporary storage for code lengths */ + uint16_t work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + + inflate_allocs *alloc_bufs; /* struct for handling memory allocations */ + +#ifdef INFLATE_STRICT + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ +#endif +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + int sane; /* if false, allow invalid distance too far */ +#endif +#ifdef HAVE_ARCH_INFLATE_STATE + arch_inflate_state arch; /* architecture-specific extensions */ +#endif +#if defined(_M_IX86) || defined(_M_ARM) + int padding2[8]; +#endif +}; + +void Z_INTERNAL PREFIX(fixedtables)(struct inflate_state *state); +Z_INTERNAL inflate_allocs* alloc_inflate(PREFIX3(stream) *strm); +Z_INTERNAL void free_inflate(PREFIX3(stream) *strm); + +#endif /* INFLATE_H_ */ diff --git a/inflate_p.h b/inflate_p.h new file mode 100644 index 0000000000..179f76f734 --- /dev/null +++ b/inflate_p.h @@ -0,0 +1,215 @@ +/* inflate_p.h -- Private inline functions and macros shared with more than one deflate method + * + */ + +#ifndef INFLATE_P_H +#define INFLATE_P_H + +#include +#include "zmemory.h" + +/* Architecture-specific hooks. */ +#ifdef S390_DFLTCC_INFLATE +# include "arch/s390/dfltcc_inflate.h" +/* DFLTCC instructions require window to be page-aligned */ +# define PAD_WINDOW PAD_4096 +# define WINDOW_PAD_SIZE 4096 +# define HINT_ALIGNED_WINDOW HINT_ALIGNED_4096 +#else +# define PAD_WINDOW PAD_64 +# define WINDOW_PAD_SIZE 64 +# define HINT_ALIGNED_WINDOW HINT_ALIGNED_64 +/* Adjust the window size for the arch-specific inflate code. */ +# define INFLATE_ADJUST_WINDOW_SIZE(n) (n) +/* Invoked at the end of inflateResetKeep(). Useful for initializing arch-specific extension blocks. */ +# define INFLATE_RESET_KEEP_HOOK(strm) do {} while (0) +/* Invoked at the beginning of inflatePrime(). Useful for updating arch-specific buffers. */ +# define INFLATE_PRIME_HOOK(strm, bits, value) do {} while (0) +/* Invoked at the beginning of each block. Useful for plugging arch-specific inflation code. */ +# define INFLATE_TYPEDO_HOOK(strm, flush) do {} while (0) +/* Returns whether zlib-ng should compute a checksum. Set to 0 if arch-specific inflation code already does that. */ +# define INFLATE_NEED_CHECKSUM(strm) 1 +/* Returns whether zlib-ng should update a window. Set to 0 if arch-specific inflation code already does that. */ +# define INFLATE_NEED_UPDATEWINDOW(strm) 1 +/* Invoked at the beginning of inflateMark(). Useful for updating arch-specific pointers and offsets. */ +# define INFLATE_MARK_HOOK(strm) do {} while (0) +/* Invoked at the beginning of inflateSyncPoint(). Useful for performing arch-specific state checks. */ +# define INFLATE_SYNC_POINT_HOOK(strm) do {} while (0) +/* Invoked at the beginning of inflateSetDictionary(). Useful for checking arch-specific window data. */ +# define INFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) +/* Invoked at the beginning of inflateGetDictionary(). Useful for adjusting arch-specific window data. */ +# define INFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) +#endif + +/* + * Macros shared by inflate() and inflateBack() + */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? PREFIX(crc32)(check, buf, len) : FUNCTABLE_CALL(adler32)(check, buf, len)) +#else +# define UPDATE(check, buf, len) FUNCTABLE_CALL(adler32)(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = PREFIX(crc32)(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = PREFIX(crc32)(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = (z_const unsigned char *)next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Ensure that there is at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate()/inflateBack(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + (hold & ((1U << (unsigned)(n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Set mode=BAD and prepare error message */ +#define SET_BAD(errmsg) \ + do { \ + state->mode = BAD; \ + strm->msg = (char *)errmsg; \ + } while (0) + +#define INFLATE_FAST_MIN_HAVE 15 +#define INFLATE_FAST_MIN_LEFT 260 + +/* Load 64 bits from IN and place the bytes at offset BITS in the result. */ +static inline uint64_t load_64_bits(const unsigned char *in, unsigned bits) { + uint64_t chunk = zng_memread_8(in); + +#if BYTE_ORDER == LITTLE_ENDIAN + return chunk << bits; +#else + return ZSWAP64(chunk) << bits; +#endif +} + +/* Behave like chunkcopy, but avoid writing beyond of legal output. */ +static inline uint8_t* chunkcopy_safe(uint8_t *out, uint8_t *from, uint64_t len, uint8_t *safe) { + uint64_t safelen = safe - out; + len = MIN(len, safelen); + int32_t olap_src = from >= out && from < out + len; + int32_t olap_dst = out >= from && out < from + len; + uint64_t tocopy; + + /* For all cases without overlap, memcpy is ideal */ + if (!(olap_src || olap_dst)) { + memcpy(out, from, (size_t)len); + return out + len; + } + + /* Complete overlap: Source == destination */ + if (out == from) { + return out + len; + } + + /* We are emulating a self-modifying copy loop here. To do this in a way that doesn't produce undefined behavior, + * we have to get a bit clever. First if the overlap is such that src falls between dst and dst+len, we can do the + * initial bulk memcpy of the nonoverlapping region. Then, we can leverage the size of this to determine the safest + * atomic memcpy size we can pick such that we have non-overlapping regions. This effectively becomes a safe look + * behind or lookahead distance. */ + uint64_t non_olap_size = llabs(from - out); // llabs vs labs for compatibility with windows + + /* So this doesn't give use a worst case scenario of function calls in a loop, + * we want to instead break this down into copy blocks of fixed lengths + * + * TODO: The memcpy calls aren't inlined on architectures with strict memory alignment + */ + while (len) { + tocopy = MIN(non_olap_size, len); + len -= tocopy; + + while (tocopy >= 16) { + memcpy(out, from, 16); + out += 16; + from += 16; + tocopy -= 16; + } + + if (tocopy >= 8) { + memcpy(out, from, 8); + out += 8; + from += 8; + tocopy -= 8; + } + + if (tocopy >= 4) { + memcpy(out, from, 4); + out += 4; + from += 4; + tocopy -= 4; + } + + while (tocopy--) { + *out++ = *from++; + } + } + + return out; +} + +#endif diff --git a/inftrees.c b/inftrees.c new file mode 100644 index 0000000000..5234fe7ae0 --- /dev/null +++ b/inftrees.c @@ -0,0 +1,295 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zutil.h" +#include "inftrees.h" + +const char PREFIX(inflate_copyright)[] = " inflate 1.3.1 Copyright 1995-2024 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int Z_INTERNAL zng_inflate_table(codetype type, uint16_t *lens, unsigned codes, + code * *table, unsigned *bits, uint16_t *work) { + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code *next; /* next available space in table */ + const uint16_t *base; /* base value table to use */ + const uint16_t *extra; /* extra bits table to use */ + unsigned match; /* use base and extra for symbol >= match */ + uint16_t count[MAX_BITS+1]; /* number of codes of each length */ + uint16_t offs[MAX_BITS+1]; /* offsets in table for each length */ + static const uint16_t lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const uint16_t lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77}; + static const uint16_t dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const uint16_t dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAX_BITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAX_BITS; max >= 1; max--) + if (count[max] != 0) break; + root = MIN(root, max); + if (UNLIKELY(max == 0)) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (uint16_t)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + root = MAX(root, min); + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAX_BITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAX_BITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (uint16_t)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + match = 20; + break; + case LENS: + base = lbase; + extra = lext; + match = 257; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + match = 0; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if (LIKELY(work[sym] >= match)) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; + } else if (work[sym] + 1U < match) { + here.op = (unsigned char)0; + here.val = work[sym]; + } else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } else { + huff = 0; + } + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) + break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) + break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (uint16_t)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (UNLIKELY(huff != 0)) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (uint16_t)0; + next[huff] = here; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/inftrees.h b/inftrees.h new file mode 100644 index 0000000000..ad2be151f2 --- /dev/null +++ b/inftrees.h @@ -0,0 +1,66 @@ +#ifndef INFTREES_H_ +#define INFTREES_H_ + +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + uint16_t val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1924, which is the sum of 1332 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distributions. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 10 15" for literal/length codes + returns 1332, and "enough 30 9 15" for distance codes returns 592. + The initial root table size (10 or 9) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 1332 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int Z_INTERNAL zng_inflate_table (codetype type, uint16_t *lens, unsigned codes, + code * *table, unsigned *bits, uint16_t *work); + +#endif /* INFTREES_H_ */ diff --git a/insert_string.c b/insert_string.c new file mode 100644 index 0000000000..11a5b97ffe --- /dev/null +++ b/insert_string.c @@ -0,0 +1,21 @@ +/* insert_string.c -- insert_string integer hash variant + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + */ + +#include "zbuild.h" +#include "deflate.h" + +#define HASH_SLIDE 16 + +#define HASH_CALC(h, val) h = ((val * 2654435761U) >> HASH_SLIDE); +#define HASH_CALC_VAR h +#define HASH_CALC_VAR_INIT uint32_t h = 0 + +#define UPDATE_HASH update_hash +#define INSERT_STRING insert_string +#define QUICK_INSERT_STRING quick_insert_string + +#include "insert_string_tpl.h" diff --git a/insert_string_roll.c b/insert_string_roll.c new file mode 100644 index 0000000000..8693f96f59 --- /dev/null +++ b/insert_string_roll.c @@ -0,0 +1,24 @@ +/* insert_string_roll.c -- insert_string rolling hash variant + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + */ + +#include "zbuild.h" +#include "deflate.h" + +#define HASH_SLIDE 5 + +#define HASH_CALC(h, val) h = ((h << HASH_SLIDE) ^ ((uint8_t)val)) +#define HASH_CALC_VAR s->ins_h +#define HASH_CALC_VAR_INIT +#define HASH_CALC_READ val = strstart[0] +#define HASH_CALC_MASK (32768u - 1u) +#define HASH_CALC_OFFSET (STD_MIN_MATCH-1) + +#define UPDATE_HASH update_hash_roll +#define INSERT_STRING insert_string_roll +#define QUICK_INSERT_STRING quick_insert_string_roll + +#include "insert_string_tpl.h" diff --git a/insert_string_tpl.h b/insert_string_tpl.h new file mode 100644 index 0000000000..1548ca741a --- /dev/null +++ b/insert_string_tpl.h @@ -0,0 +1,106 @@ +#ifndef INSERT_STRING_H_ +#define INSERT_STRING_H_ + +/* insert_string_tpl.h -- Private insert_string functions shared with more than + * one insert string implementation + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * Authors: + * Wajdi Feghali + * Jim Guilford + * Vinodh Gopal + * Erdinc Ozturk + * Jim Kukunas + * + * Portions are Copyright (C) 2016 12Sided Technology, LLC. + * Author: + * Phil Vachon + * + * For conditions of distribution and use, see copyright notice in zlib.h + * + */ + +#include "zmemory.h" + +#ifndef HASH_CALC_OFFSET +# define HASH_CALC_OFFSET 0 +#endif +#ifndef HASH_CALC_MASK +# define HASH_CALC_MASK HASH_MASK +#endif +#ifndef HASH_CALC_READ +# if BYTE_ORDER == LITTLE_ENDIAN +# define HASH_CALC_READ \ + val = zng_memread_4(strstart); +# else +# define HASH_CALC_READ \ + val = ZSWAP32(zng_memread_4(strstart)); +# endif +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +Z_INTERNAL uint32_t UPDATE_HASH(uint32_t h, uint32_t val) { + HASH_CALC(h, val); + return h & HASH_CALC_MASK; +} + +/* =========================================================================== + * Quick insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + */ +Z_INTERNAL Pos QUICK_INSERT_STRING(deflate_state *const s, uint32_t str) { + Pos head; + uint8_t *strstart = s->window + str + HASH_CALC_OFFSET; + uint32_t val, hm; + + HASH_CALC_VAR_INIT; + HASH_CALC_READ; + HASH_CALC(HASH_CALC_VAR, val); + HASH_CALC_VAR &= HASH_CALC_MASK; + hm = HASH_CALC_VAR; + + head = s->head[hm]; + if (LIKELY(head != str)) { + s->prev[str & s->w_mask] = head; + s->head[hm] = (Pos)str; + } + return head; +} + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * IN assertion: all calls to INSERT_STRING are made with consecutive + * input characters and the first STD_MIN_MATCH bytes of str are valid + * (except for the last STD_MIN_MATCH-1 bytes of the input file). + */ +Z_INTERNAL void INSERT_STRING(deflate_state *const s, uint32_t str, uint32_t count) { + uint8_t *strstart = s->window + str + HASH_CALC_OFFSET; + uint8_t *strend = strstart + count; + + for (Pos idx = (Pos)str; strstart < strend; idx++, strstart++) { + uint32_t val, hm; + + HASH_CALC_VAR_INIT; + HASH_CALC_READ; + HASH_CALC(HASH_CALC_VAR, val); + HASH_CALC_VAR &= HASH_CALC_MASK; + hm = HASH_CALC_VAR; + + Pos head = s->head[hm]; + if (LIKELY(head != idx)) { + s->prev[idx & s->w_mask] = head; + s->head[hm] = idx; + } + } +} +#endif diff --git a/match_tpl.h b/match_tpl.h new file mode 100644 index 0000000000..47e9aed9f5 --- /dev/null +++ b/match_tpl.h @@ -0,0 +1,250 @@ +/* match_tpl.h -- find longest match template for compare256 variants + * + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Portions copyright (C) 2014-2021 Konstantin Nosov + * Fast-zlib optimized longest_match + * https://github.com/gildor2/fast_zlib + */ + +#ifndef MATCH_TPL_H +#define MATCH_TPL_H + +#define EARLY_EXIT_TRIGGER_LEVEL 5 + +#endif + +/* Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is garbage. + * + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >=1 + * OUT assertion: the match length is not greater than s->lookahead + * + * The LONGEST_MATCH_SLOW variant spends more time to attempt to find longer + * matches once a match has already been found. + */ +Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, Pos cur_match) { + unsigned int strstart = s->strstart; + const unsigned wmask = s->w_mask; + unsigned char *window = s->window; + unsigned char *scan = window + strstart; + Z_REGISTER unsigned char *mbase_start = window; + Z_REGISTER unsigned char *mbase_end; + const Pos *prev = s->prev; + Pos limit; +#ifdef LONGEST_MATCH_SLOW + Pos limit_base; +#else + int32_t early_exit; +#endif + uint32_t chain_length, nice_match, best_len, offset; + uint32_t lookahead = s->lookahead; + Pos match_offset = 0; + uint64_t scan_start; + uint64_t scan_end; + +#define GOTO_NEXT_CHAIN \ + if (--chain_length && (cur_match = prev[cur_match & wmask]) > limit) \ + continue; \ + return best_len; + + /* The code is optimized for STD_MAX_MATCH-2 multiple of 16. */ + Assert(STD_MAX_MATCH == 258, "Code too clever"); + + best_len = s->prev_length ? s->prev_length : STD_MIN_MATCH-1; + + /* Calculate read offset which should only extend an extra byte + * to find the next best match length. + */ + offset = best_len-1; + if (best_len >= sizeof(uint32_t)) { + offset -= 2; + if (best_len >= sizeof(uint64_t)) + offset -= 4; + } + + scan_start = zng_memread_8(scan); + scan_end = zng_memread_8(scan+offset); + mbase_end = (mbase_start+offset); + + /* Do not waste too much time if we already have a good match */ + chain_length = s->max_chain_length; + if (best_len >= s->good_match) + chain_length >>= 2; + nice_match = (uint32_t)s->nice_match; + + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0 + */ + limit = strstart > MAX_DIST(s) ? (Pos)(strstart - MAX_DIST(s)) : 0; +#ifdef LONGEST_MATCH_SLOW + limit_base = limit; + if (best_len >= STD_MIN_MATCH) { + /* We're continuing search (lazy evaluation). */ + uint32_t i, hash; + Pos pos; + + /* Find a most distant chain starting from scan with index=1 (index=0 corresponds + * to cur_match). We cannot use s->prev[strstart+1,...] immediately, because + * these strings are not yet inserted into the hash table. + */ + hash = s->update_hash(0, scan[1]); + hash = s->update_hash(hash, scan[2]); + + for (i = 3; i <= best_len; i++) { + hash = s->update_hash(hash, scan[i]); + + /* If we're starting with best_len >= 3, we can use offset search. */ + pos = s->head[hash]; + if (pos < cur_match) { + match_offset = (Pos)(i - 2); + cur_match = pos; + } + } + + /* Update offset-dependent variables */ + limit = limit_base+match_offset; + if (cur_match <= limit) + goto break_matching; + mbase_start -= match_offset; + mbase_end -= match_offset; + } +#else + early_exit = s->level < EARLY_EXIT_TRIGGER_LEVEL; +#endif + Assert((unsigned long)strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead"); + for (;;) { + if (cur_match >= strstart) + break; + + /* Skip to next match if the match length cannot increase or if the match length is + * less than 2. Note that the checks below for insufficient lookahead only occur + * occasionally for performance reasons. + * Therefore uninitialized memory will be accessed and conditional jumps will be made + * that depend on those values. However the length of the match is limited to the + * lookahead, so the output of deflate is not affected by the uninitialized values. + */ + if (best_len < sizeof(uint32_t)) { + for (;;) { + if (zng_memcmp_2(mbase_end+cur_match, &scan_end) == 0 && + zng_memcmp_2(mbase_start+cur_match, &scan_start) == 0) + break; + GOTO_NEXT_CHAIN; + } + } else if (best_len >= sizeof(uint64_t)) { + for (;;) { + if (zng_memcmp_8(mbase_end+cur_match, &scan_end) == 0 && + zng_memcmp_8(mbase_start+cur_match, &scan_start) == 0) + break; + GOTO_NEXT_CHAIN; + } + } else { + for (;;) { + if (zng_memcmp_4(mbase_end+cur_match, &scan_end) == 0 && + zng_memcmp_4(mbase_start+cur_match, &scan_start) == 0) + break; + GOTO_NEXT_CHAIN; + } + } + uint32_t len = COMPARE256(scan+2, mbase_start+cur_match+2) + 2; + Assert(scan+len <= window+(unsigned)(s->window_size-1), "wild scan"); + + if (len > best_len) { + uint32_t match_start = cur_match - match_offset; + s->match_start = match_start; + + /* Do not look for matches beyond the end of the input. */ + if (len > lookahead) + return lookahead; + best_len = len; + if (best_len >= nice_match) + return best_len; + + offset = best_len-1; + if (best_len >= sizeof(uint32_t)) { + offset -= 2; + if (best_len >= sizeof(uint64_t)) + offset -= 4; + } + + scan_end = zng_memread_8(scan+offset); + +#ifdef LONGEST_MATCH_SLOW + /* Look for a better string offset */ + if (UNLIKELY(len > STD_MIN_MATCH && match_start + len < strstart)) { + Pos pos, next_pos; + uint32_t i, hash; + unsigned char *scan_endstr; + + /* Go back to offset 0 */ + cur_match -= match_offset; + match_offset = 0; + next_pos = cur_match; + for (i = 0; i <= len - STD_MIN_MATCH; i++) { + pos = prev[(cur_match + i) & wmask]; + if (pos < next_pos) { + /* Hash chain is more distant, use it */ + if (pos <= limit_base + i) + goto break_matching; + next_pos = pos; + match_offset = (Pos)i; + } + } + /* Switch cur_match to next_pos chain */ + cur_match = next_pos; + + /* Try hash head at len-(STD_MIN_MATCH-1) position to see if we could get + * a better cur_match at the end of string. Using (STD_MIN_MATCH-1) lets + * us include one more byte into hash - the byte which will be checked + * in main loop now, and which allows to grow match by 1. + */ + scan_endstr = scan + len - (STD_MIN_MATCH+1); + + hash = s->update_hash(0, scan_endstr[0]); + hash = s->update_hash(hash, scan_endstr[1]); + hash = s->update_hash(hash, scan_endstr[2]); + + pos = s->head[hash]; + if (pos < cur_match) { + match_offset = (Pos)(len - (STD_MIN_MATCH+1)); + if (pos <= limit_base + match_offset) + goto break_matching; + cur_match = pos; + } + + /* Update offset-dependent variables */ + limit = limit_base+match_offset; + mbase_start = window-match_offset; + mbase_end = (mbase_start+offset); + continue; + } +#endif + mbase_end = (mbase_start+offset); + } +#ifndef LONGEST_MATCH_SLOW + else if (UNLIKELY(early_exit)) { + /* The probability of finding a match later if we here is pretty low, so for + * performance it's best to outright stop here for the lower compression levels + */ + break; + } +#endif + GOTO_NEXT_CHAIN; + } + return best_len; + +#ifdef LONGEST_MATCH_SLOW +break_matching: + + if (best_len < s->lookahead) + return best_len; + + return s->lookahead; +#endif +} + +#undef LONGEST_MATCH_SLOW +#undef LONGEST_MATCH diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000000..abb1055c5b --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,262 @@ +macro(configure_test_executable target) + target_include_directories(${target} PRIVATE ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}) + set_target_properties(${target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + if(NOT WITH_GZFILEOP) + target_compile_definitions(${target} PRIVATE -DWITH_GZFILEOP) + target_sources(${target} PRIVATE ${ZLIB_GZFILE_PRIVATE_HDRS} ${ZLIB_GZFILE_SRCS}) + endif() +endmacro() + +if(ZLIBNG_ENABLE_TESTS) + add_definitions(-DZLIBNG_ENABLE_TESTS) +endif() + +add_executable(example example.c) +configure_test_executable(example) +target_link_libraries(example zlib) +add_test(NAME example COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + +add_executable(minigzip minigzip.c) +configure_test_executable(minigzip) +if(NOT DEFINED BUILD_SHARED_LIBS) + target_link_libraries(minigzip zlibstatic) +else() + target_link_libraries(minigzip zlib) +endif() +if(BASEARCH_S360_FOUND) + if(WITH_DFLTCC_DEFLATE OR WITH_DFLTCC_INFLATE) + set_source_files_properties(minigzip.c PROPERTIES COMPILE_DEFINITIONS BUFLEN=262144) + endif() +endif() +set(MINIGZIP_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + +add_executable(minideflate minideflate.c) +configure_test_executable(minideflate) +target_link_libraries(minideflate zlib) +set(MINIDEFLATE_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + +if(INSTALL_UTILS) + install(TARGETS minigzip minideflate + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") +endif() + +add_executable(switchlevels switchlevels.c) +configure_test_executable(switchlevels) +target_link_libraries(switchlevels zlib) +set(SWITCHLEVELS_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + +add_executable(infcover infcover.c) +configure_test_executable(infcover) +target_link_libraries(infcover zlib) +if(NOT DEFINED BUILD_SHARED_LIBS OR BUILD_SHARED_LIBS) + target_sources(infcover PRIVATE ${PROJECT_SOURCE_DIR}/inftrees.c) +endif() +# infcover references zng_inflate_table() and struct inflate_state, which are internal to zlib-ng. +if(ZLIBNG_ENABLE_TESTS) + add_test(NAME infcover COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) +endif() + +add_executable(makefixed ${PROJECT_SOURCE_DIR}/tools/makefixed.c ${PROJECT_SOURCE_DIR}/inftrees.c) +configure_test_executable(makefixed) +set(MAKEFIXED_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + +add_executable(maketrees ${PROJECT_SOURCE_DIR}/tools/maketrees.c ${PROJECT_SOURCE_DIR}/trees.c ${PROJECT_SOURCE_DIR}/zutil.c) +configure_test_executable(maketrees) +set(MAKETREES_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + +add_executable(makecrct ${PROJECT_SOURCE_DIR}/tools/makecrct.c) +configure_test_executable(makecrct) +set(MAKECRCT_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + +# Emscripten does not support large amounts of data via stdin/out +# https://github.com/emscripten-core/emscripten/issues/16755#issuecomment-1102732849 +if(NOT BASEARCH_WASM32_FOUND) + # Runs tests targeting CVEs + include(cmake/test-cves.cmake) + + # Run tests with data files + include(cmake/test-data.cmake) + + # Run tests targeting GitHub issues + include(cmake/test-issues.cmake) + + # Run tests targeting tools + include(cmake/test-tools.cmake) +endif() + +if(WITH_FUZZERS) + add_subdirectory(fuzz) +endif() + +if(WITH_GTEST OR WITH_BENCHMARKS) + if(CMAKE_VERSION VERSION_LESS 3.12) + message(WARNING "Minimum cmake version of 3.12 not met for Google benchmark!") + set(WITH_BENCHMARKS OFF) + set(WITH_BENCHMARKS OFF PARENT_SCOPE) + endif() + enable_language(CXX) +endif() + +if(WITH_BENCHMARKS) + add_subdirectory(benchmarks) +endif() + +if(WITH_GTEST) + # Google test requires at least C++11 + if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) + endif() + + # Google test requires MSAN instrumented LLVM C++ libraries + if(WITH_SANITIZER STREQUAL "Memory") + if(NOT DEFINED ENV{LLVM_BUILD_DIR}) + message(FATAL_ERROR "MSAN instrumented C++ libraries required!") + endif() + + # Must set include and compile options before fetching googletest + include_directories($ENV{LLVM_BUILD_DIR}/include $ENV{LLVM_BUILD_DIR}/include/c++/v1) + add_compile_options(-stdlib=libc++ -g) + elseif(NOT TARGET GTest::GTest) + find_package(GTest) + endif() + + if(NOT TARGET GTest::GTest AND NOT CMAKE_VERSION VERSION_LESS 3.11) + include(FetchContent) + + # Prevent overriding the parent project's compiler/linker settings for Windows + set(gtest_force_shared_crt ON CACHE BOOL + "Use shared (DLL) run-time lib even when Google Test is built as static lib." FORCE) + + # Allow specifying alternative Google test repository + if(NOT DEFINED GTEST_REPOSITORY) + set(GTEST_REPOSITORY https://github.com/google/googletest.git) + endif() + if(NOT DEFINED GTEST_TAG) + # Use older version of Google test to support older versions of GCC + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 5.3) + set(GTEST_TAG release-1.10.0) + else() + set(GTEST_TAG release-1.12.1) + endif() + endif() + + # Fetch Google test source code from official repository + message(STATUS "Git checking out GoogleTest ${GTEST_TAG}") + FetchContent_Declare(googletest + GIT_REPOSITORY ${GTEST_REPOSITORY} + GIT_TAG ${GTEST_TAG}) + + FetchContent_GetProperties(googletest) + if(NOT googletest_POPULATED) + FetchContent_Populate(googletest) + add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL) + endif() + add_library(GTest::GTest ALIAS gtest) + add_library(GTest::Main ALIAS gtest_main) + endif() + + if(TARGET GTest::GTest) + set(TEST_SRCS + test_compress.cc + test_compress_bound.cc + test_cve-2003-0107.cc + test_deflate_bound.cc + test_deflate_copy.cc + test_deflate_dict.cc + test_deflate_hash_head_0.cc + test_deflate_header.cc + test_deflate_params.cc + test_deflate_pending.cc + test_deflate_prime.cc + test_deflate_quick_bi_valid.cc + test_deflate_quick_block_open.cc + test_deflate_tune.cc + test_dict.cc + test_inflate_adler32.cc + test_inflate_copy.cc + test_large_buffers.cc + test_raw.cc + test_small_buffers.cc + test_small_window.cc + ) + + if(WITH_GZFILEOP) + list(APPEND TEST_SRCS test_gzio.cc) + endif() + + if(ZLIBNG_ENABLE_TESTS) + list(APPEND TEST_SRCS + test_adler32.cc # adler32_neon(), etc + test_compare256.cc # compare256_neon(), etc + test_compare256_rle.cc # compare256_rle(), etc + test_crc32.cc # crc32_acle(), etc + test_inflate_sync.cc # expects a certain compressed block layout + test_main.cc # cpu_check_features() + test_version.cc # expects a fixed version string + ) + endif() + + add_executable(gtest_zlib ${TEST_SRCS}) + configure_test_executable(gtest_zlib) + + if(MSVC) + target_compile_options(gtest_zlib PRIVATE /wd4389 /EHsc) + endif() + + if(WITH_SANITIZER STREQUAL "Memory") + target_link_directories(gtest_zlib PRIVATE $ENV{LLVM_BUILD_DIR}/lib) + target_link_options(gtest_zlib PRIVATE + -stdlib=libc++ + -lc++abi + -fsanitize=memory + -fsanitize-memory-track-origins) + endif() + + if(NOT ZLIB_COMPAT AND DEFINED ZLIB_LIBRARIES AND DEFINED ZLIB_INCLUDE_DIRS) + if(NOT IS_ABSOLUTE ${ZLIB_LIBRARIES}) + get_filename_component(ZLIB_ABSOLUTE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/${ZLIB_LIBRARIES}" + ABSOLUTE) + else() + set(ZLIB_ABSOLUTE_PATH ${ZLIB_LIBRARIES}) + endif() + + add_library(external_zlib STATIC IMPORTED) + set_property(TARGET external_zlib PROPERTY IMPORTED_LOCATION ${ZLIB_ABSOLUTE_PATH}) + message(STATUS "Added dual linking tests against zlib") + message(STATUS " Zlib include dirs: ${ZLIB_INCLUDE_DIRS}") + message(STATUS " Zlib libraries: ${ZLIB_ABSOLUTE_PATH}") + + target_sources(gtest_zlib PRIVATE test_compress_dual.cc) + target_include_directories(gtest_zlib PRIVATE ${ZLIB_INCLUDE_DIRS}) + target_link_libraries(gtest_zlib external_zlib) + endif() + + if(NOT DEFINED BUILD_SHARED_LIBS) + # Link statically in order to test internal zlib-ng functions. + target_link_libraries(gtest_zlib zlibstatic) + else() + target_link_libraries(gtest_zlib zlib) + endif() + + if(BUILD_SHARED_LIBS) + target_link_libraries(gtest_zlib GTest::Main) + endif() + target_link_libraries(gtest_zlib GTest::GTest) + + find_package(Threads) + if(Threads_FOUND AND NOT BASEARCH_WASM32_FOUND) + target_sources(gtest_zlib PRIVATE test_deflate_concurrency.cc) + if(UNIX AND NOT APPLE) + # On Linux, use a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52590 + target_link_libraries(gtest_zlib -Wl,--whole-archive -lpthread -Wl,--no-whole-archive) + endif() + target_link_libraries(gtest_zlib Threads::Threads) + endif() + + add_test(NAME gtest_zlib + COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + endif() +endif() diff --git a/test/CVE-2002-0059/test.gz b/test/CVE-2002-0059/test.gz new file mode 100644 index 0000000000000000000000000000000000000000..c5c3e184b1a90692f1c2dc729eb106476d231378 GIT binary patch literal 4610 zcmb2|=3oE==C>CV8G$T;1@EN)&o6EfRlAUMpn;K@jYq;DVU#f%2%{-sG#8BKg3(+s vnhQpA!DucR%>|>mU^Ewu=7P~&Fq#WSbHQjX7-G5L2bCV85!7kBn%P`G%zxAfEl}iz!@q6kpjs906!lM=l}o! literal 0 HcmV?d00001 diff --git a/test/CVE-2005-1849/test.gz b/test/CVE-2005-1849/test.gz new file mode 100644 index 0000000000000000000000000000000000000000..b28f278263c0a3154faeb3c3dd7b083a3a593c8d GIT binary patch literal 52 kcmb2|=3oE==C@ZA85!7kBn%P`G%zxAz!-252m>Ss01LtkQvd(} literal 0 HcmV?d00001 diff --git a/test/CVE-2005-2096/test.gz b/test/CVE-2005-2096/test.gz new file mode 100644 index 0000000000000000000000000000000000000000..11590aeab9ac844087776ab66eb2f5d2c9f6d013 GIT binary patch literal 52 pcmb2|=3oE==C>CV84oltGP4!m+X9 literal 0 HcmV?d00001 diff --git a/test/GH-382/defneg3.dat b/test/GH-382/defneg3.dat new file mode 100644 index 0000000000..5fa6a08044 --- /dev/null +++ b/test/GH-382/defneg3.dat @@ -0,0 +1 @@ +oÌ™Ì?ÌOÌÃÌḩÌÕÌ>ÌÌÌàÌ̹̘ÌÔÌEÌsÌ—ÌÌ4̢̙̑Ì6ÌÌØÌæÌ\ÌÌÌ5̪̲̕ÌmÌÌ–Ìç̺̜ÌÙ̧ÌÌíÌíÌ–ÌÌëÌmÌìÌÎ̵ÌGÌïÌOÌÛÌ ÌÃÌòÌÎÌôÌ„Ì;Ì”ÌýÌ’ÌÓÌÀÌ×Ì,ÌÑÌ¢ÌáÌAÌ9Ì»ÌæÌ‚ÌÂÌsÌý̼ÌÝÌÌ­ÌeÌòÌÝÌUÌuÌí̱ÌËÌwÌùÌ•ÌDÌß̋̽Ìt̞̣̹ÌöÌôÌOÌîÌíÌ…ÌpÌGÌḭ̀ÌÀÌ(ÌÌÌ̤Ì{Ì“ÌßÌïÌÕÌÌøÌÌMÌ#ÌÌí̵ÌdÌ·ÌIÌßÌhÌ_ÌpÌJÌÇÌ¢ÌÎÌÌoÌÌêÌÁÌ;Ì<̘ÌZÌÈÌÑÌoÌW̄̿Ì}ÌáÌÌÌ:Ìá̧̻̕ÌeÌFÌtÌ(ÌEÌoÌàÌpÌÌ¢Ì(Ì;ÌþÌëÌóÌ!̹̹ÌÉÌÌœÌîÌÖÌ4ÌÈÌ3ÌëÌ‹ÌBÌŽÌÆÌuÌPÌ6Ì“ÌþÌ&̦̳̕ÌÁÌðÌ»ÌÌÌTÌÀ̧ÌbÌÌÒÌÕÌëÌ{ÌÆÌ¡ÌÊÌNÌ9ÌÇÌÌBÌÑ \ No newline at end of file diff --git a/test/GH-751/test.txt b/test/GH-751/test.txt new file mode 100644 index 0000000000..ef2143ece8 --- /dev/null +++ b/test/GH-751/test.txt @@ -0,0 +1 @@ +abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc diff --git a/test/GH-979/pigz-2.6.tar.gz b/test/GH-979/pigz-2.6.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..0d76ef8757e36dc5ab02e579a99442c211b6d978 GIT binary patch literal 106840 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%0Dmda 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 literal 0 HcmV?d00001 diff --git a/test/Makefile.in b/test/Makefile.in new file mode 100644 index 0000000000..5b45965926 --- /dev/null +++ b/test/Makefile.in @@ -0,0 +1,82 @@ +# Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler +# Copyright 2015, Daniel Axtens, IBM Corporation +# zlib license, see zlib.h + +CC= +CFLAGS= +EXE= +SRCDIR= +SRCTOP= +LIBNAME= +TEST_LDFLAGS=-L.. ../$(LIBNAME).a + +EMU_RUN= + +all: alltests + +alltests: #set by ../configure +check_cross_dep: +ifneq (,$(findstring qemu,$(EMU_RUN))) +QEMU_VER:=$(shell command -v $(EMU_RUN) --version 2> /dev/null) +ifeq (,$(QEMU_VER)) +$(error You need QEMU to run tests on non-native platform) +endif +endif + +ALL_SRC_FILES := $(wildcard ../*) + +teststatic: check_cross_dep + @TMPST=tmpst_$$$$; \ + HELLOST=tmphellost_$$$$; \ + if echo hello world | ${EMU_RUN} ../minigzip$(EXE) > $$HELLOST && ${EMU_RUN} ../minigzip$(EXE) -d < $$HELLOST && ${EMU_RUN} ../example$(EXE) $$TMPST; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; exit 1; \ + fi; \ + rm -f $$TMPST $$HELLOST + +testshared: check_cross_dep + @LD_LIBRARY_PATH=`pwd`/..:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + LD_LIBRARYN32_PATH=`pwd`/..:$(LD_LIBRARYN32_PATH) ; export LD_LIBRARYN32_PATH; \ + DYLD_LIBRARY_PATH=`pwd`/..:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \ + SHLIB_PATH=`pwd`/..:$(SHLIB_PATH) ; export SHLIB_PATH; \ + TMPSH=tmpsh_$$$$; \ + HELLOSH=tmphellosh_$$$$; \ + if echo hello world | ${EMU_RUN} ../minigzipsh$(EXE) > $$HELLOSH && ${EMU_RUN} ../minigzipsh$(EXE) -d < $$HELLOSH && ${EMU_RUN} ../examplesh$(EXE) $$TMPSH; then \ + echo ' *** zlib shared test OK ***'; \ + else \ + echo ' *** zlib shared test FAILED ***'; exit 1; \ + fi; \ + rm -f $$TMPSH $$HELLOSH + +.PHONY: ghtests +ghtests: testGH-361 testGH-364 testGH-751 testGH-1235 + +.PHONY: testGH-361 +testGH-361: + $(EMU_RUN) ../minigzip$(EXE) -4 <$(SRCDIR)/GH-361/test.txt >/dev/null + +switchlevels$(EXE): $(SRCDIR)/switchlevels.c + $(CC) $(CFLAGS) -I.. -I$(SRCTOP) -o $@ $< $(TEST_LDFLAGS) + +.PHONY: testGH-364 +testGH-364: switchlevels$(EXE) + $(EMU_RUN) ./switchlevels$(EXE) 1 5 9 3 <$(SRCDIR)/GH-364/test.bin >/dev/null + +.PHONY: testGH-751 +testGH-751: + $(EMU_RUN) ../minigzip$(EXE) <$(SRCDIR)/GH-751/test.txt | $(EMU_RUN) ../minigzip$(EXE) -d >/dev/null + +gh1235$(EXE): $(SRCDIR)/gh1235.c + $(CC) $(CFLAGS) -I.. -I$(SRCTOP) -o $@ $< $(TEST_LDFLAGS) + +.PHONY: testGH-1235 +testGH-1235: gh1235$(EXE) + $(EMU_RUN) ./gh1235$(EXE) + +clean: + rm -f *.o *.gcda *.gcno *.gcov + rm -f switchlevels$(EXE) gh1235$(EXE) + +distclean: clean + rm -f Makefile diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000000..d844ba530f --- /dev/null +++ b/test/README.md @@ -0,0 +1,37 @@ +Contents +-------- + +|Name|Description| +|-|-| +|[CVE-2003-0107](https://nvd.nist.gov/vuln/detail/CVE-2003-0107)|Buffer overflow in the gzprintf function, requires ZLIB_COMPAT| +|[CVE-2002-0059](https://nvd.nist.gov/vuln/detail/CVE-2002-0059)|inflateEnd to release memory more than once| +|[CVE-2004-0797](https://nvd.nist.gov/vuln/detail/CVE-2004-0797)|Error handling in inflate and inflateBack causes crash| +|[CVE-2005-1849](https://nvd.nist.gov/vuln/detail/CVE-2005-1849)|inftrees.h bug causes crash| +|[CVE-2005-2096](https://nvd.nist.gov/vuln/detail/CVE-2005-2096)|Buffer overflow when incomplete code description| +|[CVE-2018-25032](https://nvd.nist.gov/vuln/detail/CVE-2018-25032)|Memory corruption when compressing if the input has many distant matches.| +|[GH-361](https://github.com/zlib-ng/zlib-ng/issues/361)|Test case for overlapping matches| +|[GH-364](https://github.com/zlib-ng/zlib-ng/issues/364)|Test case for switching compression levels| +|[GH-382](https://github.com/zlib-ng/zlib-ng/issues/382)|Test case for deflateEnd returning -3 in deflate quick| + +Copying +------- + +Some of the files in _test_ are licensed differently: + + - test/data/fireworks.jpeg is Copyright 2013 Steinar H. Gunderson, and + is licensed under the Creative Commons Attribution 3.0 license + (CC-BY-3.0). See https://creativecommons.org/licenses/by/3.0/ + for more information. + + - test/data/paper-100k.pdf is an excerpt (bytes 92160 to 194560) from the paper + “Combinatorial Modeling of Chromatin Features Quantitatively Predicts DNA + Replication Timing in _Drosophila_†by Federico Comoglio and Renato Paro, + which is licensed under the CC-BY license. See + https://www.ploscompbiol.org/static/license for more information. + + - test/data/lcet10.txt is from Project Gutenberg. It does not have expired + copyright, but is still in the public domain according to the license information. + (https://www.gutenberg.org/ebooks/53). + + - test/GH-382/defneg3.dat was the smallest file generated by Nathan Moinvaziri + that reproduced GH-382. It is licensed under the terms of the zlib license. diff --git a/test/abi/ignore b/test/abi/ignore new file mode 100644 index 0000000000..583c92184c --- /dev/null +++ b/test/abi/ignore @@ -0,0 +1,12 @@ +# See https://sourceware.org/libabigail/manual/libabigail-concepts.html#suppression-specifications + +[suppress_type] + name = internal_state + +[suppress_type] + name_regexp = z_stream.* + +# Size varies with version number +[suppress_variable] + name_regexp = z(|ng|libng)_(|v)string + diff --git a/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-aarch64-unknown-linux-gnu.abi b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-aarch64-unknown-linux-gnu.abi new file mode 100644 index 0000000000..cabe281608 --- /dev/null +++ b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-aarch64-unknown-linux-gnu.abi @@ -0,0 +1,1293 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-arm-unknown-linux-gnueabi.abi b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-arm-unknown-linux-gnueabi.abi new file mode 100644 index 0000000000..13b6e33297 --- /dev/null +++ b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-arm-unknown-linux-gnueabi.abi @@ -0,0 +1,1276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-arm-unknown-linux-gnueabihf.abi b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-arm-unknown-linux-gnueabihf.abi new file mode 100644 index 0000000000..620c5535f8 --- /dev/null +++ b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-arm-unknown-linux-gnueabihf.abi @@ -0,0 +1,1276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-mips-unknown-linux-gnu.abi b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-mips-unknown-linux-gnu.abi new file mode 100644 index 0000000000..2ab253c373 --- /dev/null +++ b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-mips-unknown-linux-gnu.abi @@ -0,0 +1,1271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-mips64-unknown-linux-gnuabi64.abi b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-mips64-unknown-linux-gnuabi64.abi new file mode 100644 index 0000000000..cd0d66f5f5 --- /dev/null +++ b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-mips64-unknown-linux-gnuabi64.abi @@ -0,0 +1,1276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc-unknown-linux-gnu.abi b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc-unknown-linux-gnu.abi new file mode 100644 index 0000000000..3eefc76467 --- /dev/null +++ b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc-unknown-linux-gnu.abi @@ -0,0 +1,1286 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc64-unknown-linux-gnu.abi b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc64-unknown-linux-gnu.abi new file mode 100644 index 0000000000..34cbcdc593 --- /dev/null +++ b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc64-unknown-linux-gnu.abi @@ -0,0 +1,1275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc64le-unknown-linux-gnu.abi b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc64le-unknown-linux-gnu.abi new file mode 100644 index 0000000000..e78d9831cc --- /dev/null +++ b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-powerpc64le-unknown-linux-gnu.abi @@ -0,0 +1,1275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-x86_64-pc-linux-gnu-m32.abi b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-x86_64-pc-linux-gnu-m32.abi new file mode 100644 index 0000000000..5b55fc6050 --- /dev/null +++ b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-x86_64-pc-linux-gnu-m32.abi @@ -0,0 +1,1270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-x86_64-pc-linux-gnu.abi b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-x86_64-pc-linux-gnu.abi new file mode 100644 index 0000000000..8152352c19 --- /dev/null +++ b/test/abi/zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc-x86_64-pc-linux-gnu.abi @@ -0,0 +1,1288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-aarch64-unknown-linux-gnu.abi b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-aarch64-unknown-linux-gnu.abi new file mode 100644 index 0000000000..cfc0eddc62 --- /dev/null +++ b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-aarch64-unknown-linux-gnu.abi @@ -0,0 +1,1904 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-arm-unknown-linux-gnueabi.abi b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-arm-unknown-linux-gnueabi.abi new file mode 100644 index 0000000000..414f8a96ec --- /dev/null +++ b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-arm-unknown-linux-gnueabi.abi @@ -0,0 +1,1889 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-arm-unknown-linux-gnueabihf.abi b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-arm-unknown-linux-gnueabihf.abi new file mode 100644 index 0000000000..f5b3aa7737 --- /dev/null +++ b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-arm-unknown-linux-gnueabihf.abi @@ -0,0 +1,1881 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-mips-unknown-linux-gnu.abi b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-mips-unknown-linux-gnu.abi new file mode 100644 index 0000000000..53e2b06b58 --- /dev/null +++ b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-mips-unknown-linux-gnu.abi @@ -0,0 +1,1241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-mips64-unknown-linux-gnuabi64.abi b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-mips64-unknown-linux-gnuabi64.abi new file mode 100644 index 0000000000..3e4322f455 --- /dev/null +++ b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-mips64-unknown-linux-gnuabi64.abi @@ -0,0 +1,1250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc-unknown-linux-gnu.abi b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc-unknown-linux-gnu.abi new file mode 100644 index 0000000000..3164f07e71 --- /dev/null +++ b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc-unknown-linux-gnu.abi @@ -0,0 +1,1895 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc64-unknown-linux-gnu.abi b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc64-unknown-linux-gnu.abi new file mode 100644 index 0000000000..1d97902bc5 --- /dev/null +++ b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc64-unknown-linux-gnu.abi @@ -0,0 +1,1894 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc64le-unknown-linux-gnu.abi b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc64le-unknown-linux-gnu.abi new file mode 100644 index 0000000000..613f5f2f6d --- /dev/null +++ b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-powerpc64le-unknown-linux-gnu.abi @@ -0,0 +1,1886 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-x86_64-pc-linux-gnu-m32.abi b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-x86_64-pc-linux-gnu-m32.abi new file mode 100644 index 0000000000..82d8943b8b --- /dev/null +++ b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-x86_64-pc-linux-gnu-m32.abi @@ -0,0 +1,2032 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-x86_64-pc-linux-gnu.abi b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-x86_64-pc-linux-gnu.abi new file mode 100644 index 0000000000..a03df554af --- /dev/null +++ b/test/abi/zlib-ng-e4614ebcb9b3e5b108dc983c155e4baf80882311-x86_64-pc-linux-gnu.abi @@ -0,0 +1,2064 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/abicheck.md b/test/abicheck.md new file mode 100644 index 0000000000..57337f5882 --- /dev/null +++ b/test/abicheck.md @@ -0,0 +1,59 @@ +ABI Compatibility test +---------------------- + +abicheck.sh uses libabigail to check ABI stability. +It will abort if the current source +tree has a change that breaks binary compatibility. + +This protects against the common scenario where: +- an app is compiled against the current zlib-ng +- the system package manager updates the zlib-ng shared library +- the app now crashes because some symbol is + missing or some public structure or parameter + has changed type or size + +If run with --zlib-compat, it verifies that the +current source tree generates a library that +is ABI-compatible with the reference release +of classic zlib. This ensures that building +zlib-ng with --zlib-compat does what it says on the tin. + +abicheck.sh is not perfect, but it can catch +many common compatibility issues. + +Cached files test/abi/*.abi +--------------------------- + +Comparing to the old version of zlib (or zlib-ng) +means someone has to check out and build +the previous source tree and extract its .abi +using abidw. This can be slow. + +If you don't mind the slowness, run abicheck.sh --refresh-if, +and it will download and build the reference version +and extract the .abi on the spot if needed. +(FIXME: should this be the default?) + +On the next run, the reference .abi file will already be +present, and that step will be skipped. +It's stored in the tests/abi directory, +in a file with the architecture and git hash in the name. + +If you're running continuous integration +which clear out the source tree on each run, +and you don't want your build machines +constantly downloading and building the old +version, you can check the .abi file into git. + +To make this easier, a helper script could be written to automatically build +all the configurations tested by .github/workflows/abicheck.yml +Then they could be checked into git en masse by a maintainer +when a new platform is added or a new major version (which +intentionally breaks backwards compatibility) is being prepared. + +Further reading +--------------- + +- https://sourceware.org/libabigail/manual/ +- https://developers.redhat.com/blog/2014/10/23/comparing-abis-for-compatibility-with-libabigail-part-1/ +- https://developers.redhat.com/blog/2020/04/02/how-to-write-an-abi-compliance-checker-using-libabigail/ diff --git a/test/abicheck.sh b/test/abicheck.sh new file mode 100644 index 0000000000..1656711f62 --- /dev/null +++ b/test/abicheck.sh @@ -0,0 +1,163 @@ +#!/bin/sh +set -ex +TESTDIR="$(cd $(dirname "$0"); pwd)" + +usage() { + cat <<_EOF_ +Usage: $0 [--zlib-compat][--refresh][--refresh-if] + +Build shared library with -ggdb, then compare its ABI to the stable +ABI, and abort if differences found. + +Options: +--zlib-compat - check the ABI of the zlib-compatible flavor of zlib-ng. +--refresh - build the reference library and extract its ABI rather than using a stored ABI file. +--refresh-if - refresh only if ABI file not present. + +Obeys CHOST, CONFIGURE_ARGS, CFLAGS, and LDFLAGS. + +Requires libabigail (on Ubuntu, install package abigail-tools). +_EOF_ +} + +# Print the multiarch tuple for the current (non-cross) machine, +# or the empty string if unavailable. +detect_chost() { + dpkg-architecture -qDEB_HOST_MULTIARCH || + $CC -print-multiarch || + $CC -print-search-dirs | sed 's/:/\n/g' | grep -E '^/lib/[^/]+$' | sed 's%.*/%%' || + true +} + +if ! test -f "configure" +then + echo "Please run from top of source tree" + exit 1 +fi + +suffix="-ng" +CONFIGURE_ARGS_NG="$CONFIGURE_ARGS" +refresh=false +refresh_if=false +for arg +do + case "$arg" in + --zlib-compat) + suffix="" + CONFIGURE_ARGS_NG="$CONFIGURE_ARGS_NG --zlib-compat" + ;; + --refresh) + refresh=true + ;; + --refresh-if) + refresh_if=true + ;; + --help) + usage + exit 0 + ;; + *) + echo "Unknown arg '$arg'" + usage + exit 1 + ;; + esac +done + +# Choose reference repo and commit +if test "$suffix" = "" +then + # Reference is zlib 1.2.13. + ABI_GIT_REPO=https://github.com/madler/zlib.git + ABI_GIT_COMMIT=04f42ceca40f73e2978b50e93806c2a18c1281fc +else + # Reference is most recent zlib-ng develop with zlib 1.2.12 compatible api. + ABI_GIT_REPO=https://github.com/zlib-ng/zlib-ng.git + ABI_GIT_COMMIT=e4614ebcb9b3e5b108dc983c155e4baf80882311 +fi + +# Test compat build for ABI compatibility with zlib +if test "$CHOST" = "" +then + # Note: don't export CHOST here, as we don't want configure seeing it + # when it's just the name for the build machine. + # Leave it as a plain shell variable, not an environment variable. + CHOST=$(detect_chost) + # Support -m32 for non-cross builds. + case "$CFLAGS" in + *-m32*) M32="-m32";; + *) M32="";; + esac +fi + +# Canonicalize CHOST to work around bug in original zlib's configure +# (Don't export it if it wasn't already exported, else may cause +# default compiler detection failure and shared library link error +# when building both zlib and zlib-ng. +# See https://github.com/zlib-ng/zlib-ng/issues/1219) +CHOST=$(sh $TESTDIR/../tools/config.sub $CHOST) + +if test "$CHOST" = "" +then + echo "abicheck: SKIP, as we don't know CHOST" + exit 0 +fi + +ABIFILE="test/abi/zlib$suffix-$ABI_GIT_COMMIT-$CHOST$M32.abi" +if ! $refresh && $refresh_if && ! test -f "$ABIFILE" +then + refresh=true +fi +abidw --version + +if $refresh +then + # Check out reference source + rm -rf btmp1 + mkdir -p btmp1/src.d + cd btmp1/src.d + git init + git remote add origin $ABI_GIT_REPO + git fetch origin $ABI_GIT_COMMIT + git reset --hard FETCH_HEAD + cd .. + # Build unstripped, uninstalled, very debug shared library + CFLAGS="$CFLAGS -ggdb" src.d/configure $CONFIGURE_ARGS + make -j2 + cd .. + # Find shared library, extract its abi + dylib1=$(find btmp1 -type f -name '*.dylib*' -print -o -type f -name '*.so.*' -print) + abidw $dylib1 > "$ABIFILE" + # Maintainers may wish to check $ABIFILE into git when a new + # target is added, or when a major release happens that is + # intended to change the ABI. Alternately, this script could + # just always rebuild the reference source, and dispense with + # caching abi files in git (but that would slow builds down). +fi + +if ! test -f "$ABIFILE" +then + echo "abicheck: SKIP: $ABIFILE not found; rerun with --refresh or --refresh-if" + exit 1 +fi + +# Build unstripped, uninstalled, very debug shared library +rm -rf btmp2 +mkdir btmp2 +cd btmp2 +CFLAGS="$CFLAGS -ggdb" ../configure $CONFIGURE_ARGS_NG +make -j2 +cd .. +# Find shared library, extract its abi +dylib2=$(find btmp2 -type f -name '*.dylib*' -print -o -type f -name '*.so.*' -print) +abidw $dylib2 > btmp2/zlib${suffix}-built.abi + +# Compare it to the reference +# FIXME: use --no-added-syms for now, but we probably want to be more strict. +if abidiff --no-added-syms --suppressions test/abi/ignore "$ABIFILE" btmp2/zlib${suffix}-built.abi +then + echo "abicheck: PASS" +else + echo "abicheck: FAIL" + exit 1 +fi diff --git a/test/add-subdirectory-project/CMakeLists.txt b/test/add-subdirectory-project/CMakeLists.txt new file mode 100644 index 0000000000..a18626febb --- /dev/null +++ b/test/add-subdirectory-project/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.5.1...3.29.0) + +project(zlib-ng-add-subdirecory-test C) + +include(CTest) + +set(BUILD_SHARED_LIBS OFF) +set(ZLIB_ENABLE_TESTS ON CACHE BOOL "Build test binaries" FORCE) + +add_subdirectory(../.. zlib-ng) + +add_executable(app main.c) +target_link_libraries(app zlibstatic) diff --git a/test/add-subdirectory-project/main.c b/test/add-subdirectory-project/main.c new file mode 100644 index 0000000000..638a35b1d3 --- /dev/null +++ b/test/add-subdirectory-project/main.c @@ -0,0 +1,7 @@ +#include +#include "zlib-ng.h" + +int main(void) { + printf("zlib-ng: %s\n", ZLIBNG_VERSION); + return 0; +} diff --git a/test/benchmarks/CMakeLists.txt b/test/benchmarks/CMakeLists.txt new file mode 100644 index 0000000000..0efed96878 --- /dev/null +++ b/test/benchmarks/CMakeLists.txt @@ -0,0 +1,116 @@ +cmake_minimum_required(VERSION 3.12) + +include(FetchContent) + +if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) +endif() +if(NOT DEFINED CMAKE_CXX_STANDARD_REQUIRED) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() +if(NOT DEFINED CMAKE_CXX_EXTENSIONS) + set(CMAKE_CXX_EXTENSIONS ON) +endif() + +enable_language(CXX) + +# Search for Google benchmark package +find_package(benchmark QUIET) +if(NOT benchmark_FOUND) + # Fetch google benchmark source code from official repository + set(BENCHMARK_ENABLE_TESTING OFF) + + # Allow specifying alternative Google benchmark repository + if(NOT DEFINED GBENCHMARK_REPOSITORY) + set(GBENCHMARK_REPOSITORY https://github.com/google/benchmark.git) + endif() + if(NOT DEFINED GBENCHMARK_TAG) + set(GBENCHMARK_TAG v1.7.1) + endif() + + FetchContent_Declare(benchmark + GIT_REPOSITORY ${GBENCHMARK_REPOSITORY} + GIT_TAG ${GBENCHMARK_TAG}) + + FetchContent_GetProperties(benchmark) + if(NOT benchmark_POPULATED) + FetchContent_Populate(benchmark) + add_subdirectory(${benchmark_SOURCE_DIR} ${benchmark_BINARY_DIR} EXCLUDE_FROM_ALL) + endif() +endif() + +add_executable(benchmark_zlib + benchmark_adler32.cc + benchmark_adler32_copy.cc + benchmark_compare256.cc + benchmark_compare256_rle.cc + benchmark_compress.cc + benchmark_crc32.cc + benchmark_main.cc + benchmark_slidehash.cc + benchmark_uncompress.cc + ) + +target_compile_definitions(benchmark_zlib PRIVATE -DBENCHMARK_STATIC_DEFINE) +target_include_directories(benchmark_zlib PRIVATE + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR} + ${benchmark_SOURCE_DIR}/benchmark/include) + +target_link_libraries(benchmark_zlib zlibstatic benchmark::benchmark) +if(WIN32) + target_link_libraries(benchmark_zlib shlwapi) +endif() + +add_test(NAME benchmark_zlib + COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + +if(WITH_BENCHMARK_APPS) + option(BUILD_ALT_BENCH "Link against alternative zlib implementation" OFF) + + # Search for libpng package + find_package(PNG QUIET) + + if(NOT PNG_FOUND) + FetchContent_Declare(PNG + GIT_REPOSITORY https://github.com/glennrp/libpng.git) + + FetchContent_GetProperties(PNG) + if(NOT PNG_POPULATED) + FetchContent_Populate(PNG) + set(PNG_INCLUDE_DIR ${png_SOURCE_DIR}) + add_subdirectory(${png_SOURCE_DIR} ${png_BINARY_DIR}) + endif() + endif() + + set(BENCH_APP_SRCS + benchmark_png_encode.cc + benchmark_png_decode.cc + benchmark_main.cc + ) + + add_executable(benchmark_zlib_apps ${BENCH_APP_SRCS}) + + if(DEFINED BUILD_ALT_BENCH) + set(ZLIB_ALT_LIB "libz.a" CACHE FILEPATH "Optional alternative zlib implementation (defaults to stock zlib)") + add_executable(benchmark_zlib_apps_alt ${BENCH_APP_SRCS}) + target_link_libraries(benchmark_zlib_apps_alt libpng.a ${ZLIB_ALT_LIB} benchmark::benchmark) + target_compile_definitions(benchmark_zlib_apps_alt PRIVATE BUILD_ALT=1) + target_include_directories(benchmark_zlib_apps_alt PRIVATE + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR} + ${PNG_INCLUDE_DIR} + ${benchmark_SOURCE_DIR}/benchmark/include) + endif() + + target_include_directories(benchmark_zlib_apps PRIVATE + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR} + ${PNG_INCLUDE_DIR} + ${benchmark_SOURCE_DIR}/benchmark/include) + + # We need the static png library if we're statically linking to zlib, + # otherwise it will resolve these things in the system provided dynamic + # libraries (likely linked to stock zlib) + target_link_libraries(benchmark_zlib_apps libpng.a zlibstatic benchmark::benchmark) +endif() diff --git a/test/benchmarks/README.md b/test/benchmarks/README.md new file mode 100644 index 0000000000..964b198cfe --- /dev/null +++ b/test/benchmarks/README.md @@ -0,0 +1,47 @@ +## Benchmarks +These benchmarks are written using [Google Benchmark](https://github.com/google/benchmark). + +*Repetitions* + +To increase the number of times each benchmark iteration is run use: + +``` +--benchmark_repetitions=20 +``` + +*Filters* + +To filter out which benchmarks are performed use: + +``` +--benchmark_filter="adler32*" +``` + +There are two different benchmarks, micro and macro. + +### Benchmark benchmark_zlib +These are microbenchmarks intended to test lower level subfunctions of the library. + +Benchmarks include implementations of: + - Adler32 + - CRC + - 256 byte comparisons + - SIMD accelerated "slide hash" routine + +By default these benchmarks report things on the nanosecond scale and are small enough +to measure very minute differences. + +### Benchmark benchmark_zlib_apps +These benchmarks measure applications of zlib as a whole. Currently the only examples +are PNG encoding and decoding. The PNG encode and decode tests leveraging procedurally +generated and highly compressible image data. + +Additionally, a test called `png_decode_realistic` that will decode any RGB 8 BPP encoded +set of PNGs in the working directory under a directory named "test_pngs" with files named +{0..1}.png. If these images do not exist, they will error out and the benchmark will move +on to the next set of benchmarks. + +*benchmark_zlib_apps_alt* + +The user can compile a comparison benchmark application linking to any zlib-compatible +implementation of his or her choosing. diff --git a/test/benchmarks/benchmark_adler32.cc b/test/benchmarks/benchmark_adler32.cc new file mode 100644 index 0000000000..b1278950d0 --- /dev/null +++ b/test/benchmarks/benchmark_adler32.cc @@ -0,0 +1,100 @@ +/* benchmark_adler32.cc -- benchmark adler32 variants + * Copyright (C) 2022 Nathan Moinvaziri, Adam Stylinski + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include + +#include + +extern "C" { +# include "zbuild.h" +# include "zutil_p.h" +# include "arch_functions.h" +# include "../test_cpu_features.h" +} + +#define MAX_RANDOM_INTS (1024 * 1024) +#define MAX_RANDOM_INTS_SIZE (MAX_RANDOM_INTS * sizeof(uint32_t)) + +class adler32: public benchmark::Fixture { +private: + uint32_t *random_ints; + +public: + void SetUp(const ::benchmark::State& state) { + /* Control the alignment so that we have the best case scenario for loads. With + * AVX512, unaligned loads can mean we're crossing a cacheline boundary at every load. + * And while this is a realistic scenario, it makes it difficult to compare benchmark + * to benchmark because one allocation could have been aligned perfectly for the loads + * while the subsequent one happened to not be. This is not to be advantageous to AVX512 + * (indeed, all lesser SIMD implementations benefit from this aligned allocation), but to + * control the _consistency_ of the results */ + random_ints = (uint32_t *)zng_alloc(MAX_RANDOM_INTS_SIZE); + assert(random_ints != NULL); + + for (int32_t i = 0; i < MAX_RANDOM_INTS; i++) { + random_ints[i] = rand(); + } + } + + void Bench(benchmark::State& state, adler32_func adler32) { + uint32_t hash = 0; + + for (auto _ : state) { + hash = adler32(hash, (const unsigned char *)random_ints, (size_t)state.range(0)); + } + + benchmark::DoNotOptimize(hash); + } + + void TearDown(const ::benchmark::State& state) { + zng_free(random_ints); + } +}; + +#define BENCHMARK_ADLER32(name, fptr, support_flag) \ + BENCHMARK_DEFINE_F(adler32, name)(benchmark::State& state) { \ + if (!support_flag) { \ + state.SkipWithError("CPU does not support " #name); \ + } \ + Bench(state, fptr); \ + } \ + BENCHMARK_REGISTER_F(adler32, name)->Arg(1)->Arg(8)->Arg(12)->Arg(16)->Arg(32)->Arg(64)->Arg(512)->Arg(4<<10)->Arg(32<<10)->Arg(256<<10)->Arg(4096<<10) + +BENCHMARK_ADLER32(c, adler32_c, 1); + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +BENCHMARK_ADLER32(native, native_adler32, 1); +#else + +#ifdef ARM_NEON +BENCHMARK_ADLER32(neon, adler32_neon, test_cpu_features.arm.has_neon); +#endif + +#ifdef PPC_VMX +BENCHMARK_ADLER32(vmx, adler32_vmx, test_cpu_features.power.has_altivec); +#endif +#ifdef POWER8_VSX +BENCHMARK_ADLER32(power8, adler32_power8, test_cpu_features.power.has_arch_2_07); +#endif + +#ifdef RISCV_RVV +BENCHMARK_ADLER32(rvv, adler32_rvv, test_cpu_features.riscv.has_rvv); +#endif + +#ifdef X86_SSSE3 +BENCHMARK_ADLER32(ssse3, adler32_ssse3, test_cpu_features.x86.has_ssse3); +#endif +#ifdef X86_AVX2 +BENCHMARK_ADLER32(avx2, adler32_avx2, test_cpu_features.x86.has_avx2); +#endif +#ifdef X86_AVX512 +BENCHMARK_ADLER32(avx512, adler32_avx512, test_cpu_features.x86.has_avx512_common); +#endif +#ifdef X86_AVX512VNNI +BENCHMARK_ADLER32(avx512_vnni, adler32_avx512_vnni, test_cpu_features.x86.has_avx512vnni); +#endif + +#endif diff --git a/test/benchmarks/benchmark_adler32_copy.cc b/test/benchmarks/benchmark_adler32_copy.cc new file mode 100644 index 0000000000..50e6333c43 --- /dev/null +++ b/test/benchmarks/benchmark_adler32_copy.cc @@ -0,0 +1,130 @@ +/* benchmark_adler32_copy.cc -- benchmark adler32 (elided copy) variants + * Copyright (C) 2022 Nathan Moinvaziri, Adam Stylinski + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include +#include + +#include + +extern "C" { +# include "zbuild.h" +# include "zutil_p.h" +# include "arch_functions.h" +# include "../test_cpu_features.h" +} + +#define MAX_RANDOM_INTS (1024 * 1024) +#define MAX_RANDOM_INTS_SIZE (MAX_RANDOM_INTS * sizeof(uint32_t)) + +typedef uint32_t (*adler32_cpy_func)(uint32_t adler, unsigned char *dst, const uint8_t *buf, size_t len); + +class adler32_copy: public benchmark::Fixture { +private: + uint32_t *random_ints_src; + uint32_t *random_ints_dst; + +public: + void SetUp(const ::benchmark::State& state) { + /* Control the alignment so that we have the best case scenario for loads. With + * AVX512, unaligned loads can mean we're crossing a cacheline boundary at every load. + * And while this is a realistic scenario, it makes it difficult to compare benchmark + * to benchmark because one allocation could have been aligned perfectly for the loads + * while the subsequent one happened to not be. This is not to be advantageous to AVX512 + * (indeed, all lesser SIMD implementations benefit from this aligned allocation), but to + * control the _consistency_ of the results */ + random_ints_src = (uint32_t *)zng_alloc(MAX_RANDOM_INTS_SIZE); + random_ints_dst = (uint32_t *)zng_alloc(MAX_RANDOM_INTS_SIZE); + assert(random_ints_src != NULL); + assert(random_ints_dst != NULL); + + for (int32_t i = 0; i < MAX_RANDOM_INTS; i++) { + random_ints_src[i] = rand(); + } + } + + void Bench(benchmark::State& state, adler32_cpy_func adler32_func) { + uint32_t hash = 0; + + for (auto _ : state) { + hash = adler32_func(hash, (unsigned char *)random_ints_dst, + (const unsigned char*)random_ints_src, (size_t)state.range(0)); + } + + benchmark::DoNotOptimize(hash); + } + + void TearDown(const ::benchmark::State& state) { + zng_free(random_ints_src); + zng_free(random_ints_dst); + } +}; + +#define BENCHMARK_ADLER32_COPY(name, fptr, support_flag) \ + BENCHMARK_DEFINE_F(adler32_copy, name)(benchmark::State& state) { \ + if (!support_flag) { \ + state.SkipWithError("CPU does not support " #name); \ + } \ + Bench(state, fptr); \ + } \ + BENCHMARK_REGISTER_F(adler32_copy, name)->Range(8192, MAX_RANDOM_INTS_SIZE); + +#define BENCHMARK_ADLER32_BASELINE_COPY(name, fptr, support_flag) \ + BENCHMARK_DEFINE_F(adler32_copy, name)(benchmark::State& state) { \ + if (!support_flag) { \ + state.SkipWithError("CPU does not support " #name); \ + } \ + Bench(state, [](uint32_t init_sum, unsigned char *dst, \ + const uint8_t *buf, size_t len) -> uint32_t { \ + memcpy(dst, buf, (size_t)len); \ + return fptr(init_sum, buf, len); \ + }); \ + } \ + BENCHMARK_REGISTER_F(adler32_copy, name)->Range(8192, MAX_RANDOM_INTS_SIZE); + +BENCHMARK_ADLER32_BASELINE_COPY(c, adler32_c, 1); + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +BENCHMARK_ADLER32_BASELINE_COPY(native, native_adler32, 1); +#else + +#ifdef ARM_NEON +/* If we inline this copy for neon, the function would go here */ +//BENCHMARK_ADLER32_COPY(neon, adler32_neon, test_cpu_features.arm.has_neon); +BENCHMARK_ADLER32_BASELINE_COPY(neon_copy_baseline, adler32_neon, test_cpu_features.arm.has_neon); +#endif + +#ifdef PPC_VMX +//BENCHMARK_ADLER32_COPY(vmx_inline_copy, adler32_fold_copy_vmx, test_cpu_features.power.has_altivec); +BENCHMARK_ADLER32_BASELINE_COPY(vmx_copy_baseline, adler32_vmx, test_cpu_features.power.has_altivec); +#endif +#ifdef POWER8_VSX +//BENCHMARK_ADLER32_COPY(power8_inline_copy, adler32_fold_copy_power8, test_cpu_features.power.has_arch_2_07); +BENCHMARK_ADLER32_BASELINE_COPY(power8, adler32_power8, test_cpu_features.power.has_arch_2_07); +#endif + +#ifdef RISCV_RVV +//BENCHMARK_ADLER32_COPY(rvv, adler32_rvv, test_cpu_features.riscv.has_rvv); +BENCHMARK_ADLER32_BASELINE_COPY(rvv, adler32_rvv, test_cpu_features.riscv.has_rvv); +#endif + +#ifdef X86_SSE42 +BENCHMARK_ADLER32_BASELINE_COPY(sse42_baseline, adler32_ssse3, test_cpu_features.x86.has_ssse3); +BENCHMARK_ADLER32_COPY(sse42, adler32_fold_copy_sse42, test_cpu_features.x86.has_sse42); +#endif +#ifdef X86_AVX2 +BENCHMARK_ADLER32_BASELINE_COPY(avx2_baseline, adler32_avx2, test_cpu_features.x86.has_avx2); +BENCHMARK_ADLER32_COPY(avx2, adler32_fold_copy_avx2, test_cpu_features.x86.has_avx2); +#endif +#ifdef X86_AVX512 +BENCHMARK_ADLER32_BASELINE_COPY(avx512_baseline, adler32_avx512, test_cpu_features.x86.has_avx512_common); +BENCHMARK_ADLER32_COPY(avx512, adler32_fold_copy_avx512, test_cpu_features.x86.has_avx512_common); +#endif +#ifdef X86_AVX512VNNI +BENCHMARK_ADLER32_BASELINE_COPY(avx512_vnni_baseline, adler32_avx512_vnni, test_cpu_features.x86.has_avx512vnni); +BENCHMARK_ADLER32_COPY(avx512_vnni, adler32_fold_copy_avx512_vnni, test_cpu_features.x86.has_avx512vnni); +#endif + +#endif diff --git a/test/benchmarks/benchmark_compare256.cc b/test/benchmarks/benchmark_compare256.cc new file mode 100644 index 0000000000..c27bff1360 --- /dev/null +++ b/test/benchmarks/benchmark_compare256.cc @@ -0,0 +1,93 @@ +/* benchmark_compare256.cc -- benchmark compare256 variants + * Copyright (C) 2022 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include + +#include + +extern "C" { +# include "zbuild.h" +# include "zutil_p.h" +# include "arch_functions.h" +# include "../test_cpu_features.h" +# include "arch/generic/compare256_p.h" +} + +#define MAX_COMPARE_SIZE (256) + +class compare256: public benchmark::Fixture { +private: + uint8_t *str1; + uint8_t *str2; + +public: + void SetUp(const ::benchmark::State& state) { + str1 = (uint8_t *)zng_alloc(MAX_COMPARE_SIZE); + assert(str1 != NULL); + memset(str1, 'a', MAX_COMPARE_SIZE); + + str2 = (uint8_t *)zng_alloc(MAX_COMPARE_SIZE); + assert(str2 != NULL); + memset(str2, 'a', MAX_COMPARE_SIZE); + } + + void Bench(benchmark::State& state, compare256_func compare256) { + int32_t match_len = (int32_t)state.range(0) - 1; + uint32_t len = 0; + + str2[match_len] = 0; + for (auto _ : state) { + len = compare256((const uint8_t *)str1, (const uint8_t *)str2); + } + str2[match_len] = 'a'; + + benchmark::DoNotOptimize(len); + } + + void TearDown(const ::benchmark::State& state) { + zng_free(str1); + zng_free(str2); + } +}; + +#define BENCHMARK_COMPARE256(name, fptr, support_flag) \ + BENCHMARK_DEFINE_F(compare256, name)(benchmark::State& state) { \ + if (!support_flag) { \ + state.SkipWithError("CPU does not support " #name); \ + } \ + Bench(state, fptr); \ + } \ + BENCHMARK_REGISTER_F(compare256, name)->Range(1, MAX_COMPARE_SIZE); + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +BENCHMARK_COMPARE256(native, native_compare256, 1); +#else + +BENCHMARK_COMPARE256(8, compare256_8, 1); +BENCHMARK_COMPARE256(16, compare256_16, 1); +#if defined(HAVE_BUILTIN_CTZ) +BENCHMARK_COMPARE256(32, compare256_32, 1); +#endif +#if defined(HAVE_BUILTIN_CTZLL) +BENCHMARK_COMPARE256(64, compare256_64, 1); +#endif + +#if defined(X86_SSE2) && defined(HAVE_BUILTIN_CTZ) +BENCHMARK_COMPARE256(sse2, compare256_sse2, test_cpu_features.x86.has_sse2); +#endif +#if defined(X86_AVX2) && defined(HAVE_BUILTIN_CTZ) +BENCHMARK_COMPARE256(avx2, compare256_avx2, test_cpu_features.x86.has_avx2); +#endif +#if defined(ARM_NEON) && defined(HAVE_BUILTIN_CTZLL) +BENCHMARK_COMPARE256(neon, compare256_neon, test_cpu_features.arm.has_neon); +#endif +#ifdef POWER9 +BENCHMARK_COMPARE256(power9, compare256_power9, test_cpu_features.power.has_arch_3_00); +#endif +#ifdef RISCV_RVV +BENCHMARK_COMPARE256(rvv, compare256_rvv, test_cpu_features.riscv.has_rvv); +#endif + +#endif diff --git a/test/benchmarks/benchmark_compare256_rle.cc b/test/benchmarks/benchmark_compare256_rle.cc new file mode 100644 index 0000000000..5e6bb643c8 --- /dev/null +++ b/test/benchmarks/benchmark_compare256_rle.cc @@ -0,0 +1,69 @@ +/* benchmark_compare256_rle.cc -- benchmark compare256_rle variants + * Copyright (C) 2022 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include + +#include + +extern "C" { +# include "zbuild.h" +# include "zutil_p.h" +# include "compare256_rle.h" +} + +#define MAX_COMPARE_SIZE (256) + +class compare256_rle: public benchmark::Fixture { +private: + uint8_t *str1; + uint8_t *str2; + +public: + void SetUp(const ::benchmark::State& state) { + str1 = (uint8_t *)zng_alloc(MAX_COMPARE_SIZE); + assert(str1 != NULL); + memset(str1, 'a', MAX_COMPARE_SIZE); + + str2 = (uint8_t *)zng_alloc(MAX_COMPARE_SIZE); + assert(str2 != NULL); + memset(str2, 'a', MAX_COMPARE_SIZE); + } + + void Bench(benchmark::State& state, compare256_rle_func compare256_rle) { + int32_t match_len = (int32_t)state.range(0) - 1; + uint32_t len = 0; + + str2[match_len] = 0; + for (auto _ : state) { + len = compare256_rle((const uint8_t *)str1, (const uint8_t *)str2); + } + str2[match_len] = 'a'; + + benchmark::DoNotOptimize(len); + } + + void TearDown(const ::benchmark::State& state) { + zng_free(str1); + zng_free(str2); + } +}; + +#define BENCHMARK_COMPARE256_RLE(name, fptr, support_flag) \ + BENCHMARK_DEFINE_F(compare256_rle, name)(benchmark::State& state) { \ + if (!support_flag) { \ + state.SkipWithError("CPU does not support " #name); \ + } \ + Bench(state, fptr); \ + } \ + BENCHMARK_REGISTER_F(compare256_rle, name)->Range(1, MAX_COMPARE_SIZE); + +BENCHMARK_COMPARE256_RLE(8, compare256_rle_8, 1); +BENCHMARK_COMPARE256_RLE(16, compare256_rle_16, 1); +#if defined(HAVE_BUILTIN_CTZ) +BENCHMARK_COMPARE256_RLE(32, compare256_rle_32, 1); +#endif +#if defined(HAVE_BUILTIN_CTZLL) +BENCHMARK_COMPARE256_RLE(64, compare256_rle_64, 1); +#endif diff --git a/test/benchmarks/benchmark_compress.cc b/test/benchmarks/benchmark_compress.cc new file mode 100644 index 0000000000..400a7869e4 --- /dev/null +++ b/test/benchmarks/benchmark_compress.cc @@ -0,0 +1,67 @@ +/* benchmark_compress.cc -- benchmark compress() + * Copyright (C) 2024 Hans Kristian Rosbach + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include +#include + +extern "C" { +# include "zbuild.h" +# include "zutil_p.h" +# if defined(ZLIB_COMPAT) +# include "zlib.h" +# else +# include "zlib-ng.h" +# endif +} + +#define MAX_SIZE (32 * 1024) + +class compress_bench: public benchmark::Fixture { +private: + size_t maxlen; + uint8_t *inbuff; + uint8_t *outbuff; + +public: + void SetUp(const ::benchmark::State& state) { + const char teststr[42] = "Hello hello World broken Test tast mello."; + maxlen = MAX_SIZE; + + inbuff = (uint8_t *)zng_alloc(MAX_SIZE + 1); + assert(inbuff != NULL); + + outbuff = (uint8_t *)zng_alloc(MAX_SIZE + 1); + assert(outbuff != NULL); + + int pos = 0; + for (int32_t i = 0; i < MAX_SIZE - 42 ; i+=42){ + pos += sprintf((char *)inbuff+pos, "%s", teststr); + } + } + + void Bench(benchmark::State& state) { + int err = 0; + + for (auto _ : state) { + err = PREFIX(compress)(outbuff, &maxlen, inbuff, (size_t)state.range(0)); + } + + benchmark::DoNotOptimize(err); + } + + void TearDown(const ::benchmark::State& state) { + zng_free(inbuff); + zng_free(outbuff); + } +}; + +#define BENCHMARK_COMPRESS(name) \ + BENCHMARK_DEFINE_F(compress_bench, name)(benchmark::State& state) { \ + Bench(state); \ + } \ + BENCHMARK_REGISTER_F(compress_bench, name)->Arg(1)->Arg(8)->Arg(16)->Arg(32)->Arg(64)->Arg(512)->Arg(4<<10)->Arg(32<<10); + +BENCHMARK_COMPRESS(compress_bench); diff --git a/test/benchmarks/benchmark_crc32.cc b/test/benchmarks/benchmark_crc32.cc new file mode 100644 index 0000000000..7aba7c3367 --- /dev/null +++ b/test/benchmarks/benchmark_crc32.cc @@ -0,0 +1,83 @@ +/* benchmark_crc32.cc -- benchmark crc32 variants + * Copyright (C) 2022 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include + +#include + +extern "C" { +# include "zbuild.h" +# include "zutil_p.h" +# include "arch_functions.h" +# include "../test_cpu_features.h" +} + +#define MAX_RANDOM_INTS (1024 * 1024) +#define MAX_RANDOM_INTS_SIZE (MAX_RANDOM_INTS * sizeof(uint32_t)) + +class crc32: public benchmark::Fixture { +private: + uint32_t *random_ints; + +public: + void SetUp(const ::benchmark::State& state) { + random_ints = (uint32_t *)zng_alloc(MAX_RANDOM_INTS_SIZE); + assert(random_ints != NULL); + + for (int32_t i = 0; i < MAX_RANDOM_INTS; i++) { + random_ints[i] = rand(); + } + } + + void Bench(benchmark::State& state, crc32_func crc32) { + uint32_t hash = 0; + + for (auto _ : state) { + hash = crc32(hash, (const unsigned char *)random_ints, (size_t)state.range(0)); + } + + benchmark::DoNotOptimize(hash); + } + + void TearDown(const ::benchmark::State& state) { + zng_free(random_ints); + } +}; + +#define BENCHMARK_CRC32(name, fptr, support_flag) \ + BENCHMARK_DEFINE_F(crc32, name)(benchmark::State& state) { \ + if (!support_flag) { \ + state.SkipWithError("CPU does not support " #name); \ + } \ + Bench(state, fptr); \ + } \ + BENCHMARK_REGISTER_F(crc32, name)->Arg(1)->Arg(8)->Arg(12)->Arg(16)->Arg(32)->Arg(64)->Arg(512)->Arg(4<<10)->Arg(32<<10)->Arg(256<<10)->Arg(4096<<10); + +BENCHMARK_CRC32(braid, PREFIX(crc32_braid), 1); + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +BENCHMARK_CRC32(native, native_crc32, 1); +#else + +#ifdef ARM_ACLE +BENCHMARK_CRC32(acle, crc32_acle, test_cpu_features.arm.has_crc32); +#endif +#ifdef POWER8_VSX_CRC32 +BENCHMARK_CRC32(power8, crc32_power8, test_cpu_features.power.has_arch_2_07); +#endif +#ifdef S390_CRC32_VX +BENCHMARK_CRC32(vx, crc32_s390_vx, test_cpu_features.s390.has_vx); +#endif +#ifdef X86_PCLMULQDQ_CRC +/* CRC32 fold does a memory copy while hashing */ +BENCHMARK_CRC32(pclmulqdq, crc32_pclmulqdq, test_cpu_features.x86.has_pclmulqdq); +#endif +#ifdef X86_VPCLMULQDQ_CRC +/* CRC32 fold does a memory copy while hashing */ +BENCHMARK_CRC32(vpclmulqdq, crc32_vpclmulqdq, (test_cpu_features.x86.has_pclmulqdq && test_cpu_features.x86.has_avx512_common && test_cpu_features.x86.has_vpclmulqdq)); +#endif + +#endif diff --git a/test/benchmarks/benchmark_main.cc b/test/benchmarks/benchmark_main.cc new file mode 100644 index 0000000000..f3c227bdf7 --- /dev/null +++ b/test/benchmarks/benchmark_main.cc @@ -0,0 +1,32 @@ +/* benchmark_main.cc -- benchmark suite main entry point + * Copyright (C) 2022 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include + +#include + +#ifndef BUILD_ALT +extern "C" { +# include "zbuild.h" +# include "../test_cpu_features.h" + +# ifndef DISABLE_RUNTIME_CPU_DETECTION + struct cpu_features test_cpu_features; +# endif +} +#endif + +int main(int argc, char** argv) { +#ifndef BUILD_ALT +# ifndef DISABLE_RUNTIME_CPU_DETECTION + cpu_check_features(&test_cpu_features); +# endif +#endif + + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); + + return EXIT_SUCCESS; +} diff --git a/test/benchmarks/benchmark_png_decode.cc b/test/benchmarks/benchmark_png_decode.cc new file mode 100644 index 0000000000..c037976c8c --- /dev/null +++ b/test/benchmarks/benchmark_png_decode.cc @@ -0,0 +1,126 @@ +#include +#include +#include "benchmark_png_shared.h" +#include + +class png_decode: public benchmark::Fixture { +protected: + png_dat inpng[10]; + + /* Backing this on the heap is a more realistic benchmark */ + uint8_t *output_img_buf = NULL; + +public: + /* Let's make the vanilla version have something extremely compressible */ + virtual void init_img(png_bytep img_bytes, size_t width, size_t height) { + init_compressible(img_bytes, width*height); + } + + void SetUp(const ::benchmark::State& state) { + output_img_buf = (uint8_t*)malloc(IMWIDTH * IMHEIGHT * 3); + assert(output_img_buf != NULL); + init_img(output_img_buf, IMWIDTH, IMHEIGHT); + + /* First we need to author the png bytes to be decoded */ + for (int i = 0; i < 10; ++i) { + inpng[i] = {NULL, 0, 0}; + encode_png(output_img_buf, &inpng[i], i, IMWIDTH, IMHEIGHT); + } + } + + /* State in this circumstance will convey the compression level */ + void Bench(benchmark::State &state) { + for (auto _ : state) { + int compress_lvl = state.range(0); + png_parse_dat in = { inpng[compress_lvl].buf }; + uint32_t width, height; + decode_png(&in, (png_bytepp)&output_img_buf, IMWIDTH * IMHEIGHT * 3, width, height); + } + } + + void TearDown(const ::benchmark::State &state) { + free(output_img_buf); + for (int i = 0; i < 10; ++i) { + free(inpng[i].buf); + } + } +}; + +class png_decode_realistic: public png_decode { +private: + bool test_files_found = false; + +public: + void SetUp(const ::benchmark::State &state) { + output_img_buf = NULL; + output_img_buf = (uint8_t*)malloc(IMWIDTH * IMHEIGHT * 3); + /* Let's take all the images at different compression levels and jam their bytes into buffers */ + char test_fname[25]; + FILE *files[10]; + + /* Set all to NULL */ + memset(files, 0, sizeof(FILE*)); + + for (size_t i = 0; i < 10; ++i) { + sprintf(test_fname, "test_pngs/%1lu.png", i); + FILE *in_img = fopen(test_fname, "r"); + if (in_img == NULL) { + for (size_t j = 0; j < i; ++j) { + if (files[j]) + fclose(files[j]); + } + + /* For proper cleanup */ + for (size_t j = i; j < 10; ++j) { + inpng[i] = { NULL, 0, 0 }; + } + + return; + } + files[i] = in_img; + } + + test_files_found = true; + /* Now that we've established we have all the png files, let's read all of their bytes into buffers */ + for (size_t i = 0; i < 10; ++i) { + FILE *in_file = files[i]; + fseek(in_file, 0, SEEK_END); + size_t num_bytes = ftell(in_file); + rewind(in_file); + + uint8_t *raw_file = (uint8_t*)malloc(num_bytes); + if (raw_file == NULL) + abort(); + + inpng[i].buf = raw_file; + inpng[i].len = num_bytes; + inpng[i].buf_rem = 0; + + size_t bytes_read = fread(raw_file, 1, num_bytes, in_file); + if (bytes_read != num_bytes) { + fprintf(stderr, "couldn't read all of the bytes for file test_pngs/%lu.png", i); + abort(); + } + + fclose(in_file); + } + } + + void Bench(benchmark::State &state) { + if (!test_files_found) { + state.SkipWithError("Test imagery in test_pngs not found"); + } + + png_decode::Bench(state); + } +}; + +BENCHMARK_DEFINE_F(png_decode, png_decode)(benchmark::State &state) { + Bench(state); +} +BENCHMARK_REGISTER_F(png_decode, png_decode)->DenseRange(0, 9, 1)->Unit(benchmark::kMicrosecond); + +BENCHMARK_DEFINE_F(png_decode_realistic, png_decode_realistic)(benchmark::State &state) { + Bench(state); +} +BENCHMARK_REGISTER_F(png_decode_realistic, png_decode_realistic)->DenseRange(0, 9, 1)->Unit(benchmark::kMicrosecond); diff --git a/test/benchmarks/benchmark_png_encode.cc b/test/benchmarks/benchmark_png_encode.cc new file mode 100644 index 0000000000..f1c597d36b --- /dev/null +++ b/test/benchmarks/benchmark_png_encode.cc @@ -0,0 +1,54 @@ +#include +#include +#include +#include "benchmark_png_shared.h" + +#define IMWIDTH 1024 +#define IMHEIGHT 1024 + +class png_encode: public benchmark::Fixture { +private: + png_dat outpng; + + /* Backing this on the heap is a more realistic benchmark */ + uint8_t *input_img_buf = NULL; + +public: + /* Let's make the vanilla version have something extremely compressible */ + virtual void init_img(png_bytep img_bytes, size_t width, size_t height) { + init_compressible(img_bytes, width * height); + } + + void SetUp(const ::benchmark::State& state) { + input_img_buf = (uint8_t*)malloc(IMWIDTH * IMHEIGHT * 3); + outpng.buf = (uint8_t*)malloc(IMWIDTH * IMHEIGHT * 3); + /* Using malloc rather than zng_alloc so that we can call realloc. + * IMWIDTH * IMHEIGHT is likely to be more than enough bytes, though, + * given that a simple run length encoding already pretty much can + * reduce to this */ + outpng.len = 0; + outpng.buf_rem = IMWIDTH * IMHEIGHT * 3; + assert(input_img_buf != NULL); + assert(outpng.buf != NULL); + init_img(input_img_buf, IMWIDTH, IMHEIGHT); + } + + /* State in this circumstance will convey the compression level */ + void Bench(benchmark::State &state) { + for (auto _ : state) { + encode_png((png_bytep)input_img_buf, &outpng, state.range(0), IMWIDTH, IMHEIGHT); + outpng.buf_rem = outpng.len; + outpng.len = 0; + } + } + + void TearDown(const ::benchmark::State &state) { + free(input_img_buf); + free(outpng.buf); + } +}; + +BENCHMARK_DEFINE_F(png_encode, encode_compressible)(benchmark::State &state) { + Bench(state); +} +BENCHMARK_REGISTER_F(png_encode, encode_compressible)->DenseRange(0, 9, 1)->Unit(benchmark::kMicrosecond); diff --git a/test/benchmarks/benchmark_png_shared.h b/test/benchmarks/benchmark_png_shared.h new file mode 100644 index 0000000000..bde679e7d3 --- /dev/null +++ b/test/benchmarks/benchmark_png_shared.h @@ -0,0 +1,146 @@ +#pragma once + +#include +#include +#include + +#define IMWIDTH 1024 +#define IMHEIGHT 1024 + +extern "C" { +# include +} + +typedef struct _png_dat { + uint8_t *buf; + int64_t len; + size_t buf_rem; +} png_dat; + +typedef struct _png_parse_dat { + uint8_t *cur_pos; +} png_parse_dat; + +/* Write a customized write callback so that we write back to an in-memory buffer. + * This allows the testing to not involve disk IO */ +static void png_write_cb(png_structp pngp, png_bytep data, png_size_t len) { + png_dat *dat = (png_dat*)png_get_io_ptr(pngp); + size_t curSize = dat->len + len; + + /* realloc double the requested buffer size to prevent excessive reallocs */ + if (dat->buf_rem < len) { + dat->buf = (uint8_t*)realloc(dat->buf, dat->len + dat->buf_rem + 2 * len); + + if (!dat->buf) { + /* Pretty unlikely but we'll put it here just in case */ + fprintf(stderr, "realloc failed, exiting\n"); + exit(1); + } + + dat->buf_rem += 2 * len; + } + + memcpy(dat->buf + dat->len, data, len); + dat->len = curSize; + dat->buf_rem -= len; +} + +static void init_compressible(png_bytep buf, size_t num_pix) { + /* It doesn't actually matter what we make this, but for + * the sake of a reasonable test image, let's make this + * be a stripe of R, G, & B, with no alpha channel */ + int32_t i = 0; + int32_t red_stop = num_pix / 3; + int32_t blue_stop = 2 * num_pix / 3; + int32_t green_stop = num_pix; + + for (int32_t x = 0; i < red_stop; x += 3, ++i) { + buf[x] = 255; + buf[x + 1] = 0; + buf[x + 2] = 0; + } + + for (int32_t x = 3 * i; i < blue_stop; x+= 3, ++i) { + buf[x] = 0; + buf[x + 1] = 255; + buf[x + 2] = 0; + } + + for (int32_t x = 3 * i; i < green_stop; x += 3, ++i) { + buf[x] = 0; + buf[x + 1] = 0; + buf[x + 2] = 255; + } +} + +static inline void encode_png(png_bytep buf, png_dat *outpng, int32_t comp_level, uint32_t width, uint32_t height) { + png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + /* Most of this error handling is _likely_ not necessary. Likewise it's likely + * a lot of this stuff can be done in the setup function to avoid measuring this + * fixed setup time, but for now we'll do it here */ + if (!png) abort(); + + png_infop info = png_create_info_struct(png); + if (!info) abort(); + + png_set_write_fn(png, outpng, png_write_cb, NULL); + png_bytep *png_row_ptrs = new png_bytep[height]; + for (int i = 0; i < IMHEIGHT; ++i) { + png_row_ptrs[i] = (png_bytep)&buf[3*i*width]; + } + + png_set_IHDR(png, info, IMWIDTH, IMHEIGHT, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + png_write_info(png, info); + png_set_compression_level(png, comp_level); + png_set_filter(png, 0, PNG_FILTER_NONE); + png_write_image(png, (png_bytepp)png_row_ptrs); + png_write_end(png, NULL); + png_destroy_write_struct(&png, &info); + delete[] png_row_ptrs; +} + +static void read_from_pngdat(png_structp png, png_bytep out, png_size_t bytes_to_read) { + png_parse_dat *io = (png_parse_dat*)png_get_io_ptr(png); + memcpy(out, io->cur_pos, bytes_to_read); + io->cur_pos += bytes_to_read; +} + +static inline int decode_png(png_parse_dat *dat, png_bytepp out_bytes, size_t in_size, uint32_t &width, uint32_t &height) { + png_structp png = NULL; + png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!png) abort(); + png_infop info = NULL; + info = png_create_info_struct(png); + if (!info) abort(); + + png_set_read_fn(png, dat, read_from_pngdat); + png_read_info(png, info); + + int bit_depth = 0, color_type = -1; + png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); + + size_t im_size = width * height * bit_depth/8 * 3; + if (color_type != PNG_COLOR_TYPE_RGB) { + fprintf(stderr, "expected an 8 bpp RGB image\n"); + abort(); + } + + if (im_size > in_size) { + *out_bytes = (png_bytep)realloc(*out_bytes, im_size); + } + + png_bytep *out_rows = new png_bytep[height]; + for (size_t i = 0; i < height; ++i) + out_rows[i] = *out_bytes + (width*i*3); + + png_read_rows(png, out_rows, NULL, height); + png_destroy_read_struct(&png, &info, NULL); + delete[] out_rows; + + return im_size; +} diff --git a/test/benchmarks/benchmark_slidehash.cc b/test/benchmarks/benchmark_slidehash.cc new file mode 100644 index 0000000000..e51aa685a9 --- /dev/null +++ b/test/benchmarks/benchmark_slidehash.cc @@ -0,0 +1,98 @@ +/* benchmark_slidehash.cc -- benchmark slide_hash variants + * Copyright (C) 2022 Adam Stylinski, Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include + +#include + +extern "C" { +# include "zbuild.h" +# include "zutil_p.h" +# include "deflate.h" +# include "arch_functions.h" +# include "../test_cpu_features.h" +} + +#define MAX_RANDOM_INTS 32768 + +class slide_hash: public benchmark::Fixture { +private: + uint16_t *l0; + uint16_t *l1; + deflate_state *s_g; + +public: + void SetUp(const ::benchmark::State& state) { + l0 = (uint16_t *)zng_alloc(HASH_SIZE * sizeof(uint16_t)); + + for (uint32_t i = 0; i < HASH_SIZE; i++) { + l0[i] = rand(); + } + + l1 = (uint16_t *)zng_alloc(MAX_RANDOM_INTS * sizeof(uint16_t)); + + for (int32_t i = 0; i < MAX_RANDOM_INTS; i++) { + l1[i] = rand(); + } + + deflate_state *s = (deflate_state*)malloc(sizeof(deflate_state)); + s->head = l0; + s->prev = l1; + s_g = s; + } + + void Bench(benchmark::State& state, slide_hash_func slide_hash) { + s_g->w_size = (uint32_t)state.range(0); + + for (auto _ : state) { + slide_hash(s_g); + benchmark::DoNotOptimize(s_g); + } + } + + void TearDown(const ::benchmark::State& state) { + zng_free(l0); + zng_free(l1); + } +}; + +#define BENCHMARK_SLIDEHASH(name, fptr, support_flag) \ + BENCHMARK_DEFINE_F(slide_hash, name)(benchmark::State& state) { \ + if (!support_flag) { \ + state.SkipWithError("CPU does not support " #name); \ + } \ + Bench(state, fptr); \ + } \ + BENCHMARK_REGISTER_F(slide_hash, name)->RangeMultiplier(2)->Range(1024, MAX_RANDOM_INTS); + +BENCHMARK_SLIDEHASH(c, slide_hash_c, 1); + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +BENCHMARK_SLIDEHASH(native, native_slide_hash, 1); +#else + +#ifdef ARM_SIMD +BENCHMARK_SLIDEHASH(armv6, slide_hash_armv6, test_cpu_features.arm.has_simd); +#endif +#ifdef ARM_NEON +BENCHMARK_SLIDEHASH(neon, slide_hash_neon, test_cpu_features.arm.has_neon); +#endif +#ifdef POWER8_VSX +BENCHMARK_SLIDEHASH(power8, slide_hash_power8, test_cpu_features.power.has_arch_2_07); +#endif +#ifdef PPC_VMX +BENCHMARK_SLIDEHASH(vmx, slide_hash_vmx, test_cpu_features.power.has_altivec); +#endif +#ifdef RISCV_RVV +BENCHMARK_SLIDEHASH(rvv, slide_hash_rvv, test_cpu_features.riscv.has_rvv); +#endif +#ifdef X86_SSE2 +BENCHMARK_SLIDEHASH(sse2, slide_hash_sse2, test_cpu_features.x86.has_sse2); +#endif +#ifdef X86_AVX2 +BENCHMARK_SLIDEHASH(avx2, slide_hash_avx2, test_cpu_features.x86.has_avx2); +#endif + +#endif diff --git a/test/benchmarks/benchmark_uncompress.cc b/test/benchmarks/benchmark_uncompress.cc new file mode 100644 index 0000000000..58830c146a --- /dev/null +++ b/test/benchmarks/benchmark_uncompress.cc @@ -0,0 +1,94 @@ +/* benchmark_uncompress.cc -- benchmark uncompress() + * Copyright (C) 2024 Hans Kristian Rosbach + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include +#include + +extern "C" { +# include "zbuild.h" +# include "zutil_p.h" +# if defined(ZLIB_COMPAT) +# include "zlib.h" +# else +# include "zlib-ng.h" +# endif +} + +#define MAX_SIZE (1024 * 1024) +#define NUM_TESTS 6 + +class uncompress_bench: public benchmark::Fixture { +private: + size_t maxlen; + uint8_t *inbuff; + uint8_t *outbuff; + uint8_t *compressed_buff[NUM_TESTS]; + uLong compressed_sizes[NUM_TESTS]; + int64_t sizes[NUM_TESTS] = {1, 64, 1024, 16384, 128*1024, 1024*1024}; + +public: + void SetUp(const ::benchmark::State& state) { + const char teststr[42] = "Hello hello World broken Test tast mello."; + maxlen = MAX_SIZE; + + inbuff = (uint8_t *)zng_alloc(MAX_SIZE + 1); + assert(inbuff != NULL); + + outbuff = (uint8_t *)zng_alloc(MAX_SIZE + 1); + assert(outbuff != NULL); + + // Initialize input buffer + int pos = 0; + for (int32_t i = 0; i < MAX_SIZE - 42 ; i+=42){ + pos += sprintf((char *)inbuff+pos, "%s", teststr); + } + + // Compress data into different buffers + for (size_t i = 0; i < NUM_TESTS; ++i) { + compressed_buff[i] = (uint8_t *)zng_alloc(MAX_SIZE + 1); + assert(compressed_buff[i] != NULL); + + uLong compressed_size = maxlen; + int err = PREFIX(compress)(compressed_buff[i], &compressed_size, inbuff, sizes[i]); + if (err != Z_OK) { + fprintf(stderr, "Compression failed with error %d\n", err); + abort(); + } + compressed_sizes[i] = compressed_size; + } + } + + void Bench(benchmark::State& state) { + int err = 0; + + for (auto _ : state) { + int index = 0; + while (sizes[index] != state.range(0)) ++index; + + uLong out_size = maxlen; + err = PREFIX(uncompress)(outbuff, &out_size, compressed_buff[index], compressed_sizes[index]); + } + + benchmark::DoNotOptimize(err); + } + + void TearDown(const ::benchmark::State& state) { + zng_free(inbuff); + zng_free(outbuff); + + for (size_t i = 0; i < NUM_TESTS; ++i) { + zng_free(compressed_buff[i]); + } + } +}; + +#define BENCHMARK_UNCOMPRESS(name) \ + BENCHMARK_DEFINE_F(uncompress_bench, name)(benchmark::State& state) { \ + Bench(state); \ + } \ + BENCHMARK_REGISTER_F(uncompress_bench, name)->Arg(1)->Arg(64)->Arg(1024)->Arg(16<<10)->Arg(128<<10)->Arg(1024<<10); + +BENCHMARK_UNCOMPRESS(uncompress_bench); diff --git a/test/cmake/compress-and-verify.cmake b/test/cmake/compress-and-verify.cmake new file mode 100644 index 0000000000..2e6c37f145 --- /dev/null +++ b/test/cmake/compress-and-verify.cmake @@ -0,0 +1,287 @@ +# compress-and-verify.cmake -- Runs a test against an input file to make sure that the specified +# targets are able to to compress and then decompress successfully. Optionally verify +# the results with gzip. Output files are generated with unique names to prevent parallel +# tests from corrupting one another. Default target arguments are compatible with minigzip. + +# Copyright (C) 2021 Nathan Moinvaziri +# Licensed under the Zlib license, see LICENSE.md for details + +# that test a specific input file for compression or decompression. + +# Required Variables +# INPUT - Input file to test +# TARGET or - Command to run for both compress and decompress +# COMPRESS_TARGET and - Command to run to compress input file +# DECOMPRESS_TARGET - Command to run to decompress output file + +# Optional Variables +# TEST_NAME - Name of test to use when constructing output file paths +# COMPRESS_ARGS - Arguments to pass for compress command (default: -c -k) +# DECOMPRESS_ARGS - Arguments to pass to decompress command (default: -d -c) + +# GZIP_VERIFY - Verify that gzip can decompress the COMPRESS_TARGET output and +# verify that DECOMPRESS_TARGET can decompress gzip output of INPUT +# COMPARE - Verify decompressed output is the same as input +# FILEMODE - Pass data to/from (de)compressor using files instead of stdin/stdout +# SUCCESS_EXIT - List of successful exit codes (default: 0, ie: 0;1) + +if(TARGET) + set(COMPRESS_TARGET ${TARGET}) + set(DECOMPRESS_TARGET ${TARGET}) +endif() + +if(NOT DEFINED INPUT OR NOT DEFINED COMPRESS_TARGET OR NOT DEFINED DECOMPRESS_TARGET) + message(FATAL_ERROR "Compress test arguments missing") +endif() + +# Set default values +if(NOT DEFINED COMPARE) + set(COMPARE ON) +endif() +if(NOT DEFINED FILEMODE) + set(FILEMODE OFF) +endif() +if(NOT DEFINED COMPRESS_ARGS) + set(COMPRESS_ARGS -3 -k) + if(NOT FILEMODE) + list(APPEND COMPRESS_ARGS -c) + endif() +endif() +if(NOT DEFINED DECOMPRESS_ARGS) + set(DECOMPRESS_ARGS -d -k) + if(NOT FILEMODE) + list(APPEND DECOMPRESS_ARGS -c) + endif() +endif() +if(NOT DEFINED GZIP_VERIFY) + set(GZIP_VERIFY ON) +endif() +if(NOT DEFINED SUCCESS_EXIT) + set(SUCCESS_EXIT 0) +endif() + +# Use test name from input file name +if(NOT DEFINED TEST_NAME) + get_filename_component(TEST_NAME "${INPUT}" NAME) +endif() + +# Generate unique output path so multiple tests can be executed at the same time +string(RANDOM LENGTH 6 UNIQUE_ID) +string(REPLACE "." "-" TEST_NAME "${TEST_NAME}") +set(OUTPUT_BASE "${CMAKE_CURRENT_BINARY_DIR}/Testing/Temporary/${TEST_NAME}-${UNIQUE_ID}") + +# Ensure directory exists for output files +get_filename_component(OUTPUT_DIR "${OUTPUT_BASE}" DIRECTORY) +file(MAKE_DIRECTORY "${OUTPUT_DIR}") + +# Cleanup temporary files +macro(cleanup_always) + file(GLOB TEMP_FILES ${OUTPUT_BASE}*) + file(REMOVE ${TEMP_FILES}) +endmacro() +# Clean up temporary files if not on CI +macro(cleanup) + if(NOT DEFINED ENV{CI}) + cleanup_always() + endif() +endmacro() + +# Show differences between two files +macro(diff src1 src2) + find_program(XXD xxd) + if(XXD) + find_program(DIFF diff) + if(DIFF) + set(XXD_COMMAND ${XXD} ${src1} ${src1}.hex) + execute_process(COMMAND ${XXD_COMMAND}) + set(XXD_COMMAND ${XXD} ${src2} ${src2}.hex) + execute_process(COMMAND ${XXD_COMMAND}) + + set(DIFF_COMMAND ${DIFF} -u ${src1}.hex ${src2}.hex) + execute_process(COMMAND ${DIFF_COMMAND} + OUTPUT_FILE ${src2}.diff) + + file(READ ${src2}.diff DIFF_OUTPUT) + message(STATUS "Diff:\n${DIFF_OUTPUT}") + + if(NOT DEFINED ENV{CI}) + file(REMOVE ${src1}.hex ${src2}.hex ${src2}.diff) + endif() + endif() + endif() +endmacro() + + +macro(exec_streams tcmd tsrc tdst) + execute_process(COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${tcmd}" + -DINPUT=${tsrc} + -DOUTPUT=${tdst} + "-DSUCCESS_EXIT=${SUCCESS_EXIT}" + -P ${CMAKE_CURRENT_LIST_DIR}/run-and-redirect.cmake + RESULT_VARIABLE CMD_RESULT) +endmacro() + +macro(exec_files tcmd tsrc) + execute_process(COMMAND + ${tcmd} ${tsrc} + RESULT_VARIABLE CMD_RESULT) +endmacro() + +# Compress input file +if(NOT EXISTS ${INPUT}) + message(FATAL_ERROR "Cannot find compress input: ${INPUT}") +endif() + +set(COMPRESS_COMMAND ${COMPRESS_TARGET} ${COMPRESS_ARGS}) + +set(INPUT_FILE ${OUTPUT_BASE}) + +# Make CMake copy and rename file in one operation +# The copied file permissions is standard 644 (-rw-r--r--) +if(NOT CMAKE_VERSION VERSION_LESS "3.19") + set(CONFIGURE_NO_SOURCE_PERMISSIONS NO_SOURCE_PERMISSIONS) +endif() +configure_file(${INPUT} ${INPUT_FILE} COPYONLY ${CONFIGURE_NO_SOURCE_PERMISSIONS}) + +message(STATUS "Compress ${COMPRESS_COMMAND}") +message(STATUS " Source file: ${INPUT}") +message(STATUS " Compression input file: ${INPUT_FILE}") +message(STATUS " Output: ${OUTPUT_BASE}.gz") + +if(FILEMODE) + exec_files("${COMPRESS_COMMAND}" "${INPUT_FILE}") +else() + exec_streams("${COMPRESS_COMMAND}" "${INPUT_FILE}" "${OUTPUT_BASE}.gz") +endif() + +if(CMD_RESULT) + cleanup() + message(FATAL_ERROR "Compress failed: ${CMD_RESULT}") +endif() + +# Decompress output +if(NOT EXISTS ${OUTPUT_BASE}.gz) + cleanup() + message(FATAL_ERROR "Cannot find decompress input: ${OUTPUT_BASE}.gz") +endif() + +set(DECOMPRESS_COMMAND ${DECOMPRESS_TARGET} ${DECOMPRESS_ARGS}) + +message(STATUS "Decompress ${DECOMPRESS_COMMAND}") +message(STATUS " Input: ${OUTPUT_BASE}.gz") +message(STATUS " Output: ${OUTPUT_BASE}") + +if(FILEMODE) + exec_files("${DECOMPRESS_COMMAND}" "${OUTPUT_BASE}.gz") +else() + exec_streams("${DECOMPRESS_COMMAND}" "${OUTPUT_BASE}.gz" "${OUTPUT_BASE}") +endif() + +if(CMD_RESULT) + cleanup() + message(FATAL_ERROR "Decompress failed: ${CMD_RESULT}") +endif() + +if(COMPARE) + message(STATUS "Diff comparison") + message(STATUS " Input: ${INPUT}") + message(STATUS " Output: ${OUTPUT_BASE}") + + # Compare decompressed output with original input file + execute_process(COMMAND ${CMAKE_COMMAND} + -E compare_files ${INPUT} ${OUTPUT_BASE} + RESULT_VARIABLE CMD_RESULT) + + if(CMD_RESULT) + diff(${INPUT} ${OUTPUT_BASE}) + cleanup() + message(FATAL_ERROR "Compare decompress failed: ${CMD_RESULT}") + endif() +endif() + +if(GZIP_VERIFY AND NOT "${COMPRESS_ARGS}" MATCHES "-T") + # Transparent writing does not use gzip format + find_program(GZIP gzip) + if(GZIP) + if(NOT EXISTS ${OUTPUT_BASE}.gz) + cleanup() + message(FATAL_ERROR "Cannot find gzip decompress input: ${OUTPUT_BASE}.gz") + endif() + + # Check gzip can decompress our compressed output + set(GZ_DECOMPRESS_COMMAND ${GZIP} -d) + + message(STATUS "Gzip decompress ${GZ_DECOMPRESS_COMMAND}") + message(STATUS " Input: ${OUTPUT_BASE}.gz") + message(STATUS " Output: ${OUTPUT_BASE}-ungzip") + + exec_streams("${GZ_DECOMPRESS_COMMAND}" "${OUTPUT_BASE}.gz" "${OUTPUT_BASE}-ungzip") + + if(CMD_RESULT) + cleanup() + message(FATAL_ERROR "Gzip decompress failed: ${CMD_RESULT}") + endif() + + # Compare gzip output with original input file + execute_process(COMMAND ${CMAKE_COMMAND} + -E compare_files ${INPUT} ${OUTPUT_BASE}-ungzip + RESULT_VARIABLE CMD_RESULT) + + if(CMD_RESULT) + diff(${INPUT} ${OUTPUT_BASE}-ungzip) + cleanup() + message(FATAL_ERROR "Compare gzip decompress failed: ${CMD_RESULT}") + endif() + + # Compress input file with gzip + set(GZ_COMPRESS_COMMAND ${GZIP} --stdout) + + message(STATUS "Gzip compress ${GZ_COMPRESS_COMMAND}") + message(STATUS " Input: ${INPUT}") + message(STATUS " Output: ${OUTPUT_BASE}-gzip.gz") + + exec_streams("${GZ_COMPRESS_COMMAND}" "${INPUT}" "${OUTPUT_BASE}-gzip.gz") + + if(CMD_RESULT) + cleanup() + message(FATAL_ERROR "Gzip compress failed: ${CMD_RESULT}") + endif() + + if(NOT EXISTS ${OUTPUT_BASE}-gzip.gz) + cleanup() + message(FATAL_ERROR "Cannot find decompress gzip input: ${OUTPUT_BASE}-gzip.gz") + endif() + + message(STATUS "Decompress gzip ${DECOMPRESS_COMMAND}") + message(STATUS " Input: ${OUTPUT_BASE}-gzip.gz") + message(STATUS " Output: ${OUTPUT_BASE}-gzip") + + # Check decompress target can handle gzip compressed output + if(FILEMODE) + exec_files("${DECOMPRESS_COMMAND}" "${OUTPUT_BASE}-gzip.gz") + else() + exec_streams("${DECOMPRESS_COMMAND}" "${OUTPUT_BASE}-gzip.gz" "${OUTPUT_BASE}-gzip") + endif() + + if(CMD_RESULT) + cleanup() + message(FATAL_ERROR "Decompress gzip failed: ${CMD_RESULT}") + endif() + + if(COMPARE) + # Compare original input file with gzip decompressed output + execute_process(COMMAND ${CMAKE_COMMAND} + -E compare_files ${INPUT} ${OUTPUT_BASE}-gzip + RESULT_VARIABLE CMD_RESULT) + + if(CMD_RESULT) + diff(${INPUT} ${OUTPUT_BASE}-gzip) + cleanup() + message(FATAL_ERROR "Compare decompress gzip failed: ${CMD_RESULT}") + endif() + endif() + endif() +endif() + +cleanup_always() diff --git a/test/cmake/run-and-compare.cmake b/test/cmake/run-and-compare.cmake new file mode 100644 index 0000000000..eb2218dcb5 --- /dev/null +++ b/test/cmake/run-and-compare.cmake @@ -0,0 +1,72 @@ +# run-and-compare.cmake -- Runs a command and compares its output to an expected value + +# Copyright (C) 2021 Nathan Moinvaziri +# Licensed under the Zlib license, see LICENSE.md for details + +# Required Variables +# COMMAND - Command to run +# OUTPUT - Standard output +# COMPARE - String to compare output against + +# Optional Variables +# INPUT - Standard input +# IGNORE_LINE_ENDINGS - Ignore line endings when comparing output + +if(NOT DEFINED OUTPUT OR NOT DEFINED COMPARE OR NOT DEFINED COMMAND) + message(FATAL_ERROR "Run and compare arguments missing") +endif() + +# Ensure directory exists for output files +get_filename_component(OUTPUT_DIR "${OUTPUT}" DIRECTORY) +file(MAKE_DIRECTORY "${OUTPUT_DIR}") + +if(INPUT) + # Run command with stdin input and redirect stdout to output + execute_process(COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${COMMAND}" + -DINPUT=${INPUT} + -DOUTPUT=${OUTPUT} + "-DSUCCESS_EXIT=${SUCCESS_EXIT}" + -P ${CMAKE_CURRENT_LIST_DIR}/run-and-redirect.cmake + RESULT_VARIABLE CMD_RESULT) +else() + # Run command and redirect stdout to output + execute_process(COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${COMMAND}" + -DOUTPUT=${OUTPUT} + "-DSUCCESS_EXIT=${SUCCESS_EXIT}" + -P ${CMAKE_CURRENT_LIST_DIR}/run-and-redirect.cmake + RESULT_VARIABLE CMD_RESULT) +endif() + +if(CMD_RESULT) + message(FATAL_ERROR "Run before compare failed: ${CMD_RESULT}") +endif() + +# Use configure_file to normalize line-endings +if(IGNORE_LINE_ENDINGS) + # Rewrite files with normalized line endings to temporary directory + get_filename_component(COMPARE_NAME ${COMPARE} NAME) + set(COMPARE_TEMP ${CMAKE_CURRENT_BINARY_DIR}/Testing/Temporary/${COMPARE_NAME}.cmp) + configure_file(${COMPARE} ${COMPARE_TEMP} NEWLINE_STYLE LF) + set(COMPARE ${COMPARE_TEMP}) + + get_filename_component(OUTPUT_NAME ${OUTPUT} NAME) + set(OUTPUT_TEMP ${CMAKE_CURRENT_BINARY_DIR}/Testing/Temporary/${OUTPUT_NAME}.cmp) + configure_file(${OUTPUT} ${OUTPUT_TEMP} NEWLINE_STYLE LF) + set(OUTPUT ${OUTPUT_TEMP}) +endif() + +# Compare that output is equal to specified file +execute_process(COMMAND ${CMAKE_COMMAND} + -E compare_files ${COMPARE} ${OUTPUT} + RESULT_VARIABLE CMD_RESULT) + +# Delete temporary files used to normalize line-endings +if(IGNORE_LINE_ENDINGS) + file(REMOVE ${COMPARE} ${OUTPUT}) +endif() + +if(CMD_RESULT) + message(FATAL_ERROR "Run compare failed: ${CMD_RESULT}") +endif() diff --git a/test/cmake/run-and-redirect.cmake b/test/cmake/run-and-redirect.cmake new file mode 100644 index 0000000000..6651d1a302 --- /dev/null +++ b/test/cmake/run-and-redirect.cmake @@ -0,0 +1,54 @@ +# run-and-redirect.cmake -- Runs a command and validates exit code + +# Copyright (C) 2021 Nathan Moinvaziri +# Licensed under the Zlib license, see LICENSE.md for details + +# Normally ctest will always fail with non-zero exit code, but we have tests +# that need to check specific exit codes. + +# Required Variables +# COMMAND - Command to run + +# Optional Variables +# INPUT - Standard input +# OUTPUT - Standard output (default: /dev/null) +# SUCCESS_EXIT - List of successful exit codes (default: 0, ie: 0;1) + +# If no output is specified, discard output +if(NOT DEFINED OUTPUT) + if(WIN32) + set(OUTPUT NUL) + else() + set(OUTPUT /dev/null) + endif() +endif() + +if(INPUT) + # Check to see that input file exists + if(NOT EXISTS ${INPUT}) + message(FATAL_ERROR "Cannot find input: ${INPUT}") + endif() + # Execute with both stdin and stdout file + execute_process(COMMAND ${COMMAND} + RESULT_VARIABLE CMD_RESULT + INPUT_FILE ${INPUT} + OUTPUT_FILE ${OUTPUT}) +else() + # Execute with only stdout file + execute_process(COMMAND ${COMMAND} + RESULT_VARIABLE CMD_RESULT + OUTPUT_FILE ${OUTPUT}) +endif() + +# Check if exit code is in list of successful exit codes +if(SUCCESS_EXIT) + list(FIND SUCCESS_EXIT ${CMD_RESULT} _INDEX) + if (${_INDEX} GREATER -1) + set(CMD_RESULT 0) + endif() +endif() + +# Check to see if successful +if(CMD_RESULT) + message(FATAL_ERROR "${COMMAND} failed: ${CMD_RESULT}") +endif() diff --git a/test/cmake/test-cves.cmake b/test/cmake/test-cves.cmake new file mode 100644 index 0000000000..4a08604034 --- /dev/null +++ b/test/cmake/test-cves.cmake @@ -0,0 +1,33 @@ +# test-cves.cmake -- Tests targeting common vulnerabilities and exposures + +set(CVES CVE-2002-0059 CVE-2004-0797 CVE-2005-1849 CVE-2005-2096) +foreach(cve ${CVES}) + set(CVE_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ -d) + add_test(NAME ${cve} + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${CVE_COMMAND}" + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${cve}/test.gz + "-DSUCCESS_EXIT=0;1" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake) +endforeach() + +set(CVE_COMPRESS_LEVELS 6 1 2) +foreach(cve_compress_level ${CVE_COMPRESS_LEVELS}) + add_test(NAME CVE-2018-25032-fixed-level-${cve_compress_level} + COMMAND ${CMAKE_COMMAND} + "-DTARGET=${MINIDEFLATE_COMMAND}" + "-DCOMPRESS_ARGS=-c;-k;-m;1;-w;-15;-s;4;-F;-${cve_compress_level}" + "-DDECOMPRESS_ARGS=-c;-k;-d;-m;1;-w;-15;-${cve_compress_level}" + -DGZIP_VERIFY=OFF + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/CVE-2018-25032/fixed.txt + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + + add_test(NAME CVE-2018-25032-default-level-${cve_compress_level} + COMMAND ${CMAKE_COMMAND} + "-DTARGET=${MINIDEFLATE_COMMAND}" + "-DCOMPRESS_ARGS=-c;-k;-m;1;-w;-15;-s;4;-${cve_compress_level}" + "-DDECOMPRESS_ARGS=-c;-k;-d;-m;1;-w;-15;-${cve_compress_level}" + -DGZIP_VERIFY=OFF + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/CVE-2018-25032/default.txt + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) +endforeach() diff --git a/test/cmake/test-data.cmake b/test/cmake/test-data.cmake new file mode 100644 index 0000000000..e60c356e46 --- /dev/null +++ b/test/cmake/test-data.cmake @@ -0,0 +1,68 @@ +# test-data.cmake - Tests targeting data files in the data directory + +# Test compress and verify test against data file using extra args +macro(test_minigzip name path) + # Construct compression arguments for minigzip + set(compress_args -k -c) + foreach(extra_arg IN ITEMS "${ARGN}") + list(APPEND compress_args ${extra_arg}) + endforeach() + + # Create unique friendly string for test + string(REPLACE ";" "" arg_list "${ARGN}") + string(REPLACE " " "" arg_list "${arg_list}") + string(REPLACE "-" "" arg_list "${arg_list}") + + set(test_id minigzip-${name}-${arg_list}) + + if(NOT TEST ${test_id}) + add_test(NAME ${test_id} + COMMAND ${CMAKE_COMMAND} + "-DTARGET=${MINIGZIP_COMMAND}" + "-DCOMPRESS_ARGS=${compress_args}" + "-DDECOMPRESS_ARGS=-d;-c" + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${path} + -DTEST_NAME=${test_id} + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + endif() +endmacro() + +# List of arg combinations to use during compression +set(TEST_CONFIGS + -R # Z_RLE + -h # Z_HUFFMAN_ONLY + -T # Direct store + -0 # No compression + -1 # Deflate quick + -2 # Deflate fast + -4 # Deflate medium (lazy matches) + "-5;-F" # Deflate medium (Z_FIXED) + -6 # Deflate medium + -9 # Deflate slow + "-9;-f" # Deflate slow (Z_FILTERED) +) + +# Enumerate all files in data directory to run tests against +file(GLOB_RECURSE TEST_FILE_PATHS + LIST_DIRECTORIES false + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/data/*) + +# For all files in the data directory, run tests against them +foreach(test_file_path ${TEST_FILE_PATHS}) + if("${test_file_path}" MATCHES ".gz$" OR "${test_file_path}" MATCHES ".out$" OR + "${test_file_path}" MATCHES "/.git/" OR "${test_file_path}" MATCHES ".md$") + continue() + endif() + foreach(test_config ${TEST_CONFIGS}) + get_filename_component(test_name ${test_file_path} NAME) + if (test_name STREQUAL "") + continue() + endif() + test_minigzip(${test_name} ${test_file_path} ${test_config}) + endforeach() +endforeach() + +# Additional tests to verify with automatic data type detection arg +test_minigzip("detect-text" "data/lcet10.txt" -A) +test_minigzip("detect-binary" "data/paper-100k.pdf" -A) diff --git a/test/cmake/test-issues.cmake b/test/cmake/test-issues.cmake new file mode 100644 index 0000000000..e731dd57dd --- /dev/null +++ b/test/cmake/test-issues.cmake @@ -0,0 +1,84 @@ +# test-issues.cmake -- Tests targeting specific GitHub issues + +add_test(NAME GH-361 + COMMAND ${CMAKE_COMMAND} + "-DTARGET=${MINIGZIP_COMMAND}" + "-DCOMPRESS_ARGS=-c;-k;-4" + -DTEST_NAME=GH-361-test-txt + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/GH-361/test.txt + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + +add_test(NAME GH-364 + COMMAND ${CMAKE_COMMAND} + "-DCOMPRESS_TARGET=${SWITCHLEVELS_COMMAND}" + "-DCOMPRESS_ARGS=1;5;9;3" + "-DDECOMPRESS_TARGET=${MINIGZIP_COMMAND}" + -DTEST_NAME=GH-364-test-bin + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/GH-364/test.bin + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + +add_test(NAME GH-382 + COMMAND ${CMAKE_COMMAND} + "-DTARGET=${MINIDEFLATE_COMMAND}" + "-DCOMPRESS_ARGS=-c;-m;1;-w;-15;-1;-s;4" + "-DDECOMPRESS_ARGS=-c;-d;-m;1;-w;-15" + -DGZIP_VERIFY=OFF + -DTEST_NAME=GH-382-defneg3-dat + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/GH-382/defneg3.dat + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + +add_test(NAME GH-536-segfault + COMMAND ${CMAKE_COMMAND} + "-DCOMPRESS_TARGET=${SWITCHLEVELS_COMMAND}" + "-DCOMPRESS_ARGS=6;9744;1;91207" + "-DDECOMPRESS_TARGET=${MINIGZIP_COMMAND}" + -DCOMPARE=OFF + -DGZIP_VERIFY=OFF + -DTEST_NAME=GH-536-segfault-lcet10-txt + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/data/lcet10.txt + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + +add_test(NAME GH-536-incomplete-read + COMMAND ${CMAKE_COMMAND} + "-DCOMPRESS_TARGET=${SWITCHLEVELS_COMMAND}" + "-DCOMPRESS_ARGS=6;88933;1;195840;2;45761" + "-DDECOMPRESS_TARGET=${MINIGZIP_COMMAND}" + -DCOMPARE=OFF + -DGZIP_VERIFY=OFF + -DTEST_NAME=GH-536-incomplete-read-lcet10-txt + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/data/lcet10.txt + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + +add_test(NAME GH-536-zero-stored-block + COMMAND ${CMAKE_COMMAND} + "-DCOMPRESS_TARGET=${SWITCHLEVELS_COMMAND}" + "-DCOMPRESS_ARGS=6;15248;1;1050;2;25217" + "-DDECOMPRESS_TARGET=${MINIGZIP_COMMAND}" + -DCOMPARE=OFF + -DGZIP_VERIFY=OFF + -DTEST_NAME=GH-536-zero-stored-block-lcet10-txt + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/data/lcet10.txt + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + +add_test(NAME GH-751 + COMMAND ${CMAKE_COMMAND} + "-DTARGET=${MINIGZIP_COMMAND}" + -DTEST_NAME=GH-751-test-txt + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/GH-751/test.txt + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + +set(TEST_COMMAND "${MINIDEFLATE_COMMAND};-c;-d;-k;-s;4") +add_test(NAME GH-1600-no-window-check + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${TEST_COMMAND}" + "-DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/GH-1600/packobj.gz" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake +) + +set(TEST_COMMAND "${MINIDEFLATE_COMMAND};-c;-d;-k;-s;4;-r;25") +add_test(NAME GH-1600-no-window-no-check + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${TEST_COMMAND}" + "-DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/GH-1600/packobj.gz" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake +) diff --git a/test/cmake/test-tools.cmake b/test/cmake/test-tools.cmake new file mode 100644 index 0000000000..c2a683fbd9 --- /dev/null +++ b/test/cmake/test-tools.cmake @@ -0,0 +1,80 @@ +# test-tools.cmake -- Tests targeting tool coverage + +# Compress and decompress using file_compress/file_decompress, optionally also testing MMAP +add_test(NAME minigzip-file_compress + COMMAND ${CMAKE_COMMAND} + "-DTARGET=${MINIGZIP_COMMAND}" + -DFILEMODE=ON + -DGZIP_VERIFY=ON + -DTEST_NAME=minigzip-file_compress + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/data/paper-100k.pdf + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + +add_test(NAME minideflate-file_compress + COMMAND ${CMAKE_COMMAND} + "-DTARGET=${MINIDEFLATE_COMMAND}" + -DFILEMODE=ON + -DGZIP_VERIFY=OFF + -DTEST_NAME=minideflate-file_compress + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/data/paper-100k.pdf + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake) + +# Test --help and invalid parameters for our tools +set(TEST_COMMAND ${MINIGZIP_COMMAND} "--help") +add_test(NAME minigzip-help + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${TEST_COMMAND}" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake) + +set(TEST_COMMAND ${MINIGZIP_COMMAND} "--invalid") +add_test(NAME minigzip-invalid + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${TEST_COMMAND}" + -DSUCCESS_EXIT=64 + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake) + +set(TEST_COMMAND ${MINIDEFLATE_COMMAND} "--help") +add_test(NAME minideflate-help + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${TEST_COMMAND}" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake) + +set(TEST_COMMAND ${MINIDEFLATE_COMMAND} "--invalid") +add_test(NAME minideflate-invalid + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${TEST_COMMAND}" + -DSUCCESS_EXIT=64 + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake) + +set(TEST_COMMAND ${SWITCHLEVELS_COMMAND} "--help") +add_test(NAME switchlevels-help + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${TEST_COMMAND}" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake) + +# Test generated crc32 tables match tables in source directory +add_test(NAME makecrct + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${MAKECRCT_COMMAND}" + -DOUTPUT=${PROJECT_BINARY_DIR}/Testing/Temporary/crc32_braid_tbl._h + -DCOMPARE=${PROJECT_SOURCE_DIR}/crc32_braid_tbl.h + -DIGNORE_LINE_ENDINGS=ON + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-compare.cmake) + +# Test generated inflate tables match tables in source directory +add_test(NAME makefixed + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${MAKEFIXED_COMMAND}" + -DOUTPUT=${PROJECT_BINARY_DIR}/Testing/Temporary/inffixed_tbl._h + -DCOMPARE=${PROJECT_SOURCE_DIR}/inffixed_tbl.h + -DIGNORE_LINE_ENDINGS=ON + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-compare.cmake) + +# Test generated tree tables match tables in source directory +add_test(NAME maketrees + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${MAKETREES_COMMAND}" + -DOUTPUT=${PROJECT_BINARY_DIR}/Testing/Temporary/trees_tbl._h + -DCOMPARE=${PROJECT_SOURCE_DIR}/trees_tbl.h + -DIGNORE_LINE_ENDINGS=ON + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-compare.cmake) diff --git a/test/data/fireworks.jpg b/test/data/fireworks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..078cf1755dc0853e97ad30fc7af4d6af0b67047e GIT binary patch literal 123093 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
    ma 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

    3ZRBxkF?%H#_f~x|{{V*%h1A?S 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 AYXATM literal 0 HcmV?d00001 diff --git a/test/data/lcet10.txt b/test/data/lcet10.txt new file mode 100644 index 0000000000..1dbdfc56e4 --- /dev/null +++ b/test/data/lcet10.txt @@ -0,0 +1,7519 @@ + + +The Project Gutenberg Etext of LOC WORKSHOP ON ELECTRONIC TEXTS + + + + + WORKSHOP ON ELECTRONIC TEXTS + + PROCEEDINGS + + + + Edited by James Daly + + + + + + + + 9-10 June 1992 + + + Library of Congress + Washington, D.C. + + + + Supported by a Grant from the David and Lucile Packard Foundation + + + *** *** *** ****** *** *** *** + + + TABLE OF CONTENTS + + +Acknowledgements + +Introduction + +Proceedings + Welcome + Prosser Gifford and Carl Fleischhauer + + Session I. Content in a New Form: Who Will Use It and What Will They Do? + James Daly (Moderator) + Avra Michelson, Overview + Susan H. Veccia, User Evaluation + Joanne Freeman, Beyond the Scholar + Discussion + + Session II. Show and Tell + Jacqueline Hess (Moderator) + Elli Mylonas, Perseus Project + Discussion + Eric M. Calaluca, Patrologia Latina Database + Carl Fleischhauer and Ricky Erway, American Memory + Discussion + Dorothy Twohig, The Papers of George Washington + Discussion + Maria L. Lebron, The Online Journal of Current Clinical Trials + Discussion + Lynne K. Personius, Cornell mathematics books + Discussion + + Session III. Distribution, Networks, and Networking: + Options for Dissemination + Robert G. Zich (Moderator) + Clifford A. Lynch + Discussion + Howard Besser + Discussion + Ronald L. Larsen + Edwin B. Brownrigg + Discussion + + Session IV. Image Capture, Text Capture, Overview of Text and + Image Storage Formats + William L. Hooton (Moderator) + A) Principal Methods for Image Capture of Text: + direct scanning, use of microform + Anne R. Kenney + Pamela Q.J. Andre + Judith A. Zidar + Donald J. Waters + Discussion + B) Special Problems: bound volumes, conservation, + reproducing printed halftones + George Thoma + Carl Fleischhauer + Discussion + C) Image Standards and Implications for Preservation + Jean Baronas + Patricia Battin + Discussion + D) Text Conversion: OCR vs. rekeying, standards of accuracy + and use of imperfect texts, service bureaus + Michael Lesk + Ricky Erway + Judith A. Zidar + Discussion + + Session V. Approaches to Preparing Electronic Texts + Susan Hockey (Moderator) + Stuart Weibel + Discussion + C.M. Sperberg-McQueen + Discussion + Eric M. Calaluca + Discussion + + Session VI. Copyright Issues + Marybeth Peters + + Session VII. Conclusion + Prosser Gifford (Moderator) + General discussion + +Appendix I: Program + +Appendix II: Abstracts + +Appendix III: Directory of Participants + + + *** *** *** ****** *** *** *** + + + Acknowledgements + +I would like to thank Carl Fleischhauer and Prosser Gifford for the +opportunity to learn about areas of human activity unknown to me a scant +ten months ago, and the David and Lucile Packard Foundation for +supporting that opportunity. The help given by others is acknowledged on +a separate page. + + 19 October 1992 + + + *** *** *** ****** *** *** *** + + + INTRODUCTION + +The Workshop on Electronic Texts (1) drew together representatives of +various projects and interest groups to compare ideas, beliefs, +experiences, and, in particular, methods of placing and presenting +historical textual materials in computerized form. Most attendees gained +much in insight and outlook from the event. But the assembly did not +form a new nation, or, to put it another way, the diversity of projects +and interests was too great to draw the representatives into a cohesive, +action-oriented body.(2) + +Everyone attending the Workshop shared an interest in preserving and +providing access to historical texts. But within this broad field the +attendees represented a variety of formal, informal, figurative, and +literal groups, with many individuals belonging to more than one. These +groups may be defined roughly according to the following topics or +activities: + +* Imaging +* Searchable coded texts +* National and international computer networks +* CD-ROM production and dissemination +* Methods and technology for converting older paper materials into +electronic form +* Study of the use of digital materials by scholars and others + +This summary is arranged thematically and does not follow the actual +sequence of presentations. + +NOTES: + (1) In this document, the phrase electronic text is used to mean + any computerized reproduction or version of a document, book, + article, or manuscript (including images), and not merely a machine- + readable or machine-searchable text. + + (2) The Workshop was held at the Library of Congress on 9-10 June + 1992, with funding from the David and Lucile Packard Foundation. + The document that follows represents a summary of the presentations + made at the Workshop and was compiled by James DALY. This + introduction was written by DALY and Carl FLEISCHHAUER. + + +PRESERVATION AND IMAGING + +Preservation, as that term is used by archivists,(3) was most explicitly +discussed in the context of imaging. Anne KENNEY and Lynne PERSONIUS +explained how the concept of a faithful copy and the user-friendliness of +the traditional book have guided their project at Cornell University.(4) +Although interested in computerized dissemination, participants in the +Cornell project are creating digital image sets of older books in the +public domain as a source for a fresh paper facsimile or, in a future +phase, microfilm. The books returned to the library shelves are +high-quality and useful replacements on acid-free paper that should last +a long time. To date, the Cornell project has placed little or no +emphasis on creating searchable texts; one would not be surprised to find +that the project participants view such texts as new editions, and thus +not as faithful reproductions. + +In her talk on preservation, Patricia BATTIN struck an ecumenical and +flexible note as she endorsed the creation and dissemination of a variety +of types of digital copies. Do not be too narrow in defining what counts +as a preservation element, BATTIN counseled; for the present, at least, +digital copies made with preservation in mind cannot be as narrowly +standardized as, say, microfilm copies with the same objective. Setting +standards precipitously can inhibit creativity, but delay can result in +chaos, she advised. + +In part, BATTIN's position reflected the unsettled nature of image-format +standards, and attendees could hear echoes of this unsettledness in the +comments of various speakers. For example, Jean BARONAS reviewed the +status of several formal standards moving through committees of experts; +and Clifford LYNCH encouraged the use of a new guideline for transmitting +document images on Internet. Testimony from participants in the National +Agricultural Library's (NAL) Text Digitization Program and LC's American +Memory project highlighted some of the challenges to the actual creation +or interchange of images, including difficulties in converting +preservation microfilm to digital form. Donald WATERS reported on the +progress of a master plan for a project at Yale University to convert +books on microfilm to digital image sets, Project Open Book (POB). + +The Workshop offered rather less of an imaging practicum than planned, +but "how-to" hints emerge at various points, for example, throughout +KENNEY's presentation and in the discussion of arcana such as +thresholding and dithering offered by George THOMA and FLEISCHHAUER. + +NOTES: + (3) Although there is a sense in which any reproductions of + historical materials preserve the human record, specialists in the + field have developed particular guidelines for the creation of + acceptable preservation copies. + + (4) Titles and affiliations of presenters are given at the + beginning of their respective talks and in the Directory of + Participants (Appendix III). + + +THE MACHINE-READABLE TEXT: MARKUP AND USE + +The sections of the Workshop that dealt with machine-readable text tended +to be more concerned with access and use than with preservation, at least +in the narrow technical sense. Michael SPERBERG-McQUEEN made a forceful +presentation on the Text Encoding Initiative's (TEI) implementation of +the Standard Generalized Markup Language (SGML). His ideas were echoed +by Susan HOCKEY, Elli MYLONAS, and Stuart WEIBEL. While the +presentations made by the TEI advocates contained no practicum, their +discussion focused on the value of the finished product, what the +European Community calls reusability, but what may also be termed +durability. They argued that marking up--that is, coding--a text in a +well-conceived way will permit it to be moved from one computer +environment to another, as well as to be used by various users. Two +kinds of markup were distinguished: 1) procedural markup, which +describes the features of a text (e.g., dots on a page), and 2) +descriptive markup, which describes the structure or elements of a +document (e.g., chapters, paragraphs, and front matter). + +The TEI proponents emphasized the importance of texts to scholarship. +They explained how heavily coded (and thus analyzed and annotated) texts +can underlie research, play a role in scholarly communication, and +facilitate classroom teaching. SPERBERG-McQUEEN reminded listeners that +a written or printed item (e.g., a particular edition of a book) is +merely a representation of the abstraction we call a text. To concern +ourselves with faithfully reproducing a printed instance of the text, +SPERBERG-McQUEEN argued, is to concern ourselves with the representation +of a representation ("images as simulacra for the text"). The TEI proponents' +interest in images tends to focus on corollary materials for use in teaching, +for example, photographs of the Acropolis to accompany a Greek text. + +By the end of the Workshop, SPERBERG-McQUEEN confessed to having been +converted to a limited extent to the view that electronic images +constitute a promising alternative to microfilming; indeed, an +alternative probably superior to microfilming. But he was not convinced +that electronic images constitute a serious attempt to represent text in +electronic form. HOCKEY and MYLONAS also conceded that their experience +at the Pierce Symposium the previous week at Georgetown University and +the present conference at the Library of Congress had compelled them to +reevaluate their perspective on the usefulness of text as images. +Attendees could see that the text and image advocates were in +constructive tension, so to say. + +Three nonTEI presentations described approaches to preparing +machine-readable text that are less rigorous and thus less expensive. In +the case of the Papers of George Washington, Dorothy TWOHIG explained +that the digital version will provide a not-quite-perfect rendering of +the transcribed text--some 135,000 documents, available for research +during the decades while the perfect or print version is completed. +Members of the American Memory team and the staff of NAL's Text +Digitization Program (see below) also outlined a middle ground concerning +searchable texts. In the case of American Memory, contractors produce +texts with about 99-percent accuracy that serve as "browse" or +"reference" versions of written or printed originals. End users who need +faithful copies or perfect renditions must refer to accompanying sets of +digital facsimile images or consult copies of the originals in a nearby +library or archive. American Memory staff argued that the high cost of +producing 100-percent accurate copies would prevent LC from offering +access to large parts of its collections. + + +THE MACHINE-READABLE TEXT: METHODS OF CONVERSION + +Although the Workshop did not include a systematic examination of the +methods for converting texts from paper (or from facsimile images) into +machine-readable form, nevertheless, various speakers touched upon this +matter. For example, WEIBEL reported that OCLC has experimented with a +merging of multiple optical character recognition systems that will +reduce errors from an unacceptable rate of 5 characters out of every +l,000 to an unacceptable rate of 2 characters out of every l,000. + +Pamela ANDRE presented an overview of NAL's Text Digitization Program and +Judith ZIDAR discussed the technical details. ZIDAR explained how NAL +purchased hardware and software capable of performing optical character +recognition (OCR) and text conversion and used its own staff to convert +texts. The process, ZIDAR said, required extensive editing and project +staff found themselves considering alternatives, including rekeying +and/or creating abstracts or summaries of texts. NAL reckoned costs at +$7 per page. By way of contrast, Ricky ERWAY explained that American +Memory had decided from the start to contract out conversion to external +service bureaus. The criteria used to select these contractors were cost +and quality of results, as opposed to methods of conversion. ERWAY noted +that historical documents or books often do not lend themselves to OCR. +Bound materials represent a special problem. In her experience, quality +control--inspecting incoming materials, counting errors in samples--posed +the most time-consuming aspect of contracting out conversion. ERWAY +reckoned American Memory's costs at $4 per page, but cautioned that fewer +cost-elements had been included than in NAL's figure. + + +OPTIONS FOR DISSEMINATION + +The topic of dissemination proper emerged at various points during the +Workshop. At the session devoted to national and international computer +networks, LYNCH, Howard BESSER, Ronald LARSEN, and Edwin BROWNRIGG +highlighted the virtues of Internet today and of the network that will +evolve from Internet. Listeners could discern in these narratives a +vision of an information democracy in which millions of citizens freely +find and use what they need. LYNCH noted that a lack of standards +inhibits disseminating multimedia on the network, a topic also discussed +by BESSER. LARSEN addressed the issues of network scalability and +modularity and commented upon the difficulty of anticipating the effects +of growth in orders of magnitude. BROWNRIGG talked about the ability of +packet radio to provide certain links in a network without the need for +wiring. However, the presenters also called attention to the +shortcomings and incongruities of present-day computer networks. For +example: 1) Network use is growing dramatically, but much network +traffic consists of personal communication (E-mail). 2) Large bodies of +information are available, but a user's ability to search across their +entirety is limited. 3) There are significant resources for science and +technology, but few network sources provide content in the humanities. +4) Machine-readable texts are commonplace, but the capability of the +system to deal with images (let alone other media formats) lags behind. +A glimpse of a multimedia future for networks, however, was provided by +Maria LEBRON in her overview of the Online Journal of Current Clinical +Trials (OJCCT), and the process of scholarly publishing on-line. + +The contrasting form of the CD-ROM disk was never systematically +analyzed, but attendees could glean an impression from several of the +show-and-tell presentations. The Perseus and American Memory examples +demonstrated recently published disks, while the descriptions of the +IBYCUS version of the Papers of George Washington and Chadwyck-Healey's +Patrologia Latina Database (PLD) told of disks to come. According to +Eric CALALUCA, PLD's principal focus has been on converting Jacques-Paul +Migne's definitive collection of Latin texts to machine-readable form. +Although everyone could share the network advocates' enthusiasm for an +on-line future, the possibility of rolling up one's sleeves for a session +with a CD-ROM containing both textual materials and a powerful retrieval +engine made the disk seem an appealing vessel indeed. The overall +discussion suggested that the transition from CD-ROM to on-line networked +access may prove far slower and more difficult than has been anticipated. + + +WHO ARE THE USERS AND WHAT DO THEY DO? + +Although concerned with the technicalities of production, the Workshop +never lost sight of the purposes and uses of electronic versions of +textual materials. As noted above, those interested in imaging discussed +the problematical matter of digital preservation, while the TEI proponents +described how machine-readable texts can be used in research. This latter +topic received thorough treatment in the paper read by Avra MICHELSON. +She placed the phenomenon of electronic texts within the context of +broader trends in information technology and scholarly communication. + +Among other things, MICHELSON described on-line conferences that +represent a vigorous and important intellectual forum for certain +disciplines. Internet now carries more than 700 conferences, with about +80 percent of these devoted to topics in the social sciences and the +humanities. Other scholars use on-line networks for "distance learning." +Meanwhile, there has been a tremendous growth in end-user computing; +professors today are less likely than their predecessors to ask the +campus computer center to process their data. Electronic texts are one +key to these sophisticated applications, MICHELSON reported, and more and +more scholars in the humanities now work in an on-line environment. +Toward the end of the Workshop, Michael LESK presented a corollary to +MICHELSON's talk, reporting the results of an experiment that compared +the work of one group of chemistry students using traditional printed +texts and two groups using electronic sources. The experiment +demonstrated that in the event one does not know what to read, one needs +the electronic systems; the electronic systems hold no advantage at the +moment if one knows what to read, but neither do they impose a penalty. + +DALY provided an anecdotal account of the revolutionizing impact of the +new technology on his previous methods of research in the field of classics. +His account, by extrapolation, served to illustrate in part the arguments +made by MICHELSON concerning the positive effects of the sudden and radical +transformation being wrought in the ways scholars work. + +Susan VECCIA and Joanne FREEMAN delineated the use of electronic +materials outside the university. The most interesting aspect of their +use, FREEMAN said, could be seen as a paradox: teachers in elementary +and secondary schools requested access to primary source materials but, +at the same time, found that "primariness" itself made these materials +difficult for their students to use. + + +OTHER TOPICS + +Marybeth PETERS reviewed copyright law in the United States and offered +advice during a lively discussion of this subject. But uncertainty +remains concerning the price of copyright in a digital medium, because a +solution remains to be worked out concerning management and synthesis of +copyrighted and out-of-copyright pieces of a database. + +As moderator of the final session of the Workshop, Prosser GIFFORD directed +discussion to future courses of action and the potential role of LC in +advancing them. Among the recommendations that emerged were the following: + + * Workshop participants should 1) begin to think about working + with image material, but structure and digitize it in such a + way that at a later stage it can be interpreted into text, and + 2) find a common way to build text and images together so that + they can be used jointly at some stage in the future, with + appropriate network support, because that is how users will want + to access these materials. The Library might encourage attempts + to bring together people who are working on texts and images. + + * A network version of American Memory should be developed or + consideration should be given to making the data in it + available to people interested in doing network multimedia. + Given the current dearth of digital data that is appealing and + unencumbered by extremely complex rights problems, developing a + network version of American Memory could do much to help make + network multimedia a reality. + + * Concerning the thorny issue of electronic deposit, LC should + initiate a catalytic process in terms of distributed + responsibility, that is, bring together the distributed + organizations and set up a study group to look at all the + issues related to electronic deposit and see where we as a + nation should move. For example, LC might attempt to persuade + one major library in each state to deal with its state + equivalent publisher, which might produce a cooperative project + that would be equitably distributed around the country, and one + in which LC would be dealing with a minimal number of publishers + and minimal copyright problems. LC must also deal with the + concept of on-line publishing, determining, among other things, + how serials such as OJCCT might be deposited for copyright. + + * Since a number of projects are planning to carry out + preservation by creating digital images that will end up in + on-line or near-line storage at some institution, LC might play + a helpful role, at least in the near term, by accelerating how + to catalog that information into the Research Library Information + Network (RLIN) and then into OCLC, so that it would be accessible. + This would reduce the possibility of multiple institutions digitizing + the same work. + + +CONCLUSION + +The Workshop was valuable because it brought together partisans from +various groups and provided an occasion to compare goals and methods. +The more committed partisans frequently communicate with others in their +groups, but less often across group boundaries. The Workshop was also +valuable to attendees--including those involved with American Memory--who +came less committed to particular approaches or concepts. These +attendees learned a great deal, and plan to select and employ elements of +imaging, text-coding, and networked distribution that suit their +respective projects and purposes. + +Still, reality rears its ugly head: no breakthrough has been achieved. +On the imaging side, one confronts a proliferation of competing +data-interchange standards and a lack of consensus on the role of digital +facsimiles in preservation. In the realm of machine-readable texts, one +encounters a reasonably mature standard but methodological difficulties +and high costs. These latter problems, of course, represent a special +impediment to the desire, as it is sometimes expressed in the popular +press, "to put the [contents of the] Library of Congress on line." In +the words of one participant, there was "no solution to the economic +problems--the projects that are out there are surviving, but it is going +to be a lot of work to transform the information industry, and so far the +investment to do that is not forthcoming" (LESK, per litteras). + + + *** *** *** ****** *** *** *** + + + PROCEEDINGS + + +WELCOME + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +GIFFORD * Origin of Workshop in current Librarian's desire to make LC's +collections more widely available * Desiderata arising from the prospect +of greater interconnectedness * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +After welcoming participants on behalf of the Library of Congress, +American Memory (AM), and the National Demonstration Lab, Prosser +GIFFORD, director for scholarly programs, Library of Congress, located +the origin of the Workshop on Electronic Texts in a conversation he had +had considerably more than a year ago with Carl FLEISCHHAUER concerning +some of the issues faced by AM. On the assumption that numerous other +people were asking the same questions, the decision was made to bring +together as many of these people as possible to ask the same questions +together. In a deeper sense, GIFFORD said, the origin of the Workshop +lay in the desire of the current Librarian of Congress, James H. +Billington, to make the collections of the Library, especially those +offering unique or unusual testimony on aspects of the American +experience, available to a much wider circle of users than those few +people who can come to Washington to use them. This meant that the +emphasis of AM, from the outset, has been on archival collections of the +basic material, and on making these collections themselves available, +rather than selected or heavily edited products. + +From AM's emphasis followed the questions with which the Workshop began: +who will use these materials, and in what form will they wish to use +them. But an even larger issue deserving mention, in GIFFORD's view, was +the phenomenal growth in Internet connectivity. He expressed the hope +that the prospect of greater interconnectedness than ever before would +lead to: 1) much more cooperative and mutually supportive endeavors; 2) +development of systems of shared and distributed responsibilities to +avoid duplication and to ensure accuracy and preservation of unique +materials; and 3) agreement on the necessary standards and development of +the appropriate directories and indices to make navigation +straightforward among the varied resources that are, and increasingly +will be, available. In this connection, GIFFORD requested that +participants reflect from the outset upon the sorts of outcomes they +thought the Workshop might have. Did those present constitute a group +with sufficient common interests to propose a next step or next steps, +and if so, what might those be? They would return to these questions the +following afternoon. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +FLEISCHHAUER * Core of Workshop concerns preparation and production of +materials * Special challenge in conversion of textual materials * +Quality versus quantity * Do the several groups represented share common +interests? * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Carl FLEISCHHAUER, coordinator, American Memory, Library of Congress, +emphasized that he would attempt to represent the people who perform some +of the work of converting or preparing materials and that the core of +the Workshop had to do with preparation and production. FLEISCHHAUER +then drew a distinction between the long term, when many things would be +available and connected in the ways that GIFFORD described, and the short +term, in which AM not only has wrestled with the issue of what is the +best course to pursue but also has faced a variety of technical +challenges. + +FLEISCHHAUER remarked AM's endeavors to deal with a wide range of library +formats, such as motion picture collections, sound-recording collections, +and pictorial collections of various sorts, especially collections of +photographs. In the course of these efforts, AM kept coming back to +textual materials--manuscripts or rare printed matter, bound materials, +etc. Text posed the greatest conversion challenge of all. Thus, the +genesis of the Workshop, which reflects the problems faced by AM. These +problems include physical problems. For example, those in the library +and archive business deal with collections made up of fragile and rare +manuscript items, bound materials, especially the notoriously brittle +bound materials of the late nineteenth century. These are precious +cultural artifacts, however, as well as interesting sources of +information, and LC desires to retain and conserve them. AM needs to +handle things without damaging them. Guillotining a book to run it +through a sheet feeder must be avoided at all costs. + +Beyond physical problems, issues pertaining to quality arose. For +example, the desire to provide users with a searchable text is affected +by the question of acceptable level of accuracy. One hundred percent +accuracy is tremendously expensive. On the other hand, the output of +optical character recognition (OCR) can be tremendously inaccurate. +Although AM has attempted to find a middle ground, uncertainty persists +as to whether or not it has discovered the right solution. + +Questions of quality arose concerning images as well. FLEISCHHAUER +contrasted the extremely high level of quality of the digital images in +the Cornell Xerox Project with AM's efforts to provide a browse-quality +or access-quality image, as opposed to an archival or preservation image. +FLEISCHHAUER therefore welcomed the opportunity to compare notes. + +FLEISCHHAUER observed in passing that conversations he had had about +networks have begun to signal that for various forms of media a +determination may be made that there is a browse-quality item, or a +distribution-and-access-quality item that may coexist in some systems +with a higher quality archival item that would be inconvenient to send +through the network because of its size. FLEISCHHAUER referred, of +course, to images more than to searchable text. + +As AM considered those questions, several conceptual issues arose: ought +AM occasionally to reproduce materials entirely through an image set, at +other times, entirely through a text set, and in some cases, a mix? +There probably would be times when the historical authenticity of an +artifact would require that its image be used. An image might be +desirable as a recourse for users if one could not provide 100-percent +accurate text. Again, AM wondered, as a practical matter, if a +distinction could be drawn between rare printed matter that might exist +in multiple collections--that is, in ten or fifteen libraries. In such +cases, the need for perfect reproduction would be less than for unique +items. Implicit in his remarks, FLEISCHHAUER conceded, was the admission +that AM has been tilting strongly towards quantity and drawing back a +little from perfect quality. That is, it seemed to AM that society would +be better served if more things were distributed by LC--even if they were +not quite perfect--than if fewer things, perfectly represented, were +distributed. This was stated as a proposition to be tested, with +responses to be gathered from users. + +In thinking about issues related to reproduction of materials and seeing +other people engaged in parallel activities, AM deemed it useful to +convene a conference. Hence, the Workshop. FLEISCHHAUER thereupon +surveyed the several groups represented: 1) the world of images (image +users and image makers); 2) the world of text and scholarship and, within +this group, those concerned with language--FLEISCHHAUER confessed to finding +delightful irony in the fact that some of the most advanced thinkers on +computerized texts are those dealing with ancient Greek and Roman materials; +3) the network world; and 4) the general world of library science, which +includes people interested in preservation and cataloging. + +FLEISCHHAUER concluded his remarks with special thanks to the David and +Lucile Packard Foundation for its support of the meeting, the American +Memory group, the Office for Scholarly Programs, the National +Demonstration Lab, and the Office of Special Events. He expressed the +hope that David Woodley Packard might be able to attend, noting that +Packard's work and the work of the foundation had sponsored a number of +projects in the text area. + + ****** + +SESSION I. CONTENT IN A NEW FORM: WHO WILL USE IT AND WHAT WILL THEY DO? + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DALY * Acknowledgements * A new Latin authors disk * Effects of the new +technology on previous methods of research * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Serving as moderator, James DALY acknowledged the generosity of all the +presenters for giving of their time, counsel, and patience in planning +the Workshop, as well as of members of the American Memory project and +other Library of Congress staff, and the David and Lucile Packard +Foundation and its executive director, Colburn S. Wilbur. + +DALY then recounted his visit in March to the Center for Electronic Texts +in the Humanities (CETH) and the Department of Classics at Rutgers +University, where an old friend, Lowell Edmunds, introduced him to the +department's IBYCUS scholarly personal computer, and, in particular, the +new Latin CD-ROM, containing, among other things, almost all classical +Latin literary texts through A.D. 200. Packard Humanities Institute +(PHI), Los Altos, California, released this disk late in 1991, with a +nominal triennial licensing fee. + +Playing with the disk for an hour or so at Rutgers brought home to DALY +at once the revolutionizing impact of the new technology on his previous +methods of research. Had this disk been available two or three years +earlier, DALY contended, when he was engaged in preparing a commentary on +Book 10 of Virgil's Aeneid for Cambridge University Press, he would not +have required a forty-eight-square-foot table on which to spread the +numerous, most frequently consulted items, including some ten or twelve +concordances to key Latin authors, an almost equal number of lexica to +authors who lacked concordances, and where either lexica or concordances +were lacking, numerous editions of authors antedating and postdating Virgil. + +Nor, when checking each of the average six to seven words contained in +the Virgilian hexameter for its usage elsewhere in Virgil's works or +other Latin authors, would DALY have had to maintain the laborious +mechanical process of flipping through these concordances, lexica, and +editions each time. Nor would he have had to frequent as often the +Milton S. Eisenhower Library at the Johns Hopkins University to consult +the Thesaurus Linguae Latinae. Instead of devoting countless hours, or +the bulk of his research time, to gathering data concerning Virgil's use +of words, DALY--now freed by PHI's Latin authors disk from the +tyrannical, yet in some ways paradoxically happy scholarly drudgery-- +would have been able to devote that same bulk of time to analyzing and +interpreting Virgilian verbal usage. + +Citing Theodore Brunner, Gregory Crane, Elli MYLONAS, and Avra MICHELSON, +DALY argued that this reversal in his style of work, made possible by the +new technology, would perhaps have resulted in better, more productive +research. Indeed, even in the course of his browsing the Latin authors +disk at Rutgers, its powerful search, retrieval, and highlighting +capabilities suggested to him several new avenues of research into +Virgil's use of sound effects. This anecdotal account, DALY maintained, +may serve to illustrate in part the sudden and radical transformation +being wrought in the ways scholars work. + + ****** + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +MICHELSON * Elements related to scholarship and technology * Electronic +texts within the context of broader trends within information technology +and scholarly communication * Evaluation of the prospects for the use of +electronic texts * Relationship of electronic texts to processes of +scholarly communication in humanities research * New exchange formats +created by scholars * Projects initiated to increase scholarly access to +converted text * Trend toward making electronic resources available +through research and education networks * Changes taking place in +scholarly communication among humanities scholars * Network-mediated +scholarship transforming traditional scholarly practices * Key +information technology trends affecting the conduct of scholarly +communication over the next decade * The trend toward end-user computing +* The trend toward greater connectivity * Effects of these trends * Key +transformations taking place * Summary of principal arguments * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Avra MICHELSON, Archival Research and Evaluation Staff, National Archives +and Records Administration (NARA), argued that establishing who will use +electronic texts and what they will use them for involves a consideration +of both information technology and scholarship trends. This +consideration includes several elements related to scholarship and +technology: 1) the key trends in information technology that are most +relevant to scholarship; 2) the key trends in the use of currently +available technology by scholars in the nonscientific community; and 3) +the relationship between these two very distinct but interrelated trends. +The investment in understanding this relationship being made by +information providers, technologists, and public policy developers, as +well as by scholars themselves, seems to be pervasive and growing, +MICHELSON contended. She drew on collaborative work with Jeff Rothenberg +on the scholarly use of technology. + +MICHELSON sought to place the phenomenon of electronic texts within the +context of broader trends within information technology and scholarly +communication. She argued that electronic texts are of most use to +researchers to the extent that the researchers' working context (i.e., +their relevant bibliographic sources, collegial feedback, analytic tools, +notes, drafts, etc.), along with their field's primary and secondary +sources, also is accessible in electronic form and can be integrated in +ways that are unique to the on-line environment. + +Evaluation of the prospects for the use of electronic texts includes two +elements: 1) an examination of the ways in which researchers currently +are using electronic texts along with other electronic resources, and 2) +an analysis of key information technology trends that are affecting the +long-term conduct of scholarly communication. MICHELSON limited her +discussion of the use of electronic texts to the practices of humanists +and noted that the scientific community was outside the panel's overview. + +MICHELSON examined the nature of the current relationship of electronic +texts in particular, and electronic resources in general, to what she +maintained were, essentially, five processes of scholarly communication +in humanities research. Researchers 1) identify sources, 2) communicate +with their colleagues, 3) interpret and analyze data, 4) disseminate +their research findings, and 5) prepare curricula to instruct the next +generation of scholars and students. This examination would produce a +clearer understanding of the synergy among these five processes that +fuels the tendency of the use of electronic resources for one process to +stimulate its use for other processes of scholarly communication. + +For the first process of scholarly communication, the identification of +sources, MICHELSON remarked the opportunity scholars now enjoy to +supplement traditional word-of-mouth searches for sources among their +colleagues with new forms of electronic searching. So, for example, +instead of having to visit the library, researchers are able to explore +descriptions of holdings in their offices. Furthermore, if their own +institutions' holdings prove insufficient, scholars can access more than +200 major American library catalogues over Internet, including the +universities of California, Michigan, Pennsylvania, and Wisconsin. +Direct access to the bibliographic databases offers intellectual +empowerment to scholars by presenting a comprehensive means of browsing +through libraries from their homes and offices at their convenience. + +The second process of communication involves communication among +scholars. Beyond the most common methods of communication, scholars are +using E-mail and a variety of new electronic communications formats +derived from it for further academic interchange. E-mail exchanges are +growing at an astonishing rate, reportedly 15 percent a month. They +currently constitute approximately half the traffic on research and +education networks. Moreover, the global spread of E-mail has been so +rapid that it is now possible for American scholars to use it to +communicate with colleagues in close to 140 other countries. + +Other new exchange formats created by scholars and operating on Internet +include more than 700 conferences, with about 80 percent of these devoted +to topics in the social sciences and humanities. The rate of growth of +these scholarly electronic conferences also is astonishing. From l990 to +l991, 200 new conferences were identified on Internet. From October 1991 +to June 1992, an additional 150 conferences in the social sciences and +humanities were added to this directory of listings. Scholars have +established conferences in virtually every field, within every different +discipline. For example, there are currently close to 600 active social +science and humanities conferences on topics such as art and +architecture, ethnomusicology, folklore, Japanese culture, medical +education, and gifted and talented education. The appeal to scholars of +communicating through these conferences is that, unlike any other medium, +electronic conferences today provide a forum for global communication +with peers at the front end of the research process. + +Interpretation and analysis of sources constitutes the third process of +scholarly communication that MICHELSON discussed in terms of texts and +textual resources. The methods used to analyze sources fall somewhere on +a continuum from quantitative analysis to qualitative analysis. +Typically, evidence is culled and evaluated using methods drawn from both +ends of this continuum. At one end, quantitative analysis involves the +use of mathematical processes such as a count of frequencies and +distributions of occurrences or, on a higher level, regression analysis. +At the other end of the continuum, qualitative analysis typically +involves nonmathematical processes oriented toward language +interpretation or the building of theory. Aspects of this work involve +the processing--either manual or computational--of large and sometimes +massive amounts of textual sources, although the use of nontextual +sources as evidence, such as photographs, sound recordings, film footage, +and artifacts, is significant as well. + +Scholars have discovered that many of the methods of interpretation and +analysis that are related to both quantitative and qualitative methods +are processes that can be performed by computers. For example, computers +can count. They can count brush strokes used in a Rembrandt painting or +perform regression analysis for understanding cause and effect. By means +of advanced technologies, computers can recognize patterns, analyze text, +and model concepts. Furthermore, computers can complete these processes +faster with more sources and with greater precision than scholars who +must rely on manual interpretation of data. But if scholars are to use +computers for these processes, source materials must be in a form +amenable to computer-assisted analysis. For this reason many scholars, +once they have identified the sources that are key to their research, are +converting them to machine-readable form. Thus, a representative example +of the numerous textual conversion projects organized by scholars around +the world in recent years to support computational text analysis is the +TLG, the Thesaurus Linguae Graecae. This project is devoted to +converting the extant ancient texts of classical Greece. (Editor's note: +according to the TLG Newsletter of May l992, TLG was in use in thirty-two +different countries. This figure updates MICHELSON's previous count by one.) + +The scholars performing these conversions have been asked to recognize +that the electronic sources they are converting for one use possess value +for other research purposes as well. As a result, during the past few +years, humanities scholars have initiated a number of projects to +increase scholarly access to converted text. So, for example, the Text +Encoding Initiative (TEI), about which more is said later in the program, +was established as an effort by scholars to determine standard elements +and methods for encoding machine-readable text for electronic exchange. +In a second effort to facilitate the sharing of converted text, scholars +have created a new institution, the Center for Electronic Texts in the +Humanities (CETH). The center estimates that there are 8,000 series of +source texts in the humanities that have been converted to +machine-readable form worldwide. CETH is undertaking an international +search for converted text in the humanities, compiling it into an +electronic library, and preparing bibliographic descriptions of the +sources for the Research Libraries Information Network's (RLIN) +machine-readable data file. The library profession has begun to initiate +large conversion projects as well, such as American Memory. + +While scholars have been making converted text available to one another, +typically on disk or on CD-ROM, the clear trend is toward making these +resources available through research and education networks. Thus, the +American and French Research on the Treasury of the French Language +(ARTFL) and the Dante Project are already available on Internet. +MICHELSON summarized this section on interpretation and analysis by +noting that: 1) increasing numbers of humanities scholars in the library +community are recognizing the importance to the advancement of +scholarship of retrospective conversion of source materials in the arts +and humanities; and 2) there is a growing realization that making the +sources available on research and education networks maximizes their +usefulness for the analysis performed by humanities scholars. + +The fourth process of scholarly communication is dissemination of +research findings, that is, publication. Scholars are using existing +research and education networks to engineer a new type of publication: +scholarly-controlled journals that are electronically produced and +disseminated. Although such journals are still emerging as a +communication format, their number has grown, from approximately twelve +to thirty-six during the past year (July 1991 to June 1992). Most of +these electronic scholarly journals are devoted to topics in the +humanities. As with network conferences, scholarly enthusiasm for these +electronic journals stems from the medium's unique ability to advance +scholarship in a way that no other medium can do by supporting global +feedback and interchange, practically in real time, early in the research +process. Beyond scholarly journals, MICHELSON remarked the delivery of +commercial full-text products, such as articles in professional journals, +newsletters, magazines, wire services, and reference sources. These are +being delivered via on-line local library catalogues, especially through +CD-ROMs. Furthermore, according to MICHELSON, there is general optimism +that the copyright and fees issues impeding the delivery of full text on +existing research and education networks soon will be resolved. + +The final process of scholarly communication is curriculum development +and instruction, and this involves the use of computer information +technologies in two areas. The first is the development of +computer-oriented instructional tools, which includes simulations, +multimedia applications, and computer tools that are used to assist in +the analysis of sources in the classroom, etc. The Perseus Project, a +database that provides a multimedia curriculum on classical Greek +civilization, is a good example of the way in which entire curricula are +being recast using information technologies. It is anticipated that the +current difficulty in exchanging electronically computer-based +instructional software, which in turn makes it difficult for one scholar +to build upon the work of others, will be resolved before too long. +Stand-alone curricular applications that involve electronic text will be +shareable through networks, reinforcing their significance as intellectual +products as well as instructional tools. + +The second aspect of electronic learning involves the use of research and +education networks for distance education programs. Such programs +interactively link teachers with students in geographically scattered +locations and rely on the availability of electronic instructional +resources. Distance education programs are gaining wide appeal among +state departments of education because of their demonstrated capacity to +bring advanced specialized course work and an array of experts to many +classrooms. A recent report found that at least 32 states operated at +least one statewide network for education in 1991, with networks under +development in many of the remaining states. + +MICHELSON summarized this section by noting two striking changes taking +place in scholarly communication among humanities scholars. First is the +extent to which electronic text in particular, and electronic resources +in general, are being infused into each of the five processes described +above. As mentioned earlier, there is a certain synergy at work here. +The use of electronic resources for one process tends to stimulate its +use for other processes, because the chief course of movement is toward a +comprehensive on-line working context for humanities scholars that +includes on-line availability of key bibliographies, scholarly feedback, +sources, analytical tools, and publications. MICHELSON noted further +that the movement toward a comprehensive on-line working context for +humanities scholars is not new. In fact, it has been underway for more +than forty years in the humanities, since Father Roberto Busa began +developing an electronic concordance of the works of Saint Thomas Aquinas +in 1949. What we are witnessing today, MICHELSON contended, is not the +beginning of this on-line transition but, for at least some humanities +scholars, the turning point in the transition from a print to an +electronic working context. Coinciding with the on-line transition, the +second striking change is the extent to which research and education +networks are becoming the new medium of scholarly communication. The +existing Internet and the pending National Education and Research Network +(NREN) represent the new meeting ground where scholars are going for +bibliographic information, scholarly dialogue and feedback, the most +current publications in their field, and high-level educational +offerings. Traditional scholarly practices are undergoing tremendous +transformations as a result of the emergence and growing prominence of +what is called network-mediated scholarship. + +MICHELSON next turned to the second element of the framework she proposed +at the outset of her talk for evaluating the prospects for electronic +text, namely the key information technology trends affecting the conduct +of scholarly communication over the next decade: 1) end-user computing +and 2) connectivity. + +End-user computing means that the person touching the keyboard, or +performing computations, is the same as the person who initiates or +consumes the computation. The emergence of personal computers, along +with a host of other forces, such as ubiquitous computing, advances in +interface design, and the on-line transition, is prompting the consumers +of computation to do their own computing, and is thus rendering obsolete +the traditional distinction between end users and ultimate users. + +The trend toward end-user computing is significant to consideration of +the prospects for electronic texts because it means that researchers are +becoming more adept at doing their own computations and, thus, more +competent in the use of electronic media. By avoiding programmer +intermediaries, computation is becoming central to the researcher's +thought process. This direct involvement in computing is changing the +researcher's perspective on the nature of research itself, that is, the +kinds of questions that can be posed, the analytical methodologies that +can be used, the types and amount of sources that are appropriate for +analyses, and the form in which findings are presented. The trend toward +end-user computing means that, increasingly, electronic media and +computation are being infused into all processes of humanities +scholarship, inspiring remarkable transformations in scholarly +communication. + +The trend toward greater connectivity suggests that researchers are using +computation increasingly in network environments. Connectivity is +important to scholarship because it erases the distance that separates +students from teachers and scholars from their colleagues, while allowing +users to access remote databases, share information in many different +media, connect to their working context wherever they are, and +collaborate in all phases of research. + +The combination of the trend toward end-user computing and the trend +toward connectivity suggests that the scholarly use of electronic +resources, already evident among some researchers, will soon become an +established feature of scholarship. The effects of these trends, along +with ongoing changes in scholarly practices, point to a future in which +humanities researchers will use computation and electronic communication +to help them formulate ideas, access sources, perform research, +collaborate with colleagues, seek peer review, publish and disseminate +results, and engage in many other professional and educational activities. + +In summary, MICHELSON emphasized four points: 1) A portion of humanities +scholars already consider electronic texts the preferred format for +analysis and dissemination. 2) Scholars are using these electronic +texts, in conjunction with other electronic resources, in all the +processes of scholarly communication. 3) The humanities scholars' +working context is in the process of changing from print technology to +electronic technology, in many ways mirroring transformations that have +occurred or are occurring within the scientific community. 4) These +changes are occurring in conjunction with the development of a new +communication medium: research and education networks that are +characterized by their capacity to advance scholarship in a wholly unique +way. + +MICHELSON also reiterated her three principal arguments: l) Electronic +texts are best understood in terms of the relationship to other +electronic resources and the growing prominence of network-mediated +scholarship. 2) The prospects for electronic texts lie in their capacity +to be integrated into the on-line network of electronic resources that +comprise the new working context for scholars. 3) Retrospective conversion +of portions of the scholarly record should be a key strategy as information +providers respond to changes in scholarly communication practices. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +VECCIA * AM's evaluation project and public users of electronic resources +* AM and its design * Site selection and evaluating the Macintosh +implementation of AM * Characteristics of the six public libraries +selected * Characteristics of AM's users in these libraries * Principal +ways AM is being used * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Susan VECCIA, team leader, and Joanne FREEMAN, associate coordinator, +American Memory, Library of Congress, gave a joint presentation. First, +by way of introduction, VECCIA explained her and FREEMAN's roles in +American Memory (AM). Serving principally as an observer, VECCIA has +assisted with the evaluation project of AM, placing AM collections in a +variety of different sites around the country and helping to organize and +implement that project. FREEMAN has been an associate coordinator of AM +and has been involved principally with the interpretative materials, +preparing some of the electronic exhibits and printed historical +information that accompanies AM and that is requested by users. VECCIA +and FREEMAN shared anecdotal observations concerning AM with public users +of electronic resources. Notwithstanding a fairly structured evaluation +in progress, both VECCIA and FREEMAN chose not to report on specifics in +terms of numbers, etc., because they felt it was too early in the +evaluation project to do so. + +AM is an electronic archive of primary source materials from the Library +of Congress, selected collections representing a variety of formats-- +photographs, graphic arts, recorded sound, motion pictures, broadsides, +and soon, pamphlets and books. In terms of the design of this system, +the interpretative exhibits have been kept separate from the primary +resources, with good reason. Accompanying this collection are printed +documentation and user guides, as well as guides that FREEMAN prepared for +teachers so that they may begin using the content of the system at once. + +VECCIA described the evaluation project before talking about the public +users of AM, limiting her remarks to public libraries, because FREEMAN +would talk more specifically about schools from kindergarten to twelfth +grade (K-12). Having started in spring 1991, the evaluation currently +involves testing of the Macintosh implementation of AM. Since the +primary goal of this evaluation is to determine the most appropriate +audience or audiences for AM, very different sites were selected. This +makes evaluation difficult because of the varying degrees of technology +literacy among the sites. AM is situated in forty-four locations, of +which six are public libraries and sixteen are schools. Represented +among the schools are elementary, junior high, and high schools. +District offices also are involved in the evaluation, which will +conclude in summer 1993. + +VECCIA focused the remainder of her talk on the six public libraries, one +of which doubles as a state library. They represent a range of +geographic areas and a range of demographic characteristics. For +example, three are located in urban settings, two in rural settings, and +one in a suburban setting. A range of technical expertise is to be found +among these facilities as well. For example, one is an "Apple library of +the future," while two others are rural one-room libraries--in one, AM +sits at the front desk next to a tractor manual. + +All public libraries have been extremely enthusiastic, supportive, and +appreciative of the work that AM has been doing. VECCIA characterized +various users: Most users in public libraries describe themselves as +general readers; of the students who use AM in the public libraries, +those in fourth grade and above seem most interested. Public libraries +in rural sites tend to attract retired people, who have been highly +receptive to AM. Users tend to fall into two additional categories: +people interested in the content and historical connotations of these +primary resources, and those fascinated by the technology. The format +receiving the most comments has been motion pictures. The adult users in +public libraries are more comfortable with IBM computers, whereas young +people seem comfortable with either IBM or Macintosh, although most of +them seem to come from a Macintosh background. This same tendency is +found in the schools. + +What kinds of things do users do with AM? In a public library there are +two main goals or ways that AM is being used: as an individual learning +tool, and as a leisure activity. Adult learning was one area that VECCIA +would highlight as a possible application for a tool such as AM. She +described a patron of a rural public library who comes in every day on +his lunch hour and literally reads AM, methodically going through the +collection image by image. At the end of his hour he makes an electronic +bookmark, puts it in his pocket, and returns to work. The next day he +comes in and resumes where he left off. Interestingly, this man had +never been in the library before he used AM. In another small, rural +library, the coordinator reports that AM is a popular activity for some +of the older, retired people in the community, who ordinarily would not +use "those things,"--computers. Another example of adult learning in +public libraries is book groups, one of which, in particular, is using AM +as part of its reading on industrialization, integration, and urbanization +in the early 1900s. + +One library reports that a family is using AM to help educate their +children. In another instance, individuals from a local museum came in +to use AM to prepare an exhibit on toys of the past. These two examples +emphasize the mission of the public library as a cultural institution, +reaching out to people who do not have the same resources available to +those who live in a metropolitan area or have access to a major library. +One rural library reports that junior high school students in large +numbers came in one afternoon to use AM for entertainment. A number of +public libraries reported great interest among postcard collectors in the +Detroit collection, which was essentially a collection of images used on +postcards around the turn of the century. Train buffs are similarly +interested because that was a time of great interest in railroading. +People, it was found, relate to things that they know of firsthand. For +example, in both rural public libraries where AM was made available, +observers reported that the older people with personal remembrances of +the turn of the century were gravitating to the Detroit collection. +These examples served to underscore MICHELSON's observation re the +integration of electronic tools and ideas--that people learn best when +the material relates to something they know. + +VECCIA made the final point that in many cases AM serves as a +public-relations tool for the public libraries that are testing it. In +one case, AM is being used as a vehicle to secure additional funding for +the library. In another case, AM has served as an inspiration to the +staff of a major local public library in the South to think about ways to +make its own collection of photographs more accessible to the public. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +FREEMAN * AM and archival electronic resources in a school environment * +Questions concerning context * Questions concerning the electronic format +itself * Computer anxiety * Access and availability of the system * +Hardware * Strengths gained through the use of archival resources in +schools * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Reiterating an observation made by VECCIA, that AM is an archival +resource made up of primary materials with very little interpretation, +FREEMAN stated that the project has attempted to bridge the gap between +these bare primary materials and a school environment, and in that cause +has created guided introductions to AM collections. Loud demand from the +educational community, chiefly from teachers working with the upper +grades of elementary school through high school, greeted the announcement +that AM would be tested around the country. + +FREEMAN reported not only on what was learned about AM in a school +environment, but also on several universal questions that were raised +concerning archival electronic resources in schools. She discussed +several strengths of this type of material in a school environment as +opposed to a highly structured resource that offers a limited number of +paths to follow. + +FREEMAN first raised several questions about using AM in a school +environment. There is often some difficulty in developing a sense of +what the system contains. Many students sit down at a computer resource +and assume that, because AM comes from the Library of Congress, all of +American history is now at their fingertips. As a result of that sort of +mistaken judgment, some students are known to conclude that AM contains +nothing of use to them when they look for one or two things and do not +find them. It is difficult to discover that middle ground where one has +a sense of what the system contains. Some students grope toward the idea +of an archive, a new idea to them, since they have not previously +experienced what it means to have access to a vast body of somewhat +random information. + +Other questions raised by FREEMAN concerned the electronic format itself. +For instance, in a school environment it is often difficult both for +teachers and students to gain a sense of what it is they are viewing. +They understand that it is a visual image, but they do not necessarily +know that it is a postcard from the turn of the century, a panoramic +photograph, or even machine-readable text of an eighteenth-century +broadside, a twentieth-century printed book, or a nineteenth-century +diary. That distinction is often difficult for people in a school +environment to grasp. Because of that, it occasionally becomes difficult +to draw conclusions from what one is viewing. + +FREEMAN also noted the obvious fear of the computer, which constitutes a +difficulty in using an electronic resource. Though students in general +did not suffer from this anxiety, several older students feared that they +were computer-illiterate, an assumption that became self-fulfilling when +they searched for something but failed to find it. FREEMAN said she +believed that some teachers also fear computer resources, because they +believe they lack complete control. FREEMAN related the example of +teachers shooing away students because it was not their time to use the +system. This was a case in which the situation had to be extremely +structured so that the teachers would not feel that they had lost their +grasp on what the system contained. + +A final question raised by FREEMAN concerned access and availability of +the system. She noted the occasional existence of a gap in communication +between school librarians and teachers. Often AM sits in a school +library and the librarian is the person responsible for monitoring the +system. Teachers do not always take into their world new library +resources about which the librarian is excited. Indeed, at the sites +where AM had been used most effectively within a library, the librarian +was required to go to specific teachers and instruct them in its use. As +a result, several AM sites will have in-service sessions over a summer, +in the hope that perhaps, with a more individualized link, teachers will +be more likely to use the resource. + +A related issue in the school context concerned the number of +workstations available at any one location. Centralization of equipment +at the district level, with teachers invited to download things and walk +away with them, proved unsuccessful because the hours these offices were +open were also school hours. + +Another issue was hardware. As VECCIA observed, a range of sites exists, +some technologically advanced and others essentially acquiring their +first computer for the primary purpose of using it in conjunction with +AM's testing. Users at technologically sophisticated sites want even +more sophisticated hardware, so that they can perform even more +sophisticated tasks with the materials in AM. But once they acquire a +newer piece of hardware, they must learn how to use that also; at an +unsophisticated site it takes an extremely long time simply to become +accustomed to the computer, not to mention the program offered with the +computer. All of these small issues raise one large question, namely, +are systems like AM truly rewarding in a school environment, or do they +simply act as innovative toys that do little more than spark interest? + +FREEMAN contended that the evaluation project has revealed several strengths +that were gained through the use of archival resources in schools, including: + + * Psychic rewards from using AM as a vast, rich database, with + teachers assigning various projects to students--oral presentations, + written reports, a documentary, a turn-of-the-century newspaper-- + projects that start with the materials in AM but are completed using + other resources; AM thus is used as a research tool in conjunction + with other electronic resources, as well as with books and items in + the library where the system is set up. + + * Students are acquiring computer literacy in a humanities context. + + * This sort of system is overcoming the isolation between disciplines + that often exists in schools. For example, many English teachers are + requiring their students to write papers on historical topics + represented in AM. Numerous teachers have reported that their + students are learning critical thinking skills using the system. + + * On a broader level, AM is introducing primary materials, not only + to students but also to teachers, in an environment where often + simply none exist--an exciting thing for the students because it + helps them learn to conduct research, to interpret, and to draw + their own conclusions. In learning to conduct research and what it + means, students are motivated to seek knowledge. That relates to + another positive outcome--a high level of personal involvement of + students with the materials in this system and greater motivation to + conduct their own research and draw their own conclusions. + + * Perhaps the most ironic strength of these kinds of archival + electronic resources is that many of the teachers AM interviewed + were desperate, it is no exaggeration to say, not only for primary + materials but for unstructured primary materials. These would, they + thought, foster personally motivated research, exploration, and + excitement in their students. Indeed, these materials have done + just that. Ironically, however, this lack of structure produces + some of the confusion to which the newness of these kinds of + resources may also contribute. The key to effective use of archival + products in a school environment is a clear, effective introduction + to the system and to what it contains. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Nothing known, quantitatively, about the number of +humanities scholars who must see the original versus those who would +settle for an edited transcript, or about the ways in which humanities +scholars are using information technology * Firm conclusions concerning +the manner and extent of the use of supporting materials in print +provided by AM to await completion of evaluative study * A listener's +reflections on additional applications of electronic texts * Role of +electronic resources in teaching elementary research skills to students * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +During the discussion that followed the presentations by MICHELSON, +VECCIA, and FREEMAN, additional points emerged. + +LESK asked if MICHELSON could give any quantitative estimate of the +number of humanities scholars who must see or want to see the original, +or the best possible version of the material, versus those who typically +would settle for an edited transcript. While unable to provide a figure, +she offered her impressions as an archivist who has done some reference +work and has discussed this issue with other archivists who perform +reference, that those who use archives and those who use primary sources +for what would be considered very high-level scholarly research, as +opposed to, say, undergraduate papers, were few in number, especially +given the public interest in using primary sources to conduct +genealogical or avocational research and the kind of professional +research done by people in private industry or the federal government. +More important in MICHELSON's view was that, quantitatively, nothing is +known about the ways in which, for example, humanities scholars are using +information technology. No studies exist to offer guidance in creating +strategies. The most recent study was conducted in 1985 by the American +Council of Learned Societies (ACLS), and what it showed was that 50 +percent of humanities scholars at that time were using computers. That +constitutes the extent of our knowledge. + +Concerning AM's strategy for orienting people toward the scope of +electronic resources, FREEMAN could offer no hard conclusions at this +point, because she and her colleagues were still waiting to see, +particularly in the schools, what has been made of their efforts. Within +the system, however, AM has provided what are called electronic exhibits- +-such as introductions to time periods and materials--and these are +intended to offer a student user a sense of what a broadside is and what +it might tell her or him. But FREEMAN conceded that the project staff +would have to talk with students next year, after teachers have had a +summer to use the materials, and attempt to discover what the students +were learning from the materials. In addition, FREEMAN described +supporting materials in print provided by AM at the request of local +teachers during a meeting held at LC. These included time lines, +bibliographies, and other materials that could be reproduced on a +photocopier in a classroom. Teachers could walk away with and use these, +and in this way gain a better understanding of the contents. But again, +reaching firm conclusions concerning the manner and extent of their use +would have to wait until next year. + +As to the changes she saw occurring at the National Archives and Records +Administration (NARA) as a result of the increasing emphasis on +technology in scholarly research, MICHELSON stated that NARA at this +point was absorbing the report by her and Jeff Rothenberg addressing +strategies for the archival profession in general, although not for the +National Archives specifically. NARA is just beginning to establish its +role and what it can do. In terms of changes and initiatives that NARA +can take, no clear response could be given at this time. + +GREENFIELD remarked two trends mentioned in the session. Reflecting on +DALY's opening comments on how he could have used a Latin collection of +text in an electronic form, he said that at first he thought most scholars +would be unwilling to do that. But as he thought of that in terms of the +original meaning of research--that is, having already mastered these texts, +researching them for critical and comparative purposes--for the first time, +the electronic format made a lot of sense. GREENFIELD could envision +growing numbers of scholars learning the new technologies for that very +aspect of their scholarship and for convenience's sake. + +Listening to VECCIA and FREEMAN, GREENFIELD thought of an additional +application of electronic texts. He realized that AM could be used as a +guide to lead someone to original sources. Students cannot be expected +to have mastered these sources, things they have never known about +before. Thus, AM is leading them, in theory, to a vast body of +information and giving them a superficial overview of it, enabling them +to select parts of it. GREENFIELD asked if any evidence exists that this +resource will indeed teach the new user, the K-12 students, how to do +research. Scholars already know how to do research and are applying +these new tools. But he wondered why students would go beyond picking +out things that were most exciting to them. + +FREEMAN conceded the correctness of GREENFIELD's observation as applied +to a school environment. The risk is that a student would sit down at a +system, play with it, find some things of interest, and then walk away. +But in the relatively controlled situation of a school library, much will +depend on the instructions a teacher or a librarian gives a student. She +viewed the situation not as one of fine-tuning research skills but of +involving students at a personal level in understanding and researching +things. Given the guidance one can receive at school, it then becomes +possible to teach elementary research skills to students, which in fact +one particular librarian said she was teaching her fifth graders. +FREEMAN concluded that introducing the idea of following one's own path +of inquiry, which is essentially what research entails, involves more +than teaching specific skills. To these comments VECCIA added the +observation that the individual teacher and the use of a creative +resource, rather than AM itself, seemed to make the key difference. +Some schools and some teachers are making excellent use of the nature +of critical thinking and teaching skills, she said. + +Concurring with these remarks, DALY closed the session with the thought that +the more that producers produced for teachers and for scholars to use with +their students, the more successful their electronic products would prove. + + ****** + +SESSION II. SHOW AND TELL + +Jacqueline HESS, director, National Demonstration Laboratory, served as +moderator of the "show-and-tell" session. She noted that a +question-and-answer period would follow each presentation. + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +MYLONAS * Overview and content of Perseus * Perseus' primary materials +exist in a system-independent, archival form * A concession * Textual +aspects of Perseus * Tools to use with the Greek text * Prepared indices +and full-text searches in Perseus * English-Greek word search leads to +close study of words and concepts * Navigating Perseus by tracing down +indices * Using the iconography to perform research * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Elli MYLONAS, managing editor, Perseus Project, Harvard University, first +gave an overview of Perseus, a large, collaborative effort based at +Harvard University but with contributors and collaborators located at +numerous universities and colleges in the United States (e.g., Bowdoin, +Maryland, Pomona, Chicago, Virginia). Funded primarily by the +Annenberg/CPB Project, with additional funding from Apple, Harvard, and +the Packard Humanities Institute, among others, Perseus is a multimedia, +hypertextual database for teaching and research on classical Greek +civilization, which was released in February 1992 in version 1.0 and +distributed by Yale University Press. + +Consisting entirely of primary materials, Perseus includes ancient Greek +texts and translations of those texts; catalog entries--that is, museum +catalog entries, not library catalog entries--on vases, sites, coins, +sculpture, and archaeological objects; maps; and a dictionary, among +other sources. The number of objects and the objects for which catalog +entries exist are accompanied by thousands of color images, which +constitute a major feature of the database. Perseus contains +approximately 30 megabytes of text, an amount that will double in +subsequent versions. In addition to these primary materials, the Perseus +Project has been building tools for using them, making access and +navigation easier, the goal being to build part of the electronic +environment discussed earlier in the morning in which students or +scholars can work with their sources. + +The demonstration of Perseus will show only a fraction of the real work +that has gone into it, because the project had to face the dilemma of +what to enter when putting something into machine-readable form: should +one aim for very high quality or make concessions in order to get the +material in? Since Perseus decided to opt for very high quality, all of +its primary materials exist in a system-independent--insofar as it is +possible to be system-independent--archival form. Deciding what that +archival form would be and attaining it required much work and thought. +For example, all the texts are marked up in SGML, which will be made +compatible with the guidelines of the Text Encoding Initiative (TEI) when +they are issued. + +Drawings are postscript files, not meeting international standards, but +at least designed to go across platforms. Images, or rather the real +archival forms, consist of the best available slides, which are being +digitized. Much of the catalog material exists in database form--a form +that the average user could use, manipulate, and display on a personal +computer, but only at great cost. Thus, this is where the concession +comes in: All of this rich, well-marked-up information is stripped of +much of its content; the images are converted into bit-maps and the text +into small formatted chunks. All this information can then be imported +into HyperCard and run on a mid-range Macintosh, which is what Perseus +users have. This fact has made it possible for Perseus to attain wide +use fairly rapidly. Without those archival forms the HyperCard version +being demonstrated could not be made easily, and the project could not +have the potential to move to other forms and machines and software as +they appear, none of which information is in Perseus on the CD. + +Of the numerous multimedia aspects of Perseus, MYLONAS focused on the +textual. Part of what makes Perseus such a pleasure to use, MYLONAS +said, is this effort at seamless integration and the ability to move +around both visual and textual material. Perseus also made the decision +not to attempt to interpret its material any more than one interprets by +selecting. But, MYLONAS emphasized, Perseus is not courseware: No +syllabus exists. There is no effort to define how one teaches a topic +using Perseus, although the project may eventually collect papers by +people who have used it to teach. Rather, Perseus aims to provide +primary material in a kind of electronic library, an electronic sandbox, +so to say, in which students and scholars who are working on this +material can explore by themselves. With that, MYLONAS demonstrated +Perseus, beginning with the Perseus gateway, the first thing one sees +upon opening Perseus--an effort in part to solve the contextualizing +problem--which tells the user what the system contains. + +MYLONAS demonstrated only a very small portion, beginning with primary +texts and running off the CD-ROM. Having selected Aeschylus' Prometheus +Bound, which was viewable in Greek and English pretty much in the same +segments together, MYLONAS demonstrated tools to use with the Greek text, +something not possible with a book: looking up the dictionary entry form +of an unfamiliar word in Greek after subjecting it to Perseus' +morphological analysis for all the texts. After finding out about a +word, a user may then decide to see if it is used anywhere else in Greek. +Because vast amounts of indexing support all of the primary material, one +can find out where else all forms of a particular Greek word appear-- +often not a trivial matter because Greek is highly inflected. Further, +since the story of Prometheus has to do with the origins of sacrifice, a +user may wish to study and explore sacrifice in Greek literature; by +typing sacrifice into a small window, a user goes to the English-Greek +word list--something one cannot do without the computer (Perseus has +indexed the definitions of its dictionary)--the string sacrifice appears +in the definitions of these sixty-five words. One may then find out +where any of those words is used in the work(s) of a particular author. +The English definitions are not lemmatized. + +All of the indices driving this kind of usage were originally devised for +speed, MYLONAS observed; in other words, all that kind of information-- +all forms of all words, where they exist, the dictionary form they belong +to--were collected into databases, which will expedite searching. Then +it was discovered that one can do things searching in these databases +that could not be done searching in the full texts. Thus, although there +are full-text searches in Perseus, much of the work is done behind the +scenes, using prepared indices. Re the indexing that is done behind the +scenes, MYLONAS pointed out that without the SGML forms of the text, it +could not be done effectively. Much of this indexing is based on the +structures that are made explicit by the SGML tagging. + +It was found that one of the things many of Perseus' non-Greek-reading +users do is start from the dictionary and then move into the close study +of words and concepts via this kind of English-Greek word search, by which +means they might select a concept. This exercise has been assigned to +students in core courses at Harvard--to study a concept by looking for the +English word in the dictionary, finding the Greek words, and then finding +the words in the Greek but, of course, reading across in the English. +That tells them a great deal about what a translation means as well. + +Should one also wish to see images that have to do with sacrifice, that +person would go to the object key word search, which allows one to +perform a similar kind of index retrieval on the database of +archaeological objects. Without words, pictures are useless; Perseus has +not reached the point where it can do much with images that are not +cataloged. Thus, although it is possible in Perseus with text and images +to navigate by knowing where one wants to end up--for example, a +red-figure vase from the Boston Museum of Fine Arts--one can perform this +kind of navigation very easily by tracing down indices. MYLONAS +illustrated several generic scenes of sacrifice on vases. The features +demonstrated derived from Perseus 1.0; version 2.0 will implement even +better means of retrieval. + +MYLONAS closed by looking at one of the pictures and noting again that +one can do a great deal of research using the iconography as well as the +texts. For instance, students in a core course at Harvard this year were +highly interested in Greek concepts of foreigners and representations of +non-Greeks. So they performed a great deal of research, both with texts +(e.g., Herodotus) and with iconography on vases and coins, on how the +Greeks portrayed non-Greeks. At the same time, art historians who study +iconography were also interested, and were able to use this material. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Indexing and searchability of all English words in Perseus * +Several features of Perseus 1.0 * Several levels of customization +possible * Perseus used for general education * Perseus' effects on +education * Contextual information in Perseus * Main challenge and +emphasis of Perseus * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Several points emerged in the discussion that followed MYLONAS's presentation. + +Although MYLONAS had not demonstrated Perseus' ability to cross-search +documents, she confirmed that all English words in Perseus are indexed +and can be searched. So, for example, sacrifice could have been searched +in all texts, the historical essay, and all the catalogue entries with +their descriptions--in short, in all of Perseus. + +Boolean logic is not in Perseus 1.0 but will be added to the next +version, although an effort is being made not to restrict Perseus to a +database in which one just performs searching, Boolean or otherwise. It +is possible to move laterally through the documents by selecting a word +one is interested in and selecting an area of information one is +interested in and trying to look that word up in that area. + +Since Perseus was developed in HyperCard, several levels of customization +are possible. Simple authoring tools exist that allow one to create +annotated paths through the information, which are useful for note-taking +and for guided tours for teaching purposes and for expository writing. +With a little more ingenuity it is possible to begin to add or substitute +material in Perseus. + +Perseus has not been used so much for classics education as for general +education, where it seemed to have an impact on the students in the core +course at Harvard (a general required course that students must take in +certain areas). Students were able to use primary material much more. + +The Perseus Project has an evaluation team at the University of Maryland +that has been documenting Perseus' effects on education. Perseus is very +popular, and anecdotal evidence indicates that it is having an effect at +places other than Harvard, for example, test sites at Ball State +University, Drury College, and numerous small places where opportunities +to use vast amounts of primary data may not exist. One documented effect +is that archaeological, anthropological, and philological research is +being done by the same person instead of by three different people. + +The contextual information in Perseus includes an overview essay, a +fairly linear historical essay on the fifth century B.C. that provides +links into the primary material (e.g., Herodotus, Thucydides, and +Plutarch), via small gray underscoring (on the screen) of linked +passages. These are handmade links into other material. + +To different extents, most of the production work was done at Harvard, +where the people and the equipment are located. Much of the +collaborative activity involved data collection and structuring, because +the main challenge and the emphasis of Perseus is the gathering of +primary material, that is, building a useful environment for studying +classical Greece, collecting data, and making it useful. +Systems-building is definitely not the main concern. Thus, much of the +work has involved writing essays, collecting information, rewriting it, +and tagging it. That can be done off site. The creative link for the +overview essay as well as for both systems and data was collaborative, +and was forged via E-mail and paper mail with professors at Pomona and +Bowdoin. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +CALALUCA * PLD's principal focus and contribution to scholarship * +Various questions preparatory to beginning the project * Basis for +project * Basic rule in converting PLD * Concerning the images in PLD * +Running PLD under a variety of retrieval software * Encoding the +database a hard-fought issue * Various features demonstrated * Importance +of user documentation * Limitations of the CD-ROM version * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Eric CALALUCA, vice president, Chadwyck-Healey, Inc., demonstrated a +software interpretation of the Patrologia Latina Database (PLD). PLD's +principal focus from the beginning of the project about three-and-a-half +years ago was on converting Migne's Latin series, and in the end, +CALALUCA suggested, conversion of the text will be the major contribution +to scholarship. CALALUCA stressed that, as possibly the only private +publishing organization at the Workshop, Chadwyck-Healey had sought no +federal funds or national foundation support before embarking upon the +project, but instead had relied upon a great deal of homework and +marketing to accomplish the task of conversion. + +Ever since the possibilities of computer-searching have emerged, scholars +in the field of late ancient and early medieval studies (philosophers, +theologians, classicists, and those studying the history of natural law +and the history of the legal development of Western civilization) have +been longing for a fully searchable version of Western literature, for +example, all the texts of Augustine and Bernard of Clairvaux and +Boethius, not to mention all the secondary and tertiary authors. + +Various questions arose, CALALUCA said. Should one convert Migne? +Should the database be encoded? Is it necessary to do that? How should +it be delivered? What about CD-ROM? Since this is a transitional +medium, why even bother to create software to run on a CD-ROM? Since +everybody knows people will be networking information, why go to the +trouble--which is far greater with CD-ROM than with the production of +magnetic data? Finally, how does one make the data available? Can many +of the hurdles to using electronic information that some publishers have +imposed upon databases be eliminated? + +The PLD project was based on the principle that computer-searching of +texts is most effective when it is done with a large database. Because +PLD represented a collection that serves so many disciplines across so +many periods, it was irresistible. + +The basic rule in converting PLD was to do no harm, to avoid the sins of +intrusion in such a database: no introduction of newer editions, no +on-the-spot changes, no eradicating of all possible falsehoods from an +edition. Thus, PLD is not the final act in electronic publishing for +this discipline, but simply the beginning. The conversion of PLD has +evoked numerous unanticipated questions: How will information be used? +What about networking? Can the rights of a database be protected? +Should one protect the rights of a database? How can it be made +available? + +Those converting PLD also tried to avoid the sins of omission, that is, +excluding portions of the collections or whole sections. What about the +images? PLD is full of images, some are extremely pious +nineteenth-century representations of the Fathers, while others contain +highly interesting elements. The goal was to cover all the text of Migne +(including notes, in Greek and in Hebrew, the latter of which, in +particular, causes problems in creating a search structure), all the +indices, and even the images, which are being scanned in separately +searchable files. + +Several North American institutions that have placed acquisition requests +for the PLD database have requested it in magnetic form without software, +which means they are already running it without software, without +anything demonstrated at the Workshop. + +What cannot practically be done is go back and reconvert and re-encode +data, a time-consuming and extremely costly enterprise. CALALUCA sees +PLD as a database that can, and should, be run under a variety of +retrieval software. This will permit the widest possible searches. +Consequently, the need to produce a CD-ROM of PLD, as well as to develop +software that could handle some 1.3 gigabyte of heavily encoded text, +developed out of conversations with collection development and reference +librarians who wanted software both compassionate enough for the +pedestrian but also capable of incorporating the most detailed +lexicographical studies that a user desires to conduct. In the end, the +encoding and conversion of the data will prove the most enduring +testament to the value of the project. + +The encoding of the database was also a hard-fought issue: Did the +database need to be encoded? Were there normative structures for encoding +humanist texts? Should it be SGML? What about the TEI--will it last, +will it prove useful? CALALUCA expressed some minor doubts as to whether +a data bank can be fully TEI-conformant. Every effort can be made, but +in the end to be TEI-conformant means to accept the need to make some +firm encoding decisions that can, indeed, be disputed. The TEI points +the publisher in a proper direction but does not presume to make all the +decisions for him or her. Essentially, the goal of encoding was to +eliminate, as much as possible, the hindrances to information-networking, +so that if an institution acquires a database, everybody associated with +the institution can have access to it. + +CALALUCA demonstrated a portion of Volume 160, because it had the most +anomalies in it. The software was created by Electronic Book +Technologies of Providence, RI, and is called Dynatext. The software +works only with SGML-coded data. + +Viewing a table of contents on the screen, the audience saw how Dynatext +treats each element as a book and attempts to simplify movement through a +volume. Familiarity with the Patrologia in print (i.e., the text, its +source, and the editions) will make the machine-readable versions highly +useful. (Software with a Windows application was sought for PLD, +CALALUCA said, because this was the main trend for scholarly use.) + +CALALUCA also demonstrated how a user can perform a variety of searches +and quickly move to any part of a volume; the look-up screen provides +some basic, simple word-searching. + +CALALUCA argued that one of the major difficulties is not the software. +Rather, in creating a product that will be used by scholars representing +a broad spectrum of computer sophistication, user documentation proves +to be the most important service one can provide. + +CALALUCA next illustrated a truncated search under mysterium within ten +words of virtus and how one would be able to find its contents throughout +the entire database. He said that the exciting thing about PLD is that +many of the applications in the retrieval software being written for it +will exceed the capabilities of the software employed now for the CD-ROM +version. The CD-ROM faces genuine limitations, in terms of speed and +comprehensiveness, in the creation of a retrieval software to run it. +CALALUCA said he hoped that individual scholars will download the data, +if they wish, to their personal computers, and have ready access to +important texts on a constant basis, which they will be able to use in +their research and from which they might even be able to publish. + +(CALALUCA explained that the blue numbers represented Migne's column numbers, +which are the standard scholarly references. Pulling up a note, he stated +that these texts were heavily edited and the image files would appear simply +as a note as well, so that one could quickly access an image.) + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +FLEISCHHAUER/ERWAY * Several problems with which AM is still wrestling * +Various search and retrieval capabilities * Illustration of automatic +stemming and a truncated search * AM's attempt to find ways to connect +cataloging to the texts * AM's gravitation towards SGML * Striking a +balance between quantity and quality * How AM furnishes users recourse to +images * Conducting a search in a full-text environment * Macintosh and +IBM prototypes of AM * Multimedia aspects of AM * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +A demonstration of American Memory by its coordinator, Carl FLEISCHHAUER, +and Ricky ERWAY, associate coordinator, Library of Congress, concluded +the morning session. Beginning with a collection of broadsides from the +Continental Congress and the Constitutional Convention, the only text +collection in a presentable form at the time of the Workshop, FLEISCHHAUER +highlighted several of the problems with which AM is still wrestling. +(In its final form, the disk will contain two collections, not only the +broadsides but also the full text with illustrations of a set of +approximately 300 African-American pamphlets from the period 1870 to 1910.) + +As FREEMAN had explained earlier, AM has attempted to use a small amount +of interpretation to introduce collections. In the present case, the +contractor, a company named Quick Source, in Silver Spring, MD., used +software called Toolbook and put together a modestly interactive +introduction to the collection. Like the two preceding speakers, +FLEISCHHAUER argued that the real asset was the underlying collection. + +FLEISCHHAUER proceeded to describe various search and retrieval +capabilities while ERWAY worked the computer. In this particular package +the "go to" pull-down allowed the user in effect to jump out of Toolbook, +where the interactive program was located, and enter the third-party +software used by AM for this text collection, which is called Personal +Librarian. This was the Windows version of Personal Librarian, a +software application put together by a company in Rockville, Md. + +Since the broadsides came from the Revolutionary War period, a search was +conducted using the words British or war, with the default operator reset +as or. FLEISCHHAUER demonstrated both automatic stemming (which finds +other forms of the same root) and a truncated search. One of Personal +Librarian's strongest features, the relevance ranking, was represented by +a chart that indicated how often words being sought appeared in +documents, with the one receiving the most "hits" obtaining the highest +score. The "hit list" that is supplied takes the relevance ranking into +account, making the first hit, in effect, the one the software has +selected as the most relevant example. + +While in the text of one of the broadside documents, FLEISCHHAUER +remarked AM's attempt to find ways to connect cataloging to the texts, +which it does in different ways in different manifestations. In the case +shown, the cataloging was pasted on: AM took MARC records that were +written as on-line records right into one of the Library's mainframe +retrieval programs, pulled them out, and handed them off to the contractor, +who massaged them somewhat to display them in the manner shown. One of +AM's questions is, Does the cataloguing normally performed in the mainframe +work in this context, or had AM ought to think through adjustments? + +FLEISCHHAUER made the additional point that, as far as the text goes, AM +has gravitated towards SGML (he pointed to the boldface in the upper part +of the screen). Although extremely limited in its ability to translate +or interpret SGML, Personal Librarian will furnish both bold and italics +on screen; a fairly easy thing to do, but it is one of the ways in which +SGML is useful. + +Striking a balance between quantity and quality has been a major concern +of AM, with accuracy being one of the places where project staff have +felt that less than 100-percent accuracy was not unacceptable. +FLEISCHHAUER cited the example of the standard of the rekeying industry, +namely 99.95 percent; as one service bureau informed him, to go from +99.95 to 100 percent would double the cost. + +FLEISCHHAUER next demonstrated how AM furnishes users recourse to images, +and at the same time recalled LESK's pointed question concerning the +number of people who would look at those images and the number who would +work only with the text. If the implication of LESK's question was +sound, FLEISCHHAUER said, it raised the stakes for text accuracy and +reduced the value of the strategy for images. + +Contending that preservation is always a bugaboo, FLEISCHHAUER +demonstrated several images derived from a scan of a preservation +microfilm that AM had made. He awarded a grade of C at best, perhaps a +C minus or a C plus, for how well it worked out. Indeed, the matter of +learning if other people had better ideas about scanning in general, and, +in particular, scanning from microfilm, was one of the factors that drove +AM to attempt to think through the agenda for the Workshop. Skew, for +example, was one of the issues that AM in its ignorance had not reckoned +would prove so difficult. + +Further, the handling of images of the sort shown, in a desktop computer +environment, involved a considerable amount of zooming and scrolling. +Ultimately, AM staff feel that perhaps the paper copy that is printed out +might be the most useful one, but they remain uncertain as to how much +on-screen reading users will do. + +Returning to the text, FLEISCHHAUER asked viewers to imagine a person who +might be conducting a search in a full-text environment. With this +scenario, he proceeded to illustrate other features of Personal Librarian +that he considered helpful; for example, it provides the ability to +notice words as one reads. Clicking the "include" button on the bottom +of the search window pops the words that have been highlighted into the +search. Thus, a user can refine the search as he or she reads, +re-executing the search and continuing to find things in the quest for +materials. This software not only contains relevance ranking, Boolean +operators, and truncation, it also permits one to perform word algebra, +so to say, where one puts two or three words in parentheses and links +them with one Boolean operator and then a couple of words in another set +of parentheses and asks for things within so many words of others. + +Until they became acquainted recently with some of the work being done in +classics, the AM staff had not realized that a large number of the +projects that involve electronic texts were being done by people with a +profound interest in language and linguistics. Their search strategies +and thinking are oriented to those fields, as is shown in particular by +the Perseus example. As amateur historians, the AM staff were thinking +more of searching for concepts and ideas than for particular words. +Obviously, FLEISCHHAUER conceded, searching for concepts and ideas and +searching for words may be two rather closely related things. + +While displaying several images, FLEISCHHAUER observed that the Macintosh +prototype built by AM contains a greater diversity of formats. Echoing a +previous speaker, he said that it was easier to stitch things together in +the Macintosh, though it tended to be a little more anemic in search and +retrieval. AM, therefore, increasingly has been investigating +sophisticated retrieval engines in the IBM format. + +FLEISCHHAUER demonstrated several additional examples of the prototype +interfaces: One was AM's metaphor for the network future, in which a +kind of reading-room graphic suggests how one would be able to go around +to different materials. AM contains a large number of photographs in +analog video form worked up from a videodisc, which enable users to make +copies to print or incorporate in digital documents. A frame-grabber is +built into the system, making it possible to bring an image into a window +and digitize or print it out. + +FLEISCHHAUER next demonstrated sound recording, which included texts. +Recycled from a previous project, the collection included sixty 78-rpm +phonograph records of political speeches that were made during and +immediately after World War I. These constituted approximately three +hours of audio, as AM has digitized it, which occupy 150 megabytes on a +CD. Thus, they are considerably compressed. From the catalogue card, +FLEISCHHAUER proceeded to a transcript of a speech with the audio +available and with highlighted text following it as it played. +A photograph has been added and a transcription made. + +Considerable value has been added beyond what the Library of Congress +normally would do in cataloguing a sound recording, which raises several +questions for AM concerning where to draw lines about how much value it can +afford to add and at what point, perhaps, this becomes more than AM could +reasonably do or reasonably wish to do. FLEISCHHAUER also demonstrated +a motion picture. As FREEMAN had reported earlier, the motion picture +materials have proved the most popular, not surprisingly. This says more +about the medium, he thought, than about AM's presentation of it. + +Because AM's goal was to bring together things that could be used by +historians or by people who were curious about history, +turn-of-the-century footage seemed to represent the most appropriate +collections from the Library of Congress in motion pictures. These were +the very first films made by Thomas Edison's company and some others at +that time. The particular example illustrated was a Biograph film, +brought in with a frame-grabber into a window. A single videodisc +contains about fifty titles and pieces of film from that period, all of +New York City. Taken together, AM believes, they provide an interesting +documentary resource. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Using the frame-grabber in AM * Volume of material processed +and to be processed * Purpose of AM within LC * Cataloguing and the +nature of AM's material * SGML coding and the question of quality versus +quantity * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +During the question-and-answer period that followed FLEISCHHAUER's +presentation, several clarifications were made. + +AM is bringing in motion pictures from a videodisc. The frame-grabber +devices create a window on a computer screen, which permits users to +digitize a single frame of the movie or one of the photographs. It +produces a crude, rough-and-ready image that high school students can +incorporate into papers, and that has worked very nicely in this way. + +Commenting on FLEISCHHAUER's assertion that AM was looking more at +searching ideas than words, MYLONAS argued that without words an idea +does not exist. FLEISCHHAUER conceded that he ought to have articulated +his point more clearly. MYLONAS stated that they were in fact both +talking about the same thing. By searching for words and by forcing +people to focus on the word, the Perseus Project felt that they would get +them to the idea. The way one reviews results is tailored more to one +kind of user than another. + +Concerning the total volume of material that has been processed in this +way, AM at this point has in retrievable form seven or eight collections, +all of them photographic. In the Macintosh environment, for example, +there probably are 35,000-40,000 photographs. The sound recordings +number sixty items. The broadsides number about 300 items. There are +500 political cartoons in the form of drawings. The motion pictures, as +individual items, number sixty to seventy. + +AM also has a manuscript collection, the life history portion of one of +the federal project series, which will contain 2,900 individual +documents, all first-person narratives. AM has in process about 350 +African-American pamphlets, or about 12,000 printed pages for the period +1870-1910. Also in the works are some 4,000 panoramic photographs. AM +has recycled a fair amount of the work done by LC's Prints and +Photographs Division during the Library's optical disk pilot project in +the 1980s. For example, a special division of LC has tooled up and +thought through all the ramifications of electronic presentation of +photographs. Indeed, they are wheeling them out in great barrel loads. +The purpose of AM within the Library, it is hoped, is to catalyze several +of the other special collection divisions which have no particular +experience with, in some cases, mixed feelings about, an activity such as +AM. Moreover, in many cases the divisions may be characterized as not +only lacking experience in "electronifying" things but also in automated +cataloguing. MARC cataloguing as practiced in the United States is +heavily weighted toward the description of monograph and serial +materials, but is much thinner when one enters the world of manuscripts +and things that are held in the Library's music collection and other +units. In response to a comment by LESK, that AM's material is very +heavily photographic, and is so primarily because individual records have +been made for each photograph, FLEISCHHAUER observed that an item-level +catalog record exists, for example, for each photograph in the Detroit +Publishing collection of 25,000 pictures. In the case of the Federal +Writers Project, for which nearly 3,000 documents exist, representing +information from twenty-six different states, AM with the assistance of +Karen STUART of the Manuscript Division will attempt to find some way not +only to have a collection-level record but perhaps a MARC record for each +state, which will then serve as an umbrella for the 100-200 documents +that come under it. But that drama remains to be enacted. The AM staff +is conservative and clings to cataloguing, though of course visitors tout +artificial intelligence and neural networks in a manner that suggests that +perhaps one need not have cataloguing or that much of it could be put aside. + +The matter of SGML coding, FLEISCHHAUER conceded, returned the discussion +to the earlier treated question of quality versus quantity in the Library +of Congress. Of course, text conversion can be done with 100-percent +accuracy, but it means that when one's holdings are as vast as LC's only +a tiny amount will be exposed, whereas permitting lower levels of +accuracy can lead to exposing or sharing larger amounts, but with the +quality correspondingly impaired. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +TWOHIG * A contrary experience concerning electronic options * Volume of +material in the Washington papers and a suggestion of David Packard * +Implications of Packard's suggestion * Transcribing the documents for the +CD-ROM * Accuracy of transcriptions * The CD-ROM edition of the Founding +Fathers documents * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Finding encouragement in a comment of MICHELSON's from the morning +session--that numerous people in the humanities were choosing electronic +options to do their work--Dorothy TWOHIG, editor, The Papers of George +Washington, opened her illustrated talk by noting that her experience +with literary scholars and numerous people in editing was contrary to +MICHELSON's. TWOHIG emphasized literary scholars' complete ignorance of +the technological options available to them or their reluctance or, in +some cases, their downright hostility toward these options. + +After providing an overview of the five Founding Fathers projects +(Jefferson at Princeton, Franklin at Yale, John Adams at the +Massachusetts Historical Society, and Madison down the hall from her at +the University of Virginia), TWOHIG observed that the Washington papers, +like all of the projects, include both sides of the Washington +correspondence and deal with some 135,000 documents to be published with +extensive annotation in eighty to eighty-five volumes, a project that +will not be completed until well into the next century. Thus, it was +with considerable enthusiasm several years ago that the Washington Papers +Project (WPP) greeted David Packard's suggestion that the papers of the +Founding Fathers could be published easily and inexpensively, and to the +great benefit of American scholarship, via CD-ROM. + +In pragmatic terms, funding from the Packard Foundation would expedite +the transcription of thousands of documents waiting to be put on disk in +the WPP offices. Further, since the costs of collecting, editing, and +converting the Founding Fathers documents into letterpress editions were +running into the millions of dollars, and the considerable staffs +involved in all of these projects were devoting their careers to +producing the work, the Packard Foundation's suggestion had a +revolutionary aspect: Transcriptions of the entire corpus of the +Founding Fathers papers would be available on CD-ROM to public and +college libraries, even high schools, at a fraction of the cost-- +$100-$150 for the annual license fee--to produce a limited university +press run of 1,000 of each volume of the published papers at $45-$150 per +printed volume. Given the current budget crunch in educational systems +and the corresponding constraints on librarians in smaller institutions +who wish to add these volumes to their collections, producing the +documents on CD-ROM would likely open a greatly expanded audience for the +papers. TWOHIG stressed, however, that development of the Founding +Fathers CD-ROM is still in its infancy. Serious software problems remain +to be resolved before the material can be put into readable form. + +Funding from the Packard Foundation resulted in a major push to +transcribe the 75,000 or so documents of the Washington papers remaining +to be transcribed onto computer disks. Slides illustrated several of the +problems encountered, for example, the present inability of CD-ROM to +indicate the cross-outs (deleted material) in eighteenth century +documents. TWOHIG next described documents from various periods in the +eighteenth century that have been transcribed in chronological order and +delivered to the Packard offices in California, where they are converted +to the CD-ROM, a process that is expected to consume five years to +complete (that is, reckoning from David Packard's suggestion made several +years ago, until about July 1994). TWOHIG found an encouraging +indication of the project's benefits in the ongoing use made by scholars +of the search functions of the CD-ROM, particularly in reducing the time +spent in manually turning the pages of the Washington papers. + +TWOHIG next furnished details concerning the accuracy of transcriptions. +For instance, the insertion of thousands of documents on the CD-ROM +currently does not permit each document to be verified against the +original manuscript several times as in the case of documents that appear +in the published edition. However, the transcriptions receive a cursory +check for obvious typos, the misspellings of proper names, and other +errors from the WPP CD-ROM editor. Eventually, all documents that appear +in the electronic version will be checked by project editors. Although +this process has met with opposition from some of the editors on the +grounds that imperfect work may leave their offices, the advantages in +making this material available as a research tool outweigh fears about the +misspelling of proper names and other relatively minor editorial matters. + +Completion of all five Founding Fathers projects (i.e., retrievability +and searchability of all of the documents by proper names, alternate +spellings, or varieties of subjects) will provide one of the richest +sources of this size for the history of the United States in the latter +part of the eighteenth century. Further, publication on CD-ROM will +allow editors to include even minutiae, such as laundry lists, not +included in the printed volumes. + +It seems possible that the extensive annotation provided in the printed +volumes eventually will be added to the CD-ROM edition, pending +negotiations with the publishers of the papers. At the moment, the +Founding Fathers CD-ROM is accessible only on the IBYCUS, a computer +developed out of the Thesaurus Linguae Graecae project and designed for +the use of classical scholars. There are perhaps 400 IBYCUS computers in +the country, most of which are in university classics departments. +Ultimately, it is anticipated that the CD-ROM edition of the Founding +Fathers documents will run on any IBM-compatible or Macintosh computer +with a CD-ROM drive. Numerous changes in the software will also occur +before the project is completed. (Editor's note: an IBYCUS was +unavailable to demonstrate the CD-ROM.) + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Several additional features of WPP clarified * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Discussion following TWOHIG's presentation served to clarify several +additional features, including (1) that the project's primary +intellectual product consists in the electronic transcription of the +material; (2) that the text transmitted to the CD-ROM people is not +marked up; (3) that cataloging and subject-indexing of the material +remain to be worked out (though at this point material can be retrieved +by name); and (4) that because all the searching is done in the hardware, +the IBYCUS is designed to read a CD-ROM which contains only sequential +text files. Technically, it then becomes very easy to read the material +off and put it on another device. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LEBRON * Overview of the history of the joint project between AAAS and +OCLC * Several practices the on-line environment shares with traditional +publishing on hard copy * Several technical and behavioral barriers to +electronic publishing * How AAAS and OCLC arrived at the subject of +clinical trials * Advantages of the electronic format and other features +of OJCCT * An illustrated tour of the journal * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Maria LEBRON, managing editor, The Online Journal of Current Clinical +Trials (OJCCT), presented an illustrated overview of the history of the +joint project between the American Association for the Advancement of +Science (AAAS) and the Online Computer Library Center, Inc. (OCLC). The +joint venture between AAAS and OCLC owes its beginning to a +reorganization launched by the new chief executive officer at OCLC about +three years ago and combines the strengths of these two disparate +organizations. In short, OJCCT represents the process of scholarly +publishing on line. + +LEBRON next discussed several practices the on-line environment shares +with traditional publishing on hard copy--for example, peer review of +manuscripts--that are highly important in the academic world. LEBRON +noted in particular the implications of citation counts for tenure +committees and grants committees. In the traditional hard-copy +environment, citation counts are readily demonstrable, whereas the +on-line environment represents an ethereal medium to most academics. + +LEBRON remarked several technical and behavioral barriers to electronic +publishing, for instance, the problems in transmission created by special +characters or by complex graphics and halftones. In addition, she noted +economic limitations such as the storage costs of maintaining back issues +and market or audience education. + +Manuscripts cannot be uploaded to OJCCT, LEBRON explained, because it is +not a bulletin board or E-mail, forms of electronic transmission of +information that have created an ambience clouding people's understanding +of what the journal is attempting to do. OJCCT, which publishes +peer-reviewed medical articles dealing with the subject of clinical +trials, includes text, tabular material, and graphics, although at this +time it can transmit only line illustrations. + +Next, LEBRON described how AAAS and OCLC arrived at the subject of +clinical trials: It is 1) a highly statistical discipline that 2) does +not require halftones but can satisfy the needs of its audience with line +illustrations and graphic material, and 3) there is a need for the speedy +dissemination of high-quality research results. Clinical trials are +research activities that involve the administration of a test treatment +to some experimental unit in order to test its usefulness before it is +made available to the general population. LEBRON proceeded to give +additional information on OJCCT concerning its editor-in-chief, editorial +board, editorial content, and the types of articles it publishes +(including peer-reviewed research reports and reviews), as well as +features shared by other traditional hard-copy journals. + +Among the advantages of the electronic format are faster dissemination of +information, including raw data, and the absence of space constraints +because pages do not exist. (This latter fact creates an interesting +situation when it comes to citations.) Nor are there any issues. AAAS's +capacity to download materials directly from the journal to a +subscriber's printer, hard drive, or floppy disk helps ensure highly +accurate transcription. Other features of OJCCT include on-screen alerts +that allow linkage of subsequently published documents to the original +documents; on-line searching by subject, author, title, etc.; indexing of +every single word that appears in an article; viewing access to an +article by component (abstract, full text, or graphs); numbered +paragraphs to replace page counts; publication in Science every thirty +days of indexing of all articles published in the journal; +typeset-quality screens; and Hypertext links that enable subscribers to +bring up Medline abstracts directly without leaving the journal. + +After detailing the two primary ways to gain access to the journal, +through the OCLC network and Compuserv if one desires graphics or through +the Internet if just an ASCII file is desired, LEBRON illustrated the +speedy editorial process and the coding of the document using SGML tags +after it has been accepted for publication. She also gave an illustrated +tour of the journal, its search-and-retrieval capabilities in particular, +but also including problems associated with scanning in illustrations, +and the importance of on-screen alerts to the medical profession re +retractions or corrections, or more frequently, editorials, letters to +the editors, or follow-up reports. She closed by inviting the audience +to join AAAS on 1 July, when OJCCT was scheduled to go on-line. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Additional features of OJCCT * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +In the lengthy discussion that followed LEBRON's presentation, these +points emerged: + + * The SGML text can be tailored as users wish. + + * All these articles have a fairly simple document definition. + + * Document-type definitions (DTDs) were developed and given to OJCCT + for coding. + + * No articles will be removed from the journal. (Because there are + no back issues, there are no lost issues either. Once a subscriber + logs onto the journal he or she has access not only to the currently + published materials, but retrospectively to everything that has been + published in it. Thus the table of contents grows bigger. The date + of publication serves to distinguish between currently published + materials and older materials.) + + * The pricing system for the journal resembles that for most medical + journals: for 1992, $95 for a year, plus telecommunications charges + (there are no connect time charges); for 1993, $110 for the + entire year for single users, though the journal can be put on a + local area network (LAN). However, only one person can access the + journal at a time. Site licenses may come in the future. + + * AAAS is working closely with colleagues at OCLC to display + mathematical equations on screen. + + * Without compromising any steps in the editorial process, the + technology has reduced the time lag between when a manuscript is + originally submitted and the time it is accepted; the review process + does not differ greatly from the standard six-to-eight weeks + employed by many of the hard-copy journals. The process still + depends on people. + + * As far as a preservation copy is concerned, articles will be + maintained on the computer permanently and subscribers, as part of + their subscription, will receive a microfiche-quality archival copy + of everything published during that year; in addition, reprints can + be purchased in much the same way as in a hard-copy environment. + Hard copies are prepared but are not the primary medium for the + dissemination of the information. + + * Because OJCCT is not yet on line, it is difficult to know how many + people would simply browse through the journal on the screen as + opposed to downloading the whole thing and printing it out; a mix of + both types of users likely will result. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +PERSONIUS * Developments in technology over the past decade * The CLASS +Project * Advantages for technology and for the CLASS Project * +Developing a network application an underlying assumption of the project +* Details of the scanning process * Print-on-demand copies of books * +Future plans include development of a browsing tool * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Lynne PERSONIUS, assistant director, Cornell Information Technologies for +Scholarly Information Services, Cornell University, first commented on +the tremendous impact that developments in technology over the past ten +years--networking, in particular--have had on the way information is +handled, and how, in her own case, these developments have counterbalanced +Cornell's relative geographical isolation. Other significant technologies +include scanners, which are much more sophisticated than they were ten years +ago; mass storage and the dramatic savings that result from it in terms of +both space and money relative to twenty or thirty years ago; new and +improved printing technologies, which have greatly affected the distribution +of information; and, of course, digital technologies, whose applicability to +library preservation remains at issue. + +Given that context, PERSONIUS described the College Library Access and +Storage System (CLASS) Project, a library preservation project, +primarily, and what has been accomplished. Directly funded by the +Commission on Preservation and Access and by the Xerox Corporation, which +has provided a significant amount of hardware, the CLASS Project has been +working with a development team at Xerox to develop a software +application tailored to library preservation requirements. Within +Cornell, participants in the project have been working jointly with both +library and information technologies. The focus of the project has been +on reformatting and saving books that are in brittle condition. +PERSONIUS showed Workshop participants a brittle book, and described how +such books were the result of developments in papermaking around the +beginning of the Industrial Revolution. The papermaking process was +changed so that a significant amount of acid was introduced into the +actual paper itself, which deteriorates as it sits on library shelves. + +One of the advantages for technology and for the CLASS Project is that +the information in brittle books is mostly out of copyright and thus +offers an opportunity to work with material that requires library +preservation, and to create and work on an infrastructure to save the +material. Acknowledging the familiarity of those working in preservation +with this information, PERSONIUS noted that several things are being +done: the primary preservation technology used today is photocopying of +brittle material. Saving the intellectual content of the material is the +main goal. With microfilm copy, the intellectual content is preserved on +the assumption that in the future the image can be reformatted in any +other way that then exists. + +An underlying assumption of the CLASS Project from the beginning was +that it would develop a network application. Project staff scan books +at a workstation located in the library, near the brittle material. +An image-server filing system is located at a distance from that +workstation, and a printer is located in another building. All of the +materials digitized and stored on the image-filing system are cataloged +in the on-line catalogue. In fact, a record for each of these electronic +books is stored in the RLIN database so that a record exists of what is +in the digital library throughout standard catalogue procedures. In the +future, researchers working from their own workstations in their offices, +or their networks, will have access--wherever they might be--through a +request server being built into the new digital library. A second +assumption is that the preferred means of finding the material will be by +looking through a catalogue. PERSONIUS described the scanning process, +which uses a prototype scanner being developed by Xerox and which scans a +very high resolution image at great speed. Another significant feature, +because this is a preservation application, is the placing of the pages +that fall apart one for one on the platen. Ordinarily, a scanner could +be used with some sort of a document feeder, but because of this +application that is not feasible. Further, because CLASS is a +preservation application, after the paper replacement is made there, a +very careful quality control check is performed. An original book is +compared to the printed copy and verification is made, before proceeding, +that all of the image, all of the information, has been captured. Then, +a new library book is produced: The printed images are rebound by a +commercial binder and a new book is returned to the shelf. +Significantly, the books returned to the library shelves are beautiful +and useful replacements on acid-free paper that should last a long time, +in effect, the equivalent of preservation photocopies. Thus, the project +has a library of digital books. In essence, CLASS is scanning and +storing books as 600 dot-per-inch bit-mapped images, compressed using +Group 4 CCITT (i.e., the French acronym for International Consultative +Committee for Telegraph and Telephone) compression. They are stored as +TIFF files on an optical filing system that is composed of a database +used for searching and locating the books and an optical jukebox that +stores 64 twelve-inch platters. A very-high-resolution printed copy of +these books at 600 dots per inch is created, using a Xerox DocuTech +printer to make the paper replacements on acid-free paper. + +PERSONIUS maintained that the CLASS Project presents an opportunity to +introduce people to books as digital images by using a paper medium. +Books are returned to the shelves while people are also given the ability +to print on demand--to make their own copies of books. (PERSONIUS +distributed copies of an engineering journal published by engineering +students at Cornell around 1900 as an example of what a print-on-demand +copy of material might be like. This very cheap copy would be available +to people to use for their own research purposes and would bridge the gap +between an electronic work and the paper that readers like to have.) +PERSONIUS then attempted to illustrate a very early prototype of +networked access to this digital library. Xerox Corporation has +developed a prototype of a view station that can send images across the +network to be viewed. + +The particular library brought down for demonstration contained two +mathematics books. CLASS is developing and will spend the next year +developing an application that allows people at workstations to browse +the books. Thus, CLASS is developing a browsing tool, on the assumption +that users do not want to read an entire book from a workstation, but +would prefer to be able to look through and decide if they would like to +have a printed copy of it. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Re retrieval software * "Digital file copyright" * Scanning +rate during production * Autosegmentation * Criteria employed in +selecting books for scanning * Compression and decompression of images * +OCR not precluded * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +During the question-and-answer period that followed her presentation, +PERSONIUS made these additional points: + + * Re retrieval software, Cornell is developing a Unix-based server + as well as clients for the server that support multiple platforms + (Macintosh, IBM and Sun workstations), in the hope that people from + any of those platforms will retrieve books; a further operating + assumption is that standard interfaces will be used as much as + possible, where standards can be put in place, because CLASS + considers this retrieval software a library application and would + like to be able to look at material not only at Cornell but at other + institutions. + + * The phrase "digital file copyright by Cornell University" was + added at the advice of Cornell's legal staff with the caveat that it + probably would not hold up in court. Cornell does not want people + to copy its books and sell them but would like to keep them + available for use in a library environment for library purposes. + + * In production the scanner can scan about 300 pages per hour, + capturing 600 dots per inch. + + * The Xerox software has filters to scan halftone material and avoid + the moire patterns that occur when halftone material is scanned. + Xerox has been working on hardware and software that would enable + the scanner itself to recognize this situation and deal with it + appropriately--a kind of autosegmentation that would enable the + scanner to handle halftone material as well as text on a single page. + + * The books subjected to the elaborate process described above were + selected because CLASS is a preservation project, with the first 500 + books selected coming from Cornell's mathematics collection, because + they were still being heavily used and because, although they were + in need of preservation, the mathematics library and the mathematics + faculty were uncomfortable having them microfilmed. (They wanted a + printed copy.) Thus, these books became a logical choice for this + project. Other books were chosen by the project's selection committees + for experiments with the technology, as well as to meet a demand or need. + + * Images will be decompressed before they are sent over the line; at + this time they are compressed and sent to the image filing system + and then sent to the printer as compressed images; they are returned + to the workstation as compressed 600-dpi images and the workstation + decompresses and scales them for display--an inefficient way to + access the material though it works quite well for printing and + other purposes. + + * CLASS is also decompressing on Macintosh and IBM, a slow process + right now. Eventually, compression and decompression will take + place on an image conversion server. Trade-offs will be made, based + on future performance testing, concerning where the file is + compressed and what resolution image is sent. + + * OCR has not been precluded; images are being stored that have been + scanned at a high resolution, which presumably would suit them well + to an OCR process. Because the material being scanned is about 100 + years old and was printed with less-than-ideal technologies, very + early and preliminary tests have not produced good results. But the + project is capturing an image that is of sufficient resolution to be + subjected to OCR in the future. Moreover, the system architecture + and the system plan have a logical place to store an OCR image if it + has been captured. But that is not being done now. + + ****** + +SESSION III. DISTRIBUTION, NETWORKS, AND NETWORKING: OPTIONS FOR +DISSEMINATION + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +ZICH * Issues pertaining to CD-ROMs * Options for publishing in CD-ROM * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Robert ZICH, special assistant to the associate librarian for special +projects, Library of Congress, and moderator of this session, first noted +the blessed but somewhat awkward circumstance of having four very +distinguished people representing networks and networking or at least +leaning in that direction, while lacking anyone to speak from the +strongest possible background in CD-ROMs. ZICH expressed the hope that +members of the audience would join the discussion. He stressed the +subtitle of this particular session, "Options for Dissemination," and, +concerning CD-ROMs, the importance of determining when it would be wise +to consider dissemination in CD-ROM versus networks. A shopping list of +issues pertaining to CD-ROMs included: the grounds for selecting +commercial publishers, and in-house publication where possible versus +nonprofit or government publication. A similar list for networks +included: determining when one should consider dissemination through a +network, identifying the mechanisms or entities that exist to place items +on networks, identifying the pool of existing networks, determining how a +producer would choose between networks, and identifying the elements of +a business arrangement in a network. + +Options for publishing in CD-ROM: an outside publisher versus +self-publication. If an outside publisher is used, it can be nonprofit, +such as the Government Printing Office (GPO) or the National Technical +Information Service (NTIS), in the case of government. The pros and cons +associated with employing an outside publisher are obvious. Among the +pros, there is no trouble getting accepted. One pays the bill and, in +effect, goes one's way. Among the cons, when one pays an outside +publisher to perform the work, that publisher will perform the work it is +obliged to do, but perhaps without the production expertise and skill in +marketing and dissemination that some would seek. There is the body of +commercial publishers that do possess that kind of expertise in +distribution and marketing but that obviously are selective. In +self-publication, one exercises full control, but then one must handle +matters such as distribution and marketing. Such are some of the options +for publishing in the case of CD-ROM. + +In the case of technical and design issues, which are also important, +there are many matters which many at the Workshop already knew a good +deal about: retrieval system requirements and costs, what to do about +images, the various capabilities and platforms, the trade-offs between +cost and performance, concerns about local-area networkability, +interoperability, etc. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LYNCH * Creating networked information is different from using networks +as an access or dissemination vehicle * Networked multimedia on a large +scale does not yet work * Typical CD-ROM publication model a two-edged +sword * Publishing information on a CD-ROM in the present world of +immature standards * Contrast between CD-ROM and network pricing * +Examples demonstrated earlier in the day as a set of insular information +gems * Paramount need to link databases * Layering to become increasingly +necessary * Project NEEDS and the issues of information reuse and active +versus passive use * X-Windows as a way of differentiating between +network access and networked information * Barriers to the distribution +of networked multimedia information * Need for good, real-time delivery +protocols * The question of presentation integrity in client-server +computing in the academic world * Recommendations for producing multimedia ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Clifford LYNCH, director, Library Automation, University of California, +opened his talk with the general observation that networked information +constituted a difficult and elusive topic because it is something just +starting to develop and not yet fully understood. LYNCH contended that +creating genuinely networked information was different from using +networks as an access or dissemination vehicle and was more sophisticated +and more subtle. He invited the members of the audience to extrapolate, +from what they heard about the preceding demonstration projects, to what +sort of a world of electronics information--scholarly, archival, +cultural, etc.--they wished to end up with ten or fifteen years from now. +LYNCH suggested that to extrapolate directly from these projects would +produce unpleasant results. + +Putting the issue of CD-ROM in perspective before getting into +generalities on networked information, LYNCH observed that those engaged +in multimedia today who wish to ship a product, so to say, probably do +not have much choice except to use CD-ROM: networked multimedia on a +large scale basically does not yet work because the technology does not +exist. For example, anybody who has tried moving images around over the +Internet knows that this is an exciting touch-and-go process, a +fascinating and fertile area for experimentation, research, and +development, but not something that one can become deeply enthusiastic +about committing to production systems at this time. + +This situation will change, LYNCH said. He differentiated CD-ROM from +the practices that have been followed up to now in distributing data on +CD-ROM. For LYNCH the problem with CD-ROM is not its portability or its +slowness but the two-edged sword of having the retrieval application and +the user interface inextricably bound up with the data, which is the +typical CD-ROM publication model. It is not a case of publishing data +but of distributing a typically stand-alone, typically closed system, +all--software, user interface, and data--on a little disk. Hence, all +the between-disk navigational issues as well as the impossibility in most +cases of integrating data on one disk with that on another. Most CD-ROM +retrieval software does not network very gracefully at present. However, +in the present world of immature standards and lack of understanding of +what network information is or what the ground rules are for creating or +using it, publishing information on a CD-ROM does add value in a very +real sense. + +LYNCH drew a contrast between CD-ROM and network pricing and in doing so +highlighted something bizarre in information pricing. A large +institution such as the University of California has vendors who will +offer to sell information on CD-ROM for a price per year in four digits, +but for the same data (e.g., an abstracting and indexing database) on +magnetic tape, regardless of how many people may use it concurrently, +will quote a price in six digits. + +What is packaged with the CD-ROM in one sense adds value--a complete +access system, not just raw, unrefined information--although it is not +generally perceived that way. This is because the access software, +although it adds value, is viewed by some people, particularly in the +university environment where there is a very heavy commitment to +networking, as being developed in the wrong direction. + +Given that context, LYNCH described the examples demonstrated as a set of +insular information gems--Perseus, for example, offers nicely linked +information, but would be very difficult to integrate with other +databases, that is, to link together seamlessly with other source files +from other sources. It resembles an island, and in this respect is +similar to numerous stand-alone projects that are based on videodiscs, +that is, on the single-workstation concept. + +As scholarship evolves in a network environment, the paramount need will +be to link databases. We must link personal databases to public +databases, to group databases, in fairly seamless ways--which is +extremely difficult in the environments under discussion with copies of +databases proliferating all over the place. + +The notion of layering also struck LYNCH as lurking in several of the +projects demonstrated. Several databases in a sense constitute +information archives without a significant amount of navigation built in. +Educators, critics, and others will want a layered structure--one that +defines or links paths through the layers to allow users to reach +specific points. In LYNCH's view, layering will become increasingly +necessary, and not just within a single resource but across resources +(e.g., tracing mythology and cultural themes across several classics +databases as well as a database of Renaissance culture). This ability to +organize resources, to build things out of multiple other things on the +network or select pieces of it, represented for LYNCH one of the key +aspects of network information. + +Contending that information reuse constituted another significant issue, +LYNCH commended to the audience's attention Project NEEDS (i.e., National +Engineering Education Delivery System). This project's objective is to +produce a database of engineering courseware as well as the components +that can be used to develop new courseware. In a number of the existing +applications, LYNCH said, the issue of reuse (how much one can take apart +and reuse in other applications) was not being well considered. He also +raised the issue of active versus passive use, one aspect of which is +how much information will be manipulated locally by users. Most people, +he argued, may do a little browsing and then will wish to print. LYNCH +was uncertain how these resources would be used by the vast majority of +users in the network environment. + +LYNCH next said a few words about X-Windows as a way of differentiating +between network access and networked information. A number of the +applications demonstrated at the Workshop could be rewritten to use X +across the network, so that one could run them from any X-capable device- +-a workstation, an X terminal--and transact with a database across the +network. Although this opens up access a little, assuming one has enough +network to handle it, it does not provide an interface to develop a +program that conveniently integrates information from multiple databases. +X is a viewing technology that has limits. In a real sense, it is just a +graphical version of remote log-in across the network. X-type applications +represent only one step in the progression towards real access. + +LYNCH next discussed barriers to the distribution of networked multimedia +information. The heart of the problem is a lack of standards to provide +the ability for computers to talk to each other, retrieve information, +and shuffle it around fairly casually. At the moment, little progress is +being made on standards for networked information; for example, present +standards do not cover images, digital voice, and digital video. A +useful tool kit of exchange formats for basic texts is only now being +assembled. The synchronization of content streams (i.e., synchronizing a +voice track to a video track, establishing temporal relations between +different components in a multimedia object) constitutes another issue +for networked multimedia that is just beginning to receive attention. + +Underlying network protocols also need some work; good, real-time +delivery protocols on the Internet do not yet exist. In LYNCH's view, +highly important in this context is the notion of networked digital +object IDs, the ability of one object on the network to point to another +object (or component thereof) on the network. Serious bandwidth issues +also exist. LYNCH was uncertain if billion-bit-per-second networks would +prove sufficient if numerous people ran video in parallel. + +LYNCH concluded by offering an issue for database creators to consider, +as well as several comments about what might constitute good trial +multimedia experiments. In a networked information world the database +builder or service builder (publisher) does not exercise the same +extensive control over the integrity of the presentation; strange +programs "munge" with one's data before the user sees it. Serious +thought must be given to what guarantees integrity of presentation. Part +of that is related to where one draws the boundaries around a networked +information service. This question of presentation integrity in +client-server computing has not been stressed enough in the academic +world, LYNCH argued, though commercial service providers deal with it +regularly. + +Concerning multimedia, LYNCH observed that good multimedia at the moment +is hideously expensive to produce. He recommended producing multimedia +with either very high sale value, or multimedia with a very long life +span, or multimedia that will have a very broad usage base and whose +costs therefore can be amortized among large numbers of users. In this +connection, historical and humanistically oriented material may be a good +place to start, because it tends to have a longer life span than much of +the scientific material, as well as a wider user base. LYNCH noted, for +example, that American Memory fits many of the criteria outlined. He +remarked the extensive discussion about bringing the Internet or the +National Research and Education Network (NREN) into the K-12 environment +as a way of helping the American educational system. + +LYNCH closed by noting that the kinds of applications demonstrated struck +him as excellent justifications of broad-scale networking for K-12, but +that at this time no "killer" application exists to mobilize the K-12 +community to obtain connectivity. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Dearth of genuinely interesting applications on the network +a slow-changing situation * The issue of the integrity of presentation in +a networked environment * Several reasons why CD-ROM software does not +network * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +During the discussion period that followed LYNCH's presentation, several +additional points were made. + +LYNCH reiterated even more strongly his contention that, historically, +once one goes outside high-end science and the group of those who need +access to supercomputers, there is a great dearth of genuinely +interesting applications on the network. He saw this situation changing +slowly, with some of the scientific databases and scholarly discussion +groups and electronic journals coming on as well as with the availability +of Wide Area Information Servers (WAIS) and some of the databases that +are being mounted there. However, many of those things do not seem to +have piqued great popular interest. For instance, most high school +students of LYNCH's acquaintance would not qualify as devotees of serious +molecular biology. + +Concerning the issue of the integrity of presentation, LYNCH believed +that a couple of information providers have laid down the law at least on +certain things. For example, his recollection was that the National +Library of Medicine feels strongly that one needs to employ the +identifier field if he or she is to mount a database commercially. The +problem with a real networked environment is that one does not know who +is reformatting and reprocessing one's data when one enters a client +server mode. It becomes anybody's guess, for example, if the network +uses a Z39.50 server, or what clients are doing with one's data. A data +provider can say that his contract will only permit clients to have +access to his data after he vets them and their presentation and makes +certain it suits him. But LYNCH held out little expectation that the +network marketplace would evolve in that way, because it required too +much prior negotiation. + +CD-ROM software does not network for a variety of reasons, LYNCH said. +He speculated that CD-ROM publishers are not eager to have their products +really hook into wide area networks, because they fear it will make their +data suppliers nervous. Moreover, until relatively recently, one had to +be rather adroit to run a full TCP/IP stack plus applications on a +PC-size machine, whereas nowadays it is becoming easier as PCs grow +bigger and faster. LYNCH also speculated that software providers had not +heard from their customers until the last year or so, or had not heard +from enough of their customers. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +BESSER * Implications of disseminating images on the network; planning +the distribution of multimedia documents poses two critical +implementation problems * Layered approach represents the way to deal +with users' capabilities * Problems in platform design; file size and its +implications for networking * Transmission of megabyte size images +impractical * Compression and decompression at the user's end * Promising +trends for compression * A disadvantage of using X-Windows * A project at +the Smithsonian that mounts images on several networks * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Howard BESSER, School of Library and Information Science, University of +Pittsburgh, spoke primarily about multimedia, focusing on images and the +broad implications of disseminating them on the network. He argued that +planning the distribution of multimedia documents posed two critical +implementation problems, which he framed in the form of two questions: +1) What platform will one use and what hardware and software will users +have for viewing of the material? and 2) How can one deliver a +sufficiently robust set of information in an accessible format in a +reasonable amount of time? Depending on whether network or CD-ROM is the +medium used, this question raises different issues of storage, +compression, and transmission. + +Concerning the design of platforms (e.g., sound, gray scale, simple +color, etc.) and the various capabilities users may have, BESSER +maintained that a layered approach was the way to deal with users' +capabilities. A result would be that users with less powerful +workstations would simply have less functionality. He urged members of +the audience to advocate standards and accompanying software that handle +layered functionality across a wide variety of platforms. + +BESSER also addressed problems in platform design, namely, deciding how +large a machine to design for situations when the largest number of users +have the lowest level of the machine, and one desires higher +functionality. BESSER then proceeded to the question of file size and +its implications for networking. He discussed still images in the main. +For example, a digital color image that fills the screen of a standard +mega-pel workstation (Sun or Next) will require one megabyte of storage +for an eight-bit image or three megabytes of storage for a true color or +twenty-four-bit image. Lossless compression algorithms (that is, +computational procedures in which no data is lost in the process of +compressing [and decompressing] an image--the exact bit-representation is +maintained) might bring storage down to a third of a megabyte per image, +but not much further than that. The question of size makes it difficult +to fit an appropriately sized set of these images on a single disk or to +transmit them quickly enough on a network. + +With these full screen mega-pel images that constitute a third of a +megabyte, one gets 1,000-3,000 full-screen images on a one-gigabyte disk; +a standard CD-ROM represents approximately 60 percent of that. Storing +images the size of a PC screen (just 8 bit color) increases storage +capacity to 4,000-12,000 images per gigabyte; 60 percent of that gives +one the size of a CD-ROM, which in turn creates a major problem. One +cannot have full-screen, full-color images with lossless compression; one +must compress them or use a lower resolution. For megabyte-size images, +anything slower than a T-1 speed is impractical. For example, on a +fifty-six-kilobaud line, it takes three minutes to transfer a +one-megabyte file, if it is not compressed; and this speed assumes ideal +circumstances (no other user contending for network bandwidth). Thus, +questions of disk access, remote display, and current telephone +connection speed make transmission of megabyte-size images impractical. + +BESSER then discussed ways to deal with these large images, for example, +compression and decompression at the user's end. In this connection, the +issues of how much one is willing to lose in the compression process and +what image quality one needs in the first place are unknown. But what is +known is that compression entails some loss of data. BESSER urged that +more studies be conducted on image quality in different situations, for +example, what kind of images are needed for what kind of disciplines, and +what kind of image quality is needed for a browsing tool, an intermediate +viewing tool, and archiving. + +BESSER remarked two promising trends for compression: from a technical +perspective, algorithms that use what is called subjective redundancy +employ principles from visual psycho-physics to identify and remove +information from the image that the human eye cannot perceive; from an +interchange and interoperability perspective, the JPEG (i.e., Joint +Photographic Experts Group, an ISO standard) compression algorithms also +offer promise. These issues of compression and decompression, BESSER +argued, resembled those raised earlier concerning the design of different +platforms. Gauging the capabilities of potential users constitutes a +primary goal. BESSER advocated layering or separating the images from +the applications that retrieve and display them, to avoid tying them to +particular software. + +BESSER detailed several lessons learned from his work at Berkeley with +Imagequery, especially the advantages and disadvantages of using +X-Windows. In the latter category, for example, retrieval is tied +directly to one's data, an intolerable situation in the long run on a +networked system. Finally, BESSER described a project of Jim Wallace at +the Smithsonian Institution, who is mounting images in a extremely +rudimentary way on the Compuserv and Genie networks and is preparing to +mount them on America On Line. Although the average user takes over +thirty minutes to download these images (assuming a fairly fast modem), +nevertheless, images have been downloaded 25,000 times. + +BESSER concluded his talk with several comments on the business +arrangement between the Smithsonian and Compuserv. He contended that not +enough is known concerning the value of images. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Creating digitized photographic collections nearly +impossible except with large organizations like museums * Need for study +to determine quality of images users will tolerate * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +During the brief exchange between LESK and BESSER that followed, several +clarifications emerged. + +LESK argued that the photographers were far ahead of BESSER: It is +almost impossible to create such digitized photographic collections +except with large organizations like museums, because all the +photographic agencies have been going crazy about this and will not sign +licensing agreements on any sort of reasonable terms. LESK had heard +that National Geographic, for example, had tried to buy the right to use +some image in some kind of educational production for $100 per image, but +the photographers will not touch it. They want accounting and payment +for each use, which cannot be accomplished within the system. BESSER +responded that a consortium of photographers, headed by a former National +Geographic photographer, had started assembling its own collection of +electronic reproductions of images, with the money going back to the +cooperative. + +LESK contended that BESSER was unnecessarily pessimistic about multimedia +images, because people are accustomed to low-quality images, particularly +from video. BESSER urged the launching of a study to determine what +users would tolerate, what they would feel comfortable with, and what +absolutely is the highest quality they would ever need. Conceding that +he had adopted a dire tone in order to arouse people about the issue, +BESSER closed on a sanguine note by saying that he would not be in this +business if he did not think that things could be accomplished. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LARSEN * Issues of scalability and modularity * Geometric growth of the +Internet and the role played by layering * Basic functions sustaining +this growth * A library's roles and functions in a network environment * +Effects of implementation of the Z39.50 protocol for information +retrieval on the library system * The trade-off between volumes of data +and its potential usage * A snapshot of current trends * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Ronald LARSEN, associate director for information technology, University +of Maryland at College Park, first addressed the issues of scalability +and modularity. He noted the difficulty of anticipating the effects of +orders-of-magnitude growth, reflecting on the twenty years of experience +with the Arpanet and Internet. Recalling the day's demonstrations of +CD-ROM and optical disk material, he went on to ask if the field has yet +learned how to scale new systems to enable delivery and dissemination +across large-scale networks. + +LARSEN focused on the geometric growth of the Internet from its inception +circa 1969 to the present, and the adjustments required to respond to +that rapid growth. To illustrate the issue of scalability, LARSEN +considered computer networks as including three generic components: +computers, network communication nodes, and communication media. Each +component scales (e.g., computers range from PCs to supercomputers; +network nodes scale from interface cards in a PC through sophisticated +routers and gateways; and communication media range from 2,400-baud +dial-up facilities through 4.5-Mbps backbone links, and eventually to +multigigabit-per-second communication lines), and architecturally, the +components are organized to scale hierarchically from local area networks +to international-scale networks. Such growth is made possible by +building layers of communication protocols, as BESSER pointed out. +By layering both physically and logically, a sense of scalability is +maintained from local area networks in offices, across campuses, through +bridges, routers, campus backbones, fiber-optic links, etc., up into +regional networks and ultimately into national and international +networks. + +LARSEN then illustrated the geometric growth over a two-year period-- +through September 1991--of the number of networks that comprise the +Internet. This growth has been sustained largely by the availability of +three basic functions: electronic mail, file transfer (ftp), and remote +log-on (telnet). LARSEN also reviewed the growth in the kind of traffic +that occurs on the network. Network traffic reflects the joint contributions +of a larger population of users and increasing use per user. Today one sees +serious applications involving moving images across the network--a rarity +ten years ago. LARSEN recalled and concurred with BESSER's main point +that the interesting problems occur at the application level. + +LARSEN then illustrated a model of a library's roles and functions in a +network environment. He noted, in particular, the placement of on-line +catalogues onto the network and patrons obtaining access to the library +increasingly through local networks, campus networks, and the Internet. +LARSEN supported LYNCH's earlier suggestion that we need to address +fundamental questions of networked information in order to build +environments that scale in the information sense as well as in the +physical sense. + +LARSEN supported the role of the library system as the access point into +the nation's electronic collections. Implementation of the Z39.50 +protocol for information retrieval would make such access practical and +feasible. For example, this would enable patrons in Maryland to search +California libraries, or other libraries around the world that are +conformant with Z39.50 in a manner that is familiar to University of +Maryland patrons. This client-server model also supports moving beyond +secondary content into primary content. (The notion of how one links +from secondary content to primary content, LARSEN said, represents a +fundamental problem that requires rigorous thought.) After noting +numerous network experiments in accessing full-text materials, including +projects supporting the ordering of materials across the network, LARSEN +revisited the issue of transmitting high-density, high-resolution color +images across the network and the large amounts of bandwidth they +require. He went on to address the bandwidth and synchronization +problems inherent in sending full-motion video across the network. + +LARSEN illustrated the trade-off between volumes of data in bytes or +orders of magnitude and the potential usage of that data. He discussed +transmission rates (particularly, the time it takes to move various forms +of information), and what one could do with a network supporting +multigigabit-per-second transmission. At the moment, the network +environment includes a composite of data-transmission requirements, +volumes and forms, going from steady to bursty (high-volume) and from +very slow to very fast. This aggregate must be considered in the design, +construction, and operation of multigigabyte networks. + +LARSEN's objective is to use the networks and library systems now being +constructed to increase access to resources wherever they exist, and +thus, to evolve toward an on-line electronic virtual library. + +LARSEN concluded by offering a snapshot of current trends: continuing +geometric growth in network capacity and number of users; slower +development of applications; and glacial development and adoption of +standards. The challenge is to design and develop each new application +system with network access and scalability in mind. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +BROWNRIGG * Access to the Internet cannot be taken for granted * Packet +radio and the development of MELVYL in 1980-81 in the Division of Library +Automation at the University of California * Design criteria for packet +radio * A demonstration project in San Diego and future plans * Spread +spectrum * Frequencies at which the radios will run and plans to +reimplement the WAIS server software in the public domain * Need for an +infrastructure of radios that do not move around * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Edwin BROWNRIGG, executive director, Memex Research Institute, first +polled the audience in order to seek out regular users of the Internet as +well as those planning to use it some time in the future. With nearly +everybody in the room falling into one category or the other, BROWNRIGG +made a point re access, namely that numerous individuals, especially those +who use the Internet every day, take for granted their access to it, the +speeds with which they are connected, and how well it all works. +However, as BROWNRIGG discovered between 1987 and 1989 in Australia, +if one wants access to the Internet but cannot afford it or has some +physical boundary that prevents her or him from gaining access, it can +be extremely frustrating. He suggested that because of economics and +physical barriers we were beginning to create a world of haves and have-nots +in the process of scholarly communication, even in the United States. + +BROWNRIGG detailed the development of MELVYL in academic year 1980-81 in +the Division of Library Automation at the University of California, in +order to underscore the issue of access to the system, which at the +outset was extremely limited. In short, the project needed to build a +network, which at that time entailed use of satellite technology, that is, +putting earth stations on campus and also acquiring some terrestrial links +from the State of California's microwave system. The installation of +satellite links, however, did not solve the problem (which actually +formed part of a larger problem involving politics and financial resources). +For while the project team could get a signal onto a campus, it had no means +of distributing the signal throughout the campus. The solution involved +adopting a recent development in wireless communication called packet radio, +which combined the basic notion of packet-switching with radio. The project +used this technology to get the signal from a point on campus where it +came down, an earth station for example, into the libraries, because it +found that wiring the libraries, especially the older marble buildings, +would cost $2,000-$5,000 per terminal. + +BROWNRIGG noted that, ten years ago, the project had neither the public +policy nor the technology that would have allowed it to use packet radio +in any meaningful way. Since then much had changed. He proceeded to +detail research and development of the technology, how it is being +deployed in California, and what direction he thought it would take. +The design criteria are to produce a high-speed, one-time, low-cost, +high-quality, secure, license-free device (packet radio) that one can +plug in and play today, forget about it, and have access to the Internet. +By high speed, BROWNRIGG meant 1 megabyte and 1.5 megabytes. Those units +have been built, he continued, and are in the process of being +type-certified by an independent underwriting laboratory so that they can +be type-licensed by the Federal Communications Commission. As is the +case with citizens band, one will be able to purchase a unit and not have +to worry about applying for a license. + +The basic idea, BROWNRIGG elaborated, is to take high-speed radio data +transmission and create a backbone network that at certain strategic +points in the network will "gateway" into a medium-speed packet radio +(i.e., one that runs at 38.4 kilobytes), so that perhaps by 1994-1995 +people, like those in the audience for the price of a VCR could purchase +a medium-speed radio for the office or home, have full network connectivity +to the Internet, and partake of all its services, with no need for an FCC +license and no regular bill from the local common carrier. BROWNRIGG +presented several details of a demonstration project currently taking +place in San Diego and described plans, pending funding, to install a +full-bore network in the San Francisco area. This network will have 600 +nodes running at backbone speeds, and 100 of these nodes will be libraries, +which in turn will be the gateway ports to the 38.4 kilobyte radios that +will give coverage for the neighborhoods surrounding the libraries. + +BROWNRIGG next explained Part 15.247, a new rule within Title 47 of the +Code of Federal Regulations enacted by the FCC in 1985. This rule +challenged the industry, which has only now risen to the occasion, to +build a radio that would run at no more than one watt of output power and +use a fairly exotic method of modulating the radio wave called spread +spectrum. Spread spectrum in fact permits the building of networks so +that numerous data communications can occur simultaneously, without +interfering with each other, within the same wide radio channel. + +BROWNRIGG explained that the frequencies at which the radios would run +are very short wave signals. They are well above standard microwave and +radar. With a radio wave that small, one watt becomes a tremendous punch +per bit and thus makes transmission at reasonable speed possible. In +order to minimize the potential for congestion, the project is +undertaking to reimplement software which has been available in the +networking business and is taken for granted now, for example, TCP/IP, +routing algorithms, bridges, and gateways. In addition, the project +plans to take the WAIS server software in the public domain and +reimplement it so that one can have a WAIS server on a Mac instead of a +Unix machine. The Memex Research Institute believes that libraries, in +particular, will want to use the WAIS servers with packet radio. This +project, which has a team of about twelve people, will run through 1993 +and will include the 100 libraries already mentioned as well as other +professionals such as those in the medical profession, engineering, and +law. Thus, the need is to create an infrastructure of radios that do not +move around, which, BROWNRIGG hopes, will solve a problem not only for +libraries but for individuals who, by and large today, do not have access +to the Internet from their homes and offices. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Project operating frequencies * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +During a brief discussion period, which also concluded the day's +proceedings, BROWNRIGG stated that the project was operating in four +frequencies. The slow speed is operating at 435 megahertz, and it would +later go up to 920 megahertz. With the high-speed frequency, the +one-megabyte radios will run at 2.4 gigabits, and 1.5 will run at 5.7. +At 5.7, rain can be a factor, but it would have to be tropical rain, +unlike what falls in most parts of the United States. + + ****** + +SESSION IV. IMAGE CAPTURE, TEXT CAPTURE, OVERVIEW OF TEXT AND + IMAGE STORAGE FORMATS + +William HOOTON, vice president of operations, I-NET, moderated this session. + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +KENNEY * Factors influencing development of CXP * Advantages of using +digital technology versus photocopy and microfilm * A primary goal of +CXP; publishing challenges * Characteristics of copies printed * Quality +of samples achieved in image capture * Several factors to be considered +in choosing scanning * Emphasis of CXP on timely and cost-effective +production of black-and-white printed facsimiles * Results of producing +microfilm from digital files * Advantages of creating microfilm * Details +concerning production * Costs * Role of digital technology in library +preservation * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Anne KENNEY, associate director, Department of Preservation and +Conservation, Cornell University, opened her talk by observing that the +Cornell Xerox Project (CXP) has been guided by the assumption that the +ability to produce printed facsimiles or to replace paper with paper +would be important, at least for the present generation of users and +equipment. She described three factors that influenced development of +the project: 1) Because the project has emphasized the preservation of +deteriorating brittle books, the quality of what was produced had to be +sufficiently high to return a paper replacement to the shelf. CXP was +only interested in using: 2) a system that was cost-effective, which +meant that it had to be cost-competitive with the processes currently +available, principally photocopy and microfilm, and 3) new or currently +available product hardware and software. + +KENNEY described the advantages that using digital technology offers over +both photocopy and microfilm: 1) The potential exists to create a higher +quality reproduction of a deteriorating original than conventional +light-lens technology. 2) Because a digital image is an encoded +representation, it can be reproduced again and again with no resulting +loss of quality, as opposed to the situation with light-lens processes, +in which there is discernible difference between a second and a +subsequent generation of an image. 3) A digital image can be manipulated +in a number of ways to improve image capture; for example, Xerox has +developed a windowing application that enables one to capture a page +containing both text and illustrations in a manner that optimizes the +reproduction of both. (With light-lens technology, one must choose which +to optimize, text or the illustration; in preservation microfilming, the +current practice is to shoot an illustrated page twice, once to highlight +the text and the second time to provide the best capture for the +illustration.) 4) A digital image can also be edited, density levels +adjusted to remove underlining and stains, and to increase legibility for +faint documents. 5) On-screen inspection can take place at the time of +initial setup and adjustments made prior to scanning, factors that +substantially reduce the number of retakes required in quality control. + +A primary goal of CXP has been to evaluate the paper output printed on +the Xerox DocuTech, a high-speed printer that produces 600-dpi pages from +scanned images at a rate of 135 pages a minute. KENNEY recounted several +publishing challenges to represent faithful and legible reproductions of +the originals that the 600-dpi copy for the most part successfully +captured. For example, many of the deteriorating volumes in the project +were heavily illustrated with fine line drawings or halftones or came in +languages such as Japanese, in which the buildup of characters comprised +of varying strokes is difficult to reproduce at lower resolutions; a +surprising number of them came with annotations and mathematical +formulas, which it was critical to be able to duplicate exactly. + +KENNEY noted that 1) the copies are being printed on paper that meets the +ANSI standards for performance, 2) the DocuTech printer meets the machine +and toner requirements for proper adhesion of print to page, as described +by the National Archives, and thus 3) paper product is considered to be +the archival equivalent of preservation photocopy. + +KENNEY then discussed several samples of the quality achieved in the +project that had been distributed in a handout, for example, a copy of a +print-on-demand version of the 1911 Reed lecture on the steam turbine, +which contains halftones, line drawings, and illustrations embedded in +text; the first four loose pages in the volume compared the capture +capabilities of scanning to photocopy for a standard test target, the +IEEE standard 167A 1987 test chart. In all instances scanning proved +superior to photocopy, though only slightly more so in one. + +Conceding the simplistic nature of her review of the quality of scanning +to photocopy, KENNEY described it as one representation of the kinds of +settings that could be used with scanning capabilities on the equipment +CXP uses. KENNEY also pointed out that CXP investigated the quality +achieved with binary scanning only, and noted the great promise in gray +scale and color scanning, whose advantages and disadvantages need to be +examined. She argued further that scanning resolutions and file formats +can represent a complex trade-off between the time it takes to capture +material, file size, fidelity to the original, and on-screen display; and +printing and equipment availability. All these factors must be taken +into consideration. + +CXP placed primary emphasis on the production in a timely and +cost-effective manner of printed facsimiles that consisted largely of +black-and-white text. With binary scanning, large files may be +compressed efficiently and in a lossless manner (i.e., no data is lost in +the process of compressing [and decompressing] an image--the exact +bit-representation is maintained) using Group 4 CCITT (i.e., the French +acronym for International Consultative Committee for Telegraph and +Telephone) compression. CXP was getting compression ratios of about +forty to one. Gray-scale compression, which primarily uses JPEG, is much +less economical and can represent a lossy compression (i.e., not +lossless), so that as one compresses and decompresses, the illustration +is subtly changed. While binary files produce a high-quality printed +version, it appears 1) that other combinations of spatial resolution with +gray and/or color hold great promise as well, and 2) that gray scale can +represent a tremendous advantage for on-screen viewing. The quality +associated with binary and gray scale also depends on the equipment used. +For instance, binary scanning produces a much better copy on a binary +printer. + +Among CXP's findings concerning the production of microfilm from digital +files, KENNEY reported that the digital files for the same Reed lecture +were used to produce sample film using an electron beam recorder. The +resulting film was faithful to the image capture of the digital files, +and while CXP felt that the text and image pages represented in the Reed +lecture were superior to that of the light-lens film, the resolution +readings for the 600 dpi were not as high as standard microfilming. +KENNEY argued that the standards defined for light-lens technology are +not totally transferable to a digital environment. Moreover, they are +based on definition of quality for a preservation copy. Although making +this case will prove to be a long, uphill struggle, CXP plans to continue +to investigate the issue over the course of the next year. + +KENNEY concluded this portion of her talk with a discussion of the +advantages of creating film: it can serve as a primary backup and as a +preservation master to the digital file; it could then become the print +or production master and service copies could be paper, film, optical +disks, magnetic media, or on-screen display. + +Finally, KENNEY presented details re production: + + * Development and testing of a moderately-high resolution production + scanning workstation represented a third goal of CXP; to date, 1,000 + volumes have been scanned, or about 300,000 images. + + * The resulting digital files are stored and used to produce + hard-copy replacements for the originals and additional prints on + demand; although the initial costs are high, scanning technology + offers an affordable means for reformatting brittle material. + + * A technician in production mode can scan 300 pages per hour when + performing single-sheet scanning, which is a necessity when working + with truly brittle paper; this figure is expected to increase + significantly with subsequent iterations of the software from Xerox; + a three-month time-and-cost study of scanning found that the average + 300-page book would take about an hour and forty minutes to scan + (this figure included the time for setup, which involves keying in + primary bibliographic data, going into quality control mode to + define page size, establishing front-to-back registration, and + scanning sample pages to identify a default range of settings for + the entire book--functions not dissimilar to those performed by + filmers or those preparing a book for photocopy). + + * The final step in the scanning process involved rescans, which + happily were few and far between, representing well under 1 percent + of the total pages scanned. + +In addition to technician time, CXP costed out equipment, amortized over +four years, the cost of storing and refreshing the digital files every +four years, and the cost of printing and binding, book-cloth binding, a +paper reproduction. The total amounted to a little under $65 per single +300-page volume, with 30 percent overhead included--a figure competitive +with the prices currently charged by photocopy vendors. + +Of course, with scanning, in addition to the paper facsimile, one is left +with a digital file from which subsequent copies of the book can be +produced for a fraction of the cost of photocopy, with readers afforded +choices in the form of these copies. + +KENNEY concluded that digital technology offers an electronic means for a +library preservation effort to pay for itself. If a brittle-book program +included the means of disseminating reprints of books that are in demand +by libraries and researchers alike, the initial investment in capture +could be recovered and used to preserve additional but less popular +books. She disclosed that an economic model for a self-sustaining +program could be developed for CXP's report to the Commission on +Preservation and Access (CPA). + +KENNEY stressed that the focus of CXP has been on obtaining high quality +in a production environment. The use of digital technology is viewed as +an affordable alternative to other reformatting options. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +ANDRE * Overview and history of NATDP * Various agricultural CD-ROM +products created inhouse and by service bureaus * Pilot project on +Internet transmission * Additional products in progress * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Pamela ANDRE, associate director for automation, National Agricultural +Text Digitizing Program (NATDP), National Agricultural Library (NAL), +presented an overview of NATDP, which has been underway at NAL the last +four years, before Judith ZIDAR discussed the technical details. ANDRE +defined agricultural information as a broad range of material going from +basic and applied research in the hard sciences to the one-page pamphlets +that are distributed by the cooperative state extension services on such +things as how to grow blueberries. + +NATDP began in late 1986 with a meeting of representatives from the +land-grant library community to deal with the issue of electronic +information. NAL and forty-five of these libraries banded together to +establish this project--to evaluate the technology for converting what +were then source documents in paper form into electronic form, to provide +access to that digital information, and then to distribute it. +Distributing that material to the community--the university community as +well as the extension service community, potentially down to the county +level--constituted the group's chief concern. + +Since January 1988 (when the microcomputer-based scanning system was +installed at NAL), NATDP has done a variety of things, concerning which +ZIDAR would provide further details. For example, the first technology +considered in the project's discussion phase was digital videodisc, which +indicates how long ago it was conceived. + +Over the four years of this project, four separate CD-ROM products on +four different agricultural topics were created, two at a +scanning-and-OCR station installed at NAL, and two by service bureaus. +Thus, NATDP has gained comparative information in terms of those relative +costs. Each of these products contained the full ASCII text as well as +page images of the material, or between 4,000 and 6,000 pages of material +on these disks. Topics included aquaculture, food, agriculture and +science (i.e., international agriculture and research), acid rain, and +Agent Orange, which was the final product distributed (approximately +eighteen months before the Workshop). + +The third phase of NATDP focused on delivery mechanisms other than +CD-ROM. At the suggestion of Clifford LYNCH, who was a technical +consultant to the project at this point, NATDP became involved with the +Internet and initiated a project with the help of North Carolina State +University, in which fourteen of the land-grant university libraries are +transmitting digital images over the Internet in response to interlibrary +loan requests--a topic for another meeting. At this point, the pilot +project had been completed for about a year and the final report would be +available shortly after the Workshop. In the meantime, the project's +success had led to its extension. (ANDRE noted that one of the first +things done under the program title was to select a retrieval package to +use with subsequent products; Windows Personal Librarian was the package +of choice after a lengthy evaluation.) + +Three additional products had been planned and were in progress: + + 1) An arrangement with the American Society of Agronomy--a + professional society that has published the Agronomy Journal since + about 1908--to scan and create bit-mapped images of its journal. + ASA granted permission first to put and then to distribute this + material in electronic form, to hold it at NAL, and to use these + electronic images as a mechanism to deliver documents or print out + material for patrons, among other uses. Effectively, NAL has the + right to use this material in support of its program. + (Significantly, this arrangement offers a potential cooperative + model for working with other professional societies in agriculture + to try to do the same thing--put the journals of particular interest + to agriculture research into electronic form.) + + 2) An extension of the earlier product on aquaculture. + + 3) The George Washington Carver Papers--a joint project with + Tuskegee University to scan and convert from microfilm some 3,500 + images of Carver's papers, letters, and drawings. + +It was anticipated that all of these products would appear no more than +six months after the Workshop. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +ZIDAR * (A separate arena for scanning) * Steps in creating a database * +Image capture, with and without performing OCR * Keying in tracking data +* Scanning, with electronic and manual tracking * Adjustments during +scanning process * Scanning resolutions * Compression * De-skewing and +filtering * Image capture from microform: the papers and letters of +George Washington Carver * Equipment used for a scanning system * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Judith ZIDAR, coordinator, National Agricultural Text Digitizing Program +(NATDP), National Agricultural Library (NAL), illustrated the technical +details of NATDP, including her primary responsibility, scanning and +creating databases on a topic and putting them on CD-ROM. + +(ZIDAR remarked a separate arena from the CD-ROM projects, although the +processing of the material is nearly identical, in which NATDP is also +scanning material and loading it on a Next microcomputer, which in turn +is linked to NAL's integrated library system. Thus, searches in NAL's +bibliographic database will enable people to pull up actual page images +and text for any documents that have been entered.) + +In accordance with the session's topic, ZIDAR focused her illustrated +talk on image capture, offering a primer on the three main steps in the +process: 1) assemble the printed publications; 2) design the database +(database design occurs in the process of preparing the material for +scanning; this step entails reviewing and organizing the material, +defining the contents--what will constitute a record, what kinds of +fields will be captured in terms of author, title, etc.); 3) perform a +certain amount of markup on the paper publications. NAL performs this +task record by record, preparing work sheets or some other sort of +tracking material and designing descriptors and other enhancements to be +added to the data that will not be captured from the printed publication. +Part of this process also involves determining NATDP's file and directory +structure: NATDP attempts to avoid putting more than approximately 100 +images in a directory, because placing more than that on a CD-ROM would +reduce the access speed. + +This up-front process takes approximately two weeks for a +6,000-7,000-page database. The next step is to capture the page images. +How long this process takes is determined by the decision whether or not +to perform OCR. Not performing OCR speeds the process, whereas text +capture requires greater care because of the quality of the image: it +has to be straighter and allowance must be made for text on a page, not +just for the capture of photographs. + +NATDP keys in tracking data, that is, a standard bibliographic record +including the title of the book and the title of the chapter, which will +later either become the access information or will be attached to the +front of a full-text record so that it is searchable. + +Images are scanned from a bound or unbound publication, chiefly from +bound publications in the case of NATDP, however, because often they are +the only copies and the publications are returned to the shelves. NATDP +usually scans one record at a time, because its database tracking system +tracks the document in that way and does not require further logical +separating of the images. After performing optical character +recognition, NATDP moves the images off the hard disk and maintains a +volume sheet. Though the system tracks electronically, all the +processing steps are also tracked manually with a log sheet. + +ZIDAR next illustrated the kinds of adjustments that one can make when +scanning from paper and microfilm, for example, redoing images that need +special handling, setting for dithering or gray scale, and adjusting for +brightness or for the whole book at one time. + +NATDP is scanning at 300 dots per inch, a standard scanning resolution. +Though adequate for capturing text that is all of a standard size, 300 +dpi is unsuitable for any kind of photographic material or for very small +text. Many scanners allow for different image formats, TIFF, of course, +being a de facto standard. But if one intends to exchange images with +other people, the ability to scan other image formats, even if they are +less common, becomes highly desirable. + +CCITT Group 4 is the standard compression for normal black-and-white +images, JPEG for gray scale or color. ZIDAR recommended 1) using the +standard compressions, particularly if one attempts to make material +available and to allow users to download images and reuse them from +CD-ROMs; and 2) maintaining the ability to output an uncompressed image, +because in image exchange uncompressed images are more likely to be able +to cross platforms. + +ZIDAR emphasized the importance of de-skewing and filtering as +requirements on NATDP's upgraded system. For instance, scanning bound +books, particularly books published by the federal government whose pages +are skewed, and trying to scan them straight if OCR is to be performed, +is extremely time-consuming. The same holds for filtering of +poor-quality or older materials. + +ZIDAR described image capture from microform, using as an example three +reels from a sixty-seven-reel set of the papers and letters of George +Washington Carver that had been produced by Tuskegee University. These +resulted in approximately 3,500 images, which NATDP had had scanned by +its service contractor, Science Applications International Corporation +(SAIC). NATDP also created bibliographic records for access. (NATDP did +not have such specialized equipment as a microfilm scanner. + +Unfortunately, the process of scanning from microfilm was not an +unqualified success, ZIDAR reported: because microfilm frame sizes vary, +occasionally some frames were missed, which without spending much time +and money could not be recaptured. + +OCR could not be performed from the scanned images of the frames. The +bleeding in the text simply output text, when OCR was run, that could not +even be edited. NATDP tested for negative versus positive images, +landscape versus portrait orientation, and single- versus dual-page +microfilm, none of which seemed to affect the quality of the image; but +also on none of them could OCR be performed. + +In selecting the microfilm they would use, therefore, NATDP had other +factors in mind. ZIDAR noted two factors that influenced the quality of +the images: 1) the inherent quality of the original and 2) the amount of +size reduction on the pages. + +The Carver papers were selected because they are informative and visually +interesting, treat a single subject, and are valuable in their own right. +The images were scanned and divided into logical records by SAIC, then +delivered, and loaded onto NATDP's system, where bibliographic +information taken directly from the images was added. Scanning was +completed in summer 1991 and by the end of summer 1992 the disk was +scheduled to be published. + +Problems encountered during processing included the following: Because +the microfilm scanning had to be done in a batch, adjustment for +individual page variations was not possible. The frame size varied on +account of the nature of the material, and therefore some of the frames +were missed while others were just partial frames. The only way to go +back and capture this material was to print out the page with the +microfilm reader from the missing frame and then scan it in from the +page, which was extremely time-consuming. The quality of the images +scanned from the printout of the microfilm compared unfavorably with that +of the original images captured directly from the microfilm. The +inability to perform OCR also was a major disappointment. At the time, +computer output microfilm was unavailable to test. + +The equipment used for a scanning system was the last topic addressed by +ZIDAR. The type of equipment that one would purchase for a scanning +system included: a microcomputer, at least a 386, but preferably a 486; +a large hard disk, 380 megabyte at minimum; a multi-tasking operating +system that allows one to run some things in batch in the background +while scanning or doing text editing, for example, Unix or OS/2 and, +theoretically, Windows; a high-speed scanner and scanning software that +allows one to make the various adjustments mentioned earlier; a +high-resolution monitor (150 dpi ); OCR software and hardware to perform +text recognition; an optical disk subsystem on which to archive all the +images as the processing is done; file management and tracking software. + +ZIDAR opined that the software one purchases was more important than the +hardware and might also cost more than the hardware, but it was likely to +prove critical to the success or failure of one's system. In addition to +a stand-alone scanning workstation for image capture, then, text capture +requires one or two editing stations networked to this scanning station +to perform editing. Editing the text takes two or three times as long as +capturing the images. + +Finally, ZIDAR stressed the importance of buying an open system that allows +for more than one vendor, complies with standards, and can be upgraded. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +WATERS *Yale University Library's master plan to convert microfilm to +digital imagery (POB) * The place of electronic tools in the library of +the future * The uses of images and an image library * Primary input from +preservation microfilm * Features distinguishing POB from CXP and key +hypotheses guiding POB * Use of vendor selection process to facilitate +organizational work * Criteria for selecting vendor * Finalists and +results of process for Yale * Key factor distinguishing vendors * +Components, design principles, and some estimated costs of POB * Role of +preservation materials in developing imaging market * Factors affecting +quality and cost * Factors affecting the usability of complex documents +in image form * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Donald WATERS, head of the Systems Office, Yale University Library, +reported on the progress of a master plan for a project at Yale to +convert microfilm to digital imagery, Project Open Book (POB). Stating +that POB was in an advanced stage of planning, WATERS detailed, in +particular, the process of selecting a vendor partner and several key +issues under discussion as Yale prepares to move into the project itself. +He commented first on the vision that serves as the context of POB and +then described its purpose and scope. + +WATERS sees the library of the future not necessarily as an electronic +library but as a place that generates, preserves, and improves for its +clients ready access to both intellectual and physical recorded +knowledge. Electronic tools must find a place in the library in the +context of this vision. Several roles for electronic tools include +serving as: indirect sources of electronic knowledge or as "finding" +aids (the on-line catalogues, the article-level indices, registers for +documents and archives); direct sources of recorded knowledge; full-text +images; and various kinds of compound sources of recorded knowledge (the +so-called compound documents of Hypertext, mixed text and image, +mixed-text image format, and multimedia). + +POB is looking particularly at images and an image library, the uses to +which images will be put (e.g., storage, printing, browsing, and then use +as input for other processes), OCR as a subsequent process to image +capture, or creating an image library, and also possibly generating +microfilm. + +While input will come from a variety of sources, POB is considering +especially input from preservation microfilm. A possible outcome is that +the film and paper which provide the input for the image library +eventually may go off into remote storage, and that the image library may +be the primary access tool. + +The purpose and scope of POB focus on imaging. Though related to CXP, +POB has two features which distinguish it: 1) scale--conversion of +10,000 volumes into digital image form; and 2) source--conversion from +microfilm. Given these features, several key working hypotheses guide +POB, including: 1) Since POB is using microfilm, it is not concerned with +the image library as a preservation medium. 2) Digital imagery can improve +access to recorded knowledge through printing and network distribution at +a modest incremental cost of microfilm. 3) Capturing and storing documents +in a digital image form is necessary to further improvements in access. +(POB distinguishes between the imaging, digitizing process and OCR, +which at this stage it does not plan to perform.) + +Currently in its first or organizational phase, POB found that it could +use a vendor selection process to facilitate a good deal of the +organizational work (e.g., creating a project team and advisory board, +confirming the validity of the plan, establishing the cost of the project +and a budget, selecting the materials to convert, and then raising the +necessary funds). + +POB developed numerous selection criteria, including: a firm committed +to image-document management, the ability to serve as systems integrator +in a large-scale project over several years, interest in developing the +requisite software as a standard rather than a custom product, and a +willingness to invest substantial resources in the project itself. + +Two vendors, DEC and Xerox, were selected as finalists in October 1991, +and with the support of the Commission on Preservation and Access, each +was commissioned to generate a detailed requirements analysis for the +project and then to submit a formal proposal for the completion of the +project, which included a budget and costs. The terms were that POB would +pay the loser. The results for Yale of involving a vendor included: +broad involvement of Yale staff across the board at a relatively low +cost, which may have long-term significance in carrying out the project +(twenty-five to thirty university people are engaged in POB); better +understanding of the factors that affect corporate response to markets +for imaging products; a competitive proposal; and a more sophisticated +view of the imaging markets. + +The most important factor that distinguished the vendors under +consideration was their identification with the customer. The size and +internal complexity of the company also was an important factor. POB was +looking at large companies that had substantial resources. In the end, +the process generated for Yale two competitive proposals, with Xerox's +the clear winner. WATERS then described the components of the proposal, +the design principles, and some of the costs estimated for the process. + +Components are essentially four: a conversion subsystem, a +network-accessible storage subsystem for 10,000 books (and POB expects +200 to 600 dpi storage), browsing stations distributed on the campus +network, and network access to the image printers. + +Among the design principles, POB wanted conversion at the highest +possible resolution. Assuming TIFF files, TIFF files with Group 4 +compression, TCP/IP, and ethernet network on campus, POB wanted a +client-server approach with image documents distributed to the +workstations and made accessible through native workstation interfaces +such as Windows. POB also insisted on a phased approach to +implementation: 1) a stand-alone, single-user, low-cost entry into the +business with a workstation focused on conversion and allowing POB to +explore user access; 2) movement into a higher-volume conversion with +network-accessible storage and multiple access stations; and 3) a +high-volume conversion, full-capacity storage, and multiple browsing +stations distributed throughout the campus. + +The costs proposed for start-up assumed the existence of the Yale network +and its two DocuTech image printers. Other start-up costs are estimated +at $1 million over the three phases. At the end of the project, the annual +operating costs estimated primarily for the software and hardware proposed +come to about $60,000, but these exclude costs for labor needed in the +conversion process, network and printer usage, and facilities management. + +Finally, the selection process produced for Yale a more sophisticated +view of the imaging markets: the management of complex documents in +image form is not a preservation problem, not a library problem, but a +general problem in a broad, general industry. Preservation materials are +useful for developing that market because of the qualities of the +material. For example, much of it is out of copyright. The resolution +of key issues such as the quality of scanning and image browsing also +will affect development of that market. + +The technology is readily available but changing rapidly. In this +context of rapid change, several factors affect quality and cost, to +which POB intends to pay particular attention, for example, the various +levels of resolution that can be achieved. POB believes it can bring +resolution up to 600 dpi, but an interpolation process from 400 to 600 is +more likely. The variation quality in microfilm will prove to be a +highly important factor. POB may reexamine the standards used to film in +the first place by looking at this process as a follow-on to microfilming. + +Other important factors include: the techniques available to the +operator for handling material, the ways of integrating quality control +into the digitizing work flow, and a work flow that includes indexing and +storage. POB's requirement was to be able to deal with quality control +at the point of scanning. Thus, thanks to Xerox, POB anticipates having +a mechanism which will allow it not only to scan in batch form, but to +review the material as it goes through the scanner and control quality +from the outset. + +The standards for measuring quality and costs depend greatly on the uses +of the material, including subsequent OCR, storage, printing, and +browsing. But especially at issue for POB is the facility for browsing. +This facility, WATERS said, is perhaps the weakest aspect of imaging +technology and the most in need of development. + +A variety of factors affect the usability of complex documents in image +form, among them: 1) the ability of the system to handle the full range +of document types, not just monographs but serials, multi-part +monographs, and manuscripts; 2) the location of the database of record +for bibliographic information about the image document, which POB wants +to enter once and in the most useful place, the on-line catalog; 3) a +document identifier for referencing the bibliographic information in one +place and the images in another; 4) the technique for making the basic +internal structure of the document accessible to the reader; and finally, +5) the physical presentation on the CRT of those documents. POB is ready +to complete this phase now. One last decision involves deciding which +material to scan. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * TIFF files constitute de facto standard * NARA's experience +with image conversion software and text conversion * RFC 1314 * +Considerable flux concerning available hardware and software solutions * +NAL through-put rate during scanning * Window management questions * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +In the question-and-answer period that followed WATERS's presentation, +the following points emerged: + + * ZIDAR's statement about using TIFF files as a standard meant de + facto standard. This is what most people use and typically exchange + with other groups, across platforms, or even occasionally across + display software. + + * HOLMES commented on the unsuccessful experience of NARA in + attempting to run image-conversion software or to exchange between + applications: What are supposedly TIFF files go into other software + that is supposed to be able to accept TIFF but cannot recognize the + format and cannot deal with it, and thus renders the exchange + useless. Re text conversion, he noted the different recognition + rates obtained by substituting the make and model of scanners in + NARA's recent test of an "intelligent" character-recognition product + for a new company. In the selection of hardware and software, + HOLMES argued, software no longer constitutes the overriding factor + it did until about a year ago; rather it is perhaps important to + look at both now. + + * Danny Cohen and Alan Katz of the University of Southern California + Information Sciences Institute began circulating as an Internet RFC + (RFC 1314) about a month ago a standard for a TIFF interchange + format for Internet distribution of monochrome bit-mapped images, + which LYNCH said he believed would be used as a de facto standard. + + * FLEISCHHAUER's impression from hearing these reports and thinking + about AM's experience was that there is considerable flux concerning + available hardware and software solutions. HOOTON agreed and + commented at the same time on ZIDAR's statement that the equipment + employed affects the results produced. One cannot draw a complete + conclusion by saying it is difficult or impossible to perform OCR + from scanning microfilm, for example, with that device, that set of + parameters, and system requirements, because numerous other people + are accomplishing just that, using other components, perhaps. + HOOTON opined that both the hardware and the software were highly + important. Most of the problems discussed today have been solved in + numerous different ways by other people. Though it is good to be + cognizant of various experiences, this is not to say that it will + always be thus. + + * At NAL, the through-put rate of the scanning process for paper, + page by page, performing OCR, ranges from 300 to 600 pages per day; + not performing OCR is considerably faster, although how much faster + is not known. This is for scanning from bound books, which is much + slower. + + * WATERS commented on window management questions: DEC proposed an + X-Windows solution which was problematical for two reasons. One was + POB's requirement to be able to manipulate images on the workstation + and bring them down to the workstation itself and the other was + network usage. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +THOMA * Illustration of deficiencies in scanning and storage process * +Image quality in this process * Different costs entailed by better image +quality * Techniques for overcoming various de-ficiencies: fixed +thresholding, dynamic thresholding, dithering, image merge * Page edge +effects * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +George THOMA, chief, Communications Engineering Branch, National Library +of Medicine (NLM), illustrated several of the deficiencies discussed by +the previous speakers. He introduced the topic of special problems by +noting the advantages of electronic imaging. For example, it is regenerable +because it is a coded file, and real-time quality control is possible with +electronic capture, whereas in photographic capture it is not. + +One of the difficulties discussed in the scanning and storage process was +image quality which, without belaboring the obvious, means different +things for maps, medical X-rays, or broadcast television. In the case of +documents, THOMA said, image quality boils down to legibility of the +textual parts, and fidelity in the case of gray or color photo print-type +material. Legibility boils down to scan density, the standard in most +cases being 300 dpi. Increasing the resolution with scanners that +perform 600 or 1200 dpi, however, comes at a cost. + +Better image quality entails at least four different kinds of costs: 1) +equipment costs, because the CCD (i.e., charge-couple device) with +greater number of elements costs more; 2) time costs that translate to +the actual capture costs, because manual labor is involved (the time is +also dependent on the fact that more data has to be moved around in the +machine in the scanning or network devices that perform the scanning as +well as the storage); 3) media costs, because at high resolutions larger +files have to be stored; and 4) transmission costs, because there is just +more data to be transmitted. + +But while resolution takes care of the issue of legibility in image +quality, other deficiencies have to do with contrast and elements on the +page scanned or the image that needed to be removed or clarified. Thus, +THOMA proceeded to illustrate various deficiencies, how they are +manifested, and several techniques to overcome them. + +Fixed thresholding was the first technique described, suitable for +black-and-white text, when the contrast does not vary over the page. One +can have many different threshold levels in scanning devices. Thus, +THOMA offered an example of extremely poor contrast, which resulted from +the fact that the stock was a heavy red. This is the sort of image that +when microfilmed fails to provide any legibility whatsoever. Fixed +thresholding is the way to change the black-to-red contrast to the +desired black-to-white contrast. + +Other examples included material that had been browned or yellowed by +age. This was also a case of contrast deficiency, and correction was +done by fixed thresholding. A final example boils down to the same +thing, slight variability, but it is not significant. Fixed thresholding +solves this problem as well. The microfilm equivalent is certainly legible, +but it comes with dark areas. Though THOMA did not have a slide of the +microfilm in this case, he did show the reproduced electronic image. + +When one has variable contrast over a page or the lighting over the page +area varies, especially in the case where a bound volume has light +shining on it, the image must be processed by a dynamic thresholding +scheme. One scheme, dynamic averaging, allows the threshold level not to +be fixed but to be recomputed for every pixel from the neighboring +characteristics. The neighbors of a pixel determine where the threshold +should be set for that pixel. + +THOMA showed an example of a page that had been made deficient by a +variety of techniques, including a burn mark, coffee stains, and a yellow +marker. Application of a fixed-thresholding scheme, THOMA argued, might +take care of several deficiencies on the page but not all of them. +Performing the calculation for a dynamic threshold setting, however, +removes most of the deficiencies so that at least the text is legible. + +Another problem is representing a gray level with black-and-white pixels +by a process known as dithering or electronic screening. But dithering +does not provide good image quality for pure black-and-white textual +material. THOMA illustrated this point with examples. Although its +suitability for photoprint is the reason for electronic screening or +dithering, it cannot be used for every compound image. In the document +that was distributed by CXP, THOMA noticed that the dithered image of the +IEEE test chart evinced some deterioration in the text. He presented an +extreme example of deterioration in the text in which compounded +documents had to be set right by other techniques. The technique +illustrated by the present example was an image merge in which the page +is scanned twice and the settings go from fixed threshold to the +dithering matrix; the resulting images are merged to give the best +results with each technique. + +THOMA illustrated how dithering is also used in nonphotographic or +nonprint materials with an example of a grayish page from a medical text, +which was reproduced to show all of the gray that appeared in the +original. Dithering provided a reproduction of all the gray in the +original of another example from the same text. + +THOMA finally illustrated the problem of bordering, or page-edge, +effects. Books and bound volumes that are placed on a photocopy machine +or a scanner produce page-edge effects that are undesirable for two +reasons: 1) the aesthetics of the image; after all, if the image is to +be preserved, one does not necessarily want to keep all of its +deficiencies; 2) compression (with the bordering problem THOMA +illustrated, the compression ratio deteriorated tremendously). One way +to eliminate this more serious problem is to have the operator at the +point of scanning window the part of the image that is desirable and +automatically turn all of the pixels out of that picture to white. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +FLEISCHHAUER * AM's experience with scanning bound materials * Dithering +* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Carl FLEISCHHAUER, coordinator, American Memory, Library of Congress, +reported AM's experience with scanning bound materials, which he likened +to the problems involved in using photocopying machines. Very few +devices in the industry offer book-edge scanning, let alone book cradles. +The problem may be unsolvable, FLEISCHHAUER said, because a large enough +market does not exist for a preservation-quality scanner. AM is using a +Kurzweil scanner, which is a book-edge scanner now sold by Xerox. + +Devoting the remainder of his brief presentation to dithering, +FLEISCHHAUER related AM's experience with a contractor who was using +unsophisticated equipment and software to reduce moire patterns from +printed halftones. AM took the same image and used the dithering +algorithm that forms part of the same Kurzweil Xerox scanner; it +disguised moire patterns much more effectively. + +FLEISCHHAUER also observed that dithering produces a binary file which is +useful for numerous purposes, for example, printing it on a laser printer +without having to "re-halftone" it. But it tends to defeat efficient +compression, because the very thing that dithers to reduce moire patterns +also tends to work against compression schemes. AM thought the +difference in image quality was worth it. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Relative use as a criterion for POB's selection of books to +be converted into digital form * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +During the discussion period, WATERS noted that one of the criteria for +selecting books among the 10,000 to be converted into digital image form +would be how much relative use they would receive--a subject still +requiring evaluation. The challenge will be to understand whether +coherent bodies of material will increase usage or whether POB should +seek material that is being used, scan that, and make it more accessible. +POB might decide to digitize materials that are already heavily used, in +order to make them more accessible and decrease wear on them. Another +approach would be to provide a large body of intellectually coherent +material that may be used more in digital form than it is currently used +in microfilm. POB would seek material that was out of copyright. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +BARONAS * Origin and scope of AIIM * Types of documents produced in +AIIM's standards program * Domain of AIIM's standardization work * AIIM's +structure * TC 171 and MS23 * Electronic image management standards * +Categories of EIM standardization where AIIM standards are being +developed * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Jean BARONAS, senior manager, Department of Standards and Technology, +Association for Information and Image Management (AIIM), described the +not-for-profit association and the national and international programs +for standardization in which AIIM is active. + +Accredited for twenty-five years as the nation's standards development +organization for document image management, AIIM began life in a library +community developing microfilm standards. Today the association +maintains both its library and business-image management standardization +activities--and has moved into electronic image-management +standardization (EIM). + +BARONAS defined the program's scope. AIIM deals with: 1) the +terminology of standards and of the technology it uses; 2) methods of +measurement for the systems, as well as quality; 3) methodologies for +users to evaluate and measure quality; 4) the features of apparatus used +to manage and edit images; and 5) the procedures used to manage images. + +BARONAS noted that three types of documents are produced in the AIIM +standards program: the first two, accredited by the American National +Standards Institute (ANSI), are standards and standard recommended +practices. Recommended practices differ from standards in that they +contain more tutorial information. A technical report is not an ANSI +standard. Because AIIM's policies and procedures for developing +standards are approved by ANSI, its standards are labeled ANSI/AIIM, +followed by the number and title of the standard. + +BARONAS then illustrated the domain of AIIM's standardization work. For +example, AIIM is the administrator of the U.S. Technical Advisory Group +(TAG) to the International Standards Organization's (ISO) technical +committee, TC l7l Micrographics and Optical Memories for Document and +Image Recording, Storage, and Use. AIIM officially works through ANSI in +the international standardization process. + +BARONAS described AIIM's structure, including its board of directors, its +standards board of twelve individuals active in the image-management +industry, its strategic planning and legal admissibility task forces, and +its National Standards Council, which is comprised of the members of a +number of organizations who vote on every AIIM standard before it is +published. BARONAS pointed out that AIIM's liaisons deal with numerous +other standards developers, including the optical disk community, office +and publishing systems, image-codes-and-character set committees, and the +National Information Standards Organization (NISO). + +BARONAS illustrated the procedures of TC l7l, which covers all aspects of +image management. When AIIM's national program has conceptualized a new +project, it is usually submitted to the international level, so that the +member countries of TC l7l can simultaneously work on the development of +the standard or the technical report. BARONAS also illustrated a classic +microfilm standard, MS23, which deals with numerous imaging concepts that +apply to electronic imaging. Originally developed in the l970s, revised +in the l980s, and revised again in l991, this standard is scheduled for +another revision. MS23 is an active standard whereby users may propose +new density ranges and new methods of evaluating film images in the +standard's revision. + +BARONAS detailed several electronic image-management standards, for +instance, ANSI/AIIM MS44, a quality-control guideline for scanning 8.5" +by 11" black-and-white office documents. This standard is used with the +IEEE fax image--a continuous tone photographic image with gray scales, +text, and several continuous tone pictures--and AIIM test target number +2, a representative document used in office document management. + +BARONAS next outlined the four categories of EIM standardization in which +AIIM standards are being developed: transfer and retrieval, evaluation, +optical disc and document scanning applications, and design and +conversion of documents. She detailed several of the main projects of +each: 1) in the category of image transfer and retrieval, a bi-level +image transfer format, ANSI/AIIM MS53, which is a proposed standard that +describes a file header for image transfer between unlike systems when +the images are compressed using G3 and G4 compression; 2) the category of +image evaluation, which includes the AIIM-proposed TR26 tutorial on image +resolution (this technical report will treat the differences and +similarities between classical or photographic and electronic imaging); +3) design and conversion, which includes a proposed technical report +called "Forms Design Optimization for EIM" (this report considers how +general-purpose business forms can be best designed so that scanning is +optimized; reprographic characteristics such as type, rules, background, +tint, and color will likewise be treated in the technical report); 4) +disk and document scanning applications includes a project a) on planning +platters and disk management, b) on generating an application profile for +EIM when images are stored and distributed on CD-ROM, and c) on +evaluating SCSI2, and how a common command set can be generated for SCSI2 +so that document scanners are more easily integrated. (ANSI/AIIM MS53 +will also apply to compressed images.) + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +BATTIN * The implications of standards for preservation * A major +obstacle to successful cooperation * A hindrance to access in the digital +environment * Standards a double-edged sword for those concerned with the +preservation of the human record * Near-term prognosis for reliable +archival standards * Preservation concerns for electronic media * Need +for reconceptualizing our preservation principles * Standards in the real +world and the politics of reproduction * Need to redefine the concept of +archival and to begin to think in terms of life cycles * Cooperation and +the La Guardia Eight * Concerns generated by discussions on the problems +of preserving text and image * General principles to be adopted in a +world without standards * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Patricia BATTIN, president, the Commission on Preservation and Access +(CPA), addressed the implications of standards for preservation. She +listed several areas where the library profession and the analog world of +the printed book had made enormous contributions over the past hundred +years--for example, in bibliographic formats, binding standards, and, most +important, in determining what constitutes longevity or archival quality. + +Although standards have lightened the preservation burden through the +development of national and international collaborative programs, +nevertheless, a pervasive mistrust of other people's standards remains a +major obstacle to successful cooperation, BATTIN said. + +The zeal to achieve perfection, regardless of the cost, has hindered +rather than facilitated access in some instances, and in the digital +environment, where no real standards exist, has brought an ironically +just reward. + +BATTIN argued that standards are a double-edged sword for those concerned +with the preservation of the human record, that is, the provision of +access to recorded knowledge in a multitude of media as far into the +future as possible. Standards are essential to facilitate +interconnectivity and access, but, BATTIN said, as LYNCH pointed out +yesterday, if set too soon they can hinder creativity, expansion of +capability, and the broadening of access. The characteristics of +standards for digital imagery differ radically from those for analog +imagery. And the nature of digital technology implies continuing +volatility and change. To reiterate, precipitous standard-setting can +inhibit creativity, but delayed standard-setting results in chaos. + +Since in BATTIN'S opinion the near-term prognosis for reliable archival +standards, as defined by librarians in the analog world, is poor, two +alternatives remain: standing pat with the old technology, or +reconceptualizing. + +Preservation concerns for electronic media fall into two general domains. +One is the continuing assurance of access to knowledge originally +generated, stored, disseminated, and used in electronic form. This +domain contains several subdivisions, including 1) the closed, +proprietary systems discussed the previous day, bundled information such +as electronic journals and government agency records, and electronically +produced or captured raw data; and 2) the application of digital +technologies to the reformatting of materials originally published on a +deteriorating analog medium such as acid paper or videotape. + +The preservation of electronic media requires a reconceptualizing of our +preservation principles during a volatile, standardless transition which +may last far longer than any of us envision today. BATTIN urged the +necessity of shifting focus from assessing, measuring, and setting +standards for the permanence of the medium to the concept of managing +continuing access to information stored on a variety of media and +requiring a variety of ever-changing hardware and software for access--a +fundamental shift for the library profession. + +BATTIN offered a primer on how to move forward with reasonable confidence +in a world without standards. Her comments fell roughly into two sections: +1) standards in the real world and 2) the politics of reproduction. + +In regard to real-world standards, BATTIN argued the need to redefine the +concept of archive and to begin to think in terms of life cycles. In +the past, the naive assumption that paper would last forever produced a +cavalier attitude toward life cycles. The transient nature of the +electronic media has compelled people to recognize and accept upfront the +concept of life cycles in place of permanency. + +Digital standards have to be developed and set in a cooperative context +to ensure efficient exchange of information. Moreover, during this +transition period, greater flexibility concerning how concepts such as +backup copies and archival copies in the CXP are defined is necessary, +or the opportunity to move forward will be lost. + +In terms of cooperation, particularly in the university setting, BATTIN +also argued the need to avoid going off in a hundred different +directions. The CPA has catalyzed a small group of universities called +the La Guardia Eight--because La Guardia Airport is where meetings take +place--Harvard, Yale, Cornell, Princeton, Penn State, Tennessee, +Stanford, and USC, to develop a digital preservation consortium to look +at all these issues and develop de facto standards as we move along, +instead of waiting for something that is officially blessed. Continuing +to apply analog values and definitions of standards to the digital +environment, BATTIN said, will effectively lead to forfeiture of the +benefits of digital technology to research and scholarship. + +Under the second rubric, the politics of reproduction, BATTIN reiterated +an oft-made argument concerning the electronic library, namely, that it +is more difficult to transform than to create, and nowhere is that belief +expressed more dramatically than in the conversion of brittle books to +new media. Preserving information published in electronic media involves +making sure the information remains accessible and that digital +information is not lost through reproduction. In the analog world of +photocopies and microfilm, the issue of fidelity to the original becomes +paramount, as do issues of "Whose fidelity?" and "Whose original?" + +BATTIN elaborated these arguments with a few examples from a recent study +conducted by the CPA on the problems of preserving text and image. +Discussions with scholars, librarians, and curators in a variety of +disciplines dependent on text and image generated a variety of concerns, +for example: 1) Copy what is, not what the technology is capable of. +This is very important for the history of ideas. Scholars wish to know +what the author saw and worked from. And make available at the +workstation the opportunity to erase all the defects and enhance the +presentation. 2) The fidelity of reproduction--what is good enough, what +can we afford, and the difference it makes--issues of subjective versus +objective resolution. 3) The differences between primary and secondary +users. Restricting the definition of primary user to the one in whose +discipline the material has been published runs one headlong into the +reality that these printed books have had a host of other users from a +host of other disciplines, who not only were looking for very different +things, but who also shared values very different from those of the +primary user. 4) The relationship of the standard of reproduction to new +capabilities of scholarship--the browsing standard versus an archival +standard. How good must the archival standard be? Can a distinction be +drawn between potential users in setting standards for reproduction? +Archival storage, use copies, browsing copies--ought an attempt to set +standards even be made? 5) Finally, costs. How much are we prepared to +pay to capture absolute fidelity? What are the trade-offs between vastly +enhanced access, degrees of fidelity, and costs? + +These standards, BATTIN concluded, serve to complicate further the +reproduction process, and add to the long list of technical standards +that are necessary to ensure widespread access. Ways to articulate and +analyze the costs that are attached to the different levels of standards +must be found. + +Given the chaos concerning standards, which promises to linger for the +foreseeable future, BATTIN urged adoption of the following general +principles: + + * Strive to understand the changing information requirements of + scholarly disciplines as more and more technology is integrated into + the process of research and scholarly communication in order to meet + future scholarly needs, not to build for the past. Capture + deteriorating information at the highest affordable resolution, even + though the dissemination and display technologies will lag. + + * Develop cooperative mechanisms to foster agreement on protocols + for document structure and other interchange mechanisms necessary + for widespread dissemination and use before official standards are + set. + + * Accept that, in a transition period, de facto standards will have + to be developed. + + * Capture information in a way that keeps all options open and + provides for total convertibility: OCR, scanning of microfilm, + producing microfilm from scanned documents, etc. + + * Work closely with the generators of information and the builders + of networks and databases to ensure that continuing accessibility is + a primary concern from the beginning. + + * Piggyback on standards under development for the broad market, and + avoid library-specific standards; work with the vendors, in order to + take advantage of that which is being standardized for the rest of + the world. + + * Concentrate efforts on managing permanence in the digital world, + rather than perfecting the longevity of a particular medium. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Additional comments on TIFF * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +During the brief discussion period that followed BATTIN's presentation, +BARONAS explained that TIFF was not developed in collaboration with or +under the auspices of AIIM. TIFF is a company product, not a standard, +is owned by two corporations, and is always changing. BARONAS also +observed that ANSI/AIIM MS53, a bi-level image file transfer format that +allows unlike systems to exchange images, is compatible with TIFF as well +as with DEC's architecture and IBM's MODCA/IOCA. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +HOOTON * Several questions to be considered in discussing text conversion +* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +HOOTON introduced the final topic, text conversion, by noting that it is +becoming an increasingly important part of the imaging business. Many +people now realize that it enhances their system to be able to have more +and more character data as part of their imaging system. Re the issue of +OCR versus rekeying, HOOTON posed several questions: How does one get +text into computer-readable form? Does one use automated processes? +Does one attempt to eliminate the use of operators where possible? +Standards for accuracy, he said, are extremely important: it makes a +major difference in cost and time whether one sets as a standard 98.5 +percent acceptance or 99.5 percent. He mentioned outsourcing as a +possibility for converting text. Finally, what one does with the image +to prepare it for the recognition process is also important, he said, +because such preparation changes how recognition is viewed, as well as +facilitates recognition itself. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LESK * Roles of participants in CORE * Data flow * The scanning process * +The image interface * Results of experiments involving the use of +electronic resources and traditional paper copies * Testing the issue of +serendipity * Conclusions * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Michael LESK, executive director, Computer Science Research, Bell +Communications Research, Inc. (Bellcore), discussed the Chemical Online +Retrieval Experiment (CORE), a cooperative project involving Cornell +University, OCLC, Bellcore, and the American Chemical Society (ACS). + +LESK spoke on 1) how the scanning was performed, including the unusual +feature of page segmentation, and 2) the use made of the text and the +image in experiments. + +Working with the chemistry journals (because ACS has been saving its +typesetting tapes since the mid-1970s and thus has a significant back-run +of the most important chemistry journals in the United States), CORE is +attempting to create an automated chemical library. Approximately a +quarter of the pages by square inch are made up of images of +quasi-pictorial material; dealing with the graphic components of the +pages is extremely important. LESK described the roles of participants +in CORE: 1) ACS provides copyright permission, journals on paper, +journals on microfilm, and some of the definitions of the files; 2) at +Bellcore, LESK chiefly performs the data preparation, while Dennis Egan +performs experiments on the users of chemical abstracts, and supplies the +indexing and numerous magnetic tapes; 3) Cornell provides the site of the +experiment; 4) OCLC develops retrieval software and other user interfaces. +Various manufacturers and publishers have furnished other help. + +Concerning data flow, Bellcore receives microfilm and paper from ACS; the +microfilm is scanned by outside vendors, while the paper is scanned +inhouse on an Improvision scanner, twenty pages per minute at 300 dpi, +which provides sufficient quality for all practical uses. LESK would +prefer to have more gray level, because one of the ACS journals prints on +some colored pages, which creates a problem. + +Bellcore performs all this scanning, creates a page-image file, and also +selects from the pages the graphics, to mix with the text file (which is +discussed later in the Workshop). The user is always searching the ASCII +file, but she or he may see a display based on the ASCII or a display +based on the images. + +LESK illustrated how the program performs page analysis, and the image +interface. (The user types several words, is presented with a list-- +usually of the titles of articles contained in an issue--that derives +from the ASCII, clicks on an icon and receives an image that mirrors an +ACS page.) LESK also illustrated an alternative interface, based on text +on the ASCII, the so-called SuperBook interface from Bellcore. + +LESK next presented the results of an experiment conducted by Dennis Egan +and involving thirty-six students at Cornell, one third of them +undergraduate chemistry majors, one third senior undergraduate chemistry +majors, and one third graduate chemistry students. A third of them +received the paper journals, the traditional paper copies and chemical +abstracts on paper. A third received image displays of the pictures of +the pages, and a third received the text display with pop-up graphics. + +The students were given several questions made up by some chemistry +professors. The questions fell into five classes, ranging from very easy +to very difficult, and included questions designed to simulate browsing +as well as a traditional information retrieval-type task. + +LESK furnished the following results. In the straightforward question +search--the question being, what is the phosphorus oxygen bond distance +and hydroxy phosphate?--the students were told that they could take +fifteen minutes and, then, if they wished, give up. The students with +paper took more than fifteen minutes on average, and yet most of them +gave up. The students with either electronic format, text or image, +received good scores in reasonable time, hardly ever had to give up, and +usually found the right answer. + +In the browsing study, the students were given a list of eight topics, +told to imagine that an issue of the Journal of the American Chemical +Society had just appeared on their desks, and were also told to flip +through it and to find topics mentioned in the issue. The average scores +were about the same. (The students were told to answer yes or no about +whether or not particular topics appeared.) The errors, however, were +quite different. The students with paper rarely said that something +appeared when it had not. But they often failed to find something +actually mentioned in the issue. The computer people found numerous +things, but they also frequently said that a topic was mentioned when it +was not. (The reason, of course, was that they were performing word +searches. They were finding that words were mentioned and they were +concluding that they had accomplished their task.) + +This question also contained a trick to test the issue of serendipity. +The students were given another list of eight topics and instructed, +without taking a second look at the journal, to recall how many of this +new list of eight topics were in this particular issue. This was an +attempt to see if they performed better at remembering what they were not +looking for. They all performed about the same, paper or electronics, +about 62 percent accurate. In short, LESK said, people were not very +good when it came to serendipity, but they were no worse at it with +computers than they were with paper. + +(LESK gave a parenthetical illustration of the learning curve of students +who used SuperBook.) + +The students using the electronic systems started off worse than the ones +using print, but by the third of the three sessions in the series had +caught up to print. As one might expect, electronics provide a much +better means of finding what one wants to read; reading speeds, once the +object of the search has been found, are about the same. + +Almost none of the students could perform the hard task--the analogous +transformation. (It would require the expertise of organic chemists to +complete.) But an interesting result was that the students using the text +search performed terribly, while those using the image system did best. +That the text search system is driven by text offers the explanation. +Everything is focused on the text; to see the pictures, one must press +on an icon. Many students found the right article containing the answer +to the question, but they did not click on the icon to bring up the right +figure and see it. They did not know that they had found the right place, +and thus got it wrong. + +The short answer demonstrated by this experiment was that in the event +one does not know what to read, one needs the electronic systems; the +electronic systems hold no advantage at the moment if one knows what to +read, but neither do they impose a penalty. + +LESK concluded by commenting that, on one hand, the image system was easy +to use. On the other hand, the text display system, which represented +twenty man-years of work in programming and polishing, was not winning, +because the text was not being read, just searched. The much easier +system is highly competitive as well as remarkably effective for the +actual chemists. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +ERWAY * Most challenging aspect of working on AM * Assumptions guiding +AM's approach * Testing different types of service bureaus * AM's +requirement for 99.95 percent accuracy * Requirements for text-coding * +Additional factors influencing AM's approach to coding * Results of AM's +experience with rekeying * Other problems in dealing with service bureaus +* Quality control the most time-consuming aspect of contracting out +conversion * Long-term outlook uncertain * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +To Ricky ERWAY, associate coordinator, American Memory, Library of +Congress, the constant variety of conversion projects taking place +simultaneously represented perhaps the most challenging aspect of working +on AM. Thus, the challenge was not to find a solution for text +conversion but a tool kit of solutions to apply to LC's varied +collections that need to be converted. ERWAY limited her remarks to the +process of converting text to machine-readable form, and the variety of +LC's text collections, for example, bound volumes, microfilm, and +handwritten manuscripts. + +Two assumptions have guided AM's approach, ERWAY said: 1) A desire not +to perform the conversion inhouse. Because of the variety of formats and +types of texts, to capitalize the equipment and have the talents and +skills to operate them at LC would be extremely expensive. Further, the +natural inclination to upgrade to newer and better equipment each year +made it reasonable for AM to focus on what it did best and seek external +conversion services. Using service bureaus also allowed AM to have +several types of operations take place at the same time. 2) AM was not a +technology project, but an effort to improve access to library +collections. Hence, whether text was converted using OCR or rekeying +mattered little to AM. What mattered were cost and accuracy of results. + +AM considered different types of service bureaus and selected three to +perform several small tests in order to acquire a sense of the field. +The sample collections with which they worked included handwritten +correspondence, typewritten manuscripts from the 1940s, and +eighteenth-century printed broadsides on microfilm. On none of these +samples was OCR performed; they were all rekeyed. AM had several special +requirements for the three service bureaus it had engaged. For instance, +any errors in the original text were to be retained. Working from bound +volumes or anything that could not be sheet-fed also constituted a factor +eliminating companies that would have performed OCR. + +AM requires 99.95 percent accuracy, which, though it sounds high, often +means one or two errors per page. The initial batch of test samples +contained several handwritten materials for which AM did not require +text-coding. The results, ERWAY reported, were in all cases fairly +comparable: for the most part, all three service bureaus achieved 99.95 +percent accuracy. AM was satisfied with the work but surprised at the cost. + +As AM began converting whole collections, it retained the requirement for +99.95 percent accuracy and added requirements for text-coding. AM needed +to begin performing work more than three years ago before LC requirements +for SGML applications had been established. Since AM's goal was simply +to retain any of the intellectual content represented by the formatting +of the document (which would be lost if one performed a straight ASCII +conversion), AM used "SGML-like" codes. These codes resembled SGML tags +but were used without the benefit of document-type definitions. AM found +that many service bureaus were not yet SGML-proficient. + +Additional factors influencing the approach AM took with respect to +coding included: 1) the inability of any known microcomputer-based +user-retrieval software to take advantage of SGML coding; and 2) the +multiple inconsistencies in format of the older documents, which +confirmed AM in its desire not to attempt to force the different formats +to conform to a single document-type definition (DTD) and thus create the +need for a separate DTD for each document. + +The five text collections that AM has converted or is in the process of +converting include a collection of eighteenth-century broadsides, a +collection of pamphlets, two typescript document collections, and a +collection of 150 books. + +ERWAY next reviewed the results of AM's experience with rekeying, noting +again that because the bulk of AM's materials are historical, the quality +of the text often does not lend itself to OCR. While non-English +speakers are less likely to guess or elaborate or correct typos in the +original text, they are also less able to infer what we would; they also +are nearly incapable of converting handwritten text. Another +disadvantage of working with overseas keyers is that they are much less +likely to telephone with questions, especially on the coding, with the +result that they develop their own rules as they encounter new +situations. + +Government contracting procedures and time frames posed a major challenge +to performing the conversion. Many service bureaus are not accustomed to +retaining the image, even if they perform OCR. Thus, questions of image +format and storage media were somewhat novel to many of them. ERWAY also +remarked other problems in dealing with service bureaus, for example, +their inability to perform text conversion from the kind of microfilm +that LC uses for preservation purposes. + +But quality control, in ERWAY's experience, was the most time-consuming +aspect of contracting out conversion. AM has been attempting to perform +a 10-percent quality review, looking at either every tenth document or +every tenth page to make certain that the service bureaus are maintaining +99.95 percent accuracy. But even if they are complying with the +requirement for accuracy, finding errors produces a desire to correct +them and, in turn, to clean up the whole collection, which defeats the +purpose to some extent. Even a double entry requires a +character-by-character comparison to the original to meet the accuracy +requirement. LC is not accustomed to publish imperfect texts, which +makes attempting to deal with the industry standard an emotionally +fraught issue for AM. As was mentioned in the previous day's discussion, +going from 99.95 to 99.99 percent accuracy usually doubles costs and +means a third keying or another complete run-through of the text. + +Although AM has learned much from its experiences with various collections +and various service bureaus, ERWAY concluded pessimistically that no +breakthrough has been achieved. Incremental improvements have occurred +in some of the OCR technology, some of the processes, and some of the +standards acceptances, which, though they may lead to somewhat lower costs, +do not offer much encouragement to many people who are anxiously awaiting +the day that the entire contents of LC are available on-line. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +ZIDAR * Several answers to why one attempts to perform full-text +conversion * Per page cost of performing OCR * Typical problems +encountered during editing * Editing poor copy OCR vs. rekeying * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Judith ZIDAR, coordinator, National Agricultural Text Digitizing Program +(NATDP), National Agricultural Library (NAL), offered several answers to +the question of why one attempts to perform full-text conversion: 1) +Text in an image can be read by a human but not by a computer, so of +course it is not searchable and there is not much one can do with it. 2) +Some material simply requires word-level access. For instance, the legal +profession insists on full-text access to its material; with taxonomic or +geographic material, which entails numerous names, one virtually requires +word-level access. 3) Full text permits rapid browsing and searching, +something that cannot be achieved in an image with today's technology. +4) Text stored as ASCII and delivered in ASCII is standardized and highly +portable. 5) People just want full-text searching, even those who do not +know how to do it. NAL, for the most part, is performing OCR at an +actual cost per average-size page of approximately $7. NAL scans the +page to create the electronic image and passes it through the OCR device. + +ZIDAR next rehearsed several typical problems encountered during editing. +Praising the celerity of her student workers, ZIDAR observed that editing +requires approximately five to ten minutes per page, assuming that there +are no large tables to audit. Confusion among the three characters I, 1, +and l, constitutes perhaps the most common problem encountered. Zeroes +and O's also are frequently confused. Double M's create a particular +problem, even on clean pages. They are so wide in most fonts that they +touch, and the system simply cannot tell where one letter ends and the +other begins. Complex page formats occasionally fail to columnate +properly, which entails rescanning as though one were working with a +single column, entering the ASCII, and decolumnating for better +searching. With proportionally spaced text, OCR can have difficulty +discerning what is a space and what are merely spaces between letters, as +opposed to spaces between words, and therefore will merge text or break +up words where it should not. + +ZIDAR said that it can often take longer to edit a poor-copy OCR than to +key it from scratch. NAL has also experimented with partial editing of +text, whereby project workers go into and clean up the format, removing +stray characters but not running a spell-check. NAL corrects typos in +the title and authors' names, which provides a foothold for searching and +browsing. Even extremely poor-quality OCR (e.g., 60-percent accuracy) +can still be searched, because numerous words are correct, while the +important words are probably repeated often enough that they are likely +to be found correct somewhere. Librarians, however, cannot tolerate this +situation, though end users seem more willing to use this text for +searching, provided that NAL indicates that it is unedited. ZIDAR +concluded that rekeying of text may be the best route to take, in spite +of numerous problems with quality control and cost. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Modifying an image before performing OCR * NAL's costs per +page *AM's costs per page and experience with Federal Prison Industries * +Elements comprising NATDP's costs per page * OCR and structured markup * +Distinction between the structure of a document and its representation +when put on the screen or printed * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +HOOTON prefaced the lengthy discussion that followed with several +comments about modifying an image before one reaches the point of +performing OCR. For example, in regard to an application containing a +significant amount of redundant data, such as form-type data, numerous +companies today are working on various kinds of form renewal, prior to +going through a recognition process, by using dropout colors. Thus, +acquiring access to form design or using electronic means are worth +considering. HOOTON also noted that conversion usually makes or breaks +one's imaging system. It is extremely important, extremely costly in +terms of either capital investment or service, and determines the quality +of the remainder of one's system, because it determines the character of +the raw material used by the system. + +Concerning the four projects undertaken by NAL, two inside and two +performed by outside contractors, ZIDAR revealed that an in-house service +bureau executed the first at a cost between $8 and $10 per page for +everything, including building of the database. The project undertaken +by the Consultative Group on International Agricultural Research (CGIAR) +cost approximately $10 per page for the conversion, plus some expenses +for the software and building of the database. The Acid Rain Project--a +two-disk set produced by the University of Vermont, consisting of +Canadian publications on acid rain--cost $6.70 per page for everything, +including keying of the text, which was double keyed, scanning of the +images, and building of the database. The in-house project offered +considerable ease of convenience and greater control of the process. On +the other hand, the service bureaus know their job and perform it +expeditiously, because they have more people. + +As a useful comparison, ERWAY revealed AM's costs as follows: $0.75 +cents to $0.85 cents per thousand characters, with an average page +containing 2,700 characters. Requirements for coding and imaging +increase the costs. Thus, conversion of the text, including the coding, +costs approximately $3 per page. (This figure does not include the +imaging and database-building included in the NAL costs.) AM also +enjoyed a happy experience with Federal Prison Industries, which +precluded the necessity of going through the request-for-proposal process +to award a contract, because it is another government agency. The +prisoners performed AM's rekeying just as well as other service bureaus +and proved handy as well. AM shipped them the books, which they would +photocopy on a book-edge scanner. They would perform the markup on +photocopies, return the books as soon as they were done with them, +perform the keying, and return the material to AM on WORM disks. + +ZIDAR detailed the elements that constitute the previously noted cost of +approximately $7 per page. Most significant is the editing, correction +of errors, and spell-checkings, which though they may sound easy to +perform require, in fact, a great deal of time. Reformatting text also +takes a while, but a significant amount of NAL's expenses are for equipment, +which was extremely expensive when purchased because it was one of the few +systems on the market. The costs of equipment are being amortized over +five years but are still quite high, nearly $2,000 per month. + +HOCKEY raised a general question concerning OCR and the amount of editing +required (substantial in her experience) to generate the kind of +structured markup necessary for manipulating the text on the computer or +loading it into any retrieval system. She wondered if the speakers could +extend the previous question about the cost-benefit of adding or exerting +structured markup. ERWAY noted that several OCR systems retain italics, +bolding, and other spatial formatting. While the material may not be in +the format desired, these systems possess the ability to remove the +original materials quickly from the hands of the people performing the +conversion, as well as to retain that information so that users can work +with it. HOCKEY rejoined that the current thinking on markup is that one +should not say that something is italic or bold so much as why it is that +way. To be sure, one needs to know that something was italicized, but +how can one get from one to the other? One can map from the structure to +the typographic representation. + +FLEISCHHAUER suggested that, given the 100 million items the Library +holds, it may not be possible for LC to do more than report that a thing +was in italics as opposed to why it was italics, although that may be +desirable in some contexts. Promising to talk a bit during the afternoon +session about several experiments OCLC performed on automatic recognition +of document elements, and which they hoped to extend, WEIBEL said that in +fact one can recognize the major elements of a document with a fairly +high degree of reliability, at least as good as OCR. STEVENS drew a +useful distinction between standard, generalized markup (i.e., defining +for a document-type definition the structure of the document), and what +he termed a style sheet, which had to do with italics, bolding, and other +forms of emphasis. Thus, two different components are at work, one being +the structure of the document itself (its logic), and the other being its +representation when it is put on the screen or printed. + + ****** + +SESSION V. APPROACHES TO PREPARING ELECTRONIC TEXTS + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +HOCKEY * Text in ASCII and the representation of electronic text versus +an image * The need to look at ways of using markup to assist retrieval * +The need for an encoding format that will be reusable and multifunctional ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Susan HOCKEY, director, Center for Electronic Texts in the Humanities +(CETH), Rutgers and Princeton Universities, announced that one talk +(WEIBEL's) was moved into this session from the morning and that David +Packard was unable to attend. The session would attempt to focus more on +what one can do with a text in ASCII and the representation of electronic +text rather than just an image, what one can do with a computer that +cannot be done with a book or an image. It would be argued that one can +do much more than just read a text, and from that starting point one can +use markup and methods of preparing the text to take full advantage of +the capability of the computer. That would lead to a discussion of what +the European Community calls REUSABILITY, what may better be termed +DURABILITY, that is, how to prepare or make a text that will last a long +time and that can be used for as many applications as possible, which +would lead to issues of improving intellectual access. + +HOCKEY urged the need to look at ways of using markup to facilitate retrieval, +not just for referencing or to help locate an item that is retrieved, but also to put markup tags in +a text to help retrieve the thing sought either with linguistic tagging or +interpretation. HOCKEY also argued that little advancement had occurred in +the software tools currently available for retrieving and searching text. +She pressed the desideratum of going beyond Boolean searches and performing +more sophisticated searching, which the insertion of more markup in the text +would facilitate. Thinking about electronic texts as opposed to images means +considering material that will never appear in print form, or print will not +be its primary form, that is, material which only appears in electronic form. +HOCKEY alluded to the history and the need for markup and tagging and +electronic text, which was developed through the use of computers in the +humanities; as MICHELSON had observed, Father Busa had started in 1949 +to prepare the first-ever text on the computer. + +HOCKEY remarked several large projects, particularly in Europe, for the +compilation of dictionaries, language studies, and language analysis, in +which people have built up archives of text and have begun to recognize +the need for an encoding format that will be reusable and multifunctional, +that can be used not just to print the text, which may be assumed to be a +byproduct of what one wants to do, but to structure it inside the computer +so that it can be searched, built into a Hypertext system, etc. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +WEIBEL * OCLC's approach to preparing electronic text: retroconversion, +keying of texts, more automated ways of developing data * Project ADAPT +and the CORE Project * Intelligent character recognition does not exist * +Advantages of SGML * Data should be free of procedural markup; +descriptive markup strongly advocated * OCLC's interface illustrated * +Storage requirements and costs for putting a lot of information on line * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Stuart WEIBEL, senior research scientist, Online Computer Library Center, +Inc. (OCLC), described OCLC's approach to preparing electronic text. He +argued that the electronic world into which we are moving must +accommodate not only the future but the past as well, and to some degree +even the present. Thus, starting out at one end with retroconversion and +keying of texts, one would like to move toward much more automated ways +of developing data. + +For example, Project ADAPT had to do with automatically converting +document images into a structured document database with OCR text as +indexing and also a little bit of automatic formatting and tagging of +that text. The CORE project hosted by Cornell University, Bellcore, +OCLC, the American Chemical Society, and Chemical Abstracts, constitutes +WEIBEL's principal concern at the moment. This project is an example of +converting text for which one already has a machine-readable version into +a format more suitable for electronic delivery and database searching. +(Since Michael LESK had previously described CORE, WEIBEL would say +little concerning it.) Borrowing a chemical phrase, de novo synthesis, +WEIBEL cited the Online Journal of Current Clinical Trials as an example +of de novo electronic publishing, that is, a form in which the primary +form of the information is electronic. + +Project ADAPT, then, which OCLC completed a couple of years ago and in +fact is about to resume, is a model in which one takes page images either +in paper or microfilm and converts them automatically to a searchable +electronic database, either on-line or local. The operating assumption +is that accepting some blemishes in the data, especially for +retroconversion of materials, will make it possible to accomplish more. +Not enough money is available to support perfect conversion. + +WEIBEL related several steps taken to perform image preprocessing +(processing on the image before performing optical character +recognition), as well as image postprocessing. He denied the existence +of intelligent character recognition and asserted that what is wanted is +page recognition, which is a long way off. OCLC has experimented with +merging of multiple optical character recognition systems that will +reduce errors from an unacceptable rate of 5 characters out of every +l,000 to an unacceptable rate of 2 characters out of every l,000, but it +is not good enough. It will never be perfect. + +Concerning the CORE Project, WEIBEL observed that Bellcore is taking the +topography files, extracting the page images, and converting those +topography files to SGML markup. LESK hands that data off to OCLC, which +builds that data into a Newton database, the same system that underlies +the on-line system in virtually all of the reference products at OCLC. +The long-term goal is to make the systems interoperable so that not just +Bellcore's system and OCLC's system can access this data, but other +systems can as well, and the key to that is the Z39.50 common command +language and the full-text extension. Z39.50 is fine for MARC records, +but is not enough to do it for full text (that is, make full texts +interoperable). + +WEIBEL next outlined the critical role of SGML for a variety of purposes, +for example, as noted by HOCKEY, in the world of extremely large +databases, using highly structured data to perform field searches. +WEIBEL argued that by building the structure of the data in (i.e., the +structure of the data originally on a printed page), it becomes easy to +look at a journal article even if one cannot read the characters and know +where the title or author is, or what the sections of that document would be. +OCLC wants to make that structure explicit in the database, because it will +be important for retrieval purposes. + +The second big advantage of SGML is that it gives one the ability to +build structure into the database that can be used for display purposes +without contaminating the data with instructions about how to format +things. The distinction lies between procedural markup, which tells one +where to put dots on the page, and descriptive markup, which describes +the elements of a document. + +WEIBEL believes that there should be no procedural markup in the data at +all, that the data should be completely unsullied by information about +italics or boldness. That should be left up to the display device, +whether that display device is a page printer or a screen display device. +By keeping one's database free of that kind of contamination, one can +make decisions down the road, for example, reorganize the data in ways +that are not cramped by built-in notions of what should be italic and +what should be bold. WEIBEL strongly advocated descriptive markup. As +an example, he illustrated the index structure in the CORE data. With +subsequent illustrated examples of markup, WEIBEL acknowledged the common +complaint that SGML is hard to read in its native form, although markup +decreases considerably once one gets into the body. Without the markup, +however, one would not have the structure in the data. One can pass +markup through a LaTeX processor and convert it relatively easily to a +printed version of the document. + +WEIBEL next illustrated an extremely cluttered screen dump of OCLC's +system, in order to show as much as possible the inherent capability on +the screen. (He noted parenthetically that he had become a supporter of +X-Windows as a result of the progress of the CORE Project.) WEIBEL also +illustrated the two major parts of the interface: l) a control box that +allows one to generate lists of items, which resembles a small table of +contents based on key words one wishes to search, and 2) a document +viewer, which is a separate process in and of itself. He demonstrated +how to follow links through the electronic database simply by selecting +the appropriate button and bringing them up. He also noted problems that +remain to be accommodated in the interface (e.g., as pointed out by LESK, +what happens when users do not click on the icon for the figure). + +Given the constraints of time, WEIBEL omitted a large number of ancillary +items in order to say a few words concerning storage requirements and +what will be required to put a lot of things on line. Since it is +extremely expensive to reconvert all of this data, especially if it is +just in paper form (and even if it is in electronic form in typesetting +tapes), he advocated building journals electronically from the start. In +that case, if one only has text graphics and indexing (which is all that +one needs with de novo electronic publishing, because there is no need to +go back and look at bit-maps of pages), one can get 10,000 journals of +full text, or almost 6 million pages per year. These pages can be put in +approximately 135 gigabytes of storage, which is not all that much, +WEIBEL said. For twenty years, something less than three terabytes would +be required. WEIBEL calculated the costs of storing this information as +follows: If a gigabyte costs approximately $1,000, then a terabyte costs +approximately $1 million to buy in terms of hardware. One also needs a +building to put it in and a staff like OCLC to handle that information. +So, to support a terabyte, multiply by five, which gives $5 million per +year for a supported terabyte of data. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Tapes saved by ACS are the typography files originally +supporting publication of the journal * Cost of building tagged text into +the database * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +During the question-and-answer period that followed WEIBEL's +presentation, these clarifications emerged. The tapes saved by the +American Chemical Society are the typography files that originally +supported the publication of the journal. Although they are not tagged +in SGML, they are tagged in very fine detail. Every single sentence is +marked, all the registry numbers, all the publications issues, dates, and +volumes. No cost figures on tagging material on a per-megabyte basis +were available. Because ACS's typesetting system runs from tagged text, +there is no extra cost per article. It was unknown what it costs ACS to +keyboard the tagged text rather than just keyboard the text in the +cheapest process. In other words, since one intends to publish things +and will need to build tagged text into a typography system in any case, +if one does that in such a way that it can drive not only typography but +an electronic system (which is what ACS intends to do--move to SGML +publishing), the marginal cost is zero. The marginal cost represents the +cost of building tagged text into the database, which is small. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +SPERBERG-McQUEEN * Distinction between texts and computers * Implications +of recognizing that all representation is encoding * Dealing with +complicated representations of text entails the need for a grammar of +documents * Variety of forms of formal grammars * Text as a bit-mapped +image does not represent a serious attempt to represent text in +electronic form * SGML, the TEI, document-type declarations, and the +reusability and longevity of data * TEI conformance explicitly allows +extension or modification of the TEI tag set * Administrative background +of the TEI * Several design goals for the TEI tag set * An absolutely +fixed requirement of the TEI Guidelines * Challenges the TEI has +attempted to face * Good texts not beyond economic feasibility * The +issue of reproducibility or processability * The issue of mages as +simulacra for the text redux * One's model of text determines what one's +software can do with a text and has economic consequences * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Prior to speaking about SGML and markup, Michael SPERBERG-McQUEEN, editor, +Text Encoding Initiative (TEI), University of Illinois-Chicago, first drew +a distinction between texts and computers: Texts are abstract cultural +and linguistic objects while computers are complicated physical devices, +he said. Abstract objects cannot be placed inside physical devices; with +computers one can only represent text and act upon those representations. + +The recognition that all representation is encoding, SPERBERG-McQUEEN +argued, leads to the recognition of two things: 1) The topic description +for this session is slightly misleading, because there can be no discussion +of pros and cons of text-coding unless what one means is pros and cons of +working with text with computers. 2) No text can be represented in a +computer without some sort of encoding; images are one way of encoding text, +ASCII is another, SGML yet another. There is no encoding without some +information loss, that is, there is no perfect reproduction of a text that +allows one to do away with the original. Thus, the question becomes, +What is the most useful representation of text for a serious work? +This depends on what kind of serious work one is talking about. + +The projects demonstrated the previous day all involved highly complex +information and fairly complex manipulation of the textual material. +In order to use that complicated information, one has to calculate it +slowly or manually and store the result. It needs to be stored, therefore, +as part of one's representation of the text. Thus, one needs to store the +structure in the text. To deal with complicated representations of text, +one needs somehow to control the complexity of the representation of a text; +that means one needs a way of finding out whether a document and an +electronic representation of a document is legal or not; and that +means one needs a grammar of documents. + +SPERBERG-McQUEEN discussed the variety of forms of formal grammars, +implicit and explicit, as applied to text, and their capabilities. He +argued that these grammars correspond to different models of text that +different developers have. For example, one implicit model of the text +is that there is no internal structure, but just one thing after another, +a few characters and then perhaps a start-title command, and then a few +more characters and an end-title command. SPERBERG-McQUEEN also +distinguished several kinds of text that have a sort of hierarchical +structure that is not very well defined, which, typically, corresponds +to grammars that are not very well defined, as well as hierarchies that +are very well defined (e.g., the Thesaurus Linguae Graecae) and extremely +complicated things such as SGML, which handle strictly hierarchical data +very nicely. + +SPERBERG-McQUEEN conceded that one other model not illustrated on his two +displays was the model of text as a bit-mapped image, an image of a page, +and confessed to having been converted to a limited extent by the +Workshop to the view that electronic images constitute a promising, +probably superior alternative to microfilming. But he was not convinced +that electronic images represent a serious attempt to represent text in +electronic form. Many of their problems stem from the fact that they are +not direct attempts to represent the text but attempts to represent the +page, thus making them representations of representations. + +In this situation of increasingly complicated textual information and the +need to control that complexity in a useful way (which begs the question +of the need for good textual grammars), one has the introduction of SGML. +With SGML, one can develop specific document-type declarations +for specific text types or, as with the TEI, attempts to generate +general document-type declarations that can handle all sorts of text. +The TEI is an attempt to develop formats for text representation that +will ensure the kind of reusability and longevity of data discussed earlier. +It offers a way to stay alive in the state of permanent technological +revolution. + +It has been a continuing challenge in the TEI to create document grammars +that do some work in controlling the complexity of the textual object but +also allowing one to represent the real text that one will find. +Fundamental to the notion of the TEI is that TEI conformance allows one +the ability to extend or modify the TEI tag set so that it fits the text +that one is attempting to represent. + +SPERBERG-McQUEEN next outlined the administrative background of the TEI. +The TEI is an international project to develop and disseminate guidelines +for the encoding and interchange of machine-readable text. It is +sponsored by the Association for Computers in the Humanities, the +Association for Computational Linguistics, and the Association for +Literary and Linguistic Computing. Representatives of numerous other +professional societies sit on its advisory board. The TEI has a number +of affiliated projects that have provided assistance by testing drafts of +the guidelines. + +Among the design goals for the TEI tag set, the scheme first of all must +meet the needs of research, because the TEI came out of the research +community, which did not feel adequately served by existing tag sets. +The tag set must be extensive as well as compatible with existing and +emerging standards. In 1990, version 1.0 of the Guidelines was released +(SPERBERG-McQUEEN illustrated their contents). + +SPERBERG-McQUEEN noted that one problem besetting electronic text has +been the lack of adequate internal or external documentation for many +existing electronic texts. The TEI guidelines as currently formulated +contain few fixed requirements, but one of them is this: There must +always be a document header, an in-file SGML tag that provides +1) a bibliographic description of the electronic object one is talking +about (that is, who included it, when, what for, and under which title); +and 2) the copy text from which it was derived, if any. If there was +no copy text or if the copy text is unknown, then one states as much. +Version 2.0 of the Guidelines was scheduled to be completed in fall 1992 +and a revised third version is to be presented to the TEI advisory board +for its endorsement this coming winter. The TEI itself exists to provide +a markup language, not a marked-up text. + +Among the challenges the TEI has attempted to face is the need for a +markup language that will work for existing projects, that is, handle the +level of markup that people are using now to tag only chapter, section, +and paragraph divisions and not much else. At the same time, such a +language also will be able to scale up gracefully to handle the highly +detailed markup which many people foresee as the future destination of +much electronic text, and which is not the future destination but the +present home of numerous electronic texts in specialized areas. + +SPERBERG-McQUEEN dismissed the lowest-common-denominator approach as +unable to support the kind of applications that draw people who have +never been in the public library regularly before, and make them come +back. He advocated more interesting text and more intelligent text. +Asserting that it is not beyond economic feasibility to have good texts, +SPERBERG-McQUEEN noted that the TEI Guidelines listing 200-odd tags +contains tags that one is expected to enter every time the relevant +textual feature occurs. It contains all the tags that people need now, +and it is not expected that everyone will tag things in the same way. + +The question of how people will tag the text is in large part a function +of their reaction to what SPERBERG-McQUEEN termed the issue of +reproducibility. What one needs to be able to reproduce are the things +one wants to work with. Perhaps a more useful concept than that of +reproducibility or recoverability is that of processability, that is, +what can one get from an electronic text without reading it again +in the original. He illustrated this contention with a page from +Jan Comenius's bilingual Introduction to Latin. + +SPERBERG-McQUEEN returned at length to the issue of images as simulacra +for the text, in order to reiterate his belief that in the long run more +than images of pages of particular editions of the text are needed, +because just as second-generation photocopies and second-generation +microfilm degenerate, so second-generation representations tend to +degenerate, and one tends to overstress some relatively trivial aspects +of the text such as its layout on the page, which is not always +significant, despite what the text critics might say, and slight other +pieces of information such as the very important lexical ties between the +English and Latin versions of Comenius's bilingual text, for example. +Moreover, in many crucial respects it is easy to fool oneself concerning +what a scanned image of the text will accomplish. For example, in order +to study the transmission of texts, information concerning the text +carrier is necessary, which scanned images simply do not always handle. +Further, even the high-quality materials being produced at Cornell use +much of the information that one would need if studying those books as +physical objects. It is a choice that has been made. It is an arguably +justifiable choice, but one does not know what color those pen strokes in +the margin are or whether there was a stain on the page, because it has +been filtered out. One does not know whether there were rips in the page +because they do not show up, and on a couple of the marginal marks one +loses half of the mark because the pen is very light and the scanner +failed to pick it up, and so what is clearly a checkmark in the margin of +the original becomes a little scoop in the margin of the facsimile. +Standard problems for facsimile editions, not new to electronics, but +also true of light-lens photography, and are remarked here because it is +important that we not fool ourselves that even if we produce a very nice +image of this page with good contrast, we are not replacing the +manuscript any more than microfilm has replaced the manuscript. + +The TEI comes from the research community, where its first allegiance +lies, but it is not just an academic exercise. It has relevance far +beyond those who spend all of their time studying text, because one's +model of text determines what one's software can do with a text. Good +models lead to good software. Bad models lead to bad software. That has +economic consequences, and it is these economic consequences that have +led the European Community to help support the TEI, and that will lead, +SPERBERG-McQUEEN hoped, some software vendors to realize that if they +provide software with a better model of the text they can make a killing. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Implications of different DTDs and tag sets * ODA versus SGML * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +During the discussion that followed, several additional points were made. +Neither AAP (i.e., Association of American Publishers) nor CALS (i.e., +Computer-aided Acquisition and Logistics Support) has a document-type +definition for ancient Greek drama, although the TEI will be able to +handle that. Given this state of affairs and assuming that the +technical-journal producers and the commercial vendors decide to use the +other two types, then an institution like the Library of Congress, which +might receive all of their publications, would have to be able to handle +three different types of document definitions and tag sets and be able to +distinguish among them. + +Office Document Architecture (ODA) has some advantages that flow from its +tight focus on office documents and clear directions for implementation. +Much of the ODA standard is easier to read and clearer at first reading +than the SGML standard, which is extremely general. What that means is +that if one wants to use graphics in TIFF and ODA, one is stuck, because +ODA defines graphics formats while TIFF does not, whereas SGML says the +world is not waiting for this work group to create another graphics format. +What is needed is an ability to use whatever graphics format one wants. + +The TEI provides a socket that allows one to connect the SGML document to +the graphics. The notation that the graphics are in is clearly a choice +that one needs to make based on her or his environment, and that is one +advantage. SGML is less megalomaniacal in attempting to define formats +for all kinds of information, though more megalomaniacal in attempting to +cover all sorts of documents. The other advantage is that the model of +text represented by SGML is simply an order of magnitude richer and more +flexible than the model of text offered by ODA. Both offer hierarchical +structures, but SGML recognizes that the hierarchical model of the text +that one is looking at may not have been in the minds of the designers, +whereas ODA does not. + +ODA is not really aiming for the kind of document that the TEI wants to +encompass. The TEI can handle the kind of material ODA has, as well as a +significantly broader range of material. ODA seems to be very much +focused on office documents, which is what it started out being called-- +office document architecture. + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +CALALUCA * Text-encoding from a publisher's perspective * +Responsibilities of a publisher * Reproduction of Migne's Latin series +whole and complete with SGML tags based on perceived need and expected +use * Particular decisions arising from the general decision to produce +and publish PLD * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The final speaker in this session, Eric CALALUCA, vice president, +Chadwyck-Healey, Inc., spoke from the perspective of a publisher re +text-encoding, rather than as one qualified to discuss methods of +encoding data, and observed that the presenters sitting in the room, +whether they had chosen to or not, were acting as publishers: making +choices, gathering data, gathering information, and making assessments. +CALALUCA offered the hard-won conviction that in publishing very large +text files (such as PLD), one cannot avoid making personal judgments of +appropriateness and structure. + +In CALALUCA's view, encoding decisions stem from prior judgments. Two +notions have become axioms for him in the consideration of future sources +for electronic publication: 1) electronic text publishing is as personal +as any other kind of publishing, and questions of if and how to encode +the data are simply a consequence of that prior decision; 2) all +personal decisions are open to criticism, which is unavoidable. + +CALALUCA rehearsed his role as a publisher or, better, as an intermediary +between what is viewed as a sound idea and the people who would make use +of it. Finding the specialist to advise in this process is the core of +that function. The publisher must monitor and hug the fine line between +giving users what they want and suggesting what they might need. One +responsibility of a publisher is to represent the desires of scholars and +research librarians as opposed to bullheadedly forcing them into areas +they would not choose to enter. + +CALALUCA likened the questions being raised today about data structure +and standards to the decisions faced by the Abbe Migne himself during +production of the Patrologia series in the mid-nineteenth century. +Chadwyck-Healey's decision to reproduce Migne's Latin series whole and +complete with SGML tags was also based upon a perceived need and an +expected use. In the same way that Migne's work came to be far more than +a simple handbook for clerics, PLD is already far more than a database +for theologians. It is a bedrock source for the study of Western +civilization, CALALUCA asserted. + +In regard to the decision to produce and publish PLD, the editorial board +offered direct judgments on the question of appropriateness of these +texts for conversion, their encoding and their distribution, and +concluded that the best possible project was one that avoided overt +intrusions or exclusions in so important a resource. Thus, the general +decision to transmit the original collection as clearly as possible with +the widest possible avenues for use led to other decisions: 1) To encode +the data or not, SGML or not, TEI or not. Again, the expected user +community asserted the need for normative tagging structures of important +humanities texts, and the TEI seemed the most appropriate structure for +that purpose. Research librarians, who are trained to view the larger +impact of electronic text sources on 80 or 90 or 100 doctoral +disciplines, loudly approved the decision to include tagging. They see +what is coming better than the specialist who is completely focused on +one edition of Ambrose's De Anima, and they also understand that the +potential uses exceed present expectations. 2) What will be tagged and +what will not. Once again, the board realized that one must tag the +obvious. But in no way should one attempt to identify through encoding +schemes every single discrete area of a text that might someday be +searched. That was another decision. Searching by a column number, an +author, a word, a volume, permitting combination searches, and tagging +notations seemed logical choices as core elements. 3) How does one make +the data available? Tying it to a CD-ROM edition creates limitations, +but a magnetic tape file that is very large, is accompanied by the +encoding specifications, and that allows one to make local modifications +also allows one to incorporate any changes one may desire within the +bounds of private research, though exporting tag files from a CD-ROM +could serve just as well. Since no one on the board could possibly +anticipate each and every way in which a scholar might choose to mine +this data bank, it was decided to satisfy the basics and make some +provisions for what might come. 4) Not to encode the database would rob +it of the interchangeability and portability these important texts should +accommodate. For CALALUCA, the extensive options presented by full-text +searching require care in text selection and strongly support encoding of +data to facilitate the widest possible search strategies. Better +software can always be created, but summoning the resources, the people, +and the energy to reconvert the text is another matter. + +PLD is being encoded, captured, and distributed, because to +Chadwyck-Healey and the board it offers the widest possible array of +future research applications that can be seen today. CALALUCA concluded +by urging the encoding of all important text sources in whatever way +seems most appropriate and durable at the time, without blanching at the +thought that one's work may require emendation in the future. (Thus, +Chadwyck-Healey produced a very large humanities text database before the +final release of the TEI Guidelines.) + + ****** + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +DISCUSSION * Creating texts with markup advocated * Trends in encoding * +The TEI and the issue of interchangeability of standards * A +misconception concerning the TEI * Implications for an institution like +LC in the event that a multiplicity of DTDs develops * Producing images +as a first step towards possible conversion to full text through +character recognition * The AAP tag sets as a common starting point and +the need for caution * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +HOCKEY prefaced the discussion that followed with several comments in +favor of creating texts with markup and on trends in encoding. In the +future, when many more texts are available for on-line searching, real +problems in finding what is wanted will develop, if one is faced with +millions of words of data. It therefore becomes important to consider +putting markup in texts to help searchers home in on the actual things +they wish to retrieve. Various approaches to refining retrieval methods +toward this end include building on a computer version of a dictionary +and letting the computer look up words in it to obtain more information +about the semantic structure or semantic field of a word, its grammatical +structure, and syntactic structure. + +HOCKEY commented on the present keen interest in the encoding world +in creating: 1) machine-readable versions of dictionaries that can be +initially tagged in SGML, which gives a structure to the dictionary entry; +these entries can then be converted into a more rigid or otherwise +different database structure inside the computer, which can be treated as +a dynamic tool for searching mechanisms; 2) large bodies of text to study +the language. In order to incorporate more sophisticated mechanisms, +more about how words behave needs to be known, which can be learned in +part from information in dictionaries. However, the last ten years have +seen much interest in studying the structure of printed dictionaries +converted into computer-readable form. The information one derives about +many words from those is only partial, one or two definitions of the +common or the usual meaning of a word, and then numerous definitions of +unusual usages. If the computer is using a dictionary to help retrieve +words in a text, it needs much more information about the common usages, +because those are the ones that occur over and over again. Hence the +current interest in developing large bodies of text in computer-readable +form in order to study the language. Several projects are engaged in +compiling, for example, 100 million words. HOCKEY described one with +which she was associated briefly at Oxford University involving +compilation of 100 million words of British English: about 10 percent of +that will contain detailed linguistic tagging encoded in SGML; it will +have word class taggings, with words identified as nouns, verbs, +adjectives, or other parts of speech. This tagging can then be used by +programs which will begin to learn a bit more about the structure of the +language, and then, can go to tag more text. + +HOCKEY said that the more that is tagged accurately, the more one can +refine the tagging process and thus the bigger body of text one can build +up with linguistic tagging incorporated into it. Hence, the more tagging +or annotation there is in the text, the more one may begin to learn about +language and the more it will help accomplish more intelligent OCR. She +recommended the development of software tools that will help one begin to +understand more about a text, which can then be applied to scanning +images of that text in that format and to using more intelligence to help +one interpret or understand the text. + +HOCKEY posited the need to think about common methods of text-encoding +for a long time to come, because building these large bodies of text is +extremely expensive and will only be done once. + +In the more general discussion on approaches to encoding that followed, +these points were made: + +BESSER identified the underlying problem with standards that all have to +struggle with in adopting a standard, namely, the tension between a very +highly defined standard that is very interchangeable but does not work +for everyone because something is lacking, and a standard that is less +defined, more open, more adaptable, but less interchangeable. Contending +that the way in which people use SGML is not sufficiently defined, BESSER +wondered 1) if people resist the TEI because they think it is too defined +in certain things they do not fit into, and 2) how progress with +interchangeability can be made without frightening people away. + +SPERBERG-McQUEEN replied that the published drafts of the TEI had met +with surprisingly little objection on the grounds that they do not allow +one to handle X or Y or Z. Particular concerns of the affiliated +projects have led, in practice, to discussions of how extensions are to +be made; the primary concern of any project has to be how it can be +represented locally, thus making interchange secondary. The TEI has +received much criticism based on the notion that everything in it is +required or even recommended, which, as it happens, is a misconception +from the beginning, because none of it is required and very little is +actually actively recommended for all cases, except that one document +one's source. + +SPERBERG-McQUEEN agreed with BESSER about this trade-off: all the +projects in a set of twenty TEI-conformant projects will not necessarily +tag the material in the same way. One result of the TEI will be that the +easiest problems will be solved--those dealing with the external form of +the information; but the problem that is hardest in interchange is that +one is not encoding what another wants, and vice versa. Thus, after +the adoption of a common notation, the differences in the underlying +conceptions of what is interesting about texts become more visible. +The success of a standard like the TEI will lie in the ability of +the recipient of interchanged texts to use some of what it contains +and to add the information that was not encoded that one wants, in a +layered way, so that texts can be gradually enriched and one does not +have to put in everything all at once. Hence, having a well-behaved +markup scheme is important. + +STEVENS followed up on the paradoxical analogy that BESSER alluded to in +the example of the MARC records, namely, the formats that are the same +except that they are different. STEVENS drew a parallel between +document-type definitions and MARC records for books and serials and maps, +where one has a tagging structure and there is a text-interchange. +STEVENS opined that the producers of the information will set the terms +for the standard (i.e., develop document-type definitions for the users +of their products), creating a situation that will be problematical for +an institution like the Library of Congress, which will have to deal with +the DTDs in the event that a multiplicity of them develops. Thus, +numerous people are seeking a standard but cannot find the tag set that +will be acceptable to them and their clients. SPERBERG-McQUEEN agreed +with this view, and said that the situation was in a way worse: attempting +to unify arbitrary DTDs resembled attempting to unify a MARC record with a +bibliographic record done according to the Prussian instructions. +According to STEVENS, this situation occurred very early in the process. + +WATERS recalled from early discussions on Project Open Book the concern +of many people that merely by producing images, POB was not really +enhancing intellectual access to the material. Nevertheless, not wishing +to overemphasize the opposition between imaging and full text, WATERS +stated that POB views getting the images as a first step toward possibly +converting to full text through character recognition, if the technology +is appropriate. WATERS also emphasized that encoding is involved even +with a set of images. + +SPERBERG-McQUEEN agreed with WATERS that one can create an SGML document +consisting wholly of images. At first sight, organizing graphic images +with an SGML document may not seem to offer great advantages, but the +advantages of the scheme WATERS described would be precisely that +ability to move into something that is more of a multimedia document: +a combination of transcribed text and page images. WEIBEL concurred in +this judgment, offering evidence from Project ADAPT, where a page is +divided into text elements and graphic elements, and in fact the text +elements are organized by columns and lines. These lines may be used as +the basis for distributing documents in a network environment. As one +develops software intelligent enough to recognize what those elements +are, it makes sense to apply SGML to an image initially, that may, in +fact, ultimately become more and more text, either through OCR or edited +OCR or even just through keying. For WATERS, the labor of composing the +document and saying this set of documents or this set of images belongs +to this document constitutes a significant investment. + +WEIBEL also made the point that the AAP tag sets, while not excessively +prescriptive, offer a common starting point; they do not define the +structure of the documents, though. They have some recommendations about +DTDs one could use as examples, but they do just suggest tag sets. For +example, the CORE project attempts to use the AAP markup as much as +possible, but there are clearly areas where structure must be added. +That in no way contradicts the use of AAP tag sets. + +SPERBERG-McQUEEN noted that the TEI prepared a long working paper early +on about the AAP tag set and what it lacked that the TEI thought it +needed, and a fairly long critique of the naming conventions, which has +led to a very different style of naming in the TEI. He stressed the +importance of the opposition between prescriptive markup, the kind that a +publisher or anybody can do when producing documents de novo, and +descriptive markup, in which one has to take what the text carrier +provides. In these particular tag sets it is easy to overemphasize this +opposition, because the AAP tag set is extremely flexible. Even if one +just used the DTDs, they allow almost anything to appear almost anywhere. + + ****** + +SESSION VI. COPYRIGHT ISSUES + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +PETERS * Several cautions concerning copyright in an electronic +environment * Review of copyright law in the United States * The notion +of the public good and the desirability of incentives to promote it * +What copyright protects * Works not protected by copyright * The rights +of copyright holders * Publishers' concerns in today's electronic +environment * Compulsory licenses * The price of copyright in a digital +medium and the need for cooperation * Additional clarifications * Rough +justice oftentimes the outcome in numerous copyright matters * Copyright +in an electronic society * Copyright law always only sets up the +boundaries; anything can be changed by contract * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Marybeth PETERS, policy planning adviser to the Register of Copyrights, +Library of Congress, made several general comments and then opened the +floor to discussion of subjects of interest to the audience. + +Having attended several sessions in an effort to gain a sense of what +people did and where copyright would affect their lives, PETERS expressed +the following cautions: + + * If one takes and converts materials and puts them in new forms, + then, from a copyright point of view, one is creating something and + will receive some rights. + + * However, if what one is converting already exists, a question + immediately arises about the status of the materials in question. + + * Putting something in the public domain in the United States offers + some freedom from anxiety, but distributing it throughout the world + on a network is another matter, even if one has put it in the public + domain in the United States. Re foreign laws, very frequently a + work can be in the public domain in the United States but protected + in other countries. Thus, one must consider all of the places a + work may reach, lest one unwittingly become liable to being faced + with a suit for copyright infringement, or at least a letter + demanding discussion of what one is doing. + +PETERS reviewed copyright law in the United States. The U.S. +Constitution effectively states that Congress has the power to enact +copyright laws for two purposes: 1) to encourage the creation and +dissemination of intellectual works for the good of society as a whole; +and, significantly, 2) to give creators and those who package and +disseminate materials the economic rewards that are due them. + +Congress strives to strike a balance, which at times can become an +emotional issue. The United States has never accepted the notion of the +natural right of an author so much as it has accepted the notion of the +public good and the desirability of incentives to promote it. This state +of affairs, however, has created strains on the international level and +is the reason for several of the differences in the laws that we have. +Today the United States protects almost every kind of work that can be +called an expression of an author. The standard for gaining copyright +protection is simply originality. This is a low standard and means that +a work is not copied from something else, as well as shows a certain +minimal amount of authorship. One can also acquire copyright protection +for making a new version of preexisting material, provided it manifests +some spark of creativity. + +However, copyright does not protect ideas, methods, systems--only the way +that one expresses those things. Nor does copyright protect anything +that is mechanical, anything that does not involve choice, or criteria +concerning whether or not one should do a thing. For example, the +results of a process called declicking, in which one mechanically removes +impure sounds from old recordings, are not copyrightable. On the other +hand, the choice to record a song digitally and to increase the sound of +violins or to bring up the tympani constitutes the results of conversion +that are copyrightable. Moreover, if a work is protected by copyright in +the United States, one generally needs the permission of the copyright +owner to convert it. Normally, who will own the new--that is, converted- +-material is a matter of contract. In the absence of a contract, the +person who creates the new material is the author and owner. But people +do not generally think about the copyright implications until after the +fact. PETERS stressed the need when dealing with copyrighted works to +think about copyright in advance. One's bargaining power is much greater +up front than it is down the road. + +PETERS next discussed works not protected by copyright, for example, any +work done by a federal employee as part of his or her official duties is +in the public domain in the United States. The issue is not wholly free +of doubt concerning whether or not the work is in the public domain +outside the United States. Other materials in the public domain include: +any works published more than seventy-five years ago, and any work +published in the United States more than twenty-eight years ago, whose +copyright was not renewed. In talking about the new technology and +putting material in a digital form to send all over the world, PETERS +cautioned, one must keep in mind that while the rights may not be an +issue in the United States, they may be in different parts of the world, +where most countries previously employed a copyright term of the life of +the author plus fifty years. + +PETERS next reviewed the economics of copyright holding. Simply, +economic rights are the rights to control the reproduction of a work in +any form. They belong to the author, or in the case of a work made for +hire, the employer. The second right, which is critical to conversion, +is the right to change a work. The right to make new versions is perhaps +one of the most significant rights of authors, particularly in an +electronic world. The third right is the right to publish the work and +the right to disseminate it, something that everyone who deals in an +electronic medium needs to know. The basic rule is if a copy is sold, +all rights of distribution are extinguished with the sale of that copy. +The key is that it must be sold. A number of companies overcome this +obstacle by leasing or renting their product. These companies argue that +if the material is rented or leased and not sold, they control the uses +of a work. The fourth right, and one very important in a digital world, +is a right of public performance, which means the right to show the work +sequentially. For example, copyright owners control the showing of a +CD-ROM product in a public place such as a public library. The reverse +side of public performance is something called the right of public +display. Moral rights also exist, which at the federal level apply only +to very limited visual works of art, but in theory may apply under +contract and other principles. Moral rights may include the right of an +author to have his or her name on a work, the right of attribution, and +the right to object to distortion or mutilation--the right of integrity. + +The way copyright law is worded gives much latitude to activities such as +preservation; to use of material for scholarly and research purposes when +the user does not make multiple copies; and to the generation of +facsimile copies of unpublished works by libraries for themselves and +other libraries. But the law does not allow anyone to become the +distributor of the product for the entire world. In today's electronic +environment, publishers are extremely concerned that the entire world is +networked and can obtain the information desired from a single copy in a +single library. Hence, if there is to be only one sale, which publishers +may choose to live with, they will obtain their money in other ways, for +example, from access and use. Hence, the development of site licenses +and other kinds of agreements to cover what publishers believe they +should be compensated for. Any solution that the United States takes +today has to consider the international arena. + +Noting that the United States is a member of the Berne Convention and +subscribes to its provisions, PETERS described the permissions process. +She also defined compulsory licenses. A compulsory license, of which the +United States has had a few, builds into the law the right to use a work +subject to certain terms and conditions. In the international arena, +however, the ability to use compulsory licenses is extremely limited. +Thus, clearinghouses and other collectives comprise one option that has +succeeded in providing for use of a work. Often overlooked when one +begins to use copyrighted material and put products together is how +expensive the permissions process and managing it is. According to +PETERS, the price of copyright in a digital medium, whatever solution is +worked out, will include managing and assembling the database. She +strongly recommended that publishers and librarians or people with +various backgrounds cooperate to work out administratively feasible +systems, in order to produce better results. + +In the lengthy question-and-answer period that followed PETERS's +presentation, the following points emerged: + + * The Copyright Office maintains that anything mechanical and + totally exhaustive probably is not protected. In the event that + what an individual did in developing potentially copyrightable + material is not understood, the Copyright Office will ask about the + creative choices the applicant chose to make or not to make. As a + practical matter, if one believes she or he has made enough of those + choices, that person has a right to assert a copyright and someone + else must assert that the work is not copyrightable. The more + mechanical, the more automatic, a thing is, the less likely it is to + be copyrightable. + + * Nearly all photographs are deemed to be copyrightable, but no one + worries about them much, because everyone is free to take the same + image. Thus, a photographic copyright represents what is called a + "thin" copyright. The photograph itself must be duplicated, in + order for copyright to be violated. + + * The Copyright Office takes the position that X-rays are not + copyrightable because they are mechanical. It can be argued + whether or not image enhancement in scanning can be protected. One + must exercise care with material created with public funds and + generally in the public domain. An article written by a federal + employee, if written as part of official duties, is not + copyrightable. However, control over a scientific article written + by a National Institutes of Health grantee (i.e., someone who + receives money from the U.S. government), depends on NIH policy. If + the government agency has no policy (and that policy can be + contained in its regulations, the contract, or the grant), the + author retains copyright. If a provision of the contract, grant, or + regulation states that there will be no copyright, then it does not + exist. When a work is created, copyright automatically comes into + existence unless something exists that says it does not. + + * An enhanced electronic copy of a print copy of an older reference + work in the public domain that does not contain copyrightable new + material is a purely mechanical rendition of the original work, and + is not copyrightable. + + * Usually, when a work enters the public domain, nothing can remove + it. For example, Congress recently passed into law the concept of + automatic renewal, which means that copyright on any work published + between l964 and l978 does not have to be renewed in order to + receive a seventy-five-year term. But any work not renewed before + 1964 is in the public domain. + + * Concerning whether or not the United States keeps track of when + authors die, nothing was ever done, nor is anything being done at + the moment by the Copyright Office. + + * Software that drives a mechanical process is itself copyrightable. + If one changes platforms, the software itself has a copyright. The + World Intellectual Property Organization will hold a symposium 28 + March through 2 April l993, at Harvard University, on digital + technology, and will study this entire issue. If one purchases a + computer software package, such as MacPaint, and creates something + new, one receives protection only for that which has been added. + +PETERS added that often in copyright matters, rough justice is the +outcome, for example, in collective licensing, ASCAP (i.e., American +Society of Composers, Authors, and Publishers), and BMI (i.e., Broadcast +Music, Inc.), where it may seem that the big guys receive more than their +due. Of course, people ought not to copy a creative product without +paying for it; there should be some compensation. But the truth of the +world, and it is not a great truth, is that the big guy gets played on +the radio more frequently than the little guy, who has to do much more +until he becomes a big guy. That is true of every author, every +composer, everyone, and, unfortunately, is part of life. + +Copyright always originates with the author, except in cases of works +made for hire. (Most software falls into this category.) When an author +sends his article to a journal, he has not relinquished copyright, though +he retains the right to relinquish it. The author receives absolutely +everything. The less prominent the author, the more leverage the +publisher will have in contract negotiations. In order to transfer the +rights, the author must sign an agreement giving them away. + +In an electronic society, it is important to be able to license a writer +and work out deals. With regard to use of a work, it usually is much +easier when a publisher holds the rights. In an electronic era, a real +problem arises when one is digitizing and making information available. +PETERS referred again to electronic licensing clearinghouses. Copyright +ought to remain with the author, but as one moves forward globally in the +electronic arena, a middleman who can handle the various rights becomes +increasingly necessary. + +The notion of copyright law is that it resides with the individual, but +in an on-line environment, where a work can be adapted and tinkered with +by many individuals, there is concern. If changes are authorized and +there is no agreement to the contrary, the person who changes a work owns +the changes. To put it another way, the person who acquires permission +to change a work technically will become the author and the owner, unless +some agreement to the contrary has been made. It is typical for the +original publisher to try to control all of the versions and all of the +uses. Copyright law always only sets up the boundaries. Anything can be +changed by contract. + + ****** + +SESSION VII. CONCLUSION + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +GENERAL DISCUSSION * Two questions for discussion * Different emphases in +the Workshop * Bringing the text and image partisans together * +Desiderata in planning the long-term development of something * Questions +surrounding the issue of electronic deposit * Discussion of electronic +deposit as an allusion to the issue of standards * Need for a directory +of preservation projects in digital form and for access to their +digitized files * CETH's catalogue of machine-readable texts in the +humanities * What constitutes a publication in the electronic world? * +Need for LC to deal with the concept of on-line publishing * LC's Network +Development Office exploring the limits of MARC as a standard in terms +of handling electronic information * Magnitude of the problem and the +need for distributed responsibility in order to maintain and store +electronic information * Workshop participants to be viewed as a starting +point * Development of a network version of AM urged * A step toward AM's +construction of some sort of apparatus for network access * A delicate +and agonizing policy question for LC * Re the issue of electronic +deposit, LC urged to initiate a catalytic process in terms of distributed +responsibility * Suggestions for cooperative ventures * Commercial +publishers' fears * Strategic questions for getting the image and text +people to think through long-term cooperation * Clarification of the +driving force behind both the Perseus and the Cornell Xerox projects * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +In his role as moderator of the concluding session, GIFFORD raised two +questions he believed would benefit from discussion: 1) Are there enough +commonalities among those of us that have been here for two days so that +we can see courses of action that should be taken in the future? And, if +so, what are they and who might take them? 2) Partly derivative from +that, but obviously very dangerous to LC as host, do you see a role for +the Library of Congress in all this? Of course, the Library of Congress +holds a rather special status in a number of these matters, because it is +not perceived as a player with an economic stake in them, but are there +roles that LC can play that can help advance us toward where we are heading? + +Describing himself as an uninformed observer of the technicalities of the +last two days, GIFFORD detected three different emphases in the Workshop: +1) people who are very deeply committed to text; 2) people who are almost +passionate about images; and 3) a few people who are very committed to +what happens to the networks. In other words, the new networking +dimension, the accessibility of the processability, the portability of +all this across the networks. How do we pull those three together? + +Adding a question that reflected HOCKEY's comment that this was the +fourth workshop she had attended in the previous thirty days, FLEISCHHAUER +wondered to what extent this meeting had reinvented the wheel, or if it +had contributed anything in the way of bringing together a different group +of people from those who normally appear on the workshop circuit. + +HOCKEY confessed to being struck at this meeting and the one the +Electronic Pierce Consortium organized the previous week that this was a +coming together of people working on texts and not images. Attempting to +bring the two together is something we ought to be thinking about for the +future: How one can think about working with image material to begin +with, but structuring it and digitizing it in such a way that at a later +stage it can be interpreted into text, and find a common way of building +text and images together so that they can be used jointly in the future, +with the network support to begin there because that is how people will +want to access it. + +In planning the long-term development of something, which is what is +being done in electronic text, HOCKEY stressed the importance not only +of discussing the technical aspects of how one does it but particularly +of thinking about what the people who use the stuff will want to do. +But conversely, there are numerous things that people start to do with +electronic text or material that nobody ever thought of in the beginning. + +LESK, in response to the question concerning the role of the Library of +Congress, remarked the often suggested desideratum of having electronic +deposit: Since everything is now computer-typeset, an entire decade of +material that was machine-readable exists, but the publishers frequently +did not save it; has LC taken any action to have its copyright deposit +operation start collecting these machine-readable versions? In the +absence of PETERS, GIFFORD replied that the question was being +actively considered but that that was only one dimension of the problem. +Another dimension is the whole question of the integrity of the original +electronic document. It becomes highly important in science to prove +authorship. How will that be done? + +ERWAY explained that, under the old policy, to make a claim for a +copyright for works that were published in electronic form, including +software, one had to submit a paper copy of the first and last twenty +pages of code--something that represented the work but did not include +the entire work itself and had little value to anyone. As a temporary +measure, LC has claimed the right to demand electronic versions of +electronic publications. This measure entails a proactive role for the +Library to say that it wants a particular electronic version. Publishers +then have perhaps a year to submit it. But the real problem for LC is +what to do with all this material in all these different formats. Will +the Library mount it? How will it give people access to it? How does LC +keep track of the appropriate computers, software, and media? The situation +is so hard to control, ERWAY said, that it makes sense for each publishing +house to maintain its own archive. But LC cannot enforce that either. + +GIFFORD acknowledged LESK's suggestion that establishing a priority +offered the solution, albeit a fairly complicated one. But who maintains +that register?, he asked. GRABER noted that LC does attempt to collect a +Macintosh version and the IBM-compatible version of software. It does +not collect other versions. But while true for software, BYRUM observed, +this reply does not speak to materials, that is, all the materials that +were published that were on somebody's microcomputer or driver tapes +at a publishing office across the country. LC does well to acquire +specific machine-readable products selectively that were intended to be +machine-readable. Materials that were in machine-readable form at one time, +BYRUM said, would be beyond LC's capability at the moment, insofar as +attempting to acquire, organize, and preserve them are concerned--and +preservation would be the most important consideration. In this +connection, GIFFORD reiterated the need to work out some sense of +distributive responsibility for a number of these issues, which +inevitably will require significant cooperation and discussion. +Nobody can do it all. + +LESK suggested that some publishers may look with favor on LC beginning +to serve as a depository of tapes in an electronic manuscript standard. +Publishers may view this as a service that they did not have to perform +and they might send in tapes. However, SPERBERG-McQUEEN countered, +although publishers have had equivalent services available to them for a +long time, the electronic text archive has never turned away or been +flooded with tapes and is forever sending feedback to the depositor. +Some publishers do send in tapes. + +ANDRE viewed this discussion as an allusion to the issue of standards. +She recommended that the AAP standard and the TEI, which has already been +somewhat harmonized internationally and which also shares several +compatibilities with the AAP, be harmonized to ensure sufficient +compatibility in the software. She drew the line at saying LC ought to +be the locus or forum for such harmonization. + +Taking the group in a slightly different direction, but one where at +least in the near term LC might play a helpful role, LYNCH remarked the +plans of a number of projects to carry out preservation by creating +digital images that will end up in on-line or near-line storage at some +institution. Presumably, LC will link this material somehow to its +on-line catalog in most cases. Thus, it is in a digital form. LYNCH had +the impression that many of these institutions would be willing to make +those files accessible to other people outside the institution, provided +that there is no copyright problem. This desideratum will require +propagating the knowledge that those digitized files exist, so that they +can end up in other on-line catalogs. Although uncertain about the +mechanism for achieving this result, LYNCH said that it warranted +scrutiny because it seemed to be connected to some of the basic issues of +cataloging and distribution of records. It would be foolish, given the +amount of work that all of us have to do and our meager resources, to +discover multiple institutions digitizing the same work. Re microforms, +LYNCH said, we are in pretty good shape. + +BATTIN called this a big problem and noted that the Cornell people (who +had already departed) were working on it. At issue from the beginning +was to learn how to catalog that information into RLIN and then into +OCLC, so that it would be accessible. That issue remains to be resolved. +LYNCH rejoined that putting it into OCLC or RLIN was helpful insofar as +somebody who is thinking of performing preservation activity on that work +could learn about it. It is not necessarily helpful for institutions to +make that available. BATTIN opined that the idea was that it not only be +for preservation purposes but for the convenience of people looking for +this material. She endorsed LYNCH's dictum that duplication of this +effort was to be avoided by every means. + +HOCKEY informed the Workshop about one major current activity of CETH, +namely a catalogue of machine-readable texts in the humanities. Held on +RLIN at present, the catalogue has been concentrated on ASCII as opposed +to digitized images of text. She is exploring ways to improve the +catalogue and make it more widely available, and welcomed suggestions +about these concerns. CETH owns the records, which are not just +restricted to RLIN, and can distribute them however it wishes. + +Taking up LESK's earlier question, BATTIN inquired whether LC, since it +is accepting electronic files and designing a mechanism for dealing with +that rather than putting books on shelves, would become responsible for +the National Copyright Depository of Electronic Materials. Of course +that could not be accomplished overnight, but it would be something LC +could plan for. GIFFORD acknowledged that much thought was being devoted +to that set of problems and returned the discussion to the issue raised +by LYNCH--whether or not putting the kind of records that both BATTIN and +HOCKEY have been talking about in RLIN is not a satisfactory solution. +It seemed to him that RLIN answered LYNCH's original point concerning +some kind of directory for these kinds of materials. In a situation +where somebody is attempting to decide whether or not to scan this or +film that or to learn whether or not someone has already done so, LYNCH +suggested, RLIN is helpful, but it is not helpful in the case of a local, +on-line catalogue. Further, one would like to have her or his system be +aware that that exists in digital form, so that one can present it to a +patron, even though one did not digitize it, if it is out of copyright. +The only way to make those linkages would be to perform a tremendous +amount of real-time look-up, which would be awkward at best, or +periodically to yank the whole file from RLIN and match it against one's +own stuff, which is a nuisance. + +But where, ERWAY inquired, does one stop including things that are +available with Internet, for instance, in one's local catalogue? +It almost seems that that is LC's means to acquire access to them. +That represents LC's new form of library loan. Perhaps LC's new on-line +catalogue is an amalgamation of all these catalogues on line. LYNCH +conceded that perhaps that was true in the very long term, but was not +applicable to scanning in the short term. In his view, the totals cited +by Yale, 10,000 books over perhaps a four-year period, and 1,000-1,500 +books from Cornell, were not big numbers, while searching all over +creation for relatively rare occurrences will prove to be less efficient. +As GIFFORD wondered if this would not be a separable file on RLIN and +could be requested from them, BATTIN interjected that it was easily +accessible to an institution. SEVERTSON pointed out that that file, cum +enhancements, was available with reference information on CD-ROM, which +makes it a little more available. + +In HOCKEY's view, the real question facing the Workshop is what to put in +this catalogue, because that raises the question of what constitutes a +publication in the electronic world. (WEIBEL interjected that Eric Joule +in OCLC's Office of Research is also wrestling with this particular +problem, while GIFFORD thought it sounded fairly generic.) HOCKEY +contended that a majority of texts in the humanities are in the hands +of either a small number of large research institutions or individuals +and are not generally available for anyone else to access at all. +She wondered if these texts ought to be catalogued. + +After argument proceeded back and forth for several minutes over why +cataloguing might be a necessary service, LEBRON suggested that this +issue involved the responsibility of a publisher. The fact that someone +has created something electronically and keeps it under his or her +control does not constitute publication. Publication implies +dissemination. While it would be important for a scholar to let other +people know that this creation exists, in many respects this is no +different from an unpublished manuscript. That is what is being accessed +in there, except that now one is not looking at it in the hard-copy but +in the electronic environment. + +LEBRON expressed puzzlement at the variety of ways electronic publishing +has been viewed. Much of what has been discussed throughout these two +days has concerned CD-ROM publishing, whereas in the on-line environment +that she confronts, the constraints and challenges are very different. +Sooner or later LC will have to deal with the concept of on-line +publishing. Taking up the comment ERWAY made earlier about storing +copies, LEBRON gave her own journal as an example. How would she deposit +OJCCT for copyright?, she asked, because the journal will exist in the +mainframe at OCLC and people will be able to access it. Here the +situation is different, ownership versus access, and is something that +arises with publication in the on-line environment, faster than is +sometimes realized. Lacking clear answers to all of these questions +herself, LEBRON did not anticipate that LC would be able to take a role +in helping to define some of them for quite a while. + +GREENFIELD observed that LC's Network Development Office is attempting, +among other things, to explore the limits of MARC as a standard in terms +of handling electronic information. GREENFIELD also noted that Rebecca +GUENTHER from that office gave a paper to the American Society for +Information Science (ASIS) summarizing several of the discussion papers +that were coming out of the Network Development Office. GREENFIELD said +he understood that that office had a list-server soliciting just the kind +of feedback received today concerning the difficulties of identifying and +cataloguing electronic information. GREENFIELD hoped that everybody +would be aware of that and somehow contribute to that conversation. + +Noting two of LC's roles, first, to act as a repository of record for +material that is copyrighted in this country, and second, to make +materials it holds available in some limited form to a clientele that +goes beyond Congress, BESSER suggested that it was incumbent on LC to +extend those responsibilities to all the things being published in +electronic form. This would mean eventually accepting electronic +formats. LC could require that at some point they be in a certain +limited set of formats, and then develop mechanisms for allowing people +to access those in the same way that other things are accessed. This +does not imply that they are on the network and available to everyone. +LC does that with most of its bibliographic records, BESSER said, which +end up migrating to the utility (e.g., OCLC) or somewhere else. But just +as most of LC's books are available in some form through interlibrary +loan or some other mechanism, so in the same way electronic formats ought +to be available to others in some format, though with some copyright +considerations. BESSER was not suggesting that these mechanisms be +established tomorrow, only that they seemed to fall within LC's purview, +and that there should be long-range plans to establish them. + +Acknowledging that those from LC in the room agreed with BESSER +concerning the need to confront difficult questions, GIFFORD underscored +the magnitude of the problem of what to keep and what to select. GIFFORD +noted that LC currently receives some 31,000 items per day, not counting +electronic materials, and argued for much more distributed responsibility +in order to maintain and store electronic information. + +BESSER responded that the assembled group could be viewed as a starting +point, whose initial operating premise could be helping to move in this +direction and defining how LC could do so, for example, in areas of +standardization or distribution of responsibility. + +FLEISCHHAUER added that AM was fully engaged, wrestling with some of the +questions that pertain to the conversion of older historical materials, +which would be one thing that the Library of Congress might do. Several +points mentioned by BESSER and several others on this question have a +much greater impact on those who are concerned with cataloguing and the +networking of bibliographic information, as well as preservation itself. + +Speaking directly to AM, which he considered was a largely uncopyrighted +database, LYNCH urged development of a network version of AM, or +consideration of making the data in it available to people interested in +doing network multimedia. On account of the current great shortage of +digital data that is both appealing and unencumbered by complex rights +problems, this course of action could have a significant effect on making +network multimedia a reality. + +In this connection, FLEISCHHAUER reported on a fragmentary prototype in +LC's Office of Information Technology Services that attempts to associate +digital images of photographs with cataloguing information in ways that +work within a local area network--a step, so to say, toward AM's +construction of some sort of apparatus for access. Further, AM has +attempted to use standard data forms in order to help make that +distinction between the access tools and the underlying data, and thus +believes that the database is networkable. + +A delicate and agonizing policy question for LC, however, which comes +back to resources and unfortunately has an impact on this, is to find +some appropriate, honorable, and legal cost-recovery possibilities. A +certain skittishness concerning cost-recovery has made people unsure +exactly what to do. AM would be highly receptive to discussing further +LYNCH's offer to test or demonstrate its database in a network +environment, FLEISCHHAUER said. + +Returning the discussion to what she viewed as the vital issue of +electronic deposit, BATTIN recommended that LC initiate a catalytic +process in terms of distributed responsibility, that is, bring together +the distributed organizations and set up a study group to look at all +these issues and see where we as a nation should move. The broader +issues of how we deal with the management of electronic information will +not disappear, but only grow worse. + +LESK took up this theme and suggested that LC attempt to persuade one +major library in each state to deal with its state equivalent publisher, +which might produce a cooperative project that would be equitably +distributed around the country, and one in which LC would be dealing with +a minimal number of publishers and minimal copyright problems. + +GRABER remarked the recent development in the scientific community of a +willingness to use SGML and either deposit or interchange on a fairly +standardized format. He wondered if a similar movement was taking place +in the humanities. Although the National Library of Medicine found only +a few publishers to cooperate in a like venture two or three years ago, a +new effort might generate a much larger number willing to cooperate. + +KIMBALL recounted his unit's (Machine-Readable Collections Reading Room) +troubles with the commercial publishers of electronic media in acquiring +materials for LC's collections, in particular the publishers' fear that +they would not be able to cover their costs and would lose control of +their products, that LC would give them away or sell them and make +profits from them. He doubted that the publishing industry was prepared +to move into this area at the moment, given its resistance to allowing LC +to use its machine-readable materials as the Library would like. + +The copyright law now addresses compact disk as a medium, and LC can +request one copy of that, or two copies if it is the only version, and +can request copies of software, but that fails to address magazines or +books or anything like that which is in machine-readable form. + +GIFFORD acknowledged the thorny nature of this issue, which he illustrated +with the example of the cumbersome process involved in putting a copy of a +scientific database on a LAN in LC's science reading room. He also +acknowledged that LC needs help and could enlist the energies and talents +of Workshop participants in thinking through a number of these problems. + +GIFFORD returned the discussion to getting the image and text people to +think through together where they want to go in the long term. MYLONAS +conceded that her experience at the Pierce Symposium the previous week at +Georgetown University and this week at LC had forced her to reevaluate +her perspective on the usefulness of text as images. MYLONAS framed the +issues in a series of questions: How do we acquire machine-readable +text? Do we take pictures of it and perform OCR on it later? Is it +important to obtain very high-quality images and text, etc.? +FLEISCHHAUER agreed with MYLONAS's framing of strategic questions, adding +that a large institution such as LC probably has to do all of those +things at different times. Thus, the trick is to exercise judgment. The +Workshop had added to his and AM's considerations in making those +judgments. Concerning future meetings or discussions, MYLONAS suggested +that screening priorities would be helpful. + +WEIBEL opined that the diversity reflected in this group was a sign both +of the health and of the immaturity of the field, and more time would +have to pass before we convince one another concerning standards. + +An exchange between MYLONAS and BATTIN clarified the point that the +driving force behind both the Perseus and the Cornell Xerox projects was +the preservation of knowledge for the future, not simply for particular +research use. In the case of Perseus, MYLONAS said, the assumption was +that the texts would not be entered again into electronically readable +form. SPERBERG-McQUEEN added that a scanned image would not serve as an +archival copy for purposes of preservation in the case of, say, the Bill +of Rights, in the sense that the scanned images are effectively the +archival copies for the Cornell mathematics books. + + + *** *** *** ****** *** *** *** + + + Appendix I: PROGRAM + + + + WORKSHOP + ON + ELECTRONIC + TEXTS + + + + 9-10 June 1992 + + Library of Congress + Washington, D.C. + + + + Supported by a Grant from the David and Lucile Packard Foundation + + +Tuesday, 9 June 1992 + +NATIONAL DEMONSTRATION LAB, ATRIUM, LIBRARY MADISON + +8:30 AM Coffee and Danish, registration + +9:00 AM Welcome + + Prosser Gifford, Director for Scholarly Programs, and Carl + Fleischhauer, Coordinator, American Memory, Library of + Congress + +9:l5 AM Session I. Content in a New Form: Who Will Use It and What + Will They Do? + + Broad description of the range of electronic information. + Characterization of who uses it and how it is or may be used. + In addition to a look at scholarly uses, this session will + include a presentation on use by students (K-12 and college) + and the general public. + + Moderator: James Daly + Avra Michelson, Archival Research and Evaluation Staff, + National Archives and Records Administration (Overview) + Susan H. Veccia, Team Leader, American Memory, User Evaluation, + and + Joanne Freeman, Associate Coordinator, American Memory, Library + of Congress (Beyond the scholar) + +10:30- +11:00 AM Break + +11:00 AM Session II. Show and Tell. + + Each presentation to consist of a fifteen-minute + statement/show; group discussion will follow lunch. + + Moderator: Jacqueline Hess, Director, National Demonstration + Lab + + 1. A classics project, stressing texts and text retrieval + more than multimedia: Perseus Project, Harvard + University + Elli Mylonas, Managing Editor + + 2. Other humanities projects employing the emerging norms of + the Text Encoding Initiative (TEI): Chadwyck-Healey's + The English Poetry Full Text Database and/or Patrologia + Latina Database + Eric M. Calaluca, Vice President, Chadwyck-Healey, Inc. + + 3. American Memory + Carl Fleischhauer, Coordinator, and + Ricky Erway, Associate Coordinator, Library of Congress + + 4. Founding Fathers example from Packard Humanities + Institute: The Papers of George Washington, University + of Virginia + Dorothy Twohig, Managing Editor, and/or + David Woodley Packard + + 5. An electronic medical journal offering graphics and + full-text searchability: The Online Journal of Current + Clinical Trials, American Association for the Advancement + of Science + Maria L. Lebron, Managing Editor + + 6. A project that offers facsimile images of pages but omits + searchable text: Cornell math books + Lynne K. Personius, Assistant Director, Cornell + Information Technologies for Scholarly Information + Sources, Cornell University + +12:30 PM Lunch (Dining Room A, Library Madison 620. Exhibits + available.) + +1:30 PM Session II. Show and Tell (Cont'd.). + +3:00- +3:30 PM Break + +3:30- +5:30 PM Session III. Distribution, Networks, and Networking: Options + for Dissemination. + + Published disks: University presses and public-sector + publishers, private-sector publishers + Computer networks + + Moderator: Robert G. Zich, Special Assistant to the Associate + Librarian for Special Projects, Library of Congress + Clifford A. Lynch, Director, Library Automation, University of + California + Howard Besser, School of Library and Information Science, + University of Pittsburgh + Ronald L. Larsen, Associate Director of Libraries for + Information Technology, University of Maryland at College + Park + Edwin B. Brownrigg, Executive Director, Memex Research + Institute + +6:30 PM Reception (Montpelier Room, Library Madison 619.) + + ****** + +Wednesday, 10 June 1992 + +DINING ROOM A, LIBRARY MADISON 620 + +8:30 AM Coffee and Danish + +9:00 AM Session IV. Image Capture, Text Capture, Overview of Text and + Image Storage Formats. + + Moderator: William L. Hooton, Vice President of Operations, + I-NET + + A) Principal Methods for Image Capture of Text: + Direct scanning + Use of microform + + Anne R. Kenney, Assistant Director, Department of Preservation + and Conservation, Cornell University + Pamela Q.J. Andre, Associate Director, Automation, and + Judith A. Zidar, Coordinator, National Agricultural Text + Digitizing Program (NATDP), National Agricultural Library + (NAL) + Donald J. Waters, Head, Systems Office, Yale University Library + + B) Special Problems: + Bound volumes + Conservation + Reproducing printed halftones + + Carl Fleischhauer, Coordinator, American Memory, Library of + Congress + George Thoma, Chief, Communications Engineering Branch, + National Library of Medicine (NLM) + +10:30- +11:00 AM Break + +11:00 AM Session IV. Image Capture, Text Capture, Overview of Text and + Image Storage Formats (Cont'd.). + + C) Image Standards and Implications for Preservation + + Jean Baronas, Senior Manager, Department of Standards and + Technology, Association for Information and Image Management + (AIIM) + Patricia Battin, President, The Commission on Preservation and + Access (CPA) + + D) Text Conversion: + OCR vs. rekeying + Standards of accuracy and use of imperfect texts + Service bureaus + + Stuart Weibel, Senior Research Specialist, Online Computer + Library Center, Inc. (OCLC) + Michael Lesk, Executive Director, Computer Science Research, + Bellcore + Ricky Erway, Associate Coordinator, American Memory, Library of + Congress + Pamela Q.J. Andre, Associate Director, Automation, and + Judith A. Zidar, Coordinator, National Agricultural Text + Digitizing Program (NATDP), National Agricultural Library + (NAL) + +12:30- +1:30 PM Lunch + +1:30 PM Session V. Approaches to Preparing Electronic Texts. + + Discussion of approaches to structuring text for the computer; + pros and cons of text coding, description of methods in + practice, and comparison of text-coding methods. + + Moderator: Susan Hockey, Director, Center for Electronic Texts + in the Humanities (CETH), Rutgers and Princeton Universities + David Woodley Packard + C.M. Sperberg-McQueen, Editor, Text Encoding Initiative (TEI), + University of Illinois-Chicago + Eric M. Calaluca, Vice President, Chadwyck-Healey, Inc. + +3:30- +4:00 PM Break + +4:00 PM Session VI. Copyright Issues. + + Marybeth Peters, Policy Planning Adviser to the Register of + Copyrights, Library of Congress + +5:00 PM Session VII. Conclusion. + + General discussion. + What topics were omitted or given short shrift that anyone + would like to talk about now? + Is there a "group" here? What should the group do next, if + anything? What should the Library of Congress do next, if + anything? + Moderator: Prosser Gifford, Director for Scholarly Programs, + Library of Congress + +6:00 PM Adjourn + + + *** *** *** ****** *** *** *** + + + Appendix II: ABSTRACTS + + +SESSION I + +Avra MICHELSON Forecasting the Use of Electronic Texts by + Social Sciences and Humanities Scholars + +This presentation explores the ways in which electronic texts are likely +to be used by the non-scientific scholarly community. Many of the +remarks are drawn from a report the speaker coauthored with Jeff +Rothenberg, a computer scientist at The RAND Corporation. + +The speaker assesses 1) current scholarly use of information technology +and 2) the key trends in information technology most relevant to the +research process, in order to predict how social sciences and humanities +scholars are apt to use electronic texts. In introducing the topic, +current use of electronic texts is explored broadly within the context of +scholarly communication. From the perspective of scholarly +communication, the work of humanities and social sciences scholars +involves five processes: 1) identification of sources, 2) communication +with colleagues, 3) interpretation and analysis of data, 4) dissemination +of research findings, and 5) curriculum development and instruction. The +extent to which computation currently permeates aspects of scholarly +communication represents a viable indicator of the prospects for +electronic texts. + +The discussion of current practice is balanced by an analysis of key +trends in the scholarly use of information technology. These include the +trends toward end-user computing and connectivity, which provide a +framework for forecasting the use of electronic texts through this +millennium. The presentation concludes with a summary of the ways in +which the nonscientific scholarly community can be expected to use +electronic texts, and the implications of that use for information +providers. + +Susan VECCIA and Joanne FREEMAN Electronic Archives for the Public: + Use of American Memory in Public and + School Libraries + +This joint discussion focuses on nonscholarly applications of electronic +library materials, specifically addressing use of the Library of Congress +American Memory (AM) program in a small number of public and school +libraries throughout the United States. AM consists of selected Library +of Congress primary archival materials, stored on optical media +(CD-ROM/videodisc), and presented with little or no editing. Many +collections are accompanied by electronic introductions and user's guides +offering background information and historical context. Collections +represent a variety of formats including photographs, graphic arts, +motion pictures, recorded sound, music, broadsides and manuscripts, +books, and pamphlets. + +In 1991, the Library of Congress began a nationwide evaluation of AM in +different types of institutions. Test sites include public libraries, +elementary and secondary school libraries, college and university +libraries, state libraries, and special libraries. Susan VECCIA and +Joanne FREEMAN will discuss their observations on the use of AM by the +nonscholarly community, using evidence gleaned from this ongoing +evaluation effort. + +VECCIA will comment on the overall goals of the evaluation project, and +the types of public and school libraries included in this study. Her +comments on nonscholarly use of AM will focus on the public library as a +cultural and community institution, often bridging the gap between formal +and informal education. FREEMAN will discuss the use of AM in school +libraries. Use by students and teachers has revealed some broad +questions about the use of electronic resources, as well as definite +benefits gained by the "nonscholar." Topics will include the problem of +grasping content and context in an electronic environment, the stumbling +blocks created by "new" technologies, and the unique skills and interests +awakened through use of electronic resources. + +SESSION II + +Elli MYLONAS The Perseus Project: Interactive Sources and + Studies in Classical Greece + +The Perseus Project (5) has just released Perseus 1.0, the first publicly +available version of its hypertextual database of multimedia materials on +classical Greece. Perseus is designed to be used by a wide audience, +comprised of readers at the student and scholar levels. As such, it must +be able to locate information using different strategies, and it must +contain enough detail to serve the different needs of its users. In +addition, it must be delivered so that it is affordable to its target +audience. [These problems and the solutions we chose are described in +Mylonas, "An Interface to Classical Greek Civilization," JASIS 43:2, +March 1992.] + +In order to achieve its objective, the project staff decided to make a +conscious separation between selecting and converting textual, database, +and image data on the one hand, and putting it into a delivery system on +the other. That way, it is possible to create the electronic data +without thinking about the restrictions of the delivery system. We have +made a great effort to choose system-independent formats for our data, +and to put as much thought and work as possible into structuring it so +that the translation from paper to electronic form will enhance the value +of the data. [A discussion of these solutions as of two years ago is in +Elli Mylonas, Gregory Crane, Kenneth Morrell, and D. Neel Smith, "The +Perseus Project: Data in the Electronic Age," in Accessing Antiquity: +The Computerization of Classical Databases, J. Solomon and T. Worthen +(eds.), University of Arizona Press, in press.] + +Much of the work on Perseus is focused on collecting and converting the +data on which the project is based. At the same time, it is necessary to +provide means of access to the information, in order to make it usable, +and them to investigate how it is used. As we learn more about what +students and scholars from different backgrounds do with Perseus, we can +adjust our data collection, and also modify the system to accommodate +them. In creating a delivery system for general use, we have tried to +avoid favoring any one type of use by allowing multiple forms of access +to and navigation through the system. + +The way text is handled exemplifies some of these principles. All text +in Perseus is tagged using SGML, following the guidelines of the Text +Encoding Initiative (TEI). This markup is used to index the text, and +process it so that it can be imported into HyperCard. No SGML markup +remains in the text that reaches the user, because currently it would be +too expensive to create a system that acts on SGML in real time. +However, the regularity provided by SGML is essential for verifying the +content of the texts, and greatly speeds all the processing performed on +them. The fact that the texts exist in SGML ensures that they will be +relatively easy to port to different hardware and software, and so will +outlast the current delivery platform. Finally, the SGML markup +incorporates existing canonical reference systems (chapter, verse, line, +etc.); indexing and navigation are based on these features. This ensures +that the same canonical reference will always resolve to the same point +within a text, and that all versions of our texts, regardless of delivery +platform (even paper printouts) will function the same way. + +In order to provide tools for users, the text is processed by a +morphological analyzer, and the results are stored in a database. +Together with the index, the Greek-English Lexicon, and the index of all +the English words in the definitions of the lexicon, the morphological +analyses comprise a set of linguistic tools that allow users of all +levels to work with the textual information, and to accomplish different +tasks. For example, students who read no Greek may explore a concept as +it appears in Greek texts by using the English-Greek index, and then +looking up works in the texts and translations, or scholars may do +detailed morphological studies of word use by using the morphological +analyses of the texts. Because these tools were not designed for any one +use, the same tools and the same data can be used by both students and +scholars. + +NOTES: + (5) Perseus is based at Harvard University, with collaborators at + several other universities. The project has been funded primarily + by the Annenberg/CPB Project, as well as by Harvard University, + Apple Computer, and others. It is published by Yale University + Press. Perseus runs on Macintosh computers, under the HyperCard + program. + +Eric CALALUCA + +Chadwyck-Healey embarked last year on two distinct yet related full-text +humanities database projects. + +The English Poetry Full-Text Database and the Patrologia Latina Database +represent new approaches to linguistic research resources. The size and +complexity of the projects present problems for electronic publishers, +but surmountable ones if they remain abreast of the latest possibilities +in data capture and retrieval software techniques. + +The issues which required address prior to the commencement of the +projects were legion: + + 1. Editorial selection (or exclusion) of materials in each + database + + 2. Deciding whether or not to incorporate a normative encoding + structure into the databases? + A. If one is selected, should it be SGML? + B. If SGML, then the TEI? + + 3. Deliver as CD-ROM, magnetic tape, or both? + + 4. Can one produce retrieval software advanced enough for the + postdoctoral linguist, yet accessible enough for unattended + general use? Should one try? + + 5. Re fair and liberal networking policies, what are the risks to + an electronic publisher? + + 6. How does the emergence of national and international education + networks affect the use and viability of research projects + requiring high investment? Do the new European Community + directives concerning database protection necessitate two + distinct publishing projects, one for North America and one for + overseas? + +From new notions of "scholarly fair use" to the future of optical media, +virtually every issue related to electronic publishing was aired. The +result is two projects which have been constructed to provide the quality +research resources with the fewest encumbrances to use by teachers and +private scholars. + +Dorothy TWOHIG + +In spring 1988 the editors of the papers of George Washington, John +Adams, Thomas Jefferson, James Madison, and Benjamin Franklin were +approached by classics scholar David Packard on behalf of the Packard +Humanities Foundation with a proposal to produce a CD-ROM edition of the +complete papers of each of the Founding Fathers. This electronic edition +will supplement the published volumes, making the documents widely +available to students and researchers at reasonable cost. We estimate +that our CD-ROM edition of Washington's Papers will be substantially +completed within the next two years and ready for publication. Within +the next ten years or so, similar CD-ROM editions of the Franklin, Adams, +Jefferson, and Madison papers also will be available. At the Library of +Congress's session on technology, I would like to discuss not only the +experience of the Washington Papers in producing the CD-ROM edition, but +the impact technology has had on these major editorial projects. +Already, we are editing our volumes with an eye to the material that will +be readily available in the CD-ROM edition. The completed electronic +edition will provide immense possibilities for the searching of documents +for information in a way never possible before. The kind of technical +innovations that are currently available and on the drawing board will +soon revolutionize historical research and the production of historical +documents. Unfortunately, much of this new technology is not being used +in the planning stages of historical projects, simply because many +historians are aware only in the vaguest way of its existence. At least +two major new historical editing projects are considering microfilm +editions, simply because they are not aware of the possibilities of +electronic alternatives and the advantages of the new technology in terms +of flexibility and research potential compared to microfilm. In fact, +too many of us in history and literature are still at the stage of +struggling with our PCs. There are many historical editorial projects in +progress presently, and an equal number of literary projects. While the +two fields have somewhat different approaches to textual editing, there +are ways in which electronic technology can be of service to both. + +Since few of the editors involved in the Founding Fathers CD-ROM editions +are technical experts in any sense, I hope to point out in my discussion +of our experience how many of these electronic innovations can be used +successfully by scholars who are novices in the world of new technology. +One of the major concerns of the sponsors of the multitude of new +scholarly editions is the limited audience reached by the published +volumes. Most of these editions are being published in small quantities +and the publishers' price for them puts them out of the reach not only of +individual scholars but of most public libraries and all but the largest +educational institutions. However, little attention is being given to +ways in which technology can bypass conventional publication to make +historical and literary documents more widely available. + +What attracted us most to the CD-ROM edition of The Papers of George +Washington was the fact that David Packard's aim was to make a complete +edition of all of the 135,000 documents we have collected available in an +inexpensive format that would be placed in public libraries, small +colleges, and even high schools. This would provide an audience far +beyond our present 1,000-copy, $45 published edition. Since the CD-ROM +edition will carry none of the explanatory annotation that appears in the +published volumes, we also feel that the use of the CD-ROM will lead many +researchers to seek out the published volumes. + +In addition to ignorance of new technical advances, I have found that too +many editors--and historians and literary scholars--are resistant and +even hostile to suggestions that electronic technology may enhance their +work. I intend to discuss some of the arguments traditionalists are +advancing to resist technology, ranging from distrust of the speed with +which it changes (we are already wondering what is out there that is +better than CD-ROM) to suspicion of the technical language used to +describe electronic developments. + +Maria LEBRON + +The Online Journal of Current Clinical Trials, a joint venture of the +American Association for the Advancement of Science (AAAS) and the Online +Computer Library Center, Inc. (OCLC), is the first peer-reviewed journal +to provide full text, tabular material, and line illustrations on line. +This presentation will discuss the genesis and start-up period of the +journal. Topics of discussion will include historical overview, +day-to-day management of the editorial peer review, and manuscript +tagging and publication. A demonstration of the journal and its features +will accompany the presentation. + +Lynne PERSONIUS + +Cornell University Library, Cornell Information Technologies, and Xerox +Corporation, with the support of the Commission on Preservation and +Access, and Sun Microsystems, Inc., have been collaborating in a project +to test a prototype system for recording brittle books as digital images +and producing, on demand, high-quality archival paper replacements. The +project goes beyond that, however, to investigate some of the issues +surrounding scanning, storing, retrieving, and providing access to +digital images in a network environment. + +The Joint Study in Digital Preservation began in January 1990. Xerox +provided the College Library Access and Storage System (CLASS) software, +a prototype 600-dots-per-inch (dpi) scanner, and the hardware necessary +to support network printing on the DocuTech printer housed in Cornell's +Computing and Communications Center (CCC). + +The Cornell staff using the hardware and software became an integral part +of the development and testing process for enhancements to the CLASS +software system. The collaborative nature of this relationship is +resulting in a system that is specifically tailored to the preservation +application. + +A digital library of 1,000 volumes (or approximately 300,000 images) has +been created and is stored on an optical jukebox that resides in CCC. +The library includes a collection of select mathematics monographs that +provides mathematics faculty with an opportunity to use the electronic +library. The remaining volumes were chosen for the library to test the +various capabilities of the scanning system. + +One project objective is to provide users of the Cornell library and the +library staff with the ability to request facsimiles of digitized images +or to retrieve the actual electronic image for browsing. A prototype +viewing workstation has been created by Xerox, with input into the design +by a committee of Cornell librarians and computer professionals. This +will allow us to experiment with patron access to the images that make up +the digital library. The viewing station provides search, retrieval, and +(ultimately) printing functions with enhancements to facilitate +navigation through multiple documents. + +Cornell currently is working to extend access to the digital library to +readers using workstations from their offices. This year is devoted to +the development of a network resident image conversion and delivery +server, and client software that will support readers who use Apple +Macintosh computers, IBM windows platforms, and Sun workstations. +Equipment for this development was provided by Sun Microsystems with +support from the Commission on Preservation and Access. + +During the show-and-tell session of the Workshop on Electronic Texts, a +prototype view station will be demonstrated. In addition, a display of +original library books that have been digitized will be available for +review with associated printed copies for comparison. The fifteen-minute +overview of the project will include a slide presentation that +constitutes a "tour" of the preservation digitizing process. + +The final network-connected version of the viewing station will provide +library users with another mechanism for accessing the digital library, +and will also provide the capability of viewing images directly. This +will not require special software, although a powerful computer with good +graphics will be needed. + +The Joint Study in Digital Preservation has generated a great deal of +interest in the library community. Unfortunately, or perhaps +fortunately, this project serves to raise a vast number of other issues +surrounding the use of digital technology for the preservation and use of +deteriorating library materials, which subsequent projects will need to +examine. Much work remains. + +SESSION III + +Howard BESSER Networking Multimedia Databases + +What do we have to consider in building and distributing databases of +visual materials in a multi-user environment? This presentation examines +a variety of concerns that need to be addressed before a multimedia +database can be set up in a networked environment. + +In the past it has not been feasible to implement databases of visual +materials in shared-user environments because of technological barriers. +Each of the two basic models for multi-user multimedia databases has +posed its own problem. The analog multimedia storage model (represented +by Project Athena's parallel analog and digital networks) has required an +incredibly complex (and expensive) infrastructure. The economies of +scale that make multi-user setups cheaper per user served do not operate +in an environment that requires a computer workstation, videodisc player, +and two display devices for each user. + +The digital multimedia storage model has required vast amounts of storage +space (as much as one gigabyte per thirty still images). In the past the +cost of such a large amount of storage space made this model a +prohibitive choice as well. But plunging storage costs are finally +making this second alternative viable. + +If storage no longer poses such an impediment, what do we need to +consider in building digitally stored multi-user databases of visual +materials? This presentation will examine the networking and +telecommunication constraints that must be overcome before such databases +can become commonplace and useful to a large number of people. + +The key problem is the vast size of multimedia documents, and how this +affects not only storage but telecommunications transmission time. +Anything slower than T-1 speed is impractical for files of 1 megabyte or +larger (which is likely to be small for a multimedia document). For +instance, even on a 56 Kb line it would take three minutes to transfer a +1-megabyte file. And these figures assume ideal circumstances, and do +not take into consideration other users contending for network bandwidth, +disk access time, or the time needed for remote display. Current common +telephone transmission rates would be completely impractical; few users +would be willing to wait the hour necessary to transmit a single image at +2400 baud. + +This necessitates compression, which itself raises a number of other +issues. In order to decrease file sizes significantly, we must employ +lossy compression algorithms. But how much quality can we afford to +lose? To date there has been only one significant study done of +image-quality needs for a particular user group, and this study did not +look at loss resulting from compression. Only after identifying +image-quality needs can we begin to address storage and network bandwidth +needs. + +Experience with X-Windows-based applications (such as Imagequery, the +University of California at Berkeley image database) demonstrates the +utility of a client-server topology, but also points to the limitation of +current software for a distributed environment. For example, +applications like Imagequery can incorporate compression, but current X +implementations do not permit decompression at the end user's +workstation. Such decompression at the host computer alleviates storage +capacity problems while doing nothing to address problems of +telecommunications bandwidth. + +We need to examine the effects on network through-put of moving +multimedia documents around on a network. We need to examine various +topologies that will help us avoid bottlenecks around servers and +gateways. Experience with applications such as these raise still broader +questions. How closely is the multimedia document tied to the software +for viewing it? Can it be accessed and viewed from other applications? +Experience with the MARC format (and more recently with the Z39.50 +protocols) shows how useful it can be to store documents in a form in +which they can be accessed by a variety of application software. + +Finally, from an intellectual-access standpoint, we need to address the +issue of providing access to these multimedia documents in +interdisciplinary environments. We need to examine terminology and +indexing strategies that will allow us to provide access to this material +in a cross-disciplinary way. + +Ronald LARSEN Directions in High-Performance Networking for + Libraries + +The pace at which computing technology has advanced over the past forty +years shows no sign of abating. Roughly speaking, each five-year period +has yielded an order-of-magnitude improvement in price and performance of +computing equipment. No fundamental hurdles are likely to prevent this +pace from continuing for at least the next decade. It is only in the +past five years, though, that computing has become ubiquitous in +libraries, affecting all staff and patrons, directly or indirectly. + +During these same five years, communications rates on the Internet, the +principal academic computing network, have grown from 56 kbps to 1.5 +Mbps, and the NSFNet backbone is now running 45 Mbps. Over the next five +years, communication rates on the backbone are expected to exceed 1 Gbps. +Growth in both the population of network users and the volume of network +traffic has continued to grow geometrically, at rates approaching 15 +percent per month. This flood of capacity and use, likened by some to +"drinking from a firehose," creates immense opportunities and challenges +for libraries. Libraries must anticipate the future implications of this +technology, participate in its development, and deploy it to ensure +access to the world's information resources. + +The infrastructure for the information age is being put in place. +Libraries face strategic decisions about their role in the development, +deployment, and use of this infrastructure. The emerging infrastructure +is much more than computers and communication lines. It is more than the +ability to compute at a remote site, send electronic mail to a peer +across the country, or move a file from one library to another. The next +five years will witness substantial development of the information +infrastructure of the network. + +In order to provide appropriate leadership, library professionals must +have a fundamental understanding of and appreciation for computer +networking, from local area networks to the National Research and +Education Network (NREN). This presentation addresses these +fundamentals, and how they relate to libraries today and in the near +future. + +Edwin BROWNRIGG Electronic Library Visions and Realities + +The electronic library has been a vision desired by many--and rejected by +some--since Vannevar Bush coined the term memex to describe an automated, +intelligent, personal information system. Variations on this vision have +included Ted Nelson's Xanadau, Alan Kay's Dynabook, and Lancaster's +"paperless library," with the most recent incarnation being the +"Knowledge Navigator" described by John Scully of Apple. But the reality +of library service has been less visionary and the leap to the electronic +library has eluded universities, publishers, and information technology +files. + +The Memex Research Institute (MemRI), an independent, nonprofit research +and development organization, has created an Electronic Library Program +of shared research and development in order to make the collective vision +more concrete. The program is working toward the creation of large, +indexed publicly available electronic image collections of published +documents in academic, special, and public libraries. This strategic +plan is the result of the first stage of the program, which has been an +investigation of the information technologies available to support such +an effort, the economic parameters of electronic service compared to +traditional library operations, and the business and political factors +affecting the shift from print distribution to electronic networked +access. + +The strategic plan envisions a combination of publicly searchable access +databases, image (and text) document collections stored on network "file +servers," local and remote network access, and an intellectual property +management-control system. This combination of technology and +information content is defined in this plan as an E-library or E-library +collection. Some participating sponsors are already developing projects +based on MemRI's recommended directions. + +The E-library strategy projected in this plan is a visionary one that can +enable major changes and improvements in academic, public, and special +library service. This vision is, though, one that can be realized with +today's technology. At the same time, it will challenge the political +and social structure within which libraries operate: in academic +libraries, the traditional emphasis on local collections, extending to +accreditation issues; in public libraries, the potential of electronic +branch and central libraries fully available to the public; and for +special libraries, new opportunities for shared collections and networks. + +The environment in which this strategic plan has been developed is, at +the moment, dominated by a sense of library limits. The continued +expansion and rapid growth of local academic library collections is now +clearly at an end. Corporate libraries, and even law libraries, are +faced with operating within a difficult economic climate, as well as with +very active competition from commercial information sources. For +example, public libraries may be seen as a desirable but not critical +municipal service in a time when the budgets of safety and health +agencies are being cut back. + +Further, libraries in general have a very high labor-to-cost ratio in +their budgets, and labor costs are still increasing, notwithstanding +automation investments. It is difficult for libraries to obtain capital, +startup, or seed funding for innovative activities, and those +technology-intensive initiatives that offer the potential of decreased +labor costs can provoke the opposition of library staff. + +However, libraries have achieved some considerable successes in the past +two decades by improving both their service and their credibility within +their organizations--and these positive changes have been accomplished +mostly with judicious use of information technologies. The advances in +computing and information technology have been well-chronicled: the +continuing precipitous drop in computing costs, the growth of the +Internet and private networks, and the explosive increase in publicly +available information databases. + +For example, OCLC has become one of the largest computer network +organizations in the world by creating a cooperative cataloging network +of more than 6,000 libraries worldwide. On-line public access catalogs +now serve millions of users on more than 50,000 dedicated terminals in +the United States alone. The University of California MELVYL on-line +catalog system has now expanded into an index database reference service +and supports more than six million searches a year. And, libraries have +become the largest group of customers of CD-ROM publishing technology; +more than 30,000 optical media publications such as those offered by +InfoTrac and Silver Platter are subscribed to by U.S. libraries. + +This march of technology continues and in the next decade will result in +further innovations that are extremely difficult to predict. What is +clear is that libraries can now go beyond automation of their order files +and catalogs to automation of their collections themselves--and it is +possible to circumvent the fiscal limitations that appear to obtain +today. + +This Electronic Library Strategic Plan recommends a paradigm shift in +library service, and demonstrates the steps necessary to provide improved +library services with limited capacities and operating investments. + +SESSION IV-A + +Anne KENNEY + +The Cornell/Xerox Joint Study in Digital Preservation resulted in the +recording of 1,000 brittle books as 600-dpi digital images and the +production, on demand, of high-quality and archivally sound paper +replacements. The project, which was supported by the Commission on +Preservation and Access, also investigated some of the issues surrounding +scanning, storing, retrieving, and providing access to digital images in +a network environment. + +Anne Kenney will focus on some of the issues surrounding direct scanning +as identified in the Cornell Xerox Project. Among those to be discussed +are: image versus text capture; indexing and access; image-capture +capabilities; a comparison to photocopy and microfilm; production and +cost analysis; storage formats, protocols, and standards; and the use of +this scanning technology for preservation purposes. + +The 600-dpi digital images produced in the Cornell Xerox Project proved +highly acceptable for creating paper replacements of deteriorating +originals. The 1,000 scanned volumes provided an array of image-capture +challenges that are common to nineteenth-century printing techniques and +embrittled material, and that defy the use of text-conversion processes. +These challenges include diminished contrast between text and background, +fragile and deteriorated pages, uneven printing, elaborate type faces, +faint and bold text adjacency, handwritten text and annotations, nonRoman +languages, and a proliferation of illustrated material embedded in text. +The latter category included high-frequency and low-frequency halftones, +continuous tone photographs, intricate mathematical drawings, maps, +etchings, reverse-polarity drawings, and engravings. + +The Xerox prototype scanning system provided a number of important +features for capturing this diverse material. Technicians used multiple +threshold settings, filters, line art and halftone definitions, +autosegmentation, windowing, and software-editing programs to optimize +image capture. At the same time, this project focused on production. +The goal was to make scanning as affordable and acceptable as +photocopying and microfilming for preservation reformatting. A +time-and-cost study conducted during the last three months of this +project confirmed the economic viability of digital scanning, and these +findings will be discussed here. + +From the outset, the Cornell Xerox Project was predicated on the use of +nonproprietary standards and the use of common protocols when standards +did not exist. Digital files were created as TIFF images which were +compressed prior to storage using Group 4 CCITT compression. The Xerox +software is MS DOS based and utilizes off-the shelf programs such as +Microsoft Windows and Wang Image Wizard. The digital library is designed +to be hardware-independent and to provide interchangeability with other +institutions through network connections. Access to the digital files +themselves is two-tiered: Bibliographic records for the computer files +are created in RLIN and Cornell's local system and access into the actual +digital images comprising a book is provided through a document control +structure and a networked image file-server, both of which will be +described. + +The presentation will conclude with a discussion of some of the issues +surrounding the use of this technology as a preservation tool (storage, +refreshing, backup). + +Pamela ANDRE and Judith ZIDAR + +The National Agricultural Library (NAL) has had extensive experience with +raster scanning of printed materials. Since 1987, the Library has +participated in the National Agricultural Text Digitizing Project (NATDP) +a cooperative effort between NAL and forty-five land grant university +libraries. An overview of the project will be presented, giving its +history and NAL's strategy for the future. + +An in-depth discussion of NATDP will follow, including a description of +the scanning process, from the gathering of the printed materials to the +archiving of the electronic pages. The type of equipment required for a +stand-alone scanning workstation and the importance of file management +software will be discussed. Issues concerning the images themselves will +be addressed briefly, such as image format; black and white versus color; +gray scale versus dithering; and resolution. + +Also described will be a study currently in progress by NAL to evaluate +the usefulness of converting microfilm to electronic images in order to +improve access. With the cooperation of Tuskegee University, NAL has +selected three reels of microfilm from a collection of sixty-seven reels +containing the papers, letters, and drawings of George Washington Carver. +The three reels were converted into 3,500 electronic images using a +specialized microfilm scanner. The selection, filming, and indexing of +this material will be discussed. + +Donald WATERS + +Project Open Book, the Yale University Library's effort to convert 10, +000 books from microfilm to digital imagery, is currently in an advanced +state of planning and organization. The Yale Library has selected a +major vendor to serve as a partner in the project and as systems +integrator. In its proposal, the successful vendor helped isolate areas +of risk and uncertainty as well as key issues to be addressed during the +life of the project. The Yale Library is now poised to decide what +material it will convert to digital image form and to seek funding, +initially for the first phase and then for the entire project. + +The proposal that Yale accepted for the implementation of Project Open +Book will provide at the end of three phases a conversion subsystem, +browsing stations distributed on the campus network within the Yale +Library, a subsystem for storing 10,000 books at 200 and 600 dots per +inch, and network access to the image printers. Pricing for the system +implementation assumes the existence of Yale's campus ethernet network +and its high-speed image printers, and includes other requisite hardware +and software, as well as system integration services. Proposed operating +costs include hardware and software maintenance, but do not include +estimates for the facilities management of the storage devices and image +servers. + +Yale selected its vendor partner in a formal process, partly funded by +the Commission for Preservation and Access. Following a request for +proposal, the Yale Library selected two vendors as finalists to work with +Yale staff to generate a detailed analysis of requirements for Project +Open Book. Each vendor used the results of the requirements analysis to +generate and submit a formal proposal for the entire project. This +competitive process not only enabled the Yale Library to select its +primary vendor partner but also revealed much about the state of the +imaging industry, about the varying, corporate commitments to the markets +for imaging technology, and about the varying organizational dynamics +through which major companies are responding to and seeking to develop +these markets. + +Project Open Book is focused specifically on the conversion of images +from microfilm to digital form. The technology for scanning microfilm is +readily available but is changing rapidly. In its project requirements, +the Yale Library emphasized features of the technology that affect the +technical quality of digital image production and the costs of creating +and storing the image library: What levels of digital resolution can be +achieved by scanning microfilm? How does variation in the quality of +microfilm, particularly in film produced to preservation standards, +affect the quality of the digital images? What technologies can an +operator effectively and economically apply when scanning film to +separate two-up images and to control for and correct image +imperfections? How can quality control best be integrated into +digitizing work flow that includes document indexing and storage? + +The actual and expected uses of digital images--storage, browsing, +printing, and OCR--help determine the standards for measuring their +quality. Browsing is especially important, but the facilities available +for readers to browse image documents is perhaps the weakest aspect of +imaging technology and most in need of development. As it defined its +requirements, the Yale Library concentrated on some fundamental aspects +of usability for image documents: Does the system have sufficient +flexibility to handle the full range of document types, including +monographs, multi-part and multivolume sets, and serials, as well as +manuscript collections? What conventions are necessary to identify a +document uniquely for storage and retrieval? Where is the database of +record for storing bibliographic information about the image document? +How are basic internal structures of documents, such as pagination, made +accessible to the reader? How are the image documents physically +presented on the screen to the reader? + +The Yale Library designed Project Open Book on the assumption that +microfilm is more than adequate as a medium for preserving the content of +deteriorated library materials. As planning in the project has advanced, +it is increasingly clear that the challenge of digital image technology +and the key to the success of efforts like Project Open Book is to +provide a means of both preserving and improving access to those +deteriorated materials. + +SESSION IV-B + +George THOMA + +In the use of electronic imaging for document preservation, there are +several issues to consider, such as: ensuring adequate image quality, +maintaining substantial conversion rates (through-put), providing unique +identification for automated access and retrieval, and accommodating +bound volumes and fragile material. + +To maintain high image quality, image processing functions are required +to correct the deficiencies in the scanned image. Some commercially +available systems include these functions, while some do not. The +scanned raw image must be processed to correct contrast deficiencies-- +both poor overall contrast resulting from light print and/or dark +background, and variable contrast resulting from stains and +bleed-through. Furthermore, the scan density must be adequate to allow +legibility of print and sufficient fidelity in the pseudo-halftoned gray +material. Borders or page-edge effects must be removed for both +compactibility and aesthetics. Page skew must be corrected for aesthetic +reasons and to enable accurate character recognition if desired. +Compound images consisting of both two-toned text and gray-scale +illustrations must be processed appropriately to retain the quality of +each. + +SESSION IV-C + +Jean BARONAS + +Standards publications being developed by scientists, engineers, and +business managers in Association for Information and Image Management +(AIIM) standards committees can be applied to electronic image management +(EIM) processes including: document (image) transfer, retrieval and +evaluation; optical disk and document scanning; and document design and +conversion. When combined with EIM system planning and operations, +standards can assist in generating image databases that are +interchangeable among a variety of systems. The applications of +different approaches for image-tagging, indexing, compression, and +transfer often cause uncertainty concerning EIM system compatibility, +calibration, performance, and upward compatibility, until standard +implementation parameters are established. The AIIM standards that are +being developed for these applications can be used to decrease the +uncertainty, successfully integrate imaging processes, and promote "open +systems." AIIM is an accredited American National Standards Institute +(ANSI) standards developer with more than twenty committees comprised of +300 volunteers representing users, vendors, and manufacturers. The +standards publications that are developed in these committees have +national acceptance and provide the basis for international harmonization +in the development of new International Organization for Standardization +(ISO) standards. + +This presentation describes the development of AIIM's EIM standards and a +new effort at AIIM, a database on standards projects in a wide framework +of imaging industries including capture, recording, processing, +duplication, distribution, display, evaluation, and preservation. The +AIIM Imagery Database will cover imaging standards being developed by +many organizations in many different countries. It will contain +standards publications' dates, origins, related national and +international projects, status, key words, and abstracts. The ANSI Image +Technology Standards Board requested that such a database be established, +as did the ISO/International Electrotechnical Commission Joint Task Force +on Imagery. AIIM will take on the leadership role for the database and +coordinate its development with several standards developers. + +Patricia BATTIN + + Characteristics of standards for digital imagery: + + * Nature of digital technology implies continuing volatility. + + * Precipitous standard-setting not possible and probably not + desirable. + + * Standards are a complex issue involving the medium, the + hardware, the software, and the technical capacity for + reproductive fidelity and clarity. + + * The prognosis for reliable archival standards (as defined by + librarians) in the foreseeable future is poor. + + Significant potential and attractiveness of digital technology as a + preservation medium and access mechanism. + + Productive use of digital imagery for preservation requires a + reconceptualizing of preservation principles in a volatile, + standardless world. + + Concept of managing continuing access in the digital environment + rather than focusing on the permanence of the medium and long-term + archival standards developed for the analog world. + + Transition period: How long and what to do? + + * Redefine "archival." + + * Remove the burden of "archival copy" from paper artifacts. + + * Use digital technology for storage, develop management + strategies for refreshing medium, hardware and software. + + * Create acid-free paper copies for transition period backup + until we develop reliable procedures for ensuring continuing + access to digital files. + +SESSION IV-D + +Stuart WEIBEL The Role of SGML Markup in the CORE Project (6) + +The emergence of high-speed telecommunications networks as a basic +feature of the scholarly workplace is driving the demand for electronic +document delivery. Three distinct categories of electronic +publishing/republishing are necessary to support access demands in this +emerging environment: + + 1.) Conversion of paper or microfilm archives to electronic format + 2.) Conversion of electronic files to formats tailored to + electronic retrieval and display + 3.) Primary electronic publishing (materials for which the + electronic version is the primary format) + +OCLC has experimental or product development activities in each of these +areas. Among the challenges that lie ahead is the integration of these +three types of information stores in coherent distributed systems. + +The CORE (Chemistry Online Retrieval Experiment) Project is a model for +the conversion of large text and graphics collections for which +electronic typesetting files are available (category 2). The American +Chemical Society has made available computer typography files dating from +1980 for its twenty journals. This collection of some 250 journal-years +is being converted to an electronic format that will be accessible +through several end-user applications. + +The use of Standard Generalized Markup Language (SGML) offers the means +to capture the structural richness of the original articles in a way that +will support a variety of retrieval, navigation, and display options +necessary to navigate effectively in very large text databases. + +An SGML document consists of text that is marked up with descriptive tags +that specify the function of a given element within the document. As a +formal language construct, an SGML document can be parsed against a +document-type definition (DTD) that unambiguously defines what elements +are allowed and where in the document they can (or must) occur. This +formalized map of article structure allows the user interface design to +be uncoupled from the underlying database system, an important step +toward interoperability. Demonstration of this separability is a part of +the CORE project, wherein user interface designs born of very different +philosophies will access the same database. + +NOTES: + (6) The CORE project is a collaboration among Cornell University's + Mann Library, Bell Communications Research (Bellcore), the American + Chemical Society (ACS), the Chemical Abstracts Service (CAS), and + OCLC. + +Michael LESK The CORE Electronic Chemistry Library + +A major on-line file of chemical journal literature complete with +graphics is being developed to test the usability of fully electronic +access to documents, as a joint project of Cornell University, the +American Chemical Society, the Chemical Abstracts Service, OCLC, and +Bellcore (with additional support from Sun Microsystems, Springer-Verlag, +DigitaI Equipment Corporation, Sony Corporation of America, and Apple +Computers). Our file contains the American Chemical Society's on-line +journals, supplemented with the graphics from the paper publication. The +indexing of the articles from Chemical Abstracts Documents is available +in both image and text format, and several different interfaces can be +used. Our goals are (1) to assess the effectiveness and acceptability of +electronic access to primary journals as compared with paper, and (2) to +identify the most desirable functions of the user interface to an +electronic system of journals, including in particular a comparison of +page-image display with ASCII display interfaces. Early experiments with +chemistry students on a variety of tasks suggest that searching tasks are +completed much faster with any electronic system than with paper, but +that for reading all versions of the articles are roughly equivalent. + +Pamela ANDRE and Judith ZIDAR + +Text conversion is far more expensive and time-consuming than image +capture alone. NAL's experience with optical character recognition (OCR) +will be related and compared with the experience of having text rekeyed. +What factors affect OCR accuracy? How accurate does full text have to be +in order to be useful? How do different users react to imperfect text? +These are questions that will be explored. For many, a service bureau +may be a better solution than performing the work inhouse; this will also +be discussed. + +SESSION VI + +Marybeth PETERS + +Copyright law protects creative works. Protection granted by the law to +authors and disseminators of works includes the right to do or authorize +the following: reproduce the work, prepare derivative works, distribute +the work to the public, and publicly perform or display the work. In +addition, copyright owners of sound recordings and computer programs have +the right to control rental of their works. These rights are not +unlimited; there are a number of exceptions and limitations. + +An electronic environment places strains on the copyright system. +Copyright owners want to control uses of their work and be paid for any +use; the public wants quick and easy access at little or no cost. The +marketplace is working in this area. Contracts, guidelines on electronic +use, and collective licensing are in use and being refined. + +Issues concerning the ability to change works without detection are more +difficult to deal with. Questions concerning the integrity of the work +and the status of the changed version under the copyright law are to be +addressed. These are public policy issues which require informed +dialogue. + + + *** *** *** ****** *** *** *** + + + Appendix III: DIRECTORY OF PARTICIPANTS + + +PRESENTERS: + + Pamela Q.J. Andre + Associate Director, Automation + National Agricultural Library + 10301 Baltimore Boulevard + Beltsville, MD 20705-2351 + Phone: (301) 504-6813 + Fax: (301) 504-7473 + E-mail: INTERNET: PANDRE@ASRR.ARSUSDA.GOV + + Jean Baronas, Senior Manager + Department of Standards and Technology + Association for Information and Image Management (AIIM) + 1100 Wayne Avenue, Suite 1100 + Silver Spring, MD 20910 + Phone: (301) 587-8202 + Fax: (301) 587-2711 + + Patricia Battin, President + The Commission on Preservation and Access + 1400 16th Street, N.W. + Suite 740 + Washington, DC 20036-2217 + Phone: (202) 939-3400 + Fax: (202) 939-3407 + E-mail: CPA@GWUVM.BITNET + + Howard Besser + Centre Canadien d'Architecture + (Canadian Center for Architecture) + 1920, rue Baile + Montreal, Quebec H3H 2S6 + CANADA + Phone: (514) 939-7001 + Fax: (514) 939-7020 + E-mail: howard@lis.pitt.edu + + Edwin B. Brownrigg, Executive Director + Memex Research Institute + 422 Bonita Avenue + Roseville, CA 95678 + Phone: (916) 784-2298 + Fax: (916) 786-7559 + E-mail: BITNET: MEMEX@CALSTATE.2 + + Eric M. Calaluca, Vice President + Chadwyck-Healey, Inc. + 1101 King Street + Alexandria, VA 223l4 + Phone: (800) 752-05l5 + Fax: (703) 683-7589 + + James Daly + 4015 Deepwood Road + Baltimore, MD 21218-1404 + Phone: (410) 235-0763 + + Ricky Erway, Associate Coordinator + American Memory + Library of Congress + Phone: (202) 707-6233 + Fax: (202) 707-3764 + + Carl Fleischhauer, Coordinator + American Memory + Library of Congress + Phone: (202) 707-6233 + Fax: (202) 707-3764 + + Joanne Freeman + 2000 Jefferson Park Avenue, No. 7 + Charlottesville, VA 22903 + + Prosser Gifford + Director for Scholarly Programs + Library of Congress + Phone: (202) 707-1517 + Fax: (202) 707-9898 + E-mail: pgif@seq1.loc.gov + + Jacqueline Hess, Director + National Demonstration Laboratory + for Interactive Information Technologies + Library of Congress + Phone: (202) 707-4157 + Fax: (202) 707-2829 + + Susan Hockey, Director + Center for Electronic Texts in the Humanities (CETH) + Alexander Library + Rutgers University + 169 College Avenue + New Brunswick, NJ 08903 + Phone: (908) 932-1384 + Fax: (908) 932-1386 + E-mail: hockey@zodiac.rutgers.edu + + William L. Hooton, Vice President + Business & Technical Development + Imaging & Information Systems Group + I-NET + 6430 Rockledge Drive, Suite 400 + Bethesda, MD 208l7 + Phone: (301) 564-6750 + Fax: (513) 564-6867 + + Anne R. Kenney, Associate Director + Department of Preservation and Conservation + 701 Olin Library + Cornell University + Ithaca, NY 14853 + Phone: (607) 255-6875 + Fax: (607) 255-9346 + E-mail: LYDY@CORNELLA.BITNET + + Ronald L. Larsen + Associate Director for Information Technology + University of Maryland at College Park + Room B0224, McKeldin Library + College Park, MD 20742-7011 + Phone: (301) 405-9194 + Fax: (301) 314-9865 + E-mail: rlarsen@libr.umd.edu + + Maria L. Lebron, Managing Editor + The Online Journal of Current Clinical Trials + l333 H Street, N.W. + Washington, DC 20005 + Phone: (202) 326-6735 + Fax: (202) 842-2868 + E-mail: PUBSAAAS@GWUVM.BITNET + + Michael Lesk, Executive Director + Computer Science Research + Bell Communications Research, Inc. + Rm 2A-385 + 445 South Street + Morristown, NJ 07960-l9l0 + Phone: (201) 829-4070 + Fax: (201) 829-5981 + E-mail: lesk@bellcore.com (Internet) or bellcore!lesk (uucp) + + Clifford A. Lynch + Director, Library Automation + University of California, + Office of the President + 300 Lakeside Drive, 8th Floor + Oakland, CA 94612-3350 + Phone: (510) 987-0522 + Fax: (510) 839-3573 + E-mail: calur@uccmvsa + + Avra Michelson + National Archives and Records Administration + NSZ Rm. 14N + 7th & Pennsylvania, N.W. + Washington, D.C. 20408 + Phone: (202) 501-5544 + Fax: (202) 501-5533 + E-mail: tmi@cu.nih.gov + + Elli Mylonas, Managing Editor + Perseus Project + Department of the Classics + Harvard University + 319 Boylston Hall + Cambridge, MA 02138 + Phone: (617) 495-9025, (617) 495-0456 (direct) + Fax: (617) 496-8886 + E-mail: Elli@IKAROS.Harvard.EDU or elli@wjh12.harvard.edu + + David Woodley Packard + Packard Humanities Institute + 300 Second Street, Suite 201 + Los Altos, CA 94002 + Phone: (415) 948-0150 (PHI) + Fax: (415) 948-5793 + + Lynne K. Personius, Assistant Director + Cornell Information Technologies for + Scholarly Information Sources + 502 Olin Library + Cornell University + Ithaca, NY 14853 + Phone: (607) 255-3393 + Fax: (607) 255-9346 + E-mail: JRN@CORNELLC.BITNET + + Marybeth Peters + Policy Planning Adviser to the + Register of Copyrights + Library of Congress + Office LM 403 + Phone: (202) 707-8350 + Fax: (202) 707-8366 + + C. Michael Sperberg-McQueen + Editor, Text Encoding Initiative + Computer Center (M/C 135) + University of Illinois at Chicago + Box 6998 + Chicago, IL 60680 + Phone: (312) 413-0317 + Fax: (312) 996-6834 + E-mail: u35395@uicvm..cc.uic.edu or u35395@uicvm.bitnet + + George R. Thoma, Chief + Communications Engineering Branch + National Library of Medicine + 8600 Rockville Pike + Bethesda, MD 20894 + Phone: (301) 496-4496 + Fax: (301) 402-0341 + E-mail: thoma@lhc.nlm.nih.gov + + Dorothy Twohig, Editor + The Papers of George Washington + 504 Alderman Library + University of Virginia + Charlottesville, VA 22903-2498 + Phone: (804) 924-0523 + Fax: (804) 924-4337 + + Susan H. Veccia, Team leader + American Memory, User Evaluation + Library of Congress + American Memory Evaluation Project + Phone: (202) 707-9104 + Fax: (202) 707-3764 + E-mail: svec@seq1.loc.gov + + Donald J. Waters, Head + Systems Office + Yale University Library + New Haven, CT 06520 + Phone: (203) 432-4889 + Fax: (203) 432-7231 + E-mail: DWATERS@YALEVM.BITNET or DWATERS@YALEVM.YCC.YALE.EDU + + Stuart Weibel, Senior Research Scientist + OCLC + 6565 Frantz Road + Dublin, OH 43017 + Phone: (614) 764-608l + Fax: (614) 764-2344 + E-mail: INTERNET: Stu@rsch.oclc.org + + Robert G. Zich + Special Assistant to the Associate Librarian + for Special Projects + Library of Congress + Phone: (202) 707-6233 + Fax: (202) 707-3764 + E-mail: rzic@seq1.loc.gov + + Judith A. Zidar, Coordinator + National Agricultural Text Digitizing Program + Information Systems Division + National Agricultural Library + 10301 Baltimore Boulevard + Beltsville, MD 20705-2351 + Phone: (301) 504-6813 or 504-5853 + Fax: (301) 504-7473 + E-mail: INTERNET: JZIDAR@ASRR.ARSUSDA.GOV + + +OBSERVERS: + + Helen Aguera, Program Officer + Division of Research + Room 318 + National Endowment for the Humanities + 1100 Pennsylvania Avenue, N.W. + Washington, D.C. 20506 + Phone: (202) 786-0358 + Fax: (202) 786-0243 + + M. Ellyn Blanton, Deputy Director + National Demonstration Laboratory + for Interactive Information Technologies + Library of Congress + Phone: (202) 707-4157 + Fax: (202) 707-2829 + + Charles M. Dollar + National Archives and Records Administration + NSZ Rm. 14N + 7th & Pennsylvania, N.W. + Washington, DC 20408 + Phone: (202) 501-5532 + Fax: (202) 501-5512 + + Jeffrey Field, Deputy to the Director + Division of Preservation and Access + Room 802 + National Endowment for the Humanities + 1100 Pennsylvania Avenue, N.W. + Washington, DC 20506 + Phone: (202) 786-0570 + Fax: (202) 786-0243 + + Lorrin Garson + American Chemical Society + Research and Development Department + 1155 16th Street, N.W. + Washington, D.C. 20036 + Phone: (202) 872-4541 + Fax: E-mail: INTERNET: LRG96@ACS.ORG + + William M. Holmes, Jr. + National Archives and Records Administration + NSZ Rm. 14N + 7th & Pennsylvania, N.W. + Washington, DC 20408 + Phone: (202) 501-5540 + Fax: (202) 501-5512 + E-mail: WHOLMES@AMERICAN.EDU + + Sperling Martin + Information Resource Management + 20030 Doolittle Street + Gaithersburg, MD 20879 + Phone: (301) 924-1803 + + Michael Neuman, Director + The Center for Text and Technology + Academic Computing Center + 238 Reiss Science Building + Georgetown University + Washington, DC 20057 + Phone: (202) 687-6096 + Fax: (202) 687-6003 + E-mail: neuman@guvax.bitnet, neuman@guvax.georgetown.edu + + Barbara Paulson, Program Officer + Division of Preservation and Access + Room 802 + National Endowment for the Humanities + 1100 Pennsylvania Avenue, N.W. + Washington, DC 20506 + Phone: (202) 786-0577 + Fax: (202) 786-0243 + + Allen H. Renear + Senior Academic Planning Analyst + Brown University Computing and Information Services + 115 Waterman Street + Campus Box 1885 + Providence, R.I. 02912 + Phone: (401) 863-7312 + Fax: (401) 863-7329 + E-mail: BITNET: Allen@BROWNVM or + INTERNET: Allen@brownvm.brown.edu + + Susan M. Severtson, President + Chadwyck-Healey, Inc. + 1101 King Street + Alexandria, VA 223l4 + Phone: (800) 752-05l5 + Fax: (703) 683-7589 + + Frank Withrow + U.S. Department of Education + 555 New Jersey Avenue, N.W. + Washington, DC 20208-5644 + Phone: (202) 219-2200 + Fax: (202) 219-2106 + + +(LC STAFF) + + Linda L. Arret + Machine-Readable Collections Reading Room LJ 132 + (202) 707-1490 + + John D. Byrum, Jr. + Descriptive Cataloging Division LM 540 + (202) 707-5194 + + Mary Jane Cavallo + Science and Technology Division LA 5210 + (202) 707-1219 + + Susan Thea David + Congressional Research Service LM 226 + (202) 707-7169 + + Robert Dierker + Senior Adviser for Multimedia Activities LM 608 + (202) 707-6151 + + William W. Ellis + Associate Librarian for Science and Technology LM 611 + (202) 707-6928 + + Ronald Gephart + Manuscript Division LM 102 + (202) 707-5097 + + James Graber + Information Technology Services LM G51 + (202) 707-9628 + + Rich Greenfield + American Memory LM 603 + (202) 707-6233 + + Rebecca Guenther + Network Development LM 639 + (202) 707-5092 + + Kenneth E. Harris + Preservation LM G21 + (202) 707-5213 + + Staley Hitchcock + Manuscript Division LM 102 + (202) 707-5383 + + Bohdan Kantor + Office of Special Projects LM 612 + (202) 707-0180 + + John W. Kimball, Jr + Machine-Readable Collections Reading Room LJ 132 + (202) 707-6560 + + Basil Manns + Information Technology Services LM G51 + (202) 707-8345 + + Sally Hart McCallum + Network Development LM 639 + (202) 707-6237 + + Dana J. Pratt + Publishing Office LM 602 + (202) 707-6027 + + Jane Riefenhauser + American Memory LM 603 + (202) 707-6233 + + William Z. Schenck + Collections Development LM 650 + (202) 707-7706 + + Chandru J. Shahani + Preservation Research and Testing Office (R&T) LM G38 + (202) 707-5607 + + William J. Sittig + Collections Development LM 650 + (202) 707-7050 + + Paul Smith + Manuscript Division LM 102 + (202) 707-5097 + + James L. Stevens + Information Technology Services LM G51 + (202) 707-9688 + + Karen Stuart + Manuscript Division LM 130 + (202) 707-5389 + + Tamara Swora + Preservation Microfilming Office LM G05 + (202) 707-6293 + + Sarah Thomas + Collections Cataloging LM 642 + (202) 707-5333 + + + END + ************************************************************* + +Note: This file has been edited for use on computer networks. This +editing required the removal of diacritics, underlining, and fonts such +as italics and bold. + +kde 11/92 + +[A few of the italics (when used for emphasis) were replaced by CAPS mh] + +*End of The Project Gutenberg Etext of LOC WORKSHOP ON ELECTRONIC ETEXTS + diff --git a/test/data/paper-100k.pdf b/test/data/paper-100k.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b3325e4a2bb578419d6c7fa412aaa78d493ff274 GIT binary patch literal 102400 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 f+ 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 +#include +#include + +#include "test_shared_ng.h" + +#define TESTFILE "foo.gz" + +static const char dictionary[] = "hello"; +static unsigned long dictId = 0; /* Adler32 value of the dictionary */ + +/* Maximum dictionary size, according to inflateGetDictionary() description. */ +#define MAX_DICTIONARY_SIZE 32768 + +static alloc_func zalloc = NULL; +static free_func zfree = NULL; + +/* =========================================================================== + * Display error message and exit + */ +void error(const char *format, ...) { + va_list va; + + va_start(va, format); + vfprintf(stderr, format, va); + va_end(va); + + exit(1); +} + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) \ + error("%s error: %d\n", msg, err); \ +} + +/* =========================================================================== + * Test compress() and uncompress() + */ +static void test_compress(unsigned char *compr, z_uintmax_t comprLen, unsigned char *uncompr, z_uintmax_t uncomprLen) { + int err; + unsigned int len = (unsigned int)strlen(hello)+1; + + err = PREFIX(compress)(compr, &comprLen, (const unsigned char*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = PREFIX(uncompress)(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) + error("bad uncompress\n"); + else + printf("uncompress(): %s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test read/write of .gz files + */ +static void test_gzio(const char *fname, unsigned char *uncompr, z_size_t uncomprLen) { +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + size_t read; + size_t len = strlen(hello)+1; + gzFile file; + z_off64_t pos; + z_off64_t comprLen; + + /* Write gz file with test data */ + file = PREFIX(gzopen)(fname, "wb"); + if (file == NULL) + error("gzopen error\n"); + /* Write hello, hello! using gzputs and gzprintf */ + PREFIX(gzputc)(file, 'h'); + if (PREFIX(gzputs)(file, "ello") != 4) + error("gzputs err: %s\n", PREFIX(gzerror)(file, &err)); + if (PREFIX(gzprintf)(file, ", %s!", "hello") != 8) + error("gzprintf err: %s\n", PREFIX(gzerror)(file, &err)); + /* Write string null-teriminator using gzseek */ + if (PREFIX(gzseek)(file, 1L, SEEK_CUR) < 0) + error("gzseek error, gztell=%ld\n", (long)PREFIX(gztell)(file)); + /* Write hello, hello! using gzfwrite using best compression level */ + if (PREFIX(gzsetparams)(file, Z_BEST_COMPRESSION, Z_DEFAULT_STRATEGY) != Z_OK) + error("gzsetparams err: %s\n", PREFIX(gzerror)(file, &err)); + if (PREFIX(gzfwrite)(hello, len, 1, file) == 0) + error("gzfwrite err: %s\n", PREFIX(gzerror)(file, &err)); + /* Flush compressed bytes to file */ + if (PREFIX(gzflush)(file, Z_SYNC_FLUSH) != Z_OK) + error("gzflush err: %s\n", PREFIX(gzerror)(file, &err)); + comprLen = PREFIX(gzoffset)(file); + if (comprLen <= 0) + error("gzoffset err: %s\n", PREFIX(gzerror)(file, &err)); + PREFIX(gzclose)(file); + + /* Open gz file we previously wrote */ + file = PREFIX(gzopen)(fname, "rb"); + if (file == NULL) + error("gzopen error\n"); + + /* Read uncompressed data - hello, hello! string twice */ + strcpy((char*)uncompr, "garbages"); + if (PREFIX(gzread)(file, uncompr, (unsigned)uncomprLen) != (int)(len + len)) + error("gzread err: %s\n", PREFIX(gzerror)(file, &err)); + if (strcmp((char*)uncompr, hello)) + error("bad gzread: %s\n", (char*)uncompr); + else + printf("gzread(): %s\n", (char*)uncompr); + /* Check position at the end of the gz file */ + if (PREFIX(gzeof)(file) != 1) + error("gzeof err: not reporting end of stream\n"); + + /* Seek backwards mid-string and check char reading with gzgetc and gzungetc */ + pos = PREFIX(gzseek)(file, -22L, SEEK_CUR); + if (pos != 6 || PREFIX(gztell)(file) != pos) + error("gzseek error, pos=%ld, gztell=%ld\n", (long)pos, (long)PREFIX(gztell)(file)); + if (PREFIX(gzgetc)(file) != ' ') + error("gzgetc error\n"); + if (PREFIX(gzungetc)(' ', file) != ' ') + error("gzungetc error\n"); + /* Read first hello, hello! string with gzgets */ + strcpy((char*)uncompr, "garbages"); + PREFIX(gzgets)(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) /* " hello!" */ + error("gzgets err after gzseek: %s\n", PREFIX(gzerror)(file, &err)); + if (strcmp((char*)uncompr, hello + 6)) + error("bad gzgets after gzseek\n"); + else + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + /* Seek to second hello, hello! string */ + pos = PREFIX(gzseek)(file, 14L, SEEK_SET); + if (pos != 14 || PREFIX(gztell)(file) != pos) + error("gzseek error, pos=%ld, gztell=%ld\n", (long)pos, (long)PREFIX(gztell)(file)); + /* Check position not at end of file */ + if (PREFIX(gzeof)(file) != 0) + error("gzeof err: reporting end of stream\n"); + /* Read first hello, hello! string with gzfread */ + strcpy((char*)uncompr, "garbages"); + read = PREFIX(gzfread)(uncompr, uncomprLen, 1, file); + if (strcmp((const char *)uncompr, hello) != 0) + error("bad gzgets\n"); + else + printf("gzgets(): %s\n", (char*)uncompr); + pos = PREFIX(gzoffset)(file); + if (pos < 0 || pos != (comprLen + 10)) + error("gzoffset err: wrong offset at end\n"); + /* Trigger an error and clear it with gzclearerr */ + PREFIX(gzfread)(uncompr, (size_t)-1, (size_t)-1, file); + PREFIX(gzerror)(file, &err); + if (err == 0) + error("gzerror err: no error returned\n"); + PREFIX(gzclearerr)(file); + PREFIX(gzerror)(file, &err); + if (err != 0) + error("gzclearerr err: not zero %d\n", err); + + PREFIX(gzclose)(file); + + if (PREFIX(gzclose)(NULL) != Z_STREAM_ERROR) + error("gzclose unexpected return when handle null\n"); + Z_UNUSED(read); +#endif +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +static void test_deflate(unsigned char *compr, size_t comprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + size_t len = strlen(hello)+1; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (void *)0; + c_stream.total_in = 0; + c_stream.total_out = 0; + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +static void test_inflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { + int err; + PREFIX3(stream) d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (void *)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + d_stream.total_in = 0; + d_stream.total_out = 0; + + err = PREFIX(inflateInit)(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) + error("bad inflate\n"); + else + printf("inflate(): %s\n", (char *)uncompr); +} + +static unsigned int diff; + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +static void test_large_deflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen, int zng_params) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; +#ifndef ZLIB_COMPAT + int level = -1; + int strategy = -1; + zng_deflate_param_value params[2]; + + params[0].param = Z_DEFLATE_LEVEL; + params[0].buf = &level; + params[0].size = sizeof(level); + + params[1].param = Z_DEFLATE_STRATEGY; + params[1].buf = &strategy; + params[1].size = sizeof(strategy); +#endif + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (void *)0; + + err = PREFIX(deflateInit)(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (unsigned int)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (unsigned int)uncomprLen; + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) + error("deflate not greedy\n"); + + /* Feed in already compressed data and switch to no compression: */ + if (zng_params) { +#ifndef ZLIB_COMPAT + zng_deflateGetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); + if (level != Z_BEST_SPEED) + error("Expected compression level Z_BEST_SPEED, got %d\n", level); + if (strategy != Z_DEFAULT_STRATEGY) + error("Expected compression strategy Z_DEFAULT_STRATEGY, got %d\n", strategy); + level = Z_NO_COMPRESSION; + strategy = Z_DEFAULT_STRATEGY; + zng_deflateSetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); +#else + error("test_large_deflate() called with zng_params=1 in compat mode\n"); +#endif + } else { + PREFIX(deflateParams)(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + } + c_stream.next_in = compr; + diff = (unsigned int)(c_stream.next_out - compr); + c_stream.avail_in = diff; + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + if (zng_params) { +#ifndef ZLIB_COMPAT + level = -1; + strategy = -1; + zng_deflateGetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); + if (level != Z_NO_COMPRESSION) + error("Expected compression level Z_NO_COMPRESSION, got %d\n", level); + if (strategy != Z_DEFAULT_STRATEGY) + error("Expected compression strategy Z_DEFAULT_STRATEGY, got %d\n", strategy); + level = Z_BEST_COMPRESSION; + strategy = Z_FILTERED; + zng_deflateSetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); +#else + error("test_large_deflate() called with zng_params=1 in compat mode\n"); +#endif + } else { + PREFIX(deflateParams)(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + } + c_stream.next_in = uncompr; + c_stream.avail_in = (unsigned int)uncomprLen; + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) + error("deflate should report Z_STREAM_END\n"); + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +static void test_large_inflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { + int err; + PREFIX3(stream) d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (void *)0; + + d_stream.next_in = compr; + d_stream.avail_in = (unsigned int)comprLen; + d_stream.total_in = 0; + d_stream.total_out = 0; + + err = PREFIX(inflateInit)(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (unsigned int)uncomprLen; + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + diff) + error("bad large inflate: %" PRIu64 "\n", (uint64_t)d_stream.total_out); + else + printf("large_inflate(): OK\n"); +} + +/* =========================================================================== + * Test deflate() with full flush + */ +static void test_flush(unsigned char *compr, z_uintmax_t *comprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + unsigned int len = (unsigned int)strlen(hello)+1; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (void *)0; + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (unsigned int)*comprLen; + err = PREFIX(deflate)(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = (z_size_t)c_stream.total_out; +} + +#ifdef ZLIBNG_ENABLE_TESTS +/* =========================================================================== + * Test inflateSync() + * We expect a certain compressed block layout, so skip this with the original zlib. + */ +static void test_sync(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { + int err; + PREFIX3(stream) d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (void *)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = PREFIX(inflateInit)(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (unsigned int)uncomprLen; + + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (unsigned int)comprLen-2; /* read all compressed data */ + err = PREFIX(inflateSync)(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = PREFIX(inflate)(&d_stream, Z_FINISH); + if (err != Z_STREAM_END) + error("inflate should report Z_STREAM_END\n"); + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} +#endif + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +static void test_dict_deflate(unsigned char *compr, size_t comprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (void *)0; + c_stream.adler = 0; + + err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = PREFIX(deflateSetDictionary)(&c_stream, + (const unsigned char*)dictionary, (int)sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (unsigned int)comprLen; + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.avail_in = (unsigned int)strlen(hello)+1; + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) + error("deflate should report Z_STREAM_END\n"); + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +static void test_dict_inflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { + int err; + uint8_t check_dictionary[MAX_DICTIONARY_SIZE]; + uint32_t check_dictionary_len = 0; + PREFIX3(stream) d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage garbage garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (void *)0; + d_stream.adler = 0; + d_stream.next_in = compr; + d_stream.avail_in = (unsigned int)comprLen; + + err = PREFIX(inflateInit)(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (unsigned int)uncomprLen; + + for (;;) { + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) + error("unexpected dictionary"); + err = PREFIX(inflateSetDictionary)(&d_stream, (const unsigned char*)dictionary, + (int)sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = PREFIX(inflateGetDictionary)(&d_stream, NULL, &check_dictionary_len); + CHECK_ERR(err, "inflateGetDictionary"); +#ifndef S390_DFLTCC_INFLATE + if (check_dictionary_len < sizeof(dictionary)) + error("bad dictionary length\n"); +#endif + + err = PREFIX(inflateGetDictionary)(&d_stream, check_dictionary, &check_dictionary_len); + CHECK_ERR(err, "inflateGetDictionary"); +#ifndef S390_DFLTCC_INFLATE + if (memcmp(dictionary, check_dictionary, sizeof(dictionary)) != 0) + error("bad dictionary\n"); +#endif + + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strncmp((char*)uncompr, hello, sizeof(hello))) + error("bad inflate with dict\n"); + else + printf("inflate with dictionary: %s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflateBound() with small buffers + */ +static void test_deflate_bound(void) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + unsigned int len = (unsigned int)strlen(hello)+1; + int estimateLen = 0; + unsigned char *outBuf = NULL; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + c_stream.avail_in = len; + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.avail_out = 0; + c_stream.next_out = outBuf; + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + /* calculate actual output length and update structure */ + estimateLen = PREFIX(deflateBound)(&c_stream, len); + outBuf = malloc(estimateLen); + + if (outBuf != NULL) { + /* update zlib configuration */ + c_stream.avail_out = estimateLen; + c_stream.next_out = outBuf; + + /* do the compression */ + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) { + printf("deflateBound(): OK\n"); + } else { + CHECK_ERR(err, "deflate"); + } + } + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + free(outBuf); +} + +/* =========================================================================== + * Test deflateCopy() with small buffers + */ +static void test_deflate_copy(unsigned char *compr, size_t comprLen) { + PREFIX3(stream) c_stream, c_stream_copy; /* compression stream */ + int err; + size_t len = strlen(hello)+1; + + memset(&c_stream, 0, sizeof(c_stream)); + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = PREFIX(deflateCopy)(&c_stream_copy, &c_stream); + CHECK_ERR(err, "deflate_copy"); + + if (c_stream.state->status == c_stream_copy.state->status) { + printf("deflate_copy(): OK\n"); + } + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd original"); + + err = PREFIX(deflateEnd)(&c_stream_copy); + CHECK_ERR(err, "deflateEnd copy"); +} + +/* =========================================================================== + * Test deflateGetDictionary() with small buffers + */ +static void test_deflate_get_dict(unsigned char *compr, size_t comprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + unsigned char *dictNew = NULL; + unsigned int *dictLen; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.avail_in = (unsigned int)strlen(hello)+1; + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + + if (err != Z_STREAM_END) + error("deflate should report Z_STREAM_END\n"); + + dictNew = calloc(256, 1); + dictLen = (unsigned int *)calloc(4, 1); + err = PREFIX(deflateGetDictionary)(&c_stream, dictNew, dictLen); + + CHECK_ERR(err, "deflateGetDictionary"); + if (err == Z_OK) { + printf("deflateGetDictionary(): %s\n", dictNew); + } + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + free(dictNew); + free(dictLen); +} + +/* =========================================================================== + * Test deflatePending() with small buffers + */ +static void test_deflate_pending(unsigned char *compr, size_t comprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + int *bits = calloc(256, 1); + unsigned *ped = calloc(256, 1); + size_t len = strlen(hello)+1; + + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + + err = PREFIX(deflatePending)(&c_stream, ped, bits); + CHECK_ERR(err, "deflatePending"); + + if (*bits >= 0 && *bits <= 7) { + printf("deflatePending(): OK\n"); + } else { + printf("deflatePending(): error\n"); + } + + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + free(bits); + free(ped); +} + +/* =========================================================================== + * Test deflatePrime() wrapping gzip around deflate stream + */ +static void test_deflate_prime(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + PREFIX3(stream) d_stream; /* decompression stream */ + int err; + size_t len = strlen(hello)+1; + uint32_t crc = 0; + + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + /* Raw deflate windowBits is -15 */ + err = PREFIX(deflateInit2)(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); + CHECK_ERR(err, "deflateInit2"); + + /* Gzip magic number */ + err = PREFIX(deflatePrime)(&c_stream, 16, 0x8b1f); + CHECK_ERR(err, "deflatePrime"); + /* Gzip compression method (deflate) */ + err = PREFIX(deflatePrime)(&c_stream, 8, 0x08); + CHECK_ERR(err, "deflatePrime"); + /* Gzip flags (one byte, using two odd bit calls) */ + err = PREFIX(deflatePrime)(&c_stream, 3, 0x0); + CHECK_ERR(err, "deflatePrime"); + err = PREFIX(deflatePrime)(&c_stream, 5, 0x0); + CHECK_ERR(err, "deflatePrime"); + /* Gzip modified time */ + err = deflate_prime_32(&c_stream, 0); + CHECK_ERR(err, "deflatePrime"); + /* Gzip extra flags */ + err = PREFIX(deflatePrime)(&c_stream, 8, 0x0); + CHECK_ERR(err, "deflatePrime"); + /* Gzip operating system */ + err = PREFIX(deflatePrime)(&c_stream, 8, 255); + CHECK_ERR(err, "deflatePrime"); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.avail_in = (uint32_t)len; + c_stream.next_out = compr; + c_stream.avail_out = (uint32_t)comprLen; + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) + CHECK_ERR(err, "deflate"); + + /* Gzip uncompressed data crc32 */ + crc = PREFIX(crc32)(0, (const uint8_t *)hello, (uint32_t)len); + err = deflate_prime_32(&c_stream, crc); + CHECK_ERR(err, "deflatePrime"); + /* Gzip uncompressed data length */ + err = deflate_prime_32(&c_stream, (uint32_t)len); + CHECK_ERR(err, "deflatePrime"); + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (void *)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uint32_t)c_stream.total_out; + d_stream.next_out = uncompr; + d_stream.avail_out = (uint32_t)uncomprLen; + d_stream.total_in = 0; + d_stream.total_out = 0; + + /* Inflate with gzip header */ + err = PREFIX(inflateInit2)(&d_stream, MAX_WBITS + 32); + CHECK_ERR(err, "inflateInit"); + + err = PREFIX(inflate)(&d_stream, Z_FINISH); + if (err != Z_BUF_ERROR) { + CHECK_ERR(err, "inflate"); + } + + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((const char *)uncompr, hello) != 0) + error("bad deflatePrime\n"); + if (err == Z_OK) + printf("deflatePrime(): OK\n"); +} + +/* =========================================================================== + * Test deflateSetHeader() with small buffers + */ +static void test_deflate_set_header(unsigned char *compr, size_t comprLen) { + PREFIX(gz_header) *head = calloc(1, sizeof(PREFIX(gz_header))); + PREFIX3(stream) c_stream; /* compression stream */ + int err; + size_t len = strlen(hello)+1; + + + if (head == NULL) + error("out of memory\n"); + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + /* gzip */ + err = PREFIX(deflateInit2)(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY); + CHECK_ERR(err, "deflateInit2"); + + head->text = 1; + head->comment = (uint8_t *)"comment"; + head->name = (uint8_t *)"name"; + head->hcrc = 1; + head->extra = (uint8_t *)"extra"; + head->extra_len = (uint32_t)strlen((const char *)head->extra); + + err = PREFIX(deflateSetHeader)(&c_stream, head); + CHECK_ERR(err, "deflateSetHeader"); + if (err == Z_OK) { + printf("deflateSetHeader(): OK\n"); + } + PREFIX(deflateBound)(&c_stream, (unsigned long)comprLen); + + c_stream.next_in = (unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + free(head); +} + +/* =========================================================================== + * Test deflateTune() with small buffers + */ +static void test_deflate_tune(unsigned char *compr, size_t comprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + int good_length = 3; + int max_lazy = 5; + int nice_length = 18; + int max_chain = 6; + size_t len = strlen(hello)+1; + + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = PREFIX(deflateTune)(&c_stream,(uInt)good_length,(uInt)max_lazy,nice_length,(uInt)max_chain); + CHECK_ERR(err, "deflateTune"); + if (err == Z_OK) { + printf("deflateTune(): OK\n"); + } + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ +int main(int argc, char *argv[]) { + unsigned char *compr, *uncompr; + z_uintmax_t comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + z_uintmax_t uncomprLen = comprLen; + static const char* myVersion = PREFIX2(VERSION); + + if (zVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zVersion(), PREFIX2(VERSION)) != 0) { + fprintf(stderr, "warning: different zlib version linked: %s\n", zVersion()); + } + + printf("zlib-ng version %s = 0x%08lx, compile flags = 0x%lx\n", + ZLIBNG_VERSION, ZLIBNG_VERNUM, PREFIX(zlibCompileFlags)()); + + compr = (unsigned char*)calloc((unsigned int)comprLen, 1); + uncompr = (unsigned char*)calloc((unsigned int)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == NULL || uncompr == NULL) + error("out of memory\n"); + + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen, 0); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + +#ifndef ZLIB_COMPAT + test_large_deflate(compr, comprLen, uncompr, uncomprLen, 1); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); +#endif + + test_flush(compr, &comprLen); +#ifdef ZLIBNG_ENABLE_TESTS + test_sync(compr, comprLen, uncompr, uncomprLen); +#endif + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + test_deflate_bound(); + test_deflate_copy(compr, comprLen); + test_deflate_get_dict(compr, comprLen); + test_deflate_set_header(compr, comprLen); + test_deflate_tune(compr, comprLen); + test_deflate_pending(compr, comprLen); + test_deflate_prime(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/test/fuzz/CMakeLists.txt b/test/fuzz/CMakeLists.txt new file mode 100644 index 0000000000..beccef3b9a --- /dev/null +++ b/test/fuzz/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.5.1...3.29.0) + +if(CMAKE_C_COMPILER_ID MATCHES "Clang") + enable_language(CXX) + + if(DEFINED ENV{LIB_FUZZING_ENGINE}) + set(FUZZING_ENGINE $ENV{LIB_FUZZING_ENGINE}) + set(FUZZING_ENGINE_FOUND ON) + else() + find_library(FUZZING_ENGINE "FuzzingEngine") + endif() +endif() + +set(FUZZERS + fuzzer_checksum + fuzzer_compress + fuzzer_example_small + fuzzer_example_large + fuzzer_example_flush + fuzzer_example_dict + ) + +if(WITH_GZFILEOP) + list(APPEND FUZZERS fuzzer_minigzip) +endif() + +foreach(FUZZER ${FUZZERS}) + add_executable(${FUZZER} ${FUZZER}.c) + + if(NOT FUZZING_ENGINE_FOUND) + target_sources(${FUZZER} PRIVATE standalone_fuzz_target_runner.c) + endif() + + if(NOT DEFINED BUILD_SHARED_LIBS) + target_link_libraries(${FUZZER} zlibstatic) + else() + target_link_libraries(${FUZZER} zlib) + endif() + + if(FUZZING_ENGINE_FOUND) + target_link_libraries(${FUZZER} ${FUZZING_ENGINE}) + endif() + + if(ZLIB_ENABLE_TESTS) + file(GLOB FUZZER_TEST_FILES ${PROJECT_SOURCE_DIR}/*) + set(FUZZER_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ ${FUZZER_TEST_FILES}) + add_test(NAME ${FUZZER} COMMAND ${FUZZER_COMMAND}) + endif() +endforeach() diff --git a/test/fuzz/fuzzer_checksum.c b/test/fuzz/fuzzer_checksum.c new file mode 100644 index 0000000000..cedd284dbe --- /dev/null +++ b/test/fuzz/fuzzer_checksum.c @@ -0,0 +1,81 @@ +#include +#include + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataLen) { + uint32_t crc0 = PREFIX(crc32)(0L, NULL, 0); + uint32_t crc1 = crc0; + uint32_t crc2 = crc0; + uint32_t adler0 = PREFIX(adler32)(0L, NULL, 0); + uint32_t adler1 = adler0; + uint32_t adler2 = adler0; + uint32_t combine1, combine2; + /* Checksum with a buffer of size equal to the first byte in the input. */ + uint32_t buffSize = data[0]; + uint32_t offset = 0; + uint32_t op; + + /* Discard inputs larger than 1Mb. */ + static size_t kMaxSize = 1024 * 1024; + if (dataLen < 1 || dataLen > kMaxSize) + return 0; + + /* Make sure the buffer has at least a byte. */ + if (buffSize == 0) + ++buffSize; + + /* CRC32 */ + op = PREFIX(crc32_combine_gen)(buffSize); + for (offset = 0; offset + buffSize <= dataLen; offset += buffSize) { + uint32_t crc3 = PREFIX(crc32_z)(crc0, data + offset, buffSize); + uint32_t crc4 = PREFIX(crc32_combine_op)(crc1, crc3, op); + crc1 = PREFIX(crc32_z)(crc1, data + offset, buffSize); + assert(crc1 == crc4); + Z_UNUSED(crc1); + Z_UNUSED(crc4); + } + crc1 = PREFIX(crc32_z)(crc1, data + offset, dataLen % buffSize); + + crc2 = PREFIX(crc32_z)(crc2, data, dataLen); + + assert(crc1 == crc2); + Z_UNUSED(crc1); + Z_UNUSED(crc2); + combine1 = PREFIX(crc32_combine)(crc1, crc2, (z_off_t)dataLen); + combine2 = PREFIX(crc32_combine)(crc1, crc1, (z_off_t)dataLen); + assert(combine1 == combine2); + + /* Fast CRC32 combine. */ + op = PREFIX(crc32_combine_gen)((z_off_t)dataLen); + combine1 = PREFIX(crc32_combine_op)(crc1, crc2, op); + combine2 = PREFIX(crc32_combine_op)(crc2, crc1, op); + assert(combine1 == combine2); + combine1 = PREFIX(crc32_combine)(crc1, crc2, (z_off_t)dataLen); + combine2 = PREFIX(crc32_combine_op)(crc2, crc1, op); + assert(combine1 == combine2); + + /* Adler32 */ + for (offset = 0; offset + buffSize <= dataLen; offset += buffSize) + adler1 = PREFIX(adler32_z)(adler1, data + offset, buffSize); + adler1 = PREFIX(adler32_z)(adler1, data + offset, dataLen % buffSize); + + adler2 = PREFIX(adler32_z)(adler2, data, dataLen); + + assert(adler1 == adler2); + Z_UNUSED(adler1); + Z_UNUSED(adler2); + combine1 = PREFIX(adler32_combine)(adler1, adler2, (z_off_t)dataLen); + combine2 = PREFIX(adler32_combine)(adler1, adler1, (z_off_t)dataLen); + assert(combine1 == combine2); + Z_UNUSED(combine1); + Z_UNUSED(combine2); + + /* This function must return 0. */ + return 0; +} diff --git a/test/fuzz/fuzzer_compress.c b/test/fuzz/fuzzer_compress.c new file mode 100644 index 0000000000..71cdf99ecf --- /dev/null +++ b/test/fuzz/fuzzer_compress.c @@ -0,0 +1,82 @@ +#include +#include + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +static const uint8_t *data; +static size_t dataLen; + +static void check_compress_level(uint8_t *compr, z_size_t comprLen, + uint8_t *uncompr, z_size_t uncomprLen, + int level) { + PREFIX(compress2)(compr, &comprLen, data, dataLen, level); + PREFIX(uncompress)(uncompr, &uncomprLen, compr, comprLen); + + /* Make sure compress + uncompress gives back the input data. */ + assert(dataLen == uncomprLen); + assert(0 == memcmp(data, uncompr, dataLen)); +} + +#define put_byte(s, i, c) {s[i] = (unsigned char)(c);} + +static void write_zlib_header(uint8_t *s) { + unsigned level_flags = 0; /* compression level (0..3) */ + unsigned w_bits = 8; /* window size log2(w_size) (8..16) */ + unsigned int header = (Z_DEFLATED + ((w_bits-8)<<4)) << 8; + header |= (level_flags << 6); + + header += 31 - (header % 31); + + /* s is guaranteed to be longer than 2 bytes. */ + put_byte(s, 0, (header >> 8)); + put_byte(s, 1, (header & 0xff)); +} + +static void check_decompress(uint8_t *compr, size_t comprLen) { + /* We need to write a valid zlib header of size two bytes. Copy the input data + in a larger buffer. Do not modify the input data to avoid libFuzzer error: + fuzz target overwrites its const input. */ + size_t copyLen = dataLen + 2; + uint8_t *copy = (uint8_t *)malloc(copyLen); + memcpy(copy + 2, data, dataLen); + write_zlib_header(copy); + + PREFIX(uncompress)(compr, &comprLen, copy, copyLen); + free(copy); +} + +int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) { + /* compressBound does not provide enough space for low compression levels. */ + z_size_t comprLen = 100 + 2 * PREFIX(compressBound)(size); + z_size_t uncomprLen = (z_size_t)size; + uint8_t *compr, *uncompr; + + /* Discard inputs larger than 1Mb. */ + static size_t kMaxSize = 1024 * 1024; + + if (size < 1 || size > kMaxSize) + return 0; + + data = d; + dataLen = size; + compr = (uint8_t *)calloc(1, comprLen); + uncompr = (uint8_t *)calloc(1, uncomprLen); + + check_compress_level(compr, comprLen, uncompr, uncomprLen, 1); + check_compress_level(compr, comprLen, uncompr, uncomprLen, 3); + check_compress_level(compr, comprLen, uncompr, uncomprLen, 6); + check_compress_level(compr, comprLen, uncompr, uncomprLen, 7); + + check_decompress(compr, comprLen); + + free(compr); + free(uncompr); + + /* This function must return 0. */ + return 0; +} diff --git a/test/fuzz/fuzzer_example_dict.c b/test/fuzz/fuzzer_example_dict.c new file mode 100644 index 0000000000..053a3e101a --- /dev/null +++ b/test/fuzz/fuzzer_example_dict.c @@ -0,0 +1,164 @@ +#include +#include + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +static const uint8_t *data; +static size_t dataLen; +static alloc_func zalloc = NULL; +static free_func zfree = NULL; +static unsigned int dictionaryLen = 0; +static unsigned long dictId; /* Adler32 value of the dictionary */ + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(unsigned char **compr, size_t *comprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + int level = data[0] % 11 - 1; /* [-1..9] + compression levels + #define Z_NO_COMPRESSION 0 + #define Z_BEST_SPEED 1 + #define Z_BEST_COMPRESSION 9 + #define Z_DEFAULT_COMPRESSION (-1) */ + + int method = Z_DEFLATED; /* The deflate compression method (the only one + supported in this version) */ + int windowBits = 8 + data[(dataLen > 1) ? 1:0] % 8; /* The windowBits parameter is the base + two logarithm of the window size (the size of the history buffer). It + should be in the range 8..15 for this version of the library. */ + int memLevel = 1 + data[(dataLen > 2) ? 2:0] % 9; /* memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. */ + int strategy = data[(dataLen > 3) ? 3:0] % 5; /* [0..4] + #define Z_FILTERED 1 + #define Z_HUFFMAN_ONLY 2 + #define Z_RLE 3 + #define Z_FIXED 4 + #define Z_DEFAULT_STRATEGY 0 */ + + /* deflate would fail for no-compression or for speed levels. */ + if (level == 0 || level == 1) + level = -1; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (void *)0; + + err = PREFIX(deflateInit2)(&c_stream, level, method, windowBits, memLevel, + strategy); + CHECK_ERR(err, "deflateInit"); + + err = PREFIX(deflateSetDictionary)( + &c_stream, (const unsigned char *)data, dictionaryLen); + CHECK_ERR(err, "deflateSetDictionary"); + + /* deflateBound does not provide enough space for low compression levels. */ + *comprLen = 100 + 2 * PREFIX(deflateBound)(&c_stream, (unsigned long)dataLen); + *compr = (uint8_t *)calloc(1, *comprLen); + + dictId = c_stream.adler; + c_stream.next_out = *compr; + c_stream.avail_out = (unsigned int)(*comprLen); + + c_stream.next_in = (z_const unsigned char *)data; + c_stream.avail_in = (uint32_t)dataLen; + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate dict should report Z_STREAM_END\n"); + exit(1); + } + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(unsigned char *compr, size_t comprLen) { + int err; + PREFIX3(stream) d_stream; /* decompression stream */ + unsigned char *uncompr; + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (void *)0; + + d_stream.next_in = compr; + d_stream.avail_in = (unsigned int)comprLen; + + err = PREFIX(inflateInit)(&d_stream); + CHECK_ERR(err, "inflateInit"); + + uncompr = (uint8_t *)calloc(1, dataLen); + d_stream.next_out = uncompr; + d_stream.avail_out = (unsigned int)dataLen; + + for (;;) { + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) + break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = PREFIX(inflateSetDictionary)( + &d_stream, (const unsigned char *)data, dictionaryLen); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (memcmp(uncompr, data, dataLen)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } + + free(uncompr); +} + +int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) { + size_t comprLen = 0; + uint8_t *compr; + + /* Discard inputs larger than 100Kb. */ + static size_t kMaxSize = 100 * 1024; + + if (size < 1 || size > kMaxSize) + return 0; + + data = d; + dataLen = size; + + /* Set up the contents of the dictionary. The size of the dictionary is + intentionally selected to be of unusual size. To help cover more corner + cases, the size of the dictionary is read from the input data. */ + dictionaryLen = data[0]; + if (dictionaryLen > dataLen) + dictionaryLen = (unsigned int)dataLen; + + test_dict_deflate(&compr, &comprLen); + test_dict_inflate(compr, comprLen); + + free(compr); + + /* This function must return 0. */ + return 0; +} diff --git a/test/fuzz/fuzzer_example_flush.c b/test/fuzz/fuzzer_example_flush.c new file mode 100644 index 0000000000..baa6988e36 --- /dev/null +++ b/test/fuzz/fuzzer_example_flush.c @@ -0,0 +1,119 @@ +#include +#include + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +static const uint8_t *data; +static size_t dataLen; +static alloc_func zalloc = NULL; +static free_func zfree = NULL; + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(unsigned char *compr, z_size_t *comprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + unsigned int len = (unsigned int)dataLen; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (void *)0; + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (z_const unsigned char *)data; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (unsigned int)*comprLen; + err = PREFIX(deflate)(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate flush 1"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate flush 2"); + } + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = (z_size_t)c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { + int err; + PREFIX3(stream) d_stream; /* decompression stream */ + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (void *)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = PREFIX(inflateInit)(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (unsigned int)uncomprLen; + + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (unsigned int)comprLen - 2; /* read all compressed data */ + err = PREFIX(inflateSync)(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = PREFIX(inflate)(&d_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "inflate should report Z_STREAM_END\n"); + exit(1); + } + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); +} + +int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) { + z_size_t comprLen = 100 + 2 * PREFIX(compressBound)(size); + z_size_t uncomprLen = (z_size_t)size; + uint8_t *compr, *uncompr; + + /* Discard inputs larger than 1Mb. */ + static size_t kMaxSize = 1024 * 1024; + + // This test requires at least 3 bytes of input data. + if (size <= 3 || size > kMaxSize) + return 0; + + data = d; + dataLen = size; + compr = (uint8_t *)calloc(1, comprLen); + uncompr = (uint8_t *)calloc(1, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + /* This function must return 0. */ + return 0; +} diff --git a/test/fuzz/fuzzer_example_large.c b/test/fuzz/fuzzer_example_large.c new file mode 100644 index 0000000000..4114597218 --- /dev/null +++ b/test/fuzz/fuzzer_example_large.c @@ -0,0 +1,137 @@ +#include +#include +#include + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +static const uint8_t *data; +static size_t dataLen; +static alloc_func zalloc = NULL; +static free_func zfree = NULL; +static unsigned int diff; + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (void *)0; + + err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (unsigned int)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (unsigned int)uncomprLen; + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate large 1"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + PREFIX(deflateParams)(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + diff = (unsigned int)(c_stream.next_out - compr); + c_stream.avail_in = diff; + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate large 2"); + + /* Switch back to compressing mode: */ + PREFIX(deflateParams)(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (unsigned int)uncomprLen; + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate large 3"); + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate large should report Z_STREAM_END\n"); + exit(1); + } + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { + int err; + PREFIX3(stream) d_stream; /* decompression stream */ + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (void *)0; + + d_stream.next_in = compr; + d_stream.avail_in = (unsigned int)comprLen; + + err = PREFIX(inflateInit)(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (unsigned int)uncomprLen; + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) + break; + CHECK_ERR(err, "large inflate"); + } + + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2 * uncomprLen + diff) { + fprintf(stderr, "bad large inflate: %" PRIu64 "\n", (uint64_t)d_stream.total_out); + exit(1); + } +} + +int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) { + size_t comprLen = 100 + 3 * size; + size_t uncomprLen = comprLen; + uint8_t *compr, *uncompr; + + /* Discard inputs larger than 512Kb. */ + static size_t kMaxSize = 512 * 1024; + + if (size < 1 || size > kMaxSize) + return 0; + + data = d; + dataLen = size; + compr = (uint8_t *)calloc(1, comprLen); + uncompr = (uint8_t *)calloc(1, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + /* This function must return 0. */ + return 0; +} diff --git a/test/fuzz/fuzzer_example_small.c b/test/fuzz/fuzzer_example_small.c new file mode 100644 index 0000000000..e59c720835 --- /dev/null +++ b/test/fuzz/fuzzer_example_small.c @@ -0,0 +1,118 @@ +#include +#include + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +static const uint8_t *data; +static size_t dataLen; +static alloc_func zalloc = NULL; +static free_func zfree = NULL; + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(unsigned char *compr, size_t comprLen) { + PREFIX3(stream) c_stream; /* compression stream */ + int err; + unsigned long len = (unsigned long)dataLen; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (void *)0; + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (z_const unsigned char *)data; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate small 1"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) + break; + CHECK_ERR(err, "deflate small 2"); + } + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { + int err; + PREFIX3(stream) d_stream; /* decompression stream */ + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (void *)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = PREFIX(inflateInit)(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) + break; + CHECK_ERR(err, "inflate"); + } + + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (memcmp(uncompr, data, dataLen)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } +} + +int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) { + size_t comprLen = PREFIX(compressBound)(size); + size_t uncomprLen = size; + uint8_t *compr, *uncompr; + + /* Discard inputs larger than 1Mb. */ + static size_t kMaxSize = 1024 * 1024; + + if (size < 1 || size > kMaxSize) + return 0; + + data = d; + dataLen = size; + compr = (uint8_t *)calloc(1, comprLen); + uncompr = (uint8_t *)calloc(1, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + /* This function must return 0. */ + return 0; +} diff --git a/test/fuzz/fuzzer_minigzip.c b/test/fuzz/fuzzer_minigzip.c new file mode 100644 index 0000000000..6e38881962 --- /dev/null +++ b/test/fuzz/fuzzer_minigzip.c @@ -0,0 +1,316 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2006, 2010, 2011, 2016 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. + */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif +#include +#include + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) +#ifndef _WIN32 /* unlink already in stdio.h for Win32 */ +extern int unlink (const char *); +#endif +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 /* read buffer size */ +#define BUFLENW (BUFLEN * 3) /* write buffer size */ +#define MAX_NAME_LEN 1024 + +static const char *prog = "minigzip_fuzzer"; + +/* =========================================================================== + * Display error message and exit + */ +static void error(const char *msg) { + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ +/* =========================================================================== + * Try compressing the input file at once using mmap. Return Z_OK if + * success, Z_ERRNO otherwise. + */ +static int gz_compress_mmap(FILE *in, gzFile out) { + int len; + int err; + int ifd = fileno(in); + char *buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((void *)0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (char *)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = PREFIX(gzwrite)(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(PREFIX(gzerror)(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (PREFIX(gzclose)(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Compress input to output then close both files. + */ + +static void gz_compress(FILE *in, gzFile out) { + char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + /* Clear out the contents of buf before reading from the file to avoid + MemorySanitizer: use-of-uninitialized-value warnings. */ + memset(buf, 0, sizeof(buf)); + for (;;) { + len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (PREFIX(gzwrite)(out, buf, (unsigned)len) != len) error(PREFIX(gzerror)(out, &err)); + } + fclose(in); + if (PREFIX(gzclose)(out) != Z_OK) error("failed gzclose"); +} + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +static void gz_uncompress(gzFile in, FILE *out) { + char buf[BUFLENW]; + int len; + int err; + + for (;;) { + len = PREFIX(gzread)(in, buf, sizeof(buf)); + if (len < 0) error (PREFIX(gzerror)(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (PREFIX(gzclose)(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +static void file_compress(char *file, char *mode) { + char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + + snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = PREFIX(gzopen)(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +static void file_uncompress(char *file) { + char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + size_t len = strlen(file); + + if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + + snprintf(buf, sizeof(buf), "%s", file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX); + } + in = PREFIX(gzopen)(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataLen) { + char *inFileName = "minigzip_fuzzer.out"; + char *outFileName = "minigzip_fuzzer.out.gz"; + char outmode[20]; + FILE *in; + char buf[BUFLEN]; + uint32_t offset = 0; + + /* Discard inputs larger than 1Mb. */ + static size_t kMaxSize = 1024 * 1024; + if (dataLen < 1 || dataLen > kMaxSize) + return 0; + + in = fopen(inFileName, "wb"); + if (fwrite(data, 1, (unsigned)dataLen, in) != dataLen) + error("failed fwrite"); + if (fclose(in)) + error("failed fclose"); + + memset(outmode, 0, sizeof(outmode)); + snprintf(outmode, sizeof(outmode), "%s", "wb"); + + /* Compression level: [0..9]. */ + outmode[2] = '0' + (data[0] % 10); + + switch (data[dataLen-1] % 6) { + default: + case 0: + outmode[3] = 0; + break; + case 1: + /* compress with Z_FILTERED */ + outmode[3] = 'f'; + break; + case 2: + /* compress with Z_HUFFMAN_ONLY */ + outmode[3] = 'h'; + break; + case 3: + /* compress with Z_RLE */ + outmode[3] = 'R'; + break; + case 4: + /* compress with Z_FIXED */ + outmode[3] = 'F'; + break; + case 5: + /* direct */ + outmode[3] = 'T'; + break; + } + + file_compress(inFileName, outmode); + + /* gzopen does not support reading in direct mode */ + if (outmode[3] == 'T') + inFileName = outFileName; + else + file_uncompress(outFileName); + + /* Check that the uncompressed file matches the input data. */ + in = fopen(inFileName, "rb"); + if (in == NULL) { + perror(inFileName); + exit(1); + } + + memset(buf, 0, sizeof(buf)); + for (;;) { + int len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) + break; + int c = memcmp(data + offset, buf, len); + assert(0 == c); + Z_UNUSED(c); // in Release build, assert() is a no-op. + offset += len; + } + + if (fclose(in)) + error("failed fclose"); + + /* This function must return 0. */ + return 0; +} diff --git a/test/fuzz/standalone_fuzz_target_runner.c b/test/fuzz/standalone_fuzz_target_runner.c new file mode 100644 index 0000000000..810a56072f --- /dev/null +++ b/test/fuzz/standalone_fuzz_target_runner.c @@ -0,0 +1,37 @@ +#include +#include + +#include "zbuild.h" + +extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); + +int main(int argc, char **argv) { + int i; + fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1); + + for (i = 1; i < argc; i++) { + size_t len, n_read, err; + unsigned char *buf; + FILE *f = fopen(argv[i], "rb+"); + if (!f) { + /* Failed to open this file: it may be a directory. */ + fprintf(stderr, "Skipping: %s\n", argv[i]); + continue; + } + fprintf(stderr, "Running: %s %s\n", argv[0], argv[i]); + fseek(f, 0, SEEK_END); + len = ftell(f); + fseek(f, 0, SEEK_SET); + buf = (unsigned char *)malloc(len); + n_read = fread(buf, 1, len, f); + assert(n_read == len); + LLVMFuzzerTestOneInput(buf, len); + free(buf); + err = fclose(f); + assert(err == 0); + Z_UNUSED(err); + fprintf(stderr, "Done: %s: (%d bytes)\n", argv[i], (int)n_read); + } + + return 0; +} diff --git a/test/gh1235.c b/test/gh1235.c new file mode 100644 index 0000000000..7bf8738f34 --- /dev/null +++ b/test/gh1235.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include "zutil.h" + +int main(void) { + unsigned char plain[32]; + unsigned char compressed[130]; + PREFIX3(stream) strm; + z_size_t bound; + z_size_t bytes; + + for (int i = 0; i <= 32; i++) { + memset(plain, 6, i); + memset(&strm, 0, sizeof(strm)); + PREFIX(deflateInit2)(&strm, 0, 8, 31, 1, Z_DEFAULT_STRATEGY); + bound = PREFIX(deflateBound)(&strm, i); + strm.next_in = plain; + strm.next_out = compressed; + strm.avail_in = i; + strm.avail_out = sizeof(compressed); + if (PREFIX(deflate)(&strm, Z_FINISH) != Z_STREAM_END) return -1; + if (strm.avail_in != 0) return -1; + printf("bytes = %2i, deflateBound = %2zi, total_out = %2zi\n", i, (size_t)bound, (size_t)strm.total_out); + if (bound < strm.total_out) return -1; + if (PREFIX(deflateEnd)(&strm) != Z_OK) return -1; + } + for (int i = 0; i <= 32; i++) { + bytes = sizeof(compressed); + for (int j = 0; j < i; j++) { + plain[j] = j; + } + bound = PREFIX(compressBound)(i); + if (PREFIX(compress2)(compressed, &bytes, plain, i, 1) != Z_OK) return -1; + printf("bytes = %2i, compressBound = %2zi, total_out = %2zi\n", i, (size_t)bound, (size_t)bytes); + if (bytes > bound) return -1; + } + return 0; +} diff --git a/test/infcover.c b/test/infcover.c new file mode 100644 index 0000000000..e436888b9b --- /dev/null +++ b/test/infcover.c @@ -0,0 +1,679 @@ +/* infcover.c -- test zlib's inflate routines with full code coverage + * Copyright (C) 2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* to use, do: ./configure --cover && make cover */ + +#include +#include +#include +#undef NDEBUG +#include +#include + +/* get definition of internal structure so we can mess with it (see pull()), + and so we can call inflate_trees() (see cover5()) */ +#include "zbuild.h" +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" + +/* -- memory tracking routines -- */ + +/* + These memory tracking routines are provided to zlib and track all of zlib's + allocations and deallocations, check for LIFO operations, keep a current + and high water mark of total bytes requested, optionally set a limit on the + total memory that can be allocated, and when done check for memory leaks. + + They are used as follows: + + PREFIX3(stream) strm; + mem_setup(&strm) initializes the memory tracking and sets the + zalloc, zfree, and opaque members of strm to use + memory tracking for all zlib operations on strm + mem_limit(&strm, limit) sets a limit on the total bytes requested -- a + request that exceeds this limit will result in an + allocation failure (returns NULL) -- setting the + limit to zero means no limit, which is the default + after mem_setup() + mem_used(&strm, "msg") prints to stderr "msg" and the total bytes used + mem_high(&strm, "msg") prints to stderr "msg" and the high water mark + mem_done(&strm, "msg") ends memory tracking, releases all allocations + for the tracking as well as leaked zlib blocks, if + any. If there was anything unusual, such as leaked + blocks, non-FIFO frees, or frees of addresses not + allocated, then "msg" and information about the + problem is printed to stderr. If everything is + normal, nothing is printed. mem_done resets the + strm members to NULL to use the default memory + allocation routines on the next zlib initialization + using strm. + */ + +/* these items are strung together in a linked list, one for each allocation */ +struct mem_item { + void *ptr; /* pointer to allocated memory */ + size_t size; /* requested size of allocation */ + struct mem_item *next; /* pointer to next item in list, or NULL */ +}; + +/* this structure is at the root of the linked list, and tracks statistics */ +struct mem_zone { + struct mem_item *first; /* pointer to first item in list, or NULL */ + size_t total, highwater; /* total allocations, and largest total */ + size_t limit; /* memory allocation limit, or 0 if no limit */ + int notlifo, rogue; /* counts of non-LIFO frees and rogue frees */ +}; + +/* memory allocation routine to pass to zlib */ +static void *mem_alloc(void *mem, unsigned count, unsigned size) { + void *ptr; + struct mem_item *item; + struct mem_zone *zone = mem; + size_t len = count * (size_t)size; + + /* induced allocation failure */ + if (zone == NULL || (zone->limit && zone->total + len > zone->limit)) + return NULL; + + /* perform allocation using the standard library, fill memory with a + non-zero value to make sure that the code isn't depending on zeros */ + ptr = malloc(len); + if (ptr == NULL) + return NULL; + memset(ptr, 0xa5, len); + + /* create a new item for the list */ + item = malloc(sizeof(struct mem_item)); + if (item == NULL) { + free(ptr); + return NULL; + } + item->ptr = ptr; + item->size = len; + + /* insert item at the beginning of the list */ + item->next = zone->first; + zone->first = item; + + /* update the statistics */ + zone->total += item->size; + if (zone->total > zone->highwater) + zone->highwater = zone->total; + + /* return the allocated memory */ + return ptr; +} + +/* memory free routine to pass to zlib */ +static void mem_free(void *mem, void *ptr) { + struct mem_item *item, *next; + struct mem_zone *zone = mem; + + /* if no zone, just do a free */ + if (zone == NULL) { + free(ptr); + return; + } + + /* point next to the item that matches ptr, or NULL if not found -- remove + the item from the linked list if found */ + next = zone->first; + if (next) { + if (next->ptr == ptr) + zone->first = next->next; /* first one is it, remove from list */ + else { + do { /* search the linked list */ + item = next; + next = item->next; + } while (next != NULL && next->ptr != ptr); + if (next) { /* if found, remove from linked list */ + item->next = next->next; + zone->notlifo++; /* not a LIFO free */ + } + + } + } + + /* if found, update the statistics and free the item */ + if (next) { + zone->total -= next->size; + free(next); + } + + /* if not found, update the rogue count */ + else + zone->rogue++; + + /* in any case, do the requested free with the standard library function */ + free(ptr); +} + +/* set up a controlled memory allocation space for monitoring, set the stream + parameters to the controlled routines, with opaque pointing to the space */ +static void mem_setup(PREFIX3(stream) *strm) { + struct mem_zone *zone; + + zone = malloc(sizeof(struct mem_zone)); + assert(zone != NULL); + zone->first = NULL; + zone->total = 0; + zone->highwater = 0; + zone->limit = 0; + zone->notlifo = 0; + zone->rogue = 0; + strm->opaque = zone; + strm->zalloc = mem_alloc; + strm->zfree = mem_free; +} + +/* set a limit on the total memory allocation, or 0 to remove the limit */ +static void mem_limit(PREFIX3(stream) *strm, size_t limit) { + struct mem_zone *zone = strm->opaque; + + zone->limit = limit; +} + +/* show the current total requested allocations in bytes */ +static void mem_used(PREFIX3(stream) *strm, char *prefix) { + struct mem_zone *zone = strm->opaque; + + fprintf(stderr, "%s: %" PRIu64 " allocated\n", prefix, (uint64_t)zone->total); +} + +/* show the high water allocation in bytes */ +static void mem_high(PREFIX3(stream) *strm, char *prefix) { + struct mem_zone *zone = strm->opaque; + + fprintf(stderr, "%s: %" PRIu64 " high water mark\n", prefix, (uint64_t)zone->highwater); +} + +/* release the memory allocation zone -- if there are any surprises, notify */ +static void mem_done(PREFIX3(stream) *strm, char *prefix) { + int count = 0; + struct mem_item *item, *next; + struct mem_zone *zone = strm->opaque; + + /* show high water mark */ + mem_high(strm, prefix); + + /* free leftover allocations and item structures, if any */ + item = zone->first; + while (item != NULL) { + free(item->ptr); + next = item->next; + free(item); + item = next; + count++; + } + + /* issue alerts about anything unexpected */ + if (count || zone->total) + fprintf(stderr, "** %s: %" PRIu64 " bytes in %d blocks not freed\n", + prefix, (uint64_t)zone->total, count); + if (zone->notlifo) + fprintf(stderr, "** %s: %d frees not LIFO\n", prefix, zone->notlifo); + if (zone->rogue) + fprintf(stderr, "** %s: %d frees not recognized\n", + prefix, zone->rogue); + + /* free the zone and delete from the stream */ + free(zone); + strm->opaque = NULL; + strm->zalloc = NULL; + strm->zfree = NULL; +} + +/* -- inflate test routines -- */ + +/* Decode a hexadecimal string, set *len to length, in[] to the bytes. This + decodes liberally, in that hex digits can be adjacent, in which case two in + a row writes a byte. Or they can be delimited by any non-hex character, + where the delimiters are ignored except when a single hex digit is followed + by a delimiter, where that single digit writes a byte. The returned data is + allocated and must eventually be freed. NULL is returned if out of memory. + If the length is not needed, then len can be NULL. */ +static unsigned char *h2b(const char *hex, unsigned *len) { + unsigned char *in, *re; + unsigned next, val; + size_t inlen; + + inlen = (strlen(hex) + 1) >> 1; + assert(inlen != 0); /* tell static analyzer we won't call malloc(0) */ + in = malloc(inlen); + if (in == NULL) + return NULL; + next = 0; + val = 1; + do { + if (*hex >= '0' && *hex <= '9') + val = (val << 4) + *hex - '0'; + else if (*hex >= 'A' && *hex <= 'F') + val = (val << 4) + *hex - 'A' + 10; + else if (*hex >= 'a' && *hex <= 'f') + val = (val << 4) + *hex - 'a' + 10; + else if (val != 1 && val < 32) /* one digit followed by delimiter */ + val += 240; /* make it look like two digits */ + if (val > 255) { /* have two digits */ + in[next++] = val & 0xff; /* save the decoded byte */ + val = 1; /* start over */ + } + } while (*hex++); /* go through the loop with the terminating null */ + if (len != NULL) + *len = next; + assert(next != 0); /* tell static analyzer we won't call realloc(in, 0) */ + re = realloc(in, next); + return re == NULL ? in : re; +} + +/* generic inflate() run, where hex is the hexadecimal input data, what is the + text to include in an error message, step is how much input data to feed + inflate() on each call, or zero to feed it all, win is the window bits + parameter to inflateInit2(), len is the size of the output buffer, and err + is the error code expected from the first inflate() call (the second + inflate() call is expected to return Z_STREAM_END). If win is 47, then + header information is collected with inflateGetHeader(). If a zlib stream + is looking for a dictionary, then an empty dictionary is provided. + inflate() is run until all of the input data is consumed. */ +static void inf(char *hex, char *what, unsigned step, int win, unsigned len, int err) { + int ret; + unsigned have; + unsigned char *in, *out; + PREFIX3(stream) strm, copy; + PREFIX(gz_header) head; + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = NULL; + ret = PREFIX(inflateInit2)(&strm, win); + if (ret != Z_OK) { + mem_done(&strm, what); + return; + } + out = malloc(len); assert(out != NULL); + if (win == 47) { + head.extra = out; + head.extra_max = len; + head.name = out; + head.name_max = len; + head.comment = out; + head.comm_max = len; + ret = PREFIX(inflateGetHeader)(&strm, &head); + assert(ret == Z_OK); + } + in = h2b(hex, &have); assert(in != NULL); + if (step == 0 || step > have) + step = have; + strm.avail_in = step; + have -= step; + strm.next_in = in; + do { + strm.avail_out = len; + strm.next_out = out; + ret = PREFIX(inflate)(&strm, Z_NO_FLUSH); + assert(err == 9 || ret == err); + if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT) + break; + if (ret == Z_NEED_DICT) { + ret = PREFIX(inflateSetDictionary)(&strm, in, 1); + assert(ret == Z_DATA_ERROR); + mem_limit(&strm, 0); + ((struct inflate_state *)strm.state)->mode = DICT; + ret = PREFIX(inflateSetDictionary)(&strm, out, 0); + assert(ret == Z_OK); + ret = PREFIX(inflate)(&strm, Z_NO_FLUSH); + assert(ret == Z_BUF_ERROR); + } + ret = PREFIX(inflateCopy)(©, &strm); + assert(ret == Z_OK); + ret = PREFIX(inflateEnd)(©); assert(ret == Z_OK); + err = 9; /* don't care next time around */ + have += strm.avail_in; + strm.avail_in = step > have ? have : step; + have -= strm.avail_in; + } while (strm.avail_in); + free(in); + free(out); + ret = PREFIX(inflateReset2)(&strm, -8); assert(ret == Z_OK); + ret = PREFIX(inflateEnd)(&strm); assert(ret == Z_OK); + mem_done(&strm, what); + Z_UNUSED(err); +} + +/* cover all of the lines in inflate.c up to inflate() */ +static void cover_support(void) { + int ret; + PREFIX3(stream) strm; + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = NULL; + ret = PREFIX(inflateInit)(&strm); assert(ret == Z_OK); + mem_used(&strm, "inflate init"); + ret = PREFIX(inflatePrime)(&strm, 5, 31); assert(ret == Z_OK); + ret = PREFIX(inflatePrime)(&strm, -1, 0); assert(ret == Z_OK); + ret = PREFIX(inflateSetDictionary)(&strm, NULL, 0); + assert(ret == Z_STREAM_ERROR); + ret = PREFIX(inflateEnd)(&strm); assert(ret == Z_OK); + mem_done(&strm, "prime"); + + inf("63 0", "force window allocation", 0, -15, 1, Z_OK); + inf("63 18 5", "force window replacement", 0, -8, 259, Z_OK); + inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK); + inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END); + inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR); + +#ifdef ZLIB_COMPAT + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = NULL; + ret = PREFIX(inflateInit_)(&strm, &PREFIX2(VERSION)[1], (int)sizeof(PREFIX3(stream))); + assert(ret == Z_VERSION_ERROR); + mem_done(&strm, "wrong version"); +#endif + + strm.avail_in = 0; + strm.next_in = NULL; + ret = PREFIX(inflateInit)(&strm); assert(ret == Z_OK); + ret = PREFIX(inflateEnd)(&strm); assert(ret == Z_OK); + fputs("inflate built-in memory routines\n", stderr); + Z_UNUSED(ret); +} + +/* cover all inflate() header and trailer cases and code after inflate() */ +static void cover_wrap(void) { + int ret; + PREFIX3(stream) strm, copy; + unsigned char dict[257]; + + ret = PREFIX(inflate)(NULL, 0); assert(ret == Z_STREAM_ERROR); + ret = PREFIX(inflateEnd)(NULL); assert(ret == Z_STREAM_ERROR); + ret = PREFIX(inflateCopy)(NULL, NULL); assert(ret == Z_STREAM_ERROR); + fputs("inflate bad parameters\n", stderr); + + inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR); + inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR); + inf("77 85", "bad zlib method", 0, 15, 0, Z_DATA_ERROR); + inf("8 99", "set window size from header", 0, 0, 0, Z_OK); + inf("78 9c", "bad zlib window size", 0, 8, 0, Z_DATA_ERROR); + inf("78 9c 63 0 0 0 1 0 1", "check adler32", 0, 15, 1, Z_STREAM_END); + inf("1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1, + Z_DATA_ERROR); + inf("1f 8b 8 2 0 0 0 0 0 0 1d 26 3 0 0 0 0 0 0 0 0 0", "check gzip length", + 0, 47, 0, Z_STREAM_END); + inf("78 90", "bad zlib header check", 0, 47, 0, Z_DATA_ERROR); + inf("8 b8 0 0 0 1", "need dictionary", 0, 8, 0, Z_NEED_DICT); + inf("78 9c 63 0", "compute adler32", 0, 15, 1, Z_OK); + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = NULL; + ret = PREFIX(inflateInit2)(&strm, -8); + strm.avail_in = 2; + strm.next_in = (void *)"\x63"; + strm.avail_out = 1; + strm.next_out = (void *)&ret; + memset(dict, 0, 257); + ret = PREFIX(inflateSetDictionary)(&strm, dict, 257); + assert(ret == Z_OK); + mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256); + ret = PREFIX(inflatePrime)(&strm, 16, 0); assert(ret == Z_OK); + strm.avail_in = 2; + strm.next_in = (void *)"\x80"; + ret = PREFIX(inflateSync)(&strm); assert(ret == Z_DATA_ERROR); + ret = PREFIX(inflate)(&strm, Z_NO_FLUSH); assert(ret == Z_STREAM_ERROR); + strm.avail_in = 4; + strm.next_in = (void *)"\0\0\xff\xff"; + ret = PREFIX(inflateSync)(&strm); assert(ret == Z_OK); + (void)PREFIX(inflateSyncPoint)(&strm); + ret = PREFIX(inflateCopy)(©, &strm); assert(ret == Z_MEM_ERROR); + mem_limit(&strm, 0); + ret = PREFIX(inflateUndermine)(&strm, 1); +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + assert(ret == Z_OK); +#else + assert(ret == Z_DATA_ERROR); +#endif + (void)PREFIX(inflateMark)(&strm); + ret = PREFIX(inflateEnd)(&strm); assert(ret == Z_OK); + mem_done(&strm, "miscellaneous, force memory errors"); +} + +/* input and output functions for inflateBack() */ +static unsigned pull(void *desc, z_const unsigned char **buf) { + static unsigned int next = 0; + static unsigned char dat[] = {0x63, 0, 2, 0}; + struct inflate_state *state; + + if (desc == NULL) { + next = 0; + return 0; /* no input (already provided at next_in) */ + } + state = (void *)((PREFIX3(stream) *)desc)->state; + if (state != NULL) + state->mode = SYNC; /* force an otherwise impossible situation */ + return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0; +} + +static int push(void *desc, unsigned char *buf, unsigned len) { + buf += len; + Z_UNUSED(buf); + return desc != NULL; /* force error if desc not null */ +} + +/* cover inflateBack() up to common deflate data cases and after those */ +static void cover_back(void) { + int ret; + PREFIX3(stream) strm; + unsigned char win[32768]; + +#ifdef ZLIB_COMPAT + ret = PREFIX(inflateBackInit_)(NULL, 0, win, 0, 0); + assert(ret == Z_VERSION_ERROR); +#endif + + ret = PREFIX(inflateBackInit)(NULL, 0, win); + assert(ret == Z_STREAM_ERROR); + ret = PREFIX(inflateBack)(NULL, NULL, NULL, NULL, NULL); + assert(ret == Z_STREAM_ERROR); + ret = PREFIX(inflateBackEnd)(NULL); assert(ret == Z_STREAM_ERROR); + fputs("inflateBack bad parameters\n", stderr); + + mem_setup(&strm); + ret = PREFIX(inflateBackInit)(&strm, 15, win); + assert(ret == Z_OK); + strm.avail_in = 2; + strm.next_in = (void *)"\x03"; + ret = PREFIX(inflateBack)(&strm, pull, NULL, push, NULL); + assert(ret == Z_STREAM_END); + /* force output error */ + strm.avail_in = 3; + strm.next_in = (void *)"\x63\x00"; + ret = PREFIX(inflateBack)(&strm, pull, NULL, push, &strm); + assert(ret == Z_BUF_ERROR); + /* force mode error by mucking with state */ + ret = PREFIX(inflateBack)(&strm, pull, &strm, push, NULL); + assert(ret == Z_STREAM_ERROR); + ret = PREFIX(inflateBackEnd)(&strm); assert(ret == Z_OK); + mem_done(&strm, "inflateBack bad state"); + + ret = PREFIX(inflateBackInit)(&strm, 15, win); + assert(ret == Z_OK); + ret = PREFIX(inflateBackEnd)(&strm); assert(ret == Z_OK); + fputs("inflateBack built-in memory routines\n", stderr); + Z_UNUSED(ret); +} + +/* do a raw inflate of data in hexadecimal with both inflate and inflateBack */ +static int try(char *hex, char *id, int err) { + int ret; + unsigned len, size; + unsigned char *in, *out, *win; + char *prefix; + PREFIX3(stream) strm; + + /* convert to hex */ + in = h2b(hex, &len); + assert(in != NULL); + + /* allocate work areas */ + size = len << 3; + out = malloc(size); + assert(out != NULL); + win = malloc(32768); + assert(win != NULL); + prefix = malloc(strlen(id) + 6); + assert(prefix != NULL); + + /* first with inflate */ + strcpy(prefix, id); + strcat(prefix, "-late"); + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = NULL; + ret = PREFIX(inflateInit2)(&strm, err < 0 ? 47 : -15); + assert(ret == Z_OK); + strm.avail_in = len; + strm.next_in = in; + do { + strm.avail_out = size; + strm.next_out = out; + ret = PREFIX(inflate)(&strm, Z_TREES); + assert(ret != Z_STREAM_ERROR && ret != Z_MEM_ERROR); + if (ret == Z_DATA_ERROR || ret == Z_NEED_DICT) + break; + } while (strm.avail_in || strm.avail_out == 0); + if (err) { + assert(ret == Z_DATA_ERROR); + assert(strcmp(id, strm.msg) == 0); + } + PREFIX(inflateEnd)(&strm); + mem_done(&strm, prefix); + + /* then with inflateBack */ + if (err >= 0) { + strcpy(prefix, id); + strcat(prefix, "-back"); + mem_setup(&strm); + ret = PREFIX(inflateBackInit)(&strm, 15, win); + assert(ret == Z_OK); + strm.avail_in = len; + strm.next_in = in; + ret = PREFIX(inflateBack)(&strm, pull, NULL, push, NULL); + assert(ret != Z_STREAM_ERROR); + if (err && ret != Z_BUF_ERROR) { + assert(ret == Z_DATA_ERROR); + assert(strcmp(id, strm.msg) == 0); + } + PREFIX(inflateBackEnd)(&strm); + mem_done(&strm, prefix); + } + + /* clean up */ + free(prefix); + free(win); + free(out); + free(in); + return ret; +} + +/* cover deflate data cases in both inflate() and inflateBack() */ +static void cover_inflate(void) { + try("0 0 0 0 0", "invalid stored block lengths", 1); + try("3 0", "fixed", 0); + try("6", "invalid block type", 1); + try("1 1 0 fe ff 0", "stored", 0); + try("fc 0 0", "too many length or distance symbols", 1); + try("4 0 fe ff", "invalid code lengths set", 1); + try("4 0 24 49 0", "invalid bit length repeat", 1); + try("4 0 24 e9 ff ff", "invalid bit length repeat", 1); + try("4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1); + try("4 80 49 92 24 49 92 24 71 ff ff 93 11 0", + "invalid literal/lengths set", 1); + try("4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1); + try("4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1); + try("2 7e ff ff", "invalid distance code", 1); +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + try("c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 0); +#else + try("c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1); +#endif + + /* also trailer mismatch just in inflate() */ + try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1); + try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1", + "incorrect length check", -1); + try("5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0); + try("5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f", + "long code", 0); + try("ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0); + try("ed cf c1 b1 2c 47 10 c4 30 fa 6f 35 1d 1 82 59 3d fb be 2e 2a fc f c", + "long distance and extra", 0); + try("ed c0 81 0 0 0 0 80 a0 fd a9 17 a9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 " + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0); + inf("2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258, + Z_STREAM_END); + inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK); +} + +/* cover remaining lines in inftrees.c */ +static void cover_trees(void) { + int ret; + unsigned bits; + uint16_t lens[16], work[16]; + code *next, table[ENOUGH_DISTS]; + + /* we need to call inflate_table() directly in order to manifest not- + enough errors, since zlib ensures that enough is always enough */ + for (bits = 0; bits < 15; bits++) + lens[bits] = (uint16_t)(bits + 1); + lens[15] = 15; + next = table; + bits = 15; + ret = zng_inflate_table(DISTS, lens, 16, &next, &bits, work); + assert(ret == 1); + next = table; + bits = 1; + ret = zng_inflate_table(DISTS, lens, 16, &next, &bits, work); + assert(ret == 1); + fputs("inflate_table not enough errors\n", stderr); + Z_UNUSED(ret); +} + +/* cover remaining inffast.c decoding and window copying */ +static void cover_fast(void) { + inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68" + " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR); + inf("25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49" + " 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258, + Z_DATA_ERROR); + inf("3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258, + Z_DATA_ERROR); + inf("1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258, + Z_DATA_ERROR); + inf("d c7 1 ae eb 38 c 4 41 a0 87 72 de df fb 1f b8 36 b1 38 5d ff ff 0", + "fast 2nd level codes and too far back", 0, -8, 258, Z_DATA_ERROR); + inf("63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, Z_OK); + inf("63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0", + "contiguous and wrap around window", 6, -8, 259, Z_OK); + inf("63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259, + Z_STREAM_END); +} + +static void cover_cve_2022_37434(void) { + inf("1f 8b 08 04 61 62 63 64 61 62 52 51 1f 8b 08 04 61 62 63 64 61 62 52 51 1f 8b 08 04 61 62 63 64 61 62 52 51 1f 8b 08 04 61 62 63 64 61 62 52 51", "wtf", 13, 47, 12, Z_OK); +} + +int main(void) { + fprintf(stderr, "%s\n", zVersion()); + cover_support(); + cover_wrap(); + cover_back(); + cover_inflate(); + cover_trees(); + cover_fast(); + cover_cve_2022_37434(); + return 0; +} diff --git a/test/minideflate.c b/test/minideflate.c new file mode 100644 index 0000000000..9190d77bc1 --- /dev/null +++ b/test/minideflate.c @@ -0,0 +1,367 @@ +/* minideflate.c -- test deflate/inflate under specific conditions + * Copyright (C) 2020 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" + +#include +#include + +#include "zutil.h" + +#if defined(_WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef _MSC_VER +# include +# define strcasecmp _stricmp +#else +# include +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +/* Default read/write i/o buffer size based on GZBUFSIZE */ +#define BUFSIZE 131072 + +/* =========================================================================== + * deflate() using specialized parameters + */ +static void deflate_params(FILE *fin, FILE *fout, int32_t read_buf_size, int32_t write_buf_size, int32_t level, + int32_t window_bits, int32_t mem_level, int32_t strategy, int32_t flush) { + PREFIX3(stream) c_stream; /* compression stream */ + uint8_t *read_buf; + uint8_t *write_buf; + int32_t read; + int err; + + read_buf = (uint8_t *)malloc(read_buf_size); + if (read_buf == NULL) { + fprintf(stderr, "failed to create read buffer (%d)\n", read_buf_size); + return; + } + write_buf = (uint8_t *)malloc(write_buf_size); + if (write_buf == NULL) { + fprintf(stderr, "failed to create write buffer (%d)\n", write_buf_size); + free(read_buf); + return; + } + + c_stream.zalloc = NULL; + c_stream.zfree = NULL; + c_stream.opaque = (void *)0; + c_stream.total_in = 0; + c_stream.total_out = 0; + c_stream.next_out = write_buf; + c_stream.avail_out = write_buf_size; + + err = PREFIX(deflateInit2)(&c_stream, level, Z_DEFLATED, window_bits, mem_level, strategy); + CHECK_ERR(err, "deflateInit2"); + + /* Process input using our read buffer and flush type, + * output to stdout only once write buffer is full */ + do { + read = (int32_t)fread(read_buf, 1, read_buf_size, fin); + if (read <= 0) + break; + + c_stream.next_in = (z_const uint8_t *)read_buf; + c_stream.avail_in = read; + + do { + err = PREFIX(deflate)(&c_stream, flush); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + + if (c_stream.next_out == write_buf + write_buf_size) { + fwrite(write_buf, 1, write_buf_size, fout); + c_stream.next_out = write_buf; + c_stream.avail_out = write_buf_size; + } + } while (c_stream.next_in < read_buf + read); + } while (err == Z_OK); + + /* Finish the stream if necessary */ + if (flush != Z_FINISH) { + c_stream.avail_in = 0; + do { + if (c_stream.next_out == write_buf + write_buf_size) { + fwrite(write_buf, 1, write_buf_size, fout); + c_stream.next_out = write_buf; + c_stream.avail_out = write_buf_size; + } + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } while (1); + } + + /* Output remaining data in write buffer */ + if (c_stream.next_out != write_buf) { + fwrite(write_buf, 1, c_stream.next_out - write_buf, fout); + } + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + free(read_buf); + free(write_buf); +} + +/* =========================================================================== + * inflate() using specialized parameters + */ +static void inflate_params(FILE *fin, FILE *fout, int32_t read_buf_size, int32_t write_buf_size, int32_t window_bits, + int32_t flush) { + PREFIX3(stream) d_stream; /* decompression stream */ + uint8_t *read_buf; + uint8_t *write_buf; + int32_t read; + int err; + + + read_buf = (uint8_t *)malloc(read_buf_size); + if (read_buf == NULL) { + fprintf(stderr, "failed to create read buffer (%d)\n", read_buf_size); + return; + } + write_buf = (uint8_t *)malloc(write_buf_size); + if (write_buf == NULL) { + fprintf(stderr, "failed to create write buffer (%d)\n", write_buf_size); + free(read_buf); + return; + } + + d_stream.zalloc = NULL; + d_stream.zfree = NULL; + d_stream.opaque = (void *)0; + d_stream.total_in = 0; + d_stream.total_out = 0; + d_stream.next_out = write_buf; + d_stream.avail_out = write_buf_size; + + err = PREFIX(inflateInit2)(&d_stream, window_bits); + CHECK_ERR(err, "inflateInit2"); + + /* Process input using our read buffer and flush type, + * output to stdout only once write buffer is full */ + do { + read = (int32_t)fread(read_buf, 1, read_buf_size, fin); + if (read <= 0) + break; + + d_stream.next_in = (z_const uint8_t *)read_buf; + d_stream.avail_in = read; + + do { + err = PREFIX(inflate)(&d_stream, flush); + + /* Ignore Z_BUF_ERROR if we are finishing and read buffer size is + * purposefully limited */ + if (flush == Z_FINISH && err == Z_BUF_ERROR && read_buf_size != BUFSIZE) + err = Z_OK; + + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + + if (d_stream.next_out == write_buf + write_buf_size) { + fwrite(write_buf, 1, write_buf_size, fout); + d_stream.next_out = write_buf; + d_stream.avail_out = write_buf_size; + } + } while (d_stream.next_in < read_buf + read); + } while (err == Z_OK); + + /* Finish the stream if necessary */ + if (flush != Z_FINISH) { + d_stream.avail_in = 0; + do { + if (d_stream.next_out == write_buf + write_buf_size) { + fwrite(write_buf, 1, write_buf_size, fout); + d_stream.next_out = write_buf; + d_stream.avail_out = write_buf_size; + } + + err = PREFIX(inflate)(&d_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } while (1); + } + + /* Output remaining data in write buffer */ + if (d_stream.next_out != write_buf) { + fwrite(write_buf, 1, d_stream.next_out - write_buf, fout); + } + + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + free(read_buf); + free(write_buf); +} + +static void show_help(void) { + printf("Usage: minideflate [-c][-d][-k] [-f|-h|-R|-F] [-m level] [-r/-t size] [-s flush] [-w bits] [-0 to -9] [input file]\n\n" + " -c : write to standard output\n" + " -d : decompress\n" + " -k : keep input file\n" + " -f : compress with Z_FILTERED\n" + " -h : compress with Z_HUFFMAN_ONLY\n" + " -R : compress with Z_RLE\n" + " -F : compress with Z_FIXED\n" + " -m : memory level (1 to 8)\n" + " -w : window bits..\n" + " : -1 to -15 for raw deflate\n" + " : 0 to 15 for deflate (adler32)\n" + " : 16 to 31 for gzip (crc32)\n" + " -s : flush type (0 to 5)\n" + " -r : read buffer size\n" + " -t : write buffer size\n" + " -0 to -9 : compression level\n\n"); +} + +int main(int argc, char **argv) { + int32_t i; + int32_t mem_level = DEF_MEM_LEVEL; + int32_t window_bits = INT32_MAX; + int32_t strategy = Z_DEFAULT_STRATEGY; + int32_t level = Z_DEFAULT_COMPRESSION; + int32_t read_buf_size = BUFSIZE; + int32_t write_buf_size = BUFSIZE; + int32_t flush = Z_NO_FLUSH; + uint8_t copyout = 0; + uint8_t uncompr = 0; + uint8_t keep = 0; + FILE *fin = stdin; + FILE *fout = stdout; + + + if (argc == 1) { + show_help(); + return 64; /* EX_USAGE */ + } + + for (i = 1; i < argc; i++) { + if ((strcmp(argv[i], "-m") == 0) && (i + 1 < argc)) + mem_level = atoi(argv[++i]); + else if ((strcmp(argv[i], "-w") == 0) && (i + 1 < argc)) + window_bits = atoi(argv[++i]); + else if ((strcmp(argv[i], "-r") == 0) && (i + 1 < argc)) + read_buf_size = atoi(argv[++i]); + else if ((strcmp(argv[i], "-t") == 0) && (i + 1 < argc)) + write_buf_size = atoi(argv[++i]); + else if ((strcmp(argv[i], "-s") == 0) && (i + 1 < argc)) + flush = atoi(argv[++i]); + else if (strcmp(argv[i], "-c") == 0) + copyout = 1; + else if (strcmp(argv[i], "-d") == 0) + uncompr = 1; + else if (strcmp(argv[i], "-k") == 0) + keep = 1; + else if (strcmp(argv[i], "-f") == 0) + strategy = Z_FILTERED; + else if (strcmp(argv[i], "-F") == 0) + strategy = Z_FIXED; + else if (strcmp(argv[i], "-h") == 0) + strategy = Z_HUFFMAN_ONLY; + else if (strcmp(argv[i], "-R") == 0) + strategy = Z_RLE; + else if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9' && argv[i][2] == 0) + level = argv[i][1] - '0'; + else if (strcmp(argv[i], "--help") == 0) { + show_help(); + return 0; + } else if (argv[i][0] == '-') { + show_help(); + return 64; /* EX_USAGE */ + } else + break; + } + + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + + if (i != argc) { + fin = fopen(argv[i], "rb+"); + if (fin == NULL) { + fprintf(stderr, "Failed to open file: %s\n", argv[i]); + exit(1); + } + if (!copyout) { + char *out_file = (char *)calloc(1, strlen(argv[i]) + 6); + if (out_file == NULL) { + fprintf(stderr, "Not enough memory\n"); + exit(1); + } + strcat(out_file, argv[i]); + if (!uncompr) { + if (window_bits < 0) { + strcat(out_file, ".zraw"); + } else if (window_bits > MAX_WBITS) { + strcat(out_file, ".gz"); + } else { + strcat(out_file, ".z"); + } + } else { + char *out_ext = strrchr(out_file, '.'); + if (out_ext != NULL) { + if (strcasecmp(out_ext, ".zraw") == 0 && window_bits == INT32_MAX) { + fprintf(stderr, "Must specify window bits for raw deflate stream\n"); + exit(1); + } + *out_ext = 0; + } + } + fout = fopen(out_file, "wb"); + if (fout == NULL) { + fprintf(stderr, "Failed to open file: %s\n", out_file); + exit(1); + } + free(out_file); + } + } + + if (window_bits == INT32_MAX) { + window_bits = MAX_WBITS; + /* Auto-detect wrapper for inflateInit */ + if (uncompr) + window_bits += 32; + } + + if (window_bits == INT32_MAX) { + window_bits = MAX_WBITS; + /* Auto-detect wrapper for inflateInit */ + if (uncompr) + window_bits += 32; + } + + if (uncompr) { + inflate_params(fin, fout, read_buf_size, write_buf_size, window_bits, flush); + } else { + deflate_params(fin, fout, read_buf_size, write_buf_size, level, window_bits, mem_level, strategy, flush); + } + + if (fin != stdin) { + fclose(fin); + if (!copyout && !keep) { + unlink(argv[i]); + } + } + if (fout != stdout) { + fclose(fout); + } + + return 0; +} diff --git a/test/minigzip.c b/test/minigzip.c new file mode 100644 index 0000000000..e26364dd98 --- /dev/null +++ b/test/minigzip.c @@ -0,0 +1,367 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2006, 2010, 2011, 2016 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. + */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif +#include + +#include +#include + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) +#ifndef _WIN32 /* unlink already in stdio.h for Win32 */ +extern int unlink (const char *); +#endif +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#ifndef BUFLEN +# define BUFLEN 16384 /* read buffer size */ +#endif +#define BUFLENW (BUFLEN * 3) /* write buffer size */ +#define MAX_NAME_LEN 1024 + +static char *prog; + +/* =========================================================================== + * Display error message and exit + */ +static void error(const char *msg) { + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Display last error message of gzFile, close it and exit + */ + +static void gz_fatal(gzFile file) { + int err; + fprintf(stderr, "%s: %s\n", prog, PREFIX(gzerror)(file, &err)); + PREFIX(gzclose)(file); + exit(1); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ +/* =========================================================================== + * Try compressing the input file at once using mmap. Return Z_OK if + * success, Z_ERRNO otherwise. + */ +static int gz_compress_mmap(FILE *in, gzFile out) { + int len; + int ifd = fileno(in); + char *buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((void *)0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (char *)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = PREFIX(gzwrite)(out, buf, (unsigned)buf_len); + + if (len != (int)buf_len) gz_fatal(out); + + munmap(buf, buf_len); + fclose(in); + if (PREFIX(gzclose)(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Compress input to output then close both files. + */ + +static void gz_compress(FILE *in, gzFile out) { + char *buf; + int len; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + buf = (char *)calloc(BUFLEN, 1); + if (buf == NULL) { + perror("out of memory"); + exit(1); + } + + for (;;) { + len = (int)fread(buf, 1, BUFLEN, in); + if (ferror(in)) { + free(buf); + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (PREFIX(gzwrite)(out, buf, (unsigned)len) != len) gz_fatal(out); + } + free(buf); + fclose(in); + if (PREFIX(gzclose)(out) != Z_OK) error("failed gzclose"); +} + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +static void gz_uncompress(gzFile in, FILE *out) { + char *buf = (char *)malloc(BUFLENW); + int len; + + if (buf == NULL) error("out of memory"); + + for (;;) { + len = PREFIX(gzread)(in, buf, BUFLENW); + if (len < 0) { + free(buf); + gz_fatal(in); + } + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + free(buf); + error("failed fwrite"); + } + } + free(buf); + if (fclose(out)) error("failed fclose"); + + if (PREFIX(gzclose)(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +static void file_compress(char *file, char *mode, int keep) { + char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + + snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = PREFIX(gzopen)(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + if (!keep) + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +static void file_uncompress(char *file, int keep) { + char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + size_t len = strlen(file); + + if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + + snprintf(buf, sizeof(buf), "%s", file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX); + } + in = PREFIX(gzopen)(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + if (!keep) + unlink(infile); +} + +static void show_help(void) { + printf("Usage: minigzip [-c] [-d] [-k] [-f|-h|-R|-F|-T] [-A] [-0 to -9] [files...]\n\n" + " -c : write to standard output\n" + " -d : decompress\n" + " -k : keep input files\n" + " -f : compress with Z_FILTERED\n" + " -h : compress with Z_HUFFMAN_ONLY\n" + " -R : compress with Z_RLE\n" + " -F : compress with Z_FIXED\n" + " -T : stored raw\n" + " -A : auto detect type\n" + " -0 to -9 : compression level\n\n"); +} + +int main(int argc, char *argv[]) { + int copyout = 0; + int uncompr = 0; + int keep = 0; + int i = 0; + gzFile file; + char *bname, outmode[20]; + char *strategy = ""; + char *level = "6"; + char *type = "b"; + + prog = argv[i]; + bname = strrchr(argv[i], '/'); + if (bname) + bname++; + else + bname = argv[i]; + + if (!strcmp(bname, "gunzip")) + uncompr = 1; + else if (!strcmp(bname, "zcat")) + copyout = uncompr = 1; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-c") == 0) + copyout = 1; + else if (strcmp(argv[i], "-d") == 0) + uncompr = 1; + else if (strcmp(argv[i], "-k") == 0) + keep = 1; + else if (strcmp(argv[i], "-A") == 0) + type = ""; + else if (argv[i][0] == '-' && (argv[i][1] == 'f' || argv[i][1] == 'h' || + argv[i][1] == 'R' || argv[i][1] == 'F' || argv[i][1] == 'T') && argv[i][2] == 0) + strategy = argv[i] + 1; + else if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9' && argv[i][2] == 0) + level = argv[i] + 1; + else if (strcmp(argv[i], "--help") == 0) { + show_help(); + return 0; + } else if (argv[i][0] == '-') { + show_help(); + return 64; /* EX_USAGE */ + } else { + break; + } + } + + snprintf(outmode, sizeof(outmode), "w%s%s%s", type, strategy, level); + + if (i == argc) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = PREFIX(gzdopen)(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = PREFIX(gzdopen)(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + if (copyout) { + SET_BINARY_MODE(stdout); + } + do { + if (uncompr) { + if (copyout) { + file = PREFIX(gzopen)(argv[i], "rb"); + if (file == NULL) + fprintf(stderr, "%s: can't gzopen %s\n", prog, argv[i]); + else + gz_uncompress(file, stdout); + } else { + file_uncompress(argv[i], keep); + } + } else { + if (copyout) { + FILE * in = fopen(argv[i], "rb"); + + if (in == NULL) { + perror(argv[i]); + } else { + file = PREFIX(gzdopen)(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + + gz_compress(in, file); + } + + } else { + file_compress(argv[i], outmode, keep); + } + } + } while (++i < argc); + } + return 0; +} diff --git a/test/pigz/CMakeLists.txt b/test/pigz/CMakeLists.txt new file mode 100644 index 0000000000..bc6830ae24 --- /dev/null +++ b/test/pigz/CMakeLists.txt @@ -0,0 +1,211 @@ +# CMakeLists.txt -- Build madler/pigz against zlib variant + +# Copyright (C) 2021 Nathan Moinvaziri +# Licensed under the Zlib license, see LICENSE.md for details + +# By default pigz will be linked against the system zlib and +# pthread libraries if installed. + +# For compilation on Windows download and use shim: +# https://github.com/zlib-ng/pigzbench/tree/master/pigz/win + +# Optional Variables +# WITH_CODE_COVERAGE - Enable code coverage reporting +# WITH_THREADS - Enable threading support +# PIGZ_ENABLE_TESTS - Enable adding unit tests +# PIGZ_VERSION - Set the version of pigz to build +# ZLIB_ROOT - Path to the zlib source directory +# PTHREADS4W_ROOT - Path to pthreads4w source directory on Windows. +# If not specified then threading will be disabled. + +cmake_minimum_required(VERSION 3.11) + +include(CheckCCompilerFlag) +include(FeatureSummary) +include(FetchContent) + +include(../../cmake/detect-coverage.cmake) + +option(WITH_CODE_COVERAGE "Enable code coverage reporting" OFF) +option(WITH_THREADS "Enable threading support" ON) +option(PIGZ_ENABLE_TESTS "Build unit tests" ON) +option(PIGZ_VERSION "Set the version of pigz to build" "") + +project(pigz LANGUAGES C) + +# Set code coverage compiler flags +if(WITH_CODE_COVERAGE) + add_code_coverage() +endif() + +# Compiler definitions +if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + add_definitions(-fno-caret-diagnostics) +elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5.0) + add_definitions(-Wno-unused-result) + endif() + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8.0) + add_definitions(-fno-diagnostics-show-caret) + endif() +elseif(WIN32) + add_definitions(-D_TIMESPEC_DEFINED) + if(MSVC) + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) + endif() +endif() + +# Fetch pigz source code from official repository +if(PIGZ_VERSION STREQUAL "") + set(PIGZ_TAG master) +else() + set(PIGZ_TAG ${PIGZ_VERSION}) +endif() +FetchContent_Declare(pigz + GIT_REPOSITORY https://github.com/madler/pigz.git + GIT_TAG ${PIGZ_TAG}) + +FetchContent_GetProperties(pigz) +if(NOT pigz_POPULATED) + FetchContent_Populate(pigz) +endif() + +set(PIGZ_SRCS + ${pigz_SOURCE_DIR}/pigz.c + ${pigz_SOURCE_DIR}/try.c) + +set(PIGZ_HDRS + ${pigz_SOURCE_DIR}/try.h) + +add_executable(${PROJECT_NAME} ${PIGZ_SRCS} ${PIGZ_HDRS}) +add_definitions(-DNOZOPFLI) +if(WIN32) + target_include_directories(${PROJECT_NAME} PRIVATE win) +endif() + +# Find and link against pthreads or pthreads4w +if(WITH_THREADS) + if(WIN32) + if(DEFINED PTHREADS4W_ROOT) + set(CLEANUP_STYLE VC) + set(PTHREADS4W_VERSION 3) + + add_subdirectory(${PTHREADS4W_ROOT} ${PTHREADS4W_ROOT} EXCLUDE_FROM_ALL) + target_link_libraries(${PROJECT_NAME} pthreadVC3) + target_include_directories(${PROJECT_NAME} PRIVATE ${PTHREADS4W_ROOT}) + else() + message(WARNING "Missing pthreads4w root directory") + set(WITH_THREADS OFF) + endif() + else() + find_package(Threads REQUIRED) + target_link_libraries(${PROJECT_NAME} Threads::Threads) + if(NOT APPLE) + target_link_libraries(${PROJECT_NAME} m) + endif() + endif() +endif() + +# Disable threading support +if(NOT WITH_THREADS) + add_definitions(-DNOTHREAD) +else() + set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY SOURCES + ${pigz_SOURCE_DIR}/yarn.c + ${pigz_SOURCE_DIR}/yarn.h) +endif() + +# Find and link against zlib +if(NOT DEFINED ZLIB_ROOT) + find_package(Zlib REQUIRED) +endif() + +set(ZLIB_COMPAT ON) +set(ZLIB_ENABLE_TESTS OFF) + +add_subdirectory(${ZLIB_ROOT} ${CMAKE_CURRENT_BINARY_DIR}/zlib EXCLUDE_FROM_ALL) + +if(NOT DEFINED BUILD_SHARED_LIBS OR NOT BUILD_SHARED_LIBS) + set(ZLIB_TARGET zlibstatic) +else() + set(ZLIB_TARGET zlib) +endif() + +target_include_directories(${PROJECT_NAME} PRIVATE ${ZLIB_ROOT} ${CMAKE_CURRENT_BINARY_DIR}/zlib) +target_link_libraries(${PROJECT_NAME} ${ZLIB_TARGET}) + +if(NOT SKIP_INSTALL_BINARIES AND NOT SKIP_INSTALL_ALL) + install(TARGETS ${PROJECT_NAME} DESTINATION "bin") +endif() + +# Add unit tests +if(PIGZ_ENABLE_TESTS) + enable_testing() + + set(PIGZ_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + + macro(test_pigz name path) + # Construct compression arguments for pigz + set(compress_args -k -c) + foreach(extra_arg IN ITEMS "${ARGN}") + list(APPEND compress_args ${extra_arg}) + endforeach() + + # Create unique friendly string for test + string(REPLACE ";" "" arg_list "${ARGN}") + string(REPLACE " " "" arg_list "${arg_list}") + string(REPLACE "-" "" arg_list "${arg_list}") + + set(test_id pigz-${name}-${arg_list}) + + if(NOT TEST ${test_id}) + add_test(NAME ${test_id} + COMMAND ${CMAKE_COMMAND} + "-DTARGET=${PIGZ_COMMAND}" + "-DCOMPRESS_ARGS=${compress_args}" + "-DDECOMPRESS_ARGS=-d;-c" + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${path} + -DTEST_NAME=${test_id} + -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/compress-and-verify.cmake) + endif() + endmacro() + + set(TEST_CONFIGS + -U # RLE compression + #-H # Z_HUFFMAN_ONLY (broken in 2.6) + -0 # No compression + -1 # Deflate quick + -4 # Deflate medium (lazy matches) + -6 # Deflate medium + -9 # Deflate slow + ) + + file(GLOB_RECURSE TEST_FILE_PATHS + LIST_DIRECTORIES false + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../data/*) + + foreach(TEST_FILE_PATH ${TEST_FILE_PATHS}) + if("${TEST_FILE_PATH}" MATCHES ".gz$" OR "${TEST_FILE_PATH}" MATCHES ".out$" OR + "${TEST_FILE_PATH}" MATCHES "/.git/" OR "${TEST_FILE_PATH}" MATCHES ".md$") + continue() + endif() + foreach(TEST_CONFIG ${TEST_CONFIGS}) + get_filename_component(TEST_NAME ${TEST_FILE_PATH} NAME) + if (TEST_NAME STREQUAL "") + continue() + endif() + test_pigz(${TEST_NAME} ${TEST_FILE_PATH} ${TEST_CONFIG}) + endforeach() + endforeach() + + set(GH979_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ + -d -k -f ${CMAKE_CURRENT_SOURCE_DIR}/../GH-979/pigz-2.6.tar.gz) + add_test(NAME GH-979 COMMAND ${GH979_COMMAND}) +endif() + +add_feature_info(WITH_CODE_COVERAGE WITH_CODE_COVERAGE "Enable code coverage reporting") +add_feature_info(WITH_THREADS WITH_THREADS "Enable threading support") +add_feature_info(PIGZ_ENABLE_TESTS PIGZ_ENABLE_TESTS "Build unit tests") + +FEATURE_SUMMARY(WHAT ALL INCLUDE_QUIET_PACKAGES) diff --git a/test/pkgcheck.sh b/test/pkgcheck.sh new file mode 100644 index 0000000000..29668a9f4f --- /dev/null +++ b/test/pkgcheck.sh @@ -0,0 +1,180 @@ +#!/bin/sh + +usage() { + cat <<"_EOF_" +Usage: sh test/pkgcheck.sh [--zlib-compat] + +Verifies that the various build systems produce identical results on a Unixlike system. +If --zlib-compat, tests with zlib compatible builds. + +To build the 32 bit version for the current 64 bit arch: + +$ sudo apt install ninja-build diffoscope gcc-multilib +$ export CMAKE_ARGS="-DCMAKE_C_FLAGS=-m32" CFLAGS=-m32 LDFLAGS=-m32 +$ sh test/pkgcheck.sh + +To cross-build, install the appropriate qemu and gcc packages, +and set the environment variables used by configure or cmake. +On Ubuntu, for example (values taken from .github/workflows/pkgconf.yml): + +arm HF: +$ sudo apt install ninja-build diffoscope qemu gcc-arm-linux-gnueabihf libc6-dev-armhf-cross +$ export CHOST=arm-linux-gnueabihf +$ export CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm.cmake -DCMAKE_C_COMPILER_TARGET=${CHOST}" + +aarch64: +$ sudo apt install ninja-build diffoscope qemu gcc-aarch64-linux-gnu libc6-dev-arm64-cross +$ export CHOST=aarch64-linux-gnu +$ export CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-aarch64.cmake -DCMAKE_C_COMPILER_TARGET=${CHOST}" + +ppc (32 bit big endian): +$ sudo apt install ninja-build diffoscope qemu gcc-powerpc-linux-gnu libc6-dev-powerpc-cross +$ export CHOST=powerpc-linux-gnu +$ export CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-powerpc.cmake" + +ppc64le: +$ sudo apt install ninja-build diffoscope qemu gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross +$ export CHOST=powerpc64le-linux-gnu +$ export CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-powerpc64le.cmake" + +then: +$ export CC=${CHOST}-gcc +$ sh test/pkgcheck.sh [--zlib-compat] + +Note: on Mac, you may also need to do 'sudo xcode-select -r' to get cmake to match configure/make's behavior (i.e. omit -isysroot). +_EOF_ +} + +set -ex + +case "$1" in +--zlib-compat) + suffix="" + CMAKE_ARGS="$CMAKE_ARGS -DZLIB_COMPAT=ON" + CONFIGURE_ARGS="$CONFIGURE_ARGS --zlib-compat" + ;; +"") + suffix="-ng" + ;; +*) + echo "Unknown arg '$1'" + usage + exit 1 + ;; +esac + +if ! test -f "configure" +then + echo "Please run from top of source tree" + exit 1 +fi + +# Tell GNU's ld etc. to use Jan 1 1970 when embedding timestamps +# Probably only needed on older systems (ubuntu 14.04, BSD?) +export SOURCE_DATE_EPOCH=0 +case $(uname) in +Darwin) + # Tell Apple's ar etc. to use zero timestamps + export ZERO_AR_DATE=1 + # What CPU are we running on, exactly? + sysctl -n machdep.cpu.brand_string + sysctl -n machdep.cpu.features + if test "$(uname -m)" = "x86_64" + then + sysctl -n machdep.cpu.leaf7_features + sysctl -n machdep.cpu.extfeatures + fi + ;; +esac + +# Use same compiler for make and cmake builds +if test "$CC"x = ""x +then + if clang --version + then + export CC=clang + elif gcc --version + then + export CC=gcc + fi +fi + +# New build system +# Happens to delete top-level zconf.h +# (which itself is a bug, https://github.com/madler/zlib/issues/162 ) +# which triggers another bug later in configure, +# https://github.com/madler/zlib/issues/499 +rm -rf btmp2 pkgtmp2 +mkdir btmp2 pkgtmp2 +export DESTDIR=$(pwd)/pkgtmp2 +cd btmp2 + cmake -G Ninja ${CMAKE_ARGS} .. + ninja -v + ninja install +cd .. + +# Original build system +rm -rf btmp1 pkgtmp1 +mkdir btmp1 pkgtmp1 +export DESTDIR=$(pwd)/pkgtmp1/ +cd btmp1 + case $(uname) in + Darwin) + export LDFLAGS="-Wl,-headerpad_max_install_names" + ;; + esac + ../configure $CONFIGURE_ARGS + make -j2 + make install +cd .. + +repack_ar() { + archive1=$(cd pkgtmp1; find . -type f -name '*.a'; cd ..) + archive2=$(cd pkgtmp2; find . -type f -name '*.a'; cd ..) + if ! cmp --silent pkgtmp1/$archive1 pkgtmp2/$archive2 + then + echo "libz$suffix.a does not match. Probably filenames differ (.o vs .c.o). Unpacking and renaming..." + # Note: %% is posix shell syntax meaning "Remove Largest Suffix Pattern", see + # https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02 + cd pkgtmp1; ar x $archive1; rm $archive1; cd .. + cd pkgtmp2; ar x $archive2; rm $archive2; for a in *.c.o; do mv $a ${a%%.c.o}.o; done; cd .. + # Also, remove __.SYMDEF SORTED if present, as it has those funky .c.o names embedded in it. + rm -f pkgtmp[12]/__.SYMDEF\ SORTED + fi +} + +case $(uname) in +Darwin) + # Remove the build uuid. + dylib1=$(find pkgtmp1 -type f -name '*.dylib*') + dylib2=$(find pkgtmp2 -type f -name '*.dylib*') + strip -x -no_uuid "$dylib1" + strip -x -no_uuid "$dylib2" + ;; +esac + +# Remove cmake target files to avoid mismatch with configure +find pkgtmp2 -type f -name '*.cmake' -exec rm '{}' \; + +# The ar on newer systems defaults to -D (i.e. deterministic), +# but FreeBSD 12.1, Debian 8, and Ubuntu 14.04 seem to not do that. +# I had trouble passing -D safely to the ar inside CMakeLists.txt, +# so punt and unpack the archive if needed before comparing. +# Also, cmake uses different .o suffix anyway... +repack_ar + +if diff -Nur pkgtmp1 pkgtmp2 +then + echo pkgcheck-cmake-bits-identical PASS +else + echo pkgcheck-cmake-bits-identical FAIL + dylib1=$(find pkgtmp1 -type f -name '*.dylib*' -print -o -type f -name '*.so.*' -print) + dylib2=$(find pkgtmp2 -type f -name '*.dylib*' -print -o -type f -name '*.so.*' -print) + diffoscope $dylib1 $dylib2 | cat + exit 1 +fi + +rm -rf btmp1 btmp2 pkgtmp1 pkgtmp2 + +# any failure would have caused an early exit already +echo "pkgcheck: PASS" diff --git a/test/switchlevels.c b/test/switchlevels.c new file mode 100644 index 0000000000..b31bc0f95c --- /dev/null +++ b/test/switchlevels.c @@ -0,0 +1,167 @@ +/* Compresses a user-specified number of chunks from stdin into stdout as a single gzip stream. + * Each chunk is compressed with a user-specified level. + */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include + +#if defined(_WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +static int read_all(unsigned char *buf, size_t size) { + size_t total_read = 0; + while (total_read < size) { + size_t n_read = fread(buf + total_read, 1, size - total_read, stdin); + if (ferror(stdin)) { + perror("fread\n"); + return 1; + } + if (n_read == 0) { + fprintf(stderr, "Premature EOF\n"); + return 1; + } + total_read += n_read; + } + return 0; +} + +static int write_all(unsigned char *buf, size_t size) { + size_t total_written = 0; + while (total_written < size) { + size_t n_written = fwrite(buf + total_written, 1, size - total_written, stdout); + if (ferror(stdout)) { + perror("fwrite\n"); + return 1; + } + total_written += n_written; + } + return 0; +} + +static int compress_chunk(PREFIX3(stream) *strm, int level, int size, int last) { + int ret = 1; + int err = 0; + unsigned long compsize; + unsigned char *buf; + + if (size <= 0) { + fprintf(stderr, "compress_chunk() invalid size %d\n", size); + goto done; + } + if (level < 0 || level > 9) { + fprintf(stderr, "compress_chunk() invalid level %d\n", level); + goto done; + } + + compsize = PREFIX(deflateBound)(strm, size); + buf = malloc(size + compsize); + if (buf == NULL) { + fprintf(stderr, "Out of memory\n"); + goto done; + } + if (read_all(buf, size) != 0) { + goto free_buf; + } + + /* Provide only output buffer to deflateParams(). It might need some space to flush the leftovers from the last + * deflate(), but we don't want it to compress anything new. */ + strm->next_in = NULL; + strm->avail_in = 0; + strm->next_out = buf + size; + strm->avail_out = compsize; + err = PREFIX(deflateParams)(strm, level, Z_DEFAULT_STRATEGY); + if (err != Z_OK) { + fprintf(stderr, "deflateParams() failed with code %d\n", err); + goto free_buf; + } + + /* Provide input buffer to deflate(). */ + strm->next_in = buf; + strm->avail_in = size; + err = PREFIX(deflate)(strm, last ? Z_FINISH : Z_SYNC_FLUSH); + if ((!last && err != Z_OK) || (last && err != Z_STREAM_END)) { + fprintf(stderr, "deflate() failed with code %d\n", err); + goto free_buf; + } + if (strm->avail_in != 0) { + fprintf(stderr, "deflate() did not consume %d bytes of input\n", strm->avail_in); + goto free_buf; + } + if (write_all(buf + size, compsize - strm->avail_out) != 0) { + goto free_buf; + } + ret = 0; + +free_buf: + free(buf); +done: + return ret; +} + +void show_help(void) +{ + printf("Usage: switchlevels [-w bits] level1 size1 [level2 size2 ...]\n\n" + " -w : window bits (8 to 15 for gzip, -8 to -15 for zlib)\n\n"); +} + +int main(int argc, char **argv) { + int ret = EXIT_FAILURE; + int err = 0; + int size = 0; + int level = Z_DEFAULT_COMPRESSION; + int level_arg = 1; + int window_bits = MAX_WBITS + 16; + PREFIX3(stream) strm; + + + if ((argc == 1) || (argc == 2 && strcmp(argv[1], "--help") == 0)) { + show_help(); + return 0; + } + + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + + memset(&strm, 0, sizeof(strm)); + + for (int i = 1; i < argc - 1; i++) { + if (strcmp(argv[i], "-w") == 0 && i+1 < argc) { + window_bits = atoi(argv[++i]); + } else { + level_arg = i; + level = atoi(argv[i]); + break; + } + } + + err = PREFIX(deflateInit2)(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY); + if (err != Z_OK) { + fprintf(stderr, "deflateInit() failed with code %d\n", err); + goto done; + } + + for (int i = level_arg; i < argc - 1; i += 2) { + level = atoi(argv[i]); + size = atoi(argv[i + 1]); + if (compress_chunk(&strm, level, size, i + 2 >= argc - 1) != 0) { + goto deflate_end; + } + } + ret = EXIT_SUCCESS; + +deflate_end: + PREFIX(deflateEnd)(&strm); +done: + return ret; +} diff --git a/test/test_adler32.cc b/test/test_adler32.cc new file mode 100644 index 0000000000..b3d03021e4 --- /dev/null +++ b/test/test_adler32.cc @@ -0,0 +1,395 @@ +/* test_adler32.c -- unit test for adler32 in the zlib compression library + * Copyright (C) 2020 IBM Corporation + * Author: Rogerio Alves + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include +#include + +extern "C" { +# include "zbuild.h" +# include "arch_functions.h" +# include "test_cpu_features.h" +} + +#include + +typedef struct { + uint32_t adler; + const uint8_t *buf; + uint32_t len; + uint32_t expect; +} adler32_test; + +static const uint8_t long_string[5552] = { + 'q','j','d','w','q','4','8','m','B','u','k','J','V','U','z','V','V','f','M','j','i','q','S','W','L','5','G','n','F','S','P','Q', + 'Q','D','i','6','m','E','9','Z','a','A','P','h','9','d','r','b','5','t','X','U','U','L','w','q','e','k','E','H','6','W','7','k', + 'A','x','N','Q','R','k','d','V','5','y','n','U','N','W','Q','Y','i','W','5','9','R','p','D','C','x','p','u','h','C','a','m','r', + 'z','n','z','A','d','J','6','u','N','e','r','x','7','Q','3','v','V','h','H','S','H','S','f','K','f','e','E','T','9','J','f','K', + 'w','t','x','J','2','y','7','B','x','X','X','p','G','b','T','g','3','k','U','6','E','Z','M','t','J','q','v','n','S','T','6','x', + '5','x','4','P','z','p','M','F','V','b','d','m','f','G','n','J','m','w','z','K','8','a','q','E','D','e','b','3','h','B','V','g', + 'y','3','P','L','5','8','r','z','X','b','Q','g','H','7','L','c','Z','B','3','C','4','y','t','u','k','z','h','v','C','Y','p','p', + '8','H','v','5','X','w','4','L','R','V','V','4','U','C','8','4','T','E','a','N','Z','S','7','U','u','z','f','H','p','P','J','u', + 'Y','Z','h','T','6','e','v','z','V','F','h','u','y','H','b','k','J','M','f','3','6','g','y','L','E','W','t','B','B','d','d','9', + 'u','M','Z','k','F','G','f','h','q','k','5','k','f','r','M','7','c','M','7','y','n','u','8','b','d','7','Q','f','E','m','F','K', + 'x','W','f','B','2','F','8','5','q','z','y','3','R','i','U','m','X','k','h','N','J','y','B','C','h','u','x','4','f','k','J','5', + '6','X','T','W','h','8','J','4','m','K','p','N','3','g','C','g','A','E','e','Z','x','A','P','2','E','4','t','Q','5','X','Y','j', + '6','m','b','h','G','a','v','6','t','v','6','C','M','G','P','u','B','C','A','V','b','2','9','d','2','c','5','a','b','X','w','V', + 'G','6','a','7','c','8','G','6','K','U','Q','m','w','P','V','5','N','x','b','v','x','E','N','C','A','N','t','v','N','B','z','X', + 'B','R','q','U','n','i','A','Q','d','m','a','D','7','Y','f','3','J','8','Y','m','w','Z','b','w','r','H','q','E','j','c','u','E', + 'i','i','S','b','n','G','P','a','F','j','c','R','D','D','G','F','v','i','a','i','M','7','B','e','w','m','L','E','F','2','Y','4', + '4','7','Y','C','t','y','q','7','2','V','G','m','m','E','e','V','u','m','L','p','R','X','W','z','V','K','E','k','p','V','r','J', + 'd','N','3','t','i','u','S','V','w','2','w','U','Q','3','F','q','4','h','q','k','B','7','R','X','B','F','Q','Z','b','b','4','E', + 'K','v','T','B','w','k','V','C','x','d','K','g','N','S','u','k','p','9','z','w','c','y','U','M','V','E','2','Y','P','F','h','9', + 'T','y','h','w','b','9','P','w','G','c','W','W','k','j','J','Q','N','B','U','G','6','9','U','b','v','a','N','9','N','C','G','n', + 'x','R','6','9','Q','C','h','e','j','P','U','h','U','R','i','4','T','B','W','5','w','m','J','p','e','7','r','9','t','c','9','Z', + 'j','p','r','F','C','e','U','P','x','T','A','N','7','6','a','i','y','e','w','F','C','X','H','Y','G','C','q','q','m','A','t','7', + 'z','u','D','S','L','U','C','f','7','e','t','G','V','F','u','c','x','5','M','7','N','i','M','6','h','2','n','H','S','h','K','M', + 'd','T','z','X','d','x','x','4','q','z','d','D','a','2','X','r','p','r','R','m','U','U','y','S','H','c','a','F','e','Z','a','U', + 'P','9','V','J','e','q','j','Y','M','x','e','v','K','7','M','P','N','2','b','6','f','P','h','H','4','U','X','k','n','f','Q','M', + '9','9','a','J','N','e','w','y','f','F','P','p','a','F','Y','a','M','L','W','i','T','M','B','3','U','v','X','v','G','p','7','a', + 'f','u','4','S','y','X','9','g','g','b','B','G','c','i','M','U','n','m','a','7','q','f','9','n','Q','2','V','L','6','e','T','R', + '2','4','9','d','6','Q','B','Y','q','2','4','9','G','Q','E','b','Y','5','u','2','T','Q','G','L','5','n','4','Y','2','y','G','F', + 'j','c','8','M','G','L','e','3','a','N','v','A','A','W','t','R','S','2','i','D','R','8','j','d','Q','3','6','C','V','M','e','w', + 'j','U','Z','w','M','4','b','m','8','J','P','Q','L','P','R','c','r','b','V','C','3','N','8','K','4','d','W','D','N','U','A','A', + '2','J','p','b','D','d','p','j','N','C','k','A','j','B','a','c','u','v','L','X','U','B','4','U','X','W','e','C','b','C','u','d', + 'A','v','U','z','P','t','D','e','5','y','Y','c','x','K','4','7','j','e','e','D','M','5','K','B','Q','6','d','p','T','T','R','j', + 'M','E','E','M','r','N','6','8','7','q','x','F','S','x','E','U','4','d','B','6','5','W','C','e','m','J','e','5','j','w','V','J', + 'w','v','d','7','v','f','K','u','m','8','h','W','T','e','Q','j','M','8','R','Y','d','B','R','2','r','F','j','7','d','E','q','V', + 'k','e','j','P','9','3','X','R','p','R','b','A','v','7','4','A','M','2','k','r','E','7','X','3','7','k','5','c','B','7','W','5', + 'u','J','B','Q','R','2','V','7','h','Q','h','9','g','G','y','c','c','x','M','z','7','G','2','J','w','v','j','5','9','E','b','k', + 'z','W','T','C','b','4','K','R','X','T','k','V','S','G','2','j','d','6','y','E','4','P','H','K','w','a','m','F','Z','x','9','j', + 'i','2','d','X','u','a','4','a','M','z','8','p','p','z','g','t','H','5','Y','L','Q','c','R','F','m','E','n','G','X','d','f','7', + 'x','8','j','g','J','z','D','S','a','S','h','y','5','h','Y','N','p','w','Y','W','h','E','N','v','8','Q','D','W','Z','k','f','e', + 'r','Z','D','7','R','D','T','2','H','X','z','G','X','f','v','E','z','P','v','U','H','e','4','R','W','U','x','t','t','4','w','p', + 'r','z','K','9','f','g','h','P','r','f','v','k','h','c','e','5','8','a','L','F','J','M','G','R','a','N','q','S','g','W','e','7', + 'R','K','R','A','B','z','6','v','S','p','w','n','e','x','k','E','r','j','f','Y','x','8','9','z','e','T','6','E','G','v','9','f', + 'D','A','N','v','y','U','7','D','M','2','E','5','W','G','6','b','9','q','g','Y','F','f','k','q','Q','E','x','Y','C','R','G','6', + 'R','h','4','J','d','U','D','b','9','b','8','r','f','V','d','g','b','2','z','Z','d','m','X','v','j','Y','d','w','K','8','G','r', + 'v','j','N','y','c','h','u','5','z','g','J','H','a','Z','b','z','G','C','r','P','f','y','P','6','F','P','h','7','9','w','7','y', + 'R','3','n','E','h','G','D','4','m','Y','E','q','k','a','f','a','R','B','q','t','W','E','T','p','H','7','k','X','2','d','X','6', + 'W','n','H','m','w','M','i','Y','M','E','F','5','R','p','p','y','c','b','q','R','9','Y','t','T','7','w','u','K','M','Q','z','n', + 'P','7','g','x','6','R','4','x','N','v','w','M','6','j','K','v','7','a','Y','4','a','M','6','n','z','3','E','2','V','N','4','i', + 'E','f','u','W','J','W','e','8','3','Q','e','a','F','P','c','3','P','k','i','z','d','q','m','q','M','a','d','8','D','3','F','M', + 'e','d','E','j','z','V','e','d','z','H','D','J','8','X','g','E','i','u','c','7','A','w','S','J','2','A','e','8','r','q','C','m', + '9','9','a','g','2','y','y','P','M','e','8','3','T','r','m','8','j','v','r','p','M','Z','Y','g','a','9','2','d','H','B','m','9', + '4','6','a','Z','V','u','S','H','g','3','X','h','i','N','3','B','S','E','k','9','k','2','9','R','A','i','3','L','X','M','B','S', + '4','S','F','F','F','w','u','d','M','T','9','K','B','7','R','U','R','8','D','8','T','5','U','t','E','R','x','n','x','h','v','k', + 'B','N','k','E','U','T','t','p','r','u','Z','h','t','E','4','i','P','z','f','z','q','M','p','f','A','K','2','D','t','j','f','c', + 'Y','E','N','M','x','k','g','7','T','U','2','c','d','V','g','2','z','L','i','j','Y','q','b','T','A','y','v','a','t','N','5','t', + 'Z','5','n','D','a','y','G','n','P','x','V','k','M','8','t','J','Z','G','g','5','9','R','h','P','P','J','N','X','p','G','J','p', + '2','y','A','v','d','G','U','z','3','V','M','y','q','U','N','M','Y','p','B','Z','U','h','j','q','z','q','x','w','7','d','J','Q', + 'u','F','q','3','m','9','c','Q','W','d','6','7','b','V','M','7','P','j','r','k','9','h','R','z','m','b','i','B','u','E','L','9', + 'k','v','h','h','W','2','K','e','M','U','Q','p','A','Q','Y','J','G','E','T','U','L','f','q','G','4','z','K','K','y','a','U','W', + 'K','D','P','c','N','D','V','S','Y','6','T','p','R','y','y','J','a','T','J','W','Q','9','p','F','P','X','y','k','9','z','z','4', + 'G','d','a','z','X','n','h','4','J','P','W','V','D','r','U','m','a','8','a','b','X','F','J','X','L','4','S','X','5','W','p','W', + 'h','y','x','B','f','d','C','X','w','7','r','g','V','T','H','a','i','4','N','v','c','w','n','2','3','A','i','A','J','9','N','c', + 'z','7','n','n','3','n','h','n','i','R','i','b','E','h','k','U','c','c','U','6','f','x','q','N','y','H','M','e','J','B','U','B', + 'r','g','a','8','V','a','G','V','y','u','c','c','v','C','H','W','y','g','z','Q','2','4','k','S','m','f','e','G','H','v','Q','3', + 'P','e','f','S','V','P','c','U','e','3','P','x','d','c','7','c','f','g','D','w','2','t','q','y','g','2','Q','V','4','K','a','Q', + 'g','B','b','L','x','9','m','a','K','4','i','x','g','Q','M','9','W','N','2','w','p','v','2','k','B','y','9','k','A','c','f','Z', + 'D','R','A','S','d','v','w','f','f','q','t','K','3','j','x','D','G','P','n','u','r','v','U','k','A','2','d','R','N','T','G','4', + 'B','g','k','t','h','7','J','k','F','A','C','g','W','g','J','F','z','S','Q','c','v','M','b','D','e','H','Q','S','j','v','G','E', + 'R','k','f','i','P','E','F','N','6','y','p','b','t','M','c','Q','B','7','g','w','J','7','3','d','V','E','m','z','6','6','P','P', + 'd','i','r','J','H','D','H','J','r','b','n','v','z','W','e','u','g','B','u','Z','2','m','D','5','h','F','X','B','2','r','6','w', + 'u','Y','4','N','X','K','a','v','V','3','j','B','r','r','C','c','w','R','g','S','8','V','b','F','2','N','M','c','K','8','Y','E', + 'E','N','K','X','K','V','B','x','n','Q','p','a','q','f','k','t','z','Y','E','P','Z','y','n','a','c','B','V','a','x','b','d','X', + 'r','d','8','P','H','F','v','r','V','5','g','J','w','6','i','h','d','d','p','J','c','c','Y','S','q','W','m','U','5','G','b','H', + 'N','z','E','Z','K','E','y','M','c','G','i','d','w','Z','D','N','N','w','S','t','g','y','a','Y','b','H','e','M','N','f','Y','Y', + '7','a','9','b','M','U','k','a','V','k','C','n','a','k','U','H','A','M','i','v','k','t','a','d','i','3','F','d','5','2','A','p', + 'U','c','J','U','R','h','G','d','A','Y','v','q','X','c','w','r','x','4','j','3','4','b','F','d','a','L','N','J','3','Z','g','6', + 'W','Q','R','u','P','t','M','A','3','F','6','y','K','Y','G','2','t','v','u','p','w','b','G','S','K','5','p','4','d','E','w','6', + 'g','t','V','4','b','2','n','b','Z','3','3','f','m','d','2','c','a','m','j','X','U','E','D','6','6','F','w','H','9','7','Z','Y', + 'd','X','C','K','i','g','p','F','Y','n','2','b','F','4','R','u','V','k','f','d','J','i','a','b','X','H','7','v','K','a','Q','i', + 'W','M','j','M','i','a','i','n','F','h','r','q','4','w','x','m','4','q','y','F','8','w','i','4','D','B','A','L','B','U','u','K', + 'v','K','n','a','Q','i','e','k','v','Q','U','5','w','Q','c','r','A','6','M','w','y','g','n','e','v','K','7','W','u','2','y','f', + 'Q','u','e','r','y','a','w','V','p','f','Q','z','C','u','i','i','9','S','P','q','L','r','C','H','S','3','E','p','8','S','m','Q', + 'S','K','r','V','b','J','R','m','w','c','n','Q','N','Q','4','M','u','f','X','S','f','U','Z','x','U','4','j','K','4','G','z','X', + '7','Q','j','R','h','i','G','m','q','c','V','T','x','U','a','E','b','Q','q','E','i','F','K','7','K','i','R','J','5','Y','F','V', + 'B','7','R','8','M','i','f','j','Z','w','j','b','B','u','p','N','Y','r','S','r','f','h','E','J','T','B','P','R','D','V','K','A', + 'Z','A','R','j','z','f','B','i','Y','L','F','G','V','Y','w','R','C','P','G','m','9','7','C','5','e','y','w','N','K','N','a','Q', + 'j','a','W','3','2','f','G','w','n','M','6','F','u','K','8','g','8','M','G','r','e','9','Z','z','y','2','G','U','k','G','6','m', + 'A','D','4','n','b','8','a','q','S','m','S','6','5','R','5','D','5','S','B','g','X','T','8','Q','V','d','A','n','g','y','8','a', + 'h','7','K','9','H','D','J','F','w','G','4','w','T','J','F','f','i','8','X','e','B','J','K','H','7','V','y','X','7','E','8','S', + 'A','d','b','w','S','8','Y','a','J','d','j','E','V','J','T','E','U','R','5','7','V','M','E','v','D','3','z','5','r','k','z','v', + 'e','m','A','7','P','8','j','X','E','f','Q','q','8','D','g','y','8','j','A','e','B','c','c','M','z','k','2','c','q','v','v','y', + 'Q','y','h','g','p','v','M','m','m','C','G','D','k','8','u','T','n','Q','H','G','H','f','b','J','j','5','X','c','i','7','7','q', + 'b','R','8','b','b','z','f','f','h','Y','Q','7','u','B','X','e','i','j','M','q','C','T','M','v','t','J','J','w','b','F','v','J', + 'm','e','2','u','e','8','L','V','G','q','A','j','m','7','m','g','m','5','i','r','p','p','U','y','F','6','f','b','u','6','q','L', + 'M','E','t','V','W','C','t','e','p','w','a','n','w','y','X','h','8','e','G','C','H','q','r','X','G','9','c','h','7','k','8','M', + 'G','b','a','m','Y','Q','w','8','J','z','a','F','r','4','W','M','j','P','q','a','z','U','y','u','3','b','Z','f','Y','5','7','g', + 'N','M','h','M','a','3','C','K','6','6','f','a','p','i','f','q','k','T','i','z','w','f','Z','c','H','L','X','g','6','m','g','r', + 'w','Y','u','K','8','L','p','8','P','R','A','R','A','b','Z','V','a','x','V','c','G','A','H','t','Y','6','P','T','L','W','N','z', + 'g','z','k','d','E','v','C','t','Z','M','Z','K','4','w','9','5','D','W','f','U','8','5','u','6','b','5','B','8','g','y','C','E', + 'Q','z','e','9','p','N','S','P','D','D','f','x','k','Z','4','R','v','X','V','k','p','b','n','t','c','F','R','e','x','9','C','D', + 'J','2','6','f','Z','D','w','J','R','j','j','9','b','w','N','N','p','R','f','Z','z','j','F','r','Q','e','F','x','f','t','V','V', + 'A','y','J','G','W','Z','H','r','D','5','M','u','H','V','L','N','U','V','X','z','j','9','r','v','e','d','R','c','u','V','x','r', + 'c','6','k','L','h','q','w','U','W','Q','g','G','F','C','t','E','a','D','h','x','9','5','P','R','Z','E','M','5','f','4','2','t', + 'A','6','f','r','X','G','X','Y','B','8','G','E','n','B','v','x','f','M','R','f','B','z','Y','3','2','q','z','G','t','P','C','6', + '6','r','z','J','r','c','n','d','6','h','e','w','D','D','h','V','L','u','i','b','5','K','d','S','y','9','N','p','E','r','D','k', + 'B','z','u','v','d','Q','p','K','5','m','J','r','b','Y','Z','7','p','M','J','F','E','q','x','f','E','K','U','U','4','f','a','6', + 'g','5','a','q','D','U','8','F','y','R','a','P','5','5','x','z','6','V','T','P','D','m','y','7','U','5','C','A','7','Q','h','w', + 'r','6','x','g','Q','i','b','K','F','p','B','X','Q','h','i','E','r','C','z','v','x','W','Q','6','p','6','b','M','K','V','x','u', + 'k','d','R','S','k','Q','p','n','h','d','Q','Y','x','n','x','5','K','t','5','w','A','5','p','k','F','z','W','p','j','U','y','V', + 'x','G','m','y','L','A','X','H','G','A','a','J','5','E','P','q','E','U','7','p','6','A','9','n','d','G','D','g','i','h','t','W', + 'b','c','E','2','P','d','y','J','M','u','4','g','P','S','X','J','v','w','3','v','D','q','U','i','U','T','q','E','Y','5','2','t', + 'b','j','P','2','j','D','9','y','i','B','5','Y','3','X','L','w','m','V','X','z','X','r','Z','d','H','L','A','H','k','R','X','5', + 'i','L','m','q','3','p','a','G','P','j','g','h','R','P','Y','U','z','M','5','R','M','A','E','Q','V','c','w','r','4','M','S','k', + 'N','D','i','R','R','x','t','q','T','i','u','N','K','R','x','Z','K','a','g','G','y','9','c','j','J','S','9','3','H','T','f','F', + 'q','6','D','W','F','K','h','e','p','p','b','q','N','k','A','C','m','y','u','B','J','v','q','D','e','j','e','b','2','w','R','t', + 'J','N','j','F','T','A','8','L','m','X','i','T','g','j','c','V','4','V','h','2','h','R','p','2','9','k','c','c','G','D','h','z', + 't','i','h','t','W','R','n','Y','i','8','u','6','G','9','T','P','9','9','J','P','Y','R','h','X','K','z','h','L','W','r','C','U', + '2','L','T','k','2','m','6','W','L','P','T','Z','z','t','i','H','5','G','w','t','E','v','z','k','b','H','b','b','W','W','u','b', + 'i','h','C','Q','n','H','N','u','5','u','K','X','r','M','W','U','3','Y','k','P','2','k','x','f','x','C','w','z','z','b','G','8', + 'y','W','e','j','v','2','v','r','t','q','z','p','Y','d','w','6','Z','D','J','L','9','F','z','G','U','4','a','8','H','6','U','a', + 'q','7','y','Q','J','v','m','D','P','S','j','q','v','t','n','t','g','j','3','t','8','f','K','K','7','b','W','d','F','i','N','K', + 'a','R','V','V','V','v','m','A','Q','2','y','j','c','t','f','k','j','7','X','y','j','b','U','F','w','W','3','9','6','A','S','J', + 'p','q','2','Z','7','L','p','b','7','b','5','i','p','r','r','h','P','M','h','j','c','y','e','u','h','B','d','9','9','u','f','d', + 'g','u','p','w','u','9','S','c','L','U','g','A','y','V','F','V','6','D','D','X','i','V','m','u','Y','P','J','v','L','T','A','F', + 'M','Q','H','Z','6','v','8','p','A','L','P','z','C','V','a','C','h','X','j','W','8','G','z','j','d','M','4','u','x','w','H','g', + 'V','q','K','z','b','g','2','3','D','N','y','G','X','F','T','v','T','L','y','v','L','9','g','c','C','R','8','L','A','7','Y','N', + 't','n','R','6','b','n','m','9','i','h','t','T','F','a','V','N','J','J','3','J','q','p','W','7','b','T','G','r','M','k','a','7', + 'D','H','v','y','T','A','C','U','P','u','q','L','R','Y','4','q','h','y','f','F','J','x','K','7','N','B','v','3','a','Z','M','t', + 'U','x','8','9','V','E','t','j','K','r','u','Y','Y','A','u','w','Y','2','y','Q','z','S','n','J','B','2','t','X','x','K','z','g', + '6','d','n','i','7','Z','N','F','Q','6','w','N','r','b','k','d','W','X','S','t','c','U','m','6','4','2','e','w','6','x','Z','a', + 'Q','A','7','4','h','H','z','r','e','J','q','j','w','4','q','c','i','R','4','x','n','r','j','r','P','g','E','7','t','k','b','Z', + 'r','A','b','d','g','i','G','V','D','E','U','L','b','J','U','q','2','S','K','m','A','U','L','k','Q','4','N','p','k','G','C','6', + 'R','Z','B','y','B','B','j','y','x','L','d','h','L','G','6','x','H','z','T','5','d','Y','4','2','m','q','Q','y','H','6','c','N', + 'u','m','U','v','i','Y','Z','7','4','L','K','F','b','v','2','Y','h','x','8','a','R','w','q','x','E','a','T','y','m','C','2','Q', + 'U','T','D','Q','v','u','M','9','D','8','r','8','b','m','p','E','7','C','T','9','B','A','G','k','b','G','z','Z','G','L','N','k', + 'h','3','k','J','e','f','d','x','F','8','W','K','7','T','6','h','H','V','C','h','P','u','H','e','v','w','z','P','K','r','D','G', + 'X','Z','B','X','f','H','Q','4','e','D','y','W','Z','6','4','K','A','e','a','F','S','N','h','x','S','W','J','c','E','P','g','j', + 'a','w','T','m','Z','X','E','P','Y','R','M','2','R','2','X','N','F','X','Y','W','x','z','p','J','g','n','D','4','i','p','6','N', + 'r','9','G','k','E','h','T','h','U','h','x','B','Q','9','H','7','w','U','P','Q','d','G','6','q','p','j','j','v','C','a','X','J', + 'N','G','Y','w','f','H','C','x','F','k','z','3','9','r','h','8','7','5','V','i','V','C','R','q','x','N','2','2','i','W','F','U', + '7','T','H','f','z','E','a','n','u','Q','t','U','Y','G','t','3','A','m','r','6','d','f','e','n','e','z','F','u','U','N','8','m', + 'h','p','R','N','S','H','6','6','V','M','S','t','q','P','E','i','u','y','g','8','L','Q','Y','Y','G','e','W','W','C','G','y','b', + 'y','t','u','P','R','P','5','m','N','K','B','Z','w','f','t','k','x','3','L','b','q','d','w','S','G','E','h','R','F','4','q','e', + '5','6','F','2','n','q','T','R','y','f','n','Y','h','2','F','u','x','M','i','i','h','w','G','C','Z','v','i','C','a','X','U','C', + 'Y','8','d','h','R','x','V','n','v','G','i','D','a','U','p','U','a','e','b','F','w','P','d','X','n','K','h','9','H','r','b','g', + '2','f','m','X','k','m','q','6','n','5','b','G','H','d','R','9','D','U','c','r','Z','Y','W','S','Z','x','p','t','x','y','4','k', + 'j','F','U','t','C','i','e','i','b','p','e','4','C','z','h','3','3','5','Q','P','n','G','i','A','8','c','Q','z','B','a','V','4', + '2','B','2','z','u','u','3','i','L','w','y','g','K','H','k','y','2','B','b','e','5','e','4','e','U','4','z','n','P','z','a','c', + 'E','f','u','M','G','C','g','z','j','4','E','7','R','t','D','K','c','t','p','g','W','H','C','H','J','Q','J','c','F','5','4','W', + 'K','7','j','h','A','T','K','z','t','S','f','f','j','C','c','8','n','7','c','T','U','R','Q','E','7','A','W','Z','z','K','5','j', + '2','H','k','a','j','g','g','W','w','4','T','A','9','J','U','e','S','N','P','K','d','k','L','Q','G','Z','e','W','i','H','u','j', + 'C','z','4','E','2','v','5','L','u','9','Z','a','9','A','b','C','M','G','X','B','C','2','Y','Z','e','U','n','E','5','Y','n','y', + 'F','h','H','p','9','j','Y','F','V','w','Y','r','8','Q','f','C','J','4','T','t','z','Q','N','M','e','7','4','3','y','E','M','m', + 'b','S','c','h','w','a','X','E','d','E','z','t','h','9','k','p','A','k','K','H','x','q','K','Z','B','u','a','9','3','U','U','u', + '8','E','D','v','y','k','W','Y','X','k','r','R','D','X','n','Q','V','d','e','D','g','x','E','V','Y','w','k','m','K','r','H','D', + 't','2','6','N','U','g','3','t','B','9','t','u','M','D','z','Y','K','z','K','r','V','5','i','e','p','M','d','t','w','6','a','f', + 'f','W','k','L','i','g','M','V','M','Y','b','x','e','4','h','h','Y','g','w','Z','m','e','e','6','R','W','M','x','G','y','V','n', + '6','e','g','A','g','K','a','N','7','p','a','u','E','4','6','M','t','X','h','g','b','j','p','5','x','x','B','P','3','J','M','7', + 'j','Z','P','y','e','Q','Z','e','t','j','3','t','F','V','x','m','b','b','B','y','J','L','L','9','3','R','a','5','j','S','V','t', + 'e','2','6','m','H','w','r','w','r','6','Q','3','x','z','m','A','d','x','t','E','H','c','Z','x','c','P','j','r','u','U','W','k', + '6','g','X','g','n','f','n','7','H','M','B','t','v','6','v','x','g','M','f','e','2','w','m','y','d','H','S','q','c','K','U','H', + '2','X','h','d','p','Q','7','J','X','i','X','f','a','z','V','A','F','2','8','z','v','h','C','h','e','4','g','z','w','z','h','q', + 'p','6','B','n','m','8','h','W','U','7','z','h','T','6','J','f','4','Z','n','Q','W','z','2','N','4','t','g','7','u','4','X','2', + 'C','F','L','n','J','n','m','j','3','P','3','Y','e','J','R','A','H','e','R','D','z','7','u','X','Y','y','D','w','J','m','G','U', + 'P','H','5','S','d','a','F','F','Y','c','M','f','3','3','L','v','V','B','U','C','A','d','N','H','Q','h','7','8','4','r','p','G', + 'v','M','D','H','7','e','E','r','i','K','Q','i','B','D','M','Z','p','c','R','G','u','c','H','a','N','k','E','f','9','R','7','x', + '6','3','5','u','x','3','h','v','p','6','q','r','j','u','f','W','T','q','P','n','Y','L','B','6','U','w','P','2','T','W','R','g', + '2','3','3','e','N','V','a','j','b','e','4','T','u','J','u','u','F','B','D','G','H','x','x','k','5','G','e','3','4','B','m','L', + 'S','b','i','t','T','p','M','D','Z','A','A','i','r','J','p','4','H','U','A','G','y','d','Q','5','U','R','F','8','q','a','S','H', + 'n','5','z','9','g','3','u','R','H','m','G','m','b','p','c','L','Z','Y','u','m','i','K','A','Q','R','T','X','G','t','b','8','7', + '7','6','w','M','N','f','R','G','r','L','m','q','n','7','5','k','X','8','g','u','K','7','Y','w','K','q','U','e','W','A','r','i', + 'Z','a','p','q','L','5','P','u','n','t','y','G','x','C','N','X','q','P','r','U','v','A','r','r','q','e','f','c','z','M','7','N', + '6','a','z','Z','a','t','f','p','4','v','J','Y','j','h','M','D','t','k','A','B','p','Q','A','y','x','X','7','p','S','8','m','M', + 'y','K','B','A','5','2','7','b','y','R','K','q','A','u','3','J'}; + +static const adler32_test tests[] = { + {0x1, (const uint8_t *)0x0, 0, 0x1}, + {0x1, (const uint8_t *)"", 1, 0x10001}, + {0x1, (const uint8_t *)"a", 1, 0x620062}, + {0x1, (const uint8_t *)"abacus", 6, 0x8400270}, + {0x1, (const uint8_t *)"backlog", 7, 0xb1f02d4}, + {0x1, (const uint8_t *)"campfire", 8, 0xea10348}, + {0x1, (const uint8_t *)"delta", 5, 0x61a020b}, + {0x1, (const uint8_t *)"executable", 10, 0x16fa0423}, + {0x1, (const uint8_t *)"file", 4, 0x41401a1}, + {0x1, (const uint8_t *)"greatest", 8, 0xefa0360}, + {0x1, (const uint8_t *)"inverter", 8, 0xf6f0370}, + {0x1, (const uint8_t *)"jigsaw", 6, 0x8bd0286}, + {0x1, (const uint8_t *)"karate", 6, 0x8a50279}, + {0x1, (const uint8_t *)"landscape", 9, 0x126a03ac}, + {0x1, (const uint8_t *)"machine", 7, 0xb5302d6}, + {0x1, (const uint8_t *)"nanometer", 9, 0x12d803ca}, + {0x1, (const uint8_t *)"oblivion", 8, 0xf220363}, + {0x1, (const uint8_t *)"panama", 6, 0x8a1026f}, + {0x1, (const uint8_t *)"quest", 5, 0x6970233}, + {0x1, (const uint8_t *)"resource", 8, 0xf8d0369}, + {0x1, (const uint8_t *)"secret", 6, 0x8d10287}, + {0x1, (const uint8_t *)"ultimate", 8, 0xf8d0366}, + {0x1, (const uint8_t *)"vector", 6, 0x8fb0294}, + {0x1, (const uint8_t *)"walrus", 6, 0x918029f}, + {0x1, (const uint8_t *)"xeno", 4, 0x45e01bb}, + {0x1, (const uint8_t *)"yelling", 7, 0xbfe02f5}, + {0x1, (const uint8_t *)"zero", 4, 0x46e01c1}, + {0x1, (const uint8_t *)"4BJD7PocN1VqX0jXVpWB", 20, 0x3eef064d}, + {0x1, (const uint8_t *)"F1rPWI7XvDs6nAIRx41l", 20, 0x425d065f}, + {0x1, (const uint8_t *)"ldhKlsVkPFOveXgkGtC2", 20, 0x4f1a073e}, + {0x1, (const uint8_t *)"5KKnGOOrs8BvJ35iKTOS", 20, 0x42290650}, + {0x1, (const uint8_t *)"0l1tw7GOcem06Ddu7yn4", 20, 0x43fd0690}, + {0x1, (const uint8_t *)"MCr47CjPIn9R1IvE1Tm5", 20, 0x3f770609}, + {0x1, (const uint8_t *)"UcixbzPKTIv0SvILHVdO", 20, 0x4c7c0703}, + {0x1, (const uint8_t *)"dGnAyAhRQDsWw0ESou24", 20, 0x48ac06b7}, + {0x1, (const uint8_t *)"di0nvmY9UYMYDh0r45XT", 20, 0x489a0698}, + {0x1, (const uint8_t *)"2XKDwHfAhFsV0RhbqtvH", 20, 0x44a906e6}, + {0x1, (const uint8_t *)"ZhrANFIiIvRnqClIVyeD", 20, 0x4a29071c}, + {0x1, (const uint8_t *)"v7Q9ehzioTOVeDIZioT1", 20, 0x4a7706f9}, + {0x1, (const uint8_t *)"Yod5hEeKcYqyhfXbhxj2", 20, 0x4ce60769}, + {0x1, (const uint8_t *)"GehSWY2ay4uUKhehXYb0", 20, 0x48ae06e5}, + {0x1, (const uint8_t *)"kwytJmq6UqpflV8Y8GoE", 20, 0x51d60750}, + {0x1, (const uint8_t *)"70684206568419061514", 20, 0x2b100414}, + {0x1, (const uint8_t *)"42015093765128581010", 20, 0x2a550405}, + {0x1, (const uint8_t *)"88214814356148806939", 20, 0x2b450423}, + {0x1, (const uint8_t *)"43472694284527343838", 20, 0x2b460421}, + {0x1, (const uint8_t *)"49769333513942933689", 20, 0x2bc1042b}, + {0x1, (const uint8_t *)"54979784887993251199", 20, 0x2ccd043d}, + {0x1, (const uint8_t *)"58360544869206793220", 20, 0x2b68041a}, + {0x1, (const uint8_t *)"27347953487840714234", 20, 0x2b84041d}, + {0x1, (const uint8_t *)"07650690295365319082", 20, 0x2afa0417}, + {0x1, (const uint8_t *)"42655507906821911703", 20, 0x2aff0412}, + {0x1, (const uint8_t *)"29977409200786225655", 20, 0x2b8d0420}, + {0x1, (const uint8_t *)"85181542907229116674", 20, 0x2b140419}, + {0x1, (const uint8_t *)"87963594337989416799", 20, 0x2c8e043f}, + {0x1, (const uint8_t *)"21395988329504168551", 20, 0x2b68041f}, + {0x1, (const uint8_t *)"51991013580943379423", 20, 0x2af10417}, + {0x1, (const uint8_t *)"*]+@!);({_$;}[_},?{?;(_?,=-][@", 30, 0x7c9d0841}, + {0x1, (const uint8_t *)"_@:_).&(#.[:[{[:)$++-($_;@[)}+", 30, 0x71060751}, + {0x1, (const uint8_t *)"&[!,[$_==}+.]@!;*(+},[;:)$;)-@", 30, 0x7095070a}, + {0x1, (const uint8_t *)"]{.[.+?+[[=;[?}_#&;[=)__$$:+=_", 30, 0x82530815}, + {0x1, (const uint8_t *)"-%.)=/[@].:.(:,()$;=%@-$?]{%+%", 30, 0x61250661}, + {0x1, (const uint8_t *)"+]#$(@&.=:,*];/.!]%/{:){:@(;)$", 30, 0x642006a3}, + {0x1, (const uint8_t *)")-._.:?[&:.=+}(*$/=!.${;(=$@!}", 30, 0x674206cb}, + {0x1, (const uint8_t *)":(_*&%/[[}+,?#$&*+#[([*-/#;%(]", 30, 0x67670680}, + {0x1, (const uint8_t *)"{[#-;:$/{)(+[}#]/{&!%(@)%:@-$:", 30, 0x7547070f}, + {0x1, (const uint8_t *)"_{$*,}(&,@.)):=!/%(&(,,-?$}}}!", 30, 0x69ea06ee}, + {0x1, (const uint8_t *)"e$98KNzqaV)Y:2X?]77].{gKRD4G5{mHZk,Z)SpU%L3FSgv!Wb8MLAFdi{+fp)c,@8m6v)yXg@]HBDFk?.4&}g5_udE*JHCiH=aL", 100, 0x1b01e92}, + {0x1, (const uint8_t *)"r*Fd}ef+5RJQ;+W=4jTR9)R*p!B;]Ed7tkrLi;88U7g@3v!5pk2X6D)vt,.@N8c]@yyEcKi[vwUu@.Ppm@C6%Mv*3Nw}Y,58_aH)", 100, 0xfbdb1e96}, + {0x1, (const uint8_t *)"h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&", 100, 0x47a61ec8}, + {0x1, (const uint8_t *)long_string, 5552, 0x8b81718f}, + {0x7a30360d, (const uint8_t *)0x0, 0, 0x1}, + {0x6fd767ee, (const uint8_t *)"", 1, 0xd7c567ee}, + {0xefeb7589, (const uint8_t *)"a", 1, 0x65e475ea}, + {0x61cf7e6b, (const uint8_t *)"abacus", 6, 0x60b880da}, + {0xdc712e2, (const uint8_t *)"backlog", 7, 0x9d0d15b5}, + {0xad23c7fd, (const uint8_t *)"campfire", 8, 0xfbfecb44}, + {0x85cb2317, (const uint8_t *)"delta", 5, 0x3b622521}, + {0x9eed31b0, (const uint8_t *)"executable", 10, 0xa6db35d2}, + {0xb94f34ca, (const uint8_t *)"file", 4, 0x9096366a}, + {0xab058a2, (const uint8_t *)"greatest", 8, 0xded05c01}, + {0x5bff2b7a, (const uint8_t *)"inverter", 8, 0xc7452ee9}, + {0x605c9a5f, (const uint8_t *)"jigsaw", 6, 0x7899ce4}, + {0x51bdeea5, (const uint8_t *)"karate", 6, 0xf285f11d}, + {0x85c21c79, (const uint8_t *)"landscape", 9, 0x98732024}, + {0x97216f56, (const uint8_t *)"machine", 7, 0xadf4722b}, + {0x18444af2, (const uint8_t *)"nanometer", 9, 0xcdb34ebb}, + {0xbe6ce359, (const uint8_t *)"oblivion", 8, 0xe8b7e6bb}, + {0x843071f1, (const uint8_t *)"panama", 6, 0x389e745f}, + {0xf2480c60, (const uint8_t *)"quest", 5, 0x36c90e92}, + {0x2d2feb3d, (const uint8_t *)"resource", 8, 0x9705eea5}, + {0x7490310a, (const uint8_t *)"secret", 6, 0xa3a63390}, + {0x97d247d4, (const uint8_t *)"ultimate", 8, 0xe6154b39}, + {0x93cf7599, (const uint8_t *)"vector", 6, 0x5e87782c}, + {0x73c84278, (const uint8_t *)"walrus", 6, 0xbc84516}, + {0x228a87d1, (const uint8_t *)"xeno", 4, 0x4646898b}, + {0xa7a048d0, (const uint8_t *)"yelling", 7, 0xb1654bc4}, + {0x1f0ded40, (const uint8_t *)"zero", 4, 0xd8a4ef00}, + {0xa804a62f, (const uint8_t *)"4BJD7PocN1VqX0jXVpWB", 20, 0xe34eac7b}, + {0x508fae6a, (const uint8_t *)"F1rPWI7XvDs6nAIRx41l", 20, 0x33f2b4c8}, + {0xe5adaf4f, (const uint8_t *)"ldhKlsVkPFOveXgkGtC2", 20, 0xe7b1b68c}, + {0x67136a40, (const uint8_t *)"5KKnGOOrs8BvJ35iKTOS", 20, 0xf6a0708f}, + {0xb00c4a10, (const uint8_t *)"0l1tw7GOcem06Ddu7yn4", 20, 0xbd8f509f}, + {0x2e0c84b5, (const uint8_t *)"MCr47CjPIn9R1IvE1Tm5", 20, 0xcc298abd}, + {0x81238d44, (const uint8_t *)"UcixbzPKTIv0SvILHVdO", 20, 0xd7809446}, + {0xf853aa92, (const uint8_t *)"dGnAyAhRQDsWw0ESou24", 20, 0x9525b148}, + {0x5a692325, (const uint8_t *)"di0nvmY9UYMYDh0r45XT", 20, 0x620029bc}, + {0x3275b9f, (const uint8_t *)"2XKDwHfAhFsV0RhbqtvH", 20, 0x70916284}, + {0x38371feb, (const uint8_t *)"ZhrANFIiIvRnqClIVyeD", 20, 0xd52706}, + {0xafc8bf62, (const uint8_t *)"v7Q9ehzioTOVeDIZioT1", 20, 0xeeb4c65a}, + {0x9b07db73, (const uint8_t *)"Yod5hEeKcYqyhfXbhxj2", 20, 0xde3e2db}, + {0xe75b214, (const uint8_t *)"GehSWY2ay4uUKhehXYb0", 20, 0x4171b8f8}, + {0x72d0fe6f, (const uint8_t *)"kwytJmq6UqpflV8Y8GoE", 20, 0xa66a05cd}, + {0xf857a4b1, (const uint8_t *)"70684206568419061514", 20, 0x1f9a8c4}, + {0x54b8e14, (const uint8_t *)"42015093765128581010", 20, 0x49c19218}, + {0xd6aa5616, (const uint8_t *)"88214814356148806939", 20, 0xbbfc5a38}, + {0x11e63098, (const uint8_t *)"43472694284527343838", 20, 0x93434b8}, + {0xbe92385, (const uint8_t *)"49769333513942933689", 20, 0xfe1827af}, + {0x49511de0, (const uint8_t *)"54979784887993251199", 20, 0xcba8221c}, + {0x3db13bc1, (const uint8_t *)"58360544869206793220", 20, 0x14643fda}, + {0xbb899bea, (const uint8_t *)"27347953487840714234", 20, 0x1604a006}, + {0xf6cd9436, (const uint8_t *)"07650690295365319082", 20, 0xb69f984c}, + {0x9109e6c3, (const uint8_t *)"42655507906821911703", 20, 0xc43eead4}, + {0x75770fc, (const uint8_t *)"29977409200786225655", 20, 0x707751b}, + {0x69b1d19b, (const uint8_t *)"85181542907229116674", 20, 0xf5bdd5b3}, + {0xc6132975, (const uint8_t *)"87963594337989416799", 20, 0x2fed2db3}, + {0xd58cb00c, (const uint8_t *)"21395988329504168551", 20, 0xc2a2b42a}, + {0xb63b8caa, (const uint8_t *)"51991013580943379423", 20, 0xdf0590c0}, + {0x8a45a2b8, (const uint8_t *)"*]+@!);({_$;}[_},?{?;(_?,=-][@", 30, 0x1980aaf8}, + {0xcbe95b78, (const uint8_t *)"_@:_).&(#.[:[{[:)$++-($_;@[)}+", 30, 0xf58662c8}, + {0x4ef8a54b, (const uint8_t *)"&[!,[$_==}+.]@!;*(+},[;:)$;)-@", 30, 0x1f65ac54}, + {0x76ad267a, (const uint8_t *)"]{.[.+?+[[=;[?}_#&;[=)__$$:+=_", 30, 0x7b792e8e}, + {0x569e613c, (const uint8_t *)"-%.)=/[@].:.(:,()$;=%@-$?]{%+%", 30, 0x1d61679c}, + {0x36aa61da, (const uint8_t *)"+]#$(@&.=:,*];/.!]%/{:){:@(;)$", 30, 0x12ec687c}, + {0xf67222df, (const uint8_t *)")-._.:?[&:.=+}(*$/=!.${;(=$@!}", 30, 0x740329a9}, + {0x74b34fd3, (const uint8_t *)":(_*&%/[[}+,?#$&*+#[([*-/#;%(]", 30, 0x374c5652}, + {0x351fd770, (const uint8_t *)"{[#-;:$/{)(+[}#]/{&!%(@)%:@-$:", 30, 0xeadfde7e}, + {0xc45aef77, (const uint8_t *)"_{$*,}(&,@.)):=!/%(&(,,-?$}}}!", 30, 0x3fcbf664}, + {0xd034ea71, (const uint8_t *)"e$98KNzqaV)Y:2X?]77].{gKRD4G5{mHZk,Z)SpU%L3FSgv!Wb8MLAFdi{+fp)c,@8m6v)yXg@]HBDFk?.4&}g5_udE*JHCiH=aL", 100, 0x6b080911}, + {0xdeadc0de, (const uint8_t *)"r*Fd}ef+5RJQ;+W=4jTR9)R*p!B;]Ed7tkrLi;88U7g@3v!5pk2X6D)vt,.@N8c]@yyEcKi[vwUu@.Ppm@C6%Mv*3Nw}Y,58_aH)", 100, 0x355fdf73}, + {0xba5eba11, (const uint8_t *)"h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&", 100, 0xb48bd8d8}, + {0x7712aa45, (const uint8_t *)long_string, 5552, 0x7dc51be2}, +}; + +class adler32_variant : public ::testing::TestWithParam { +public: + void hash(adler32_test param, adler32_func adler32) { + uint32_t adler = adler32((uint32_t)param.adler, param.buf, param.len); + EXPECT_EQ(adler, param.expect); + } +}; + +INSTANTIATE_TEST_SUITE_P(adler32, adler32_variant, testing::ValuesIn(tests)); + +#define TEST_ADLER32(name, func, support_flag) \ + TEST_P(adler32_variant, name) { \ + if (!support_flag) { \ + GTEST_SKIP(); \ + return; \ + } \ + hash(GetParam(), func); \ + } + +TEST_ADLER32(c, adler32_c, 1) + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +TEST_ADLER32(native, native_adler32, 1) +#else + +#ifdef ARM_NEON +TEST_ADLER32(neon, adler32_neon, test_cpu_features.arm.has_neon) +#elif defined(POWER8_VSX) +TEST_ADLER32(power8, adler32_power8, test_cpu_features.power.has_arch_2_07) +#elif defined(PPC_VMX) +TEST_ADLER32(vmx, adler32_vmx, test_cpu_features.power.has_altivec) +#elif defined(RISCV_RVV) +TEST_ADLER32(rvv, adler32_rvv, test_cpu_features.riscv.has_rvv) +#endif + +#ifdef X86_SSSE3 +TEST_ADLER32(ssse3, adler32_ssse3, test_cpu_features.x86.has_ssse3) +#endif +#ifdef X86_AVX2 +TEST_ADLER32(avx2, adler32_avx2, test_cpu_features.x86.has_avx2) +#endif +#ifdef X86_AVX512 +TEST_ADLER32(avx512, adler32_avx512, test_cpu_features.x86.has_avx512_common) +#endif +#ifdef X86_AVX512VNNI +TEST_ADLER32(avx512_vnni, adler32_avx512_vnni, test_cpu_features.x86.has_avx512vnni) +#endif + +#endif diff --git a/test/test_compare256.cc b/test/test_compare256.cc new file mode 100644 index 0000000000..035e63c966 --- /dev/null +++ b/test/test_compare256.cc @@ -0,0 +1,92 @@ +/* test_compare256.cc -- compare256 unit tests + * Copyright (C) 2022 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include +#include + +extern "C" { +# include "zbuild.h" +# include "zutil.h" +# include "arch_functions.h" +# include "test_cpu_features.h" +# include "arch/generic/compare256_p.h" +} + +#include + +#include "test_shared.h" + +#define MAX_COMPARE_SIZE (256) + + +/* Ensure that compare256 returns the correct match length */ +static inline void compare256_match_check(compare256_func compare256) { + int32_t match_len, i; + uint8_t *str1; + uint8_t *str2; + + str1 = (uint8_t *)PREFIX(zcalloc)(NULL, 1, MAX_COMPARE_SIZE); + ASSERT_TRUE(str1 != NULL); + memset(str1, 'a', MAX_COMPARE_SIZE); + + str2 = (uint8_t *)PREFIX(zcalloc)(NULL, 1, MAX_COMPARE_SIZE); + ASSERT_TRUE(str2 != NULL); + memset(str2, 'a', MAX_COMPARE_SIZE); + + for (i = 0; i <= MAX_COMPARE_SIZE; i++) { + if (i < MAX_COMPARE_SIZE) + str2[i] = 0; + + match_len = compare256(str1, str2); + EXPECT_EQ(match_len, i); + + if (i < MAX_COMPARE_SIZE) + str2[i] = 'a'; + } + + PREFIX(zcfree)(NULL, str1); + PREFIX(zcfree)(NULL, str2); +} + +#define TEST_COMPARE256(name, func, support_flag) \ + TEST(compare256, name) { \ + if (!support_flag) { \ + GTEST_SKIP(); \ + return; \ + } \ + compare256_match_check(func); \ + } + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +TEST_COMPARE256(native, native_compare256, 1) +#else + +TEST_COMPARE256(8, compare256_8, 1) +TEST_COMPARE256(16, compare256_16, 1) +#if defined(HAVE_BUILTIN_CTZ) +TEST_COMPARE256(32, compare256_32, 1) +#endif +#if defined(HAVE_BUILTIN_CTZLL) +TEST_COMPARE256(64, compare256_64, 1) +#endif + +#if defined(X86_SSE2) && defined(HAVE_BUILTIN_CTZ) +TEST_COMPARE256(sse2, compare256_sse2, test_cpu_features.x86.has_sse2) +#endif +#if defined(X86_AVX2) && defined(HAVE_BUILTIN_CTZ) +TEST_COMPARE256(avx2, compare256_avx2, test_cpu_features.x86.has_avx2) +#endif +#if defined(ARM_NEON) && defined(HAVE_BUILTIN_CTZLL) +TEST_COMPARE256(neon, compare256_neon, test_cpu_features.arm.has_neon) +#endif +#ifdef POWER9 +TEST_COMPARE256(power9, compare256_power9, test_cpu_features.power.has_arch_3_00) +#endif +#ifdef RISCV_RVV +TEST_COMPARE256(rvv, compare256_rvv, test_cpu_features.riscv.has_rvv) +#endif + +#endif diff --git a/test/test_compare256_rle.cc b/test/test_compare256_rle.cc new file mode 100644 index 0000000000..dc531195d9 --- /dev/null +++ b/test/test_compare256_rle.cc @@ -0,0 +1,60 @@ +/* test_compare256_rle.cc -- compare256_rle unit tests + * Copyright (C) 2022 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include +#include + +extern "C" { +# include "zbuild.h" +# include "zutil.h" +# include "compare256_rle.h" +} + +#include + +#define MAX_COMPARE_SIZE (256) + +/* Ensure that compare256_rle returns the correct match length */ +static inline void compare256_rle_match_check(compare256_rle_func compare256_rle) { + int32_t match_len, i; + uint8_t str1[] = {'a', 'a', 0}; + uint8_t *str2; + + str2 = (uint8_t *)PREFIX(zcalloc)(NULL, 1, MAX_COMPARE_SIZE); + ASSERT_TRUE(str2 != NULL); + memset(str2, 'a', MAX_COMPARE_SIZE); + + for (i = 0; i <= MAX_COMPARE_SIZE; i++) { + if (i < MAX_COMPARE_SIZE) + str2[i] = 0; + + match_len = compare256_rle(str1, str2); + EXPECT_EQ(match_len, i); + + if (i < MAX_COMPARE_SIZE) + str2[i] = 'a'; + } + + PREFIX(zcfree)(NULL, str2); +} + +#define TEST_COMPARE256_RLE(name, func, support_flag) \ + TEST(compare256_rle, name) { \ + if (!support_flag) { \ + GTEST_SKIP(); \ + return; \ + } \ + compare256_rle_match_check(func); \ + } + +TEST_COMPARE256_RLE(8, compare256_rle_8, 1) +TEST_COMPARE256_RLE(16, compare256_rle_16, 1) +#if defined(HAVE_BUILTIN_CTZ) +TEST_COMPARE256_RLE(32, compare256_rle_32, 1) +#endif +#if defined(HAVE_BUILTIN_CTZLL) +TEST_COMPARE256_RLE(64, compare256_rle_64, 1) +#endif diff --git a/test/test_compress.cc b/test/test_compress.cc new file mode 100644 index 0000000000..e069b69d31 --- /dev/null +++ b/test/test_compress.cc @@ -0,0 +1,33 @@ +/* test_compress.cc - Test compress() and uncompress() using hello world string */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include "test_shared.h" + +#include + +TEST(compress, basic) { + uint8_t compr[128], uncompr[128]; + z_uintmax_t compr_len = sizeof(compr), uncompr_len = sizeof(uncompr); + int err; + + err = PREFIX(compress)(compr, &compr_len, (const unsigned char *)hello, hello_len); + EXPECT_EQ(err, Z_OK); + + strcpy((char*)uncompr, "garbage"); + + err = PREFIX(uncompress)(uncompr, &uncompr_len, compr, compr_len); + EXPECT_EQ(err, Z_OK); + + EXPECT_STREQ((char *)uncompr, (char *)hello); +} diff --git a/test/test_compress_bound.cc b/test/test_compress_bound.cc new file mode 100644 index 0000000000..1acda02fc5 --- /dev/null +++ b/test/test_compress_bound.cc @@ -0,0 +1,59 @@ +/* test_compress_bound.cc - Test compressBound() with small buffers */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include + +#include "test_shared.h" + +#define MAX_LENGTH (32) + +class compress_bound_variant : public testing::TestWithParam { +public: + void estimate(int32_t level) { + z_size_t estimate_len = 0; + uint8_t *uncompressed = NULL; + uint8_t dest[128]; + int err; + + uncompressed = (uint8_t *)malloc(MAX_LENGTH); + ASSERT_TRUE(uncompressed != NULL); + + /* buffer with values for worst case compression */ + for (int32_t j = 0; j < MAX_LENGTH; j++) { + uncompressed[j] = (uint8_t)j; + } + + for (z_uintmax_t i = 0; i < MAX_LENGTH; i++) { + z_uintmax_t dest_len = sizeof(dest); + + /* calculate actual output length */ + estimate_len = PREFIX(compressBound)(i); + + err = PREFIX(compress2)(dest, &dest_len, uncompressed, i, level); + EXPECT_EQ(err, Z_OK); + EXPECT_GE(estimate_len, dest_len) << + "level: " << level << "\n" << + "length: " << i; + } + + free(uncompressed); + } +}; + +TEST_P(compress_bound_variant, estimate) { + estimate(GetParam()); +} + +INSTANTIATE_TEST_SUITE_P(compress_bound, compress_bound_variant, + testing::Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)); diff --git a/test/test_compress_dual.cc b/test/test_compress_dual.cc new file mode 100644 index 0000000000..a92ab4be39 --- /dev/null +++ b/test/test_compress_dual.cc @@ -0,0 +1,28 @@ +/* test_compress_dual.cc - Test linking against both zlib and zlib-ng */ + +#include "zlib.h" + +#include +#include +#include +#include + +#include "test_shared.h" + +#include + +TEST(compress, basic_zlib) { + Byte compr[128], uncompr[128]; + uLong compr_len = sizeof(compr), uncompr_len = sizeof(uncompr); + int err; + + err = compress(compr, &compr_len, (const unsigned char *)hello, hello_len); + EXPECT_EQ(err, Z_OK); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncompr_len, compr, compr_len); + EXPECT_EQ(err, Z_OK); + + EXPECT_STREQ((char *)uncompr, (char *)hello); +} diff --git a/test/test_cpu_features.h b/test/test_cpu_features.h new file mode 100644 index 0000000000..70b74283d2 --- /dev/null +++ b/test/test_cpu_features.h @@ -0,0 +1,12 @@ +#ifndef TEST_CPU_FEATURES_H +#define TEST_CPU_FEATURES_H + +#ifndef DISABLE_RUNTIME_CPU_DETECTION + +# include "cpu_features.h" + +extern struct cpu_features test_cpu_features; + +#endif + +#endif diff --git a/test/test_crc32.cc b/test/test_crc32.cc new file mode 100644 index 0000000000..ea839383df --- /dev/null +++ b/test/test_crc32.cc @@ -0,0 +1,265 @@ +/* test_crc32.cc -- crc32 unit test + * Copyright (C) 2019-2021 IBM Corporation + * Authors: Rogerio Alves + * Matheus Castanho + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include +#include +#include "zutil.h" +#include "zutil_p.h" + +extern "C" { +# include "zbuild.h" +# include "arch_functions.h" +# include "test_cpu_features.h" +} + +#include + +typedef struct { + unsigned long crc; + const uint8_t *buf; + size_t len; + unsigned long expect; +} crc32_test; + +static const crc32_test tests[] = { + {0x0, (const uint8_t *)0x0, 0, 0x0}, + {0xffffffff, (const uint8_t *)0x0, 0, 0x0}, + {0x0, (const uint8_t *)0x0, 255, 0x0}, /* BZ 174799. */ + {0x0, (const uint8_t *)0x0, 256, 0x0}, + {0x0, (const uint8_t *)0x0, 257, 0x0}, + {0x0, (const uint8_t *)0x0, 32767, 0x0}, + {0x0, (const uint8_t *)0x0, 32768, 0x0}, + {0x0, (const uint8_t *)0x0, 32769, 0x0}, + {0x0, (const uint8_t *)"", 0, 0x0}, + {0xffffffff, (const uint8_t *)"", 0, 0xffffffff}, + {0x0, (const uint8_t *)"abacus", 6, 0xc3d7115b}, + {0x0, (const uint8_t *)"backlog", 7, 0x269205}, + {0x0, (const uint8_t *)"campfire", 8, 0x22a515f8}, + {0x0, (const uint8_t *)"delta", 5, 0x9643fed9}, + {0x0, (const uint8_t *)"executable", 10, 0xd68eda01}, + {0x0, (const uint8_t *)"file", 4, 0x8c9f3610}, + {0x0, (const uint8_t *)"greatest", 8, 0xc1abd6cd}, + {0x0, (const uint8_t *)"hello", 5, 0x3610a686}, + {0x0, (const uint8_t *)"inverter", 8, 0xc9e962c9}, + {0x0, (const uint8_t *)"jigsaw", 6, 0xce4e3f69}, + {0x0, (const uint8_t *)"karate", 6, 0x890be0e2}, + {0x0, (const uint8_t *)"landscape", 9, 0xc4e0330b}, + {0x0, (const uint8_t *)"machine", 7, 0x1505df84}, + {0x0, (const uint8_t *)"nanometer", 9, 0xd4e19f39}, + {0x0, (const uint8_t *)"oblivion", 8, 0xdae9de77}, + {0x0, (const uint8_t *)"panama", 6, 0x66b8979c}, + {0x0, (const uint8_t *)"quest", 5, 0x4317f817}, + {0x0, (const uint8_t *)"resource", 8, 0xbc91f416}, + {0x0, (const uint8_t *)"secret", 6, 0x5ca2e8e5}, + {0x0, (const uint8_t *)"test", 4, 0xd87f7e0c}, + {0x0, (const uint8_t *)"ultimate", 8, 0x3fc79b0b}, + {0x0, (const uint8_t *)"vector", 6, 0x1b6e485b}, + {0x0, (const uint8_t *)"walrus", 6, 0xbe769b97}, + {0x0, (const uint8_t *)"xeno", 4, 0xe7a06444}, + {0x0, (const uint8_t *)"yelling", 7, 0xfe3944e5}, + {0x0, (const uint8_t *)"zlib", 4, 0x73887d3a}, + {0x0, (const uint8_t *)"4BJD7PocN1VqX0jXVpWB", 20, 0xd487a5a1}, + {0x0, (const uint8_t *)"F1rPWI7XvDs6nAIRx41l", 20, 0x61a0132e}, + {0x0, (const uint8_t *)"ldhKlsVkPFOveXgkGtC2", 20, 0xdf02f76}, + {0x0, (const uint8_t *)"5KKnGOOrs8BvJ35iKTOS", 20, 0x579b2b0a}, + {0x0, (const uint8_t *)"0l1tw7GOcem06Ddu7yn4", 20, 0xf7d16e2d}, + {0x0, (const uint8_t *)"MCr47CjPIn9R1IvE1Tm5", 20, 0x731788f5}, + {0x0, (const uint8_t *)"UcixbzPKTIv0SvILHVdO", 20, 0x7112bb11}, + {0x0, (const uint8_t *)"dGnAyAhRQDsWw0ESou24", 20, 0xf32a0dac}, + {0x0, (const uint8_t *)"di0nvmY9UYMYDh0r45XT", 20, 0x625437bb}, + {0x0, (const uint8_t *)"2XKDwHfAhFsV0RhbqtvH", 20, 0x896930f9}, + {0x0, (const uint8_t *)"ZhrANFIiIvRnqClIVyeD", 20, 0x8579a37}, + {0x0, (const uint8_t *)"v7Q9ehzioTOVeDIZioT1", 20, 0x632aa8e0}, + {0x0, (const uint8_t *)"Yod5hEeKcYqyhfXbhxj2", 20, 0xc829af29}, + {0x0, (const uint8_t *)"GehSWY2ay4uUKhehXYb0", 20, 0x1b08b7e8}, + {0x0, (const uint8_t *)"kwytJmq6UqpflV8Y8GoE", 20, 0x4e33b192}, + {0x0, (const uint8_t *)"70684206568419061514", 20, 0x59a179f0}, + {0x0, (const uint8_t *)"42015093765128581010", 20, 0xcd1013d7}, + {0x0, (const uint8_t *)"88214814356148806939", 20, 0xab927546}, + {0x0, (const uint8_t *)"43472694284527343838", 20, 0x11f3b20c}, + {0x0, (const uint8_t *)"49769333513942933689", 20, 0xd562d4ca}, + {0x0, (const uint8_t *)"54979784887993251199", 20, 0x233395f7}, + {0x0, (const uint8_t *)"58360544869206793220", 20, 0x2d167fd5}, + {0x0, (const uint8_t *)"27347953487840714234", 20, 0x8b5108ba}, + {0x0, (const uint8_t *)"07650690295365319082", 20, 0xc46b3cd8}, + {0x0, (const uint8_t *)"42655507906821911703", 20, 0xc10b2662}, + {0x0, (const uint8_t *)"29977409200786225655", 20, 0xc9a0f9d2}, + {0x0, (const uint8_t *)"85181542907229116674", 20, 0x9341357b}, + {0x0, (const uint8_t *)"87963594337989416799", 20, 0xf0424937}, + {0x0, (const uint8_t *)"21395988329504168551", 20, 0xd7c4c31f}, + {0x0, (const uint8_t *)"51991013580943379423", 20, 0xf11edcc4}, + {0x0, (const uint8_t *)"*]+@!);({_$;}[_},?{?;(_?,=-][@", 30, 0x40795df4}, + {0x0, (const uint8_t *)"_@:_).&(#.[:[{[:)$++-($_;@[)}+", 30, 0xdd61a631}, + {0x0, (const uint8_t *)"&[!,[$_==}+.]@!;*(+},[;:)$;)-@", 30, 0xca907a99}, + {0x0, (const uint8_t *)"]{.[.+?+[[=;[?}_#&;[=)__$$:+=_", 30, 0xf652deac}, + {0x0, (const uint8_t *)"-%.)=/[@].:.(:,()$;=%@-$?]{%+%", 30, 0xaf39a5a9}, + {0x0, (const uint8_t *)"+]#$(@&.=:,*];/.!]%/{:){:@(;)$", 30, 0x6bebb4cf}, + {0x0, (const uint8_t *)")-._.:?[&:.=+}(*$/=!.${;(=$@!}", 30, 0x76430bac}, + {0x0, (const uint8_t *)":(_*&%/[[}+,?#$&*+#[([*-/#;%(]", 30, 0x6c80c388}, + {0x0, (const uint8_t *)"{[#-;:$/{)(+[}#]/{&!%(@)%:@-$:", 30, 0xd54d977d}, + {0x0, (const uint8_t *)"_{$*,}(&,@.)):=!/%(&(,,-?$}}}!", 30, 0xe3966ad5}, + {0x0, (const uint8_t *)"e$98KNzqaV)Y:2X?]77].{gKRD4G5{mHZk,Z)SpU%L3FSgv!Wb8MLAFdi{+fp)c,@8m6v)yXg@]HBDFk?.4&}g5_udE*JHCiH=aL", 100, 0xe7c71db9}, + {0x0, (const uint8_t *)"r*Fd}ef+5RJQ;+W=4jTR9)R*p!B;]Ed7tkrLi;88U7g@3v!5pk2X6D)vt,.@N8c]@yyEcKi[vwUu@.Ppm@C6%Mv*3Nw}Y,58_aH)", 100, 0xeaa52777}, + {0x0, (const uint8_t *)"h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&", 100, 0xcd472048}, + {0x7a30360d, (const uint8_t *)"abacus", 6, 0xf8655a84}, + {0x6fd767ee, (const uint8_t *)"backlog", 7, 0x1ed834b1}, + {0xefeb7589, (const uint8_t *)"campfire", 8, 0x686cfca}, + {0x61cf7e6b, (const uint8_t *)"delta", 5, 0x1554e4b1}, + {0xdc712e2, (const uint8_t *)"executable", 10, 0x761b4254}, + {0xad23c7fd, (const uint8_t *)"file", 4, 0x7abdd09b}, + {0x85cb2317, (const uint8_t *)"greatest", 8, 0x4ba91c6b}, + {0x9eed31b0, (const uint8_t *)"inverter", 8, 0xd5e78ba5}, + {0xb94f34ca, (const uint8_t *)"jigsaw", 6, 0x23649109}, + {0xab058a2, (const uint8_t *)"karate", 6, 0xc5591f41}, + {0x5bff2b7a, (const uint8_t *)"landscape", 9, 0xf10eb644}, + {0x605c9a5f, (const uint8_t *)"machine", 7, 0xbaa0a636}, + {0x51bdeea5, (const uint8_t *)"nanometer", 9, 0x6af89afb}, + {0x85c21c79, (const uint8_t *)"oblivion", 8, 0xecae222b}, + {0x97216f56, (const uint8_t *)"panama", 6, 0x47dffac4}, + {0x18444af2, (const uint8_t *)"quest", 5, 0x70c2fe36}, + {0xbe6ce359, (const uint8_t *)"resource", 8, 0x1471d925}, + {0x843071f1, (const uint8_t *)"secret", 6, 0x50c9a0db}, + {0xf2480c60, (const uint8_t *)"ultimate", 8, 0xf973daf8}, + {0x2d2feb3d, (const uint8_t *)"vector", 6, 0x344ac03d}, + {0x7490310a, (const uint8_t *)"walrus", 6, 0x6d1408ef}, + {0x97d247d4, (const uint8_t *)"xeno", 4, 0xe62670b5}, + {0x93cf7599, (const uint8_t *)"yelling", 7, 0x1b36da38}, + {0x73c84278, (const uint8_t *)"zlib", 4, 0x6432d127}, + {0x228a87d1, (const uint8_t *)"4BJD7PocN1VqX0jXVpWB", 20, 0x997107d0}, + {0xa7a048d0, (const uint8_t *)"F1rPWI7XvDs6nAIRx41l", 20, 0xdc567274}, + {0x1f0ded40, (const uint8_t *)"ldhKlsVkPFOveXgkGtC2", 20, 0xdcc63870}, + {0xa804a62f, (const uint8_t *)"5KKnGOOrs8BvJ35iKTOS", 20, 0x6926cffd}, + {0x508fae6a, (const uint8_t *)"0l1tw7GOcem06Ddu7yn4", 20, 0xb52b38bc}, + {0xe5adaf4f, (const uint8_t *)"MCr47CjPIn9R1IvE1Tm5", 20, 0xf83b8178}, + {0x67136a40, (const uint8_t *)"UcixbzPKTIv0SvILHVdO", 20, 0xc5213070}, + {0xb00c4a10, (const uint8_t *)"dGnAyAhRQDsWw0ESou24", 20, 0xbc7648b0}, + {0x2e0c84b5, (const uint8_t *)"di0nvmY9UYMYDh0r45XT", 20, 0xd8123a72}, + {0x81238d44, (const uint8_t *)"2XKDwHfAhFsV0RhbqtvH", 20, 0xd5ac5620}, + {0xf853aa92, (const uint8_t *)"ZhrANFIiIvRnqClIVyeD", 20, 0xceae099d}, + {0x5a692325, (const uint8_t *)"v7Q9ehzioTOVeDIZioT1", 20, 0xb07d2b24}, + {0x3275b9f, (const uint8_t *)"Yod5hEeKcYqyhfXbhxj2", 20, 0x24ce91df}, + {0x38371feb, (const uint8_t *)"GehSWY2ay4uUKhehXYb0", 20, 0x707b3b30}, + {0xafc8bf62, (const uint8_t *)"kwytJmq6UqpflV8Y8GoE", 20, 0x16abc6a9}, + {0x9b07db73, (const uint8_t *)"70684206568419061514", 20, 0xae1fb7b7}, + {0xe75b214, (const uint8_t *)"42015093765128581010", 20, 0xd4eecd2d}, + {0x72d0fe6f, (const uint8_t *)"88214814356148806939", 20, 0x4660ec7}, + {0xf857a4b1, (const uint8_t *)"43472694284527343838", 20, 0xfd8afdf7}, + {0x54b8e14, (const uint8_t *)"49769333513942933689", 20, 0xc6d1b5f2}, + {0xd6aa5616, (const uint8_t *)"54979784887993251199", 20, 0x32476461}, + {0x11e63098, (const uint8_t *)"58360544869206793220", 20, 0xd917cf1a}, + {0xbe92385, (const uint8_t *)"27347953487840714234", 20, 0x4ad14a12}, + {0x49511de0, (const uint8_t *)"07650690295365319082", 20, 0xe37b5c6c}, + {0x3db13bc1, (const uint8_t *)"42655507906821911703", 20, 0x7cc497f1}, + {0xbb899bea, (const uint8_t *)"29977409200786225655", 20, 0x99781bb2}, + {0xf6cd9436, (const uint8_t *)"85181542907229116674", 20, 0x132256a1}, + {0x9109e6c3, (const uint8_t *)"87963594337989416799", 20, 0xbfdb2c83}, + {0x75770fc, (const uint8_t *)"21395988329504168551", 20, 0x8d9d1e81}, + {0x69b1d19b, (const uint8_t *)"51991013580943379423", 20, 0x7b6d4404}, + {0xc6132975, (const uint8_t *)"*]+@!);({_$;}[_},?{?;(_?,=-][@", 30, 0x8619f010}, + {0xd58cb00c, (const uint8_t *)"_@:_).&(#.[:[{[:)$++-($_;@[)}+", 30, 0x15746ac3}, + {0xb63b8caa, (const uint8_t *)"&[!,[$_==}+.]@!;*(+},[;:)$;)-@", 30, 0xaccf812f}, + {0x8a45a2b8, (const uint8_t *)"]{.[.+?+[[=;[?}_#&;[=)__$$:+=_", 30, 0x78af45de}, + {0xcbe95b78, (const uint8_t *)"-%.)=/[@].:.(:,()$;=%@-$?]{%+%", 30, 0x25b06b59}, + {0x4ef8a54b, (const uint8_t *)"+]#$(@&.=:,*];/.!]%/{:){:@(;)$", 30, 0x4ba0d08f}, + {0x76ad267a, (const uint8_t *)")-._.:?[&:.=+}(*$/=!.${;(=$@!}", 30, 0xe26b6aac}, + {0x569e613c, (const uint8_t *)":(_*&%/[[}+,?#$&*+#[([*-/#;%(]", 30, 0x7e2b0a66}, + {0x36aa61da, (const uint8_t *)"{[#-;:$/{)(+[}#]/{&!%(@)%:@-$:", 30, 0xb3430dc7}, + {0xf67222df, (const uint8_t *)"_{$*,}(&,@.)):=!/%(&(,,-?$}}}!", 30, 0x626c17a}, + {0x74b34fd3, (const uint8_t *)"e$98KNzqaV)Y:2X?]77].{gKRD4G5{mHZk,Z)SpU%L3FSgv!Wb8MLAFdi{+fp)c,@8m6v)yXg@]HBDFk?.4&}g5_udE*JHCiH=aL", 100, 0xccf98060}, + {0x351fd770, (const uint8_t *)"r*Fd}ef+5RJQ;+W=4jTR9)R*p!B;]Ed7tkrLi;88U7g@3v!5pk2X6D)vt,.@N8c]@yyEcKi[vwUu@.Ppm@C6%Mv*3Nw}Y,58_aH)", 100, 0xd8b95312}, + {0xc45aef77, (const uint8_t *)"h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&", 100, 0xbb1c9912}, + {0xc45aef77, (const uint8_t *) + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&" + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&" + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&" + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&" + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&" + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&", 600, 0x888AFA5B} +}; + +class crc32_variant : public ::testing::TestWithParam { +public: + void hash(crc32_test param, crc32_func crc32) { + uint32_t crc = 0; + if (param.buf != NULL) { + if (param.len) { + crc = crc32(param.crc, param.buf, param.len); + } else { + crc = param.crc; + } + } + EXPECT_EQ(crc, param.expect); + } +}; + +/* Specifically to test where we had dodgy alignment in the acle CRC32 + * function. All others are either byte level access or use intrinsics + * that work with unaligned access */ +class crc32_align : public ::testing::TestWithParam { +public: + void hash(int param, crc32_func crc32) { + uint8_t *buf = (uint8_t*)zng_alloc(sizeof(uint8_t) * (128 + param)); + if (buf != NULL) { + (void)crc32(0, buf + param, 128); + } else { + FAIL(); + } + zng_free(buf); + } +}; + +INSTANTIATE_TEST_SUITE_P(crc32, crc32_variant, testing::ValuesIn(tests)); + +#define TEST_CRC32(name, func, support_flag) \ + TEST_P(crc32_variant, name) { \ + if (!(support_flag)) { \ + GTEST_SKIP(); \ + return; \ + } \ + hash(GetParam(), func); \ + } + +TEST_CRC32(braid, PREFIX(crc32_braid), 1) + +#ifdef DISABLE_RUNTIME_CPU_DETECTION +TEST_CRC32(native, native_crc32, 1) + +#else + +#ifdef ARM_ACLE +static const int align_offsets[] = { + 1, 2, 3, 4, 5, 6, 7 +}; + +#define TEST_CRC32_ALIGN(name, func, support_flag) \ + TEST_P(crc32_align, name) { \ + if (!(support_flag)) { \ + GTEST_SKIP(); \ + return; \ + } \ + hash(GetParam(), func); \ + } + +INSTANTIATE_TEST_SUITE_P(crc32_alignment, crc32_align, testing::ValuesIn(align_offsets)); +TEST_CRC32(acle, crc32_acle, test_cpu_features.arm.has_crc32) +TEST_CRC32_ALIGN(acle_align, crc32_acle, test_cpu_features.arm.has_crc32) +#endif +#ifdef POWER8_VSX_CRC32 +TEST_CRC32(power8, crc32_power8, test_cpu_features.power.has_arch_2_07) +#endif +#ifdef S390_CRC32_VX +TEST_CRC32(vx, crc32_s390_vx, test_cpu_features.s390.has_vx) +#endif +#ifdef X86_PCLMULQDQ_CRC +TEST_CRC32(pclmulqdq, crc32_pclmulqdq, test_cpu_features.x86.has_pclmulqdq) +#endif +#ifdef X86_VPCLMULQDQ_CRC +TEST_CRC32(vpclmulqdq, crc32_vpclmulqdq, (test_cpu_features.x86.has_pclmulqdq && test_cpu_features.x86.has_avx512_common && test_cpu_features.x86.has_vpclmulqdq)) +#endif + +#endif diff --git a/test/test_cve-2003-0107.cc b/test/test_cve-2003-0107.cc new file mode 100644 index 0000000000..9d9e5b00df --- /dev/null +++ b/test/test_cve-2003-0107.cc @@ -0,0 +1,28 @@ +// https://www.securityfocus.com/archive/1/312869 --- originally by Richard Kettlewell +#include +#include +#include + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include + +#if !defined(_WIN32) && defined(ZLIB_COMPAT) +TEST(gzip, cve_2003_0107) { + gzFile f; + int ret; + + f = gzopen("/dev/null", "w"); + EXPECT_TRUE(f != NULL); + + ret = gzprintf(f, "%10240s", ""); + printf("gzprintf -> %d\n", ret); + ret = gzclose(f); + printf("gzclose -> %d [%d]\n", ret, errno); +} +#endif diff --git a/test/test_deflate_bound.cc b/test/test_deflate_bound.cc new file mode 100644 index 0000000000..c86d4e00b0 --- /dev/null +++ b/test/test_deflate_bound.cc @@ -0,0 +1,99 @@ +/* test_deflate_bound.cc - Test deflateBound() with small buffers */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include + +#include "test_shared.h" + +#define MAX_LENGTH (32) + +typedef struct { + int32_t level; + int32_t window_size; + int32_t mem_level; + bool after_init; +} deflate_bound_test; + +static const deflate_bound_test tests[] = { + {0, MAX_WBITS + 16, 1, true}, + {Z_BEST_SPEED, MAX_WBITS, MAX_MEM_LEVEL, true}, + {Z_BEST_COMPRESSION, MAX_WBITS, MAX_MEM_LEVEL, true}, + {Z_BEST_SPEED, MAX_WBITS, MAX_MEM_LEVEL, false}, + {Z_BEST_COMPRESSION, MAX_WBITS, MAX_MEM_LEVEL, false}, +}; + +class deflate_bound_variant : public testing::TestWithParam { +public: + void estimate(deflate_bound_test param) { + PREFIX3(stream) c_stream; + int estimate_len = 0; + uint8_t *uncompressed = NULL; + uint8_t *out_buf = NULL; + int err; + + uncompressed = (uint8_t *)malloc(MAX_LENGTH); + ASSERT_TRUE(uncompressed != NULL); + memset(uncompressed, 'a', MAX_LENGTH); + + for (int32_t i = 0; i < MAX_LENGTH; i++) { + memset(&c_stream, 0, sizeof(c_stream)); + + c_stream.avail_in = i; + c_stream.next_in = (z_const unsigned char *)uncompressed; + c_stream.avail_out = 0; + c_stream.next_out = out_buf; + + if (!param.after_init) + estimate_len = PREFIX(deflateBound)(&c_stream, i); + + err = PREFIX(deflateInit2)(&c_stream, param.level, Z_DEFLATED, + param.window_size, param.mem_level, Z_DEFAULT_STRATEGY); + EXPECT_EQ(err, Z_OK); + + /* calculate actual output length and update structure */ + if (param.after_init) + estimate_len = PREFIX(deflateBound)(&c_stream, i); + out_buf = (uint8_t *)malloc(estimate_len); + + if (out_buf != NULL) { + /* update zlib configuration */ + c_stream.avail_out = estimate_len; + c_stream.next_out = out_buf; + + /* do the compression */ + err = PREFIX(deflate)(&c_stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END) << + "level: " << param.level << "\n" << + "window_size: " << param.window_size << "\n" << + "mem_level: " << param.mem_level << "\n" << + "after_init: " << param.after_init << "\n" << + "length: " << i; + + free(out_buf); + out_buf = NULL; + } + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + } + + free(uncompressed); + } +}; + +TEST_P(deflate_bound_variant, estimate) { + estimate(GetParam()); +} + +INSTANTIATE_TEST_SUITE_P(deflate_bound, deflate_bound_variant, testing::ValuesIn(tests)); diff --git a/test/test_deflate_concurrency.cc b/test/test_deflate_concurrency.cc new file mode 100644 index 0000000000..1297aee644 --- /dev/null +++ b/test/test_deflate_concurrency.cc @@ -0,0 +1,170 @@ +/* Test deflate() on concurrently modified next_in. + * + * Plain zlib does not document that this is supported, but in practice it tolerates this, and QEMU live migration is + * known to rely on this. Make sure zlib-ng tolerates this as well. + */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +#include "zlib.h" +#else +#include "zlib-ng.h" +#endif + +#include + +#include +#include +#include +#include + +static uint8_t buf[8 * 1024]; +static uint8_t zbuf[4 * 1024]; +static uint8_t tmp[8 * 1024]; + +/* Thread that increments all bytes in buf by 1. */ +class Mutator { + enum class State { + PAUSED, + RUNNING, + STOPPED, + }; + +public: + Mutator() + : m_state(State::PAUSED), m_target_state(State::PAUSED), + m_thread(&Mutator::run, this) {} + ~Mutator() { + transition(State::STOPPED); + m_thread.join(); + } + + void pause() { + transition(State::PAUSED); + } + + void resume() { + transition(State::RUNNING); + } + +private: + void run() { + while (true) { + m_state.store(m_target_state); + if (m_state == State::PAUSED) + continue; + if (m_state == State::STOPPED) + break; + for (uint8_t & i: buf) + i++; + } + } + + void transition(State target_state) { + m_target_state = target_state; + while (m_state != target_state) { + } + } + + std::atomic m_state, m_target_state; + std::thread m_thread; +}; + +TEST(deflate, concurrency) { +#ifdef S390_DFLTCC_DEFLATE + GTEST_SKIP() << "Known to be broken with S390_DFLTCC_DEFLATE"; +#endif + + /* Create reusable mutator and streams. */ + Mutator mutator; + + PREFIX3(stream) dstrm; + memset(&dstrm, 0, sizeof(dstrm)); + int err = PREFIX(deflateInit2)(&dstrm, Z_BEST_SPEED, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + ASSERT_EQ(Z_OK, err) << dstrm.msg; + + PREFIX3(stream) istrm; + memset(&istrm, 0, sizeof(istrm)); + err = PREFIX(inflateInit2)(&istrm, -15); + ASSERT_EQ(Z_OK, err) << istrm.msg; + + /* Iterate for a certain amount of time. */ + auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(1); + while (std::chrono::steady_clock::now() < deadline) { + /* Start each iteration with a fresh stream state. */ + err = PREFIX(deflateReset)(&dstrm); + ASSERT_EQ(Z_OK, err) << dstrm.msg; + + err = PREFIX(inflateReset)(&istrm); + ASSERT_EQ(Z_OK, err) << istrm.msg; + + /* Mutate and compress the first half of buf concurrently. + * Decompress and throw away the results, which are unpredictable. + */ + mutator.resume(); + dstrm.next_in = buf; + dstrm.avail_in = sizeof(buf) / 2; + while (dstrm.avail_in > 0) { + dstrm.next_out = zbuf; + dstrm.avail_out = sizeof(zbuf); + err = PREFIX(deflate)(&dstrm, Z_NO_FLUSH); + ASSERT_EQ(Z_OK, err) << dstrm.msg; + istrm.next_in = zbuf; + istrm.avail_in = sizeof(zbuf) - dstrm.avail_out; + while (istrm.avail_in > 0) { + istrm.next_out = tmp; + istrm.avail_out = sizeof(tmp); + err = PREFIX(inflate)(&istrm, Z_NO_FLUSH); + ASSERT_EQ(Z_OK, err) << istrm.msg; + } + } + + /* Stop mutation and compress the second half of buf. + * Decompress and check that the result matches. + */ + mutator.pause(); + dstrm.next_in = buf + sizeof(buf) / 2; + dstrm.avail_in = sizeof(buf) - sizeof(buf) / 2; + while (dstrm.avail_in > 0) { + dstrm.next_out = zbuf; + dstrm.avail_out = sizeof(zbuf); + err = PREFIX(deflate)(&dstrm, Z_FINISH); + if (err == Z_STREAM_END) + ASSERT_EQ(0u, dstrm.avail_in); + else + ASSERT_EQ(Z_OK, err) << dstrm.msg; + istrm.next_in = zbuf; + istrm.avail_in = sizeof(zbuf) - dstrm.avail_out; + while (istrm.avail_in > 0) { + size_t orig_total_out = istrm.total_out; + istrm.next_out = tmp; + istrm.avail_out = sizeof(tmp); + err = PREFIX(inflate)(&istrm, Z_NO_FLUSH); + if (err == Z_STREAM_END) + ASSERT_EQ(0u, istrm.avail_in); + else + ASSERT_EQ(Z_OK, err) << istrm.msg; + size_t concurrent_size = sizeof(buf) - sizeof(buf) / 2; + if (istrm.total_out > concurrent_size) { + size_t tmp_offset, buf_offset, size; + if (orig_total_out >= concurrent_size) { + tmp_offset = 0; + buf_offset = orig_total_out - concurrent_size; + size = istrm.total_out - orig_total_out; + } else { + tmp_offset = concurrent_size - orig_total_out; + buf_offset = 0; + size = istrm.total_out - concurrent_size; + } + ASSERT_EQ(0, memcmp(tmp + tmp_offset, buf + sizeof(buf) / 2 + buf_offset, size)); + } + } + } + } + + err = PREFIX(inflateEnd)(&istrm); + ASSERT_EQ(Z_OK, err) << istrm.msg; + + err = PREFIX(deflateEnd)(&dstrm); + ASSERT_EQ(Z_OK, err) << istrm.msg; +} diff --git a/test/test_deflate_copy.cc b/test/test_deflate_copy.cc new file mode 100644 index 0000000000..4adc9be967 --- /dev/null +++ b/test/test_deflate_copy.cc @@ -0,0 +1,60 @@ +/* test_deflate_copy.cc - Test deflateCopy() with small buffers */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include "deflate.h" + +#include "test_shared.h" + +#include + +TEST(deflate, copy) { + PREFIX3(stream) c_stream, c_stream_copy; + uint8_t compr[128]; + z_size_t compr_len = sizeof(compr); + int err; + + memset(&c_stream, 0, sizeof(c_stream)); + memset(&c_stream_copy, 0, sizeof(c_stream_copy)); + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + EXPECT_EQ(err, Z_OK); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != hello_len && c_stream.total_out < compr_len) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_OK); + } + + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + EXPECT_EQ(err, Z_OK); + } + + err = PREFIX(deflateCopy)(&c_stream_copy, &c_stream); + EXPECT_EQ(err, Z_OK); + + EXPECT_EQ(c_stream.state->status, c_stream_copy.state->status); + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + + err = PREFIX(deflateEnd)(&c_stream_copy); + EXPECT_EQ(err, Z_OK); +} diff --git a/test/test_deflate_dict.cc b/test/test_deflate_dict.cc new file mode 100644 index 0000000000..781c70db27 --- /dev/null +++ b/test/test_deflate_dict.cc @@ -0,0 +1,54 @@ +/* test_deflate_dict.cc - Test deflateGetDictionary() with small buffers */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include + +#include "test_shared.h" + +TEST(deflate, dictionary) { + PREFIX3(stream) c_stream; + uint8_t compr[128]; + uint32_t compr_len = sizeof(compr); + uint8_t *dict_new = NULL; + uint32_t *dict_len; + int err; + + memset(&c_stream, 0, sizeof(c_stream)); + + err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION); + EXPECT_EQ(err, Z_OK); + + c_stream.next_out = compr; + c_stream.avail_out = compr_len; + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.avail_in = (uint32_t)hello_len; + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + + dict_new = (uint8_t *)calloc(256, 1); + ASSERT_TRUE(dict_new != NULL); + dict_len = (uint32_t *)calloc(4, 1); + ASSERT_TRUE(dict_len != NULL); + + err = PREFIX(deflateGetDictionary)(&c_stream, dict_new, dict_len); + EXPECT_EQ(err, Z_OK); + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + + free(dict_new); + free(dict_len); +} diff --git a/test/test_deflate_hash_head_0.cc b/test/test_deflate_hash_head_0.cc new file mode 100644 index 0000000000..cbf601038c --- /dev/null +++ b/test/test_deflate_hash_head_0.cc @@ -0,0 +1,83 @@ +/* Generated by fuzzing - test hash_head == 0 handling. */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include + +#include "test_shared.h" + +#include + +TEST(deflate, hash_head_0) { + PREFIX3(stream) strm; + int err; + + memset(&strm, 0, sizeof(strm)); + err = PREFIX(deflateInit2)(&strm, 1, Z_DEFLATED, -15, 4, Z_HUFFMAN_ONLY); + EXPECT_EQ(err, Z_OK); + + unsigned char next_in[9698]; + memset(next_in, 0x30, sizeof(next_in)); + next_in[8193] = 0x00; + next_in[8194] = 0x00; + next_in[8195] = 0x00; + next_in[8199] = 0x8a; + strm.next_in = next_in; + unsigned char next_out[21572]; + strm.next_out = next_out; + + strm.avail_in = 0; + strm.avail_out = 1348; + err = PREFIX(deflateParams(&strm, 3, Z_FILTERED)); + EXPECT_EQ(err, Z_OK); + + strm.avail_in = 6728; + strm.avail_out = 2696; + err = PREFIX(deflate(&strm, Z_SYNC_FLUSH)); + EXPECT_EQ(err, Z_OK); + + strm.avail_in = 15; + strm.avail_out = 1348; + err = PREFIX(deflateParams(&strm, 9, Z_FILTERED)); + EXPECT_EQ(err, Z_OK); + + strm.avail_in = 1453; + strm.avail_out = 1348; + err = PREFIX(deflate(&strm, Z_FULL_FLUSH)); + EXPECT_EQ(err, Z_OK); + + strm.avail_in = (uint32_t)(next_in + sizeof(next_in) - strm.next_in); + strm.avail_out = (uint32_t)(next_out + sizeof(next_out) - strm.next_out); + err = PREFIX(deflate)(&strm, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + + uint32_t compressed_size = (uint32_t)(strm.next_out - next_out); + + err = PREFIX(deflateEnd)(&strm); + EXPECT_EQ(err, Z_OK); + + memset(&strm, 0, sizeof(strm)); + err = PREFIX(inflateInit2)(&strm, -MAX_WBITS); + EXPECT_EQ(err, Z_OK); + + strm.next_in = next_out; + strm.avail_in = compressed_size; + unsigned char uncompressed[sizeof(next_in)]; + strm.next_out = uncompressed; + strm.avail_out = sizeof(uncompressed); + + err = PREFIX(inflate)(&strm, Z_NO_FLUSH); + EXPECT_EQ(err, Z_STREAM_END); + + err = PREFIX(inflateEnd)(&strm); + EXPECT_EQ(err, Z_OK); + + EXPECT_TRUE(memcmp(uncompressed, next_in, sizeof(uncompressed)) == 0); +} diff --git a/test/test_deflate_header.cc b/test/test_deflate_header.cc new file mode 100644 index 0000000000..0d1b7d0443 --- /dev/null +++ b/test/test_deflate_header.cc @@ -0,0 +1,71 @@ +/* test_deflate_header.cc - Test deflateSetHeader() with small buffers */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include + +#include "test_shared.h" + +TEST(deflate, header) { + PREFIX3(stream) c_stream; + PREFIX(gz_header) *head; + uint8_t compr[128]; + z_size_t compr_len = sizeof(compr); + int err; + + head = (PREFIX(gz_header) *)calloc(1, sizeof(PREFIX(gz_header))); + ASSERT_TRUE(head != NULL); + + memset(&c_stream, 0, sizeof(c_stream)); + + /* gzip */ + err = PREFIX(deflateInit2)(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY); + EXPECT_EQ(err, Z_OK); + + head->text = 1; + head->comment = (uint8_t *)"comment"; + head->name = (uint8_t *)"name"; + head->hcrc = 1; + head->extra = (uint8_t *)"extra"; + head->extra_len = (uint32_t)strlen((const char *)head->extra); + + err = PREFIX(deflateSetHeader)(&c_stream, head); + EXPECT_EQ(err, Z_OK); + + PREFIX(deflateBound)(&c_stream, (unsigned long)compr_len); + + c_stream.next_in = (unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != hello_len && c_stream.total_out < compr_len) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_OK); + } + + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + EXPECT_EQ(err, Z_OK); + } + + /* Check CRC32. */ + EXPECT_EQ(c_stream.adler, 0xb56c3f9dU); + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + + free(head); +} diff --git a/test/test_deflate_params.cc b/test/test_deflate_params.cc new file mode 100644 index 0000000000..9fadea85f9 --- /dev/null +++ b/test/test_deflate_params.cc @@ -0,0 +1,143 @@ +/* test_deflate_params.cc - Test deflate() with dynamic change of compression level */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "deflate.h" + +#include + +#include "test_shared.h" + +#define COMPR_BUFFER_SIZE (48 * 1024) +#define UNCOMPR_BUFFER_SIZE (64 * 1024) +#define UNCOMPR_RAND_SIZE (8 * 1024) + +TEST(deflate, params) { + PREFIX3(stream) c_stream, d_stream; + uint8_t *compr, *uncompr; + uint32_t compr_len, uncompr_len; + uint32_t diff; + int32_t i; + time_t now; + int err; +#ifndef ZLIB_COMPAT + int level = -1; + int strategy = -1; + zng_deflate_param_value params[2]; + + params[0].param = Z_DEFLATE_LEVEL; + params[0].buf = &level; + params[0].size = sizeof(level); + + params[1].param = Z_DEFLATE_STRATEGY; + params[1].buf = &strategy; + params[1].size = sizeof(strategy); +#endif + + memset(&c_stream, 0, sizeof(c_stream)); + memset(&d_stream, 0, sizeof(d_stream)); + + compr = (uint8_t *)calloc(1, COMPR_BUFFER_SIZE); + ASSERT_TRUE(compr != NULL); + uncompr = (uint8_t *)calloc(1, UNCOMPR_BUFFER_SIZE); + ASSERT_TRUE(uncompr != NULL); + + compr_len = COMPR_BUFFER_SIZE; + uncompr_len = UNCOMPR_BUFFER_SIZE; + + srand((unsigned)time(&now)); + for (i = 0; i < UNCOMPR_RAND_SIZE; i++) + uncompr[i] = (uint8_t)(rand() % 256); + + err = PREFIX(deflateInit)(&c_stream, Z_BEST_SPEED); + EXPECT_EQ(err, Z_OK); + + c_stream.next_out = compr; + c_stream.avail_out = compr_len; + c_stream.next_in = uncompr; + c_stream.avail_in = uncompr_len; + + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_OK); + EXPECT_EQ(c_stream.avail_in, 0); + + /* Feed in already compressed data and switch to no compression: */ +#ifndef ZLIB_COMPAT + zng_deflateGetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); + EXPECT_EQ(level, Z_BEST_SPEED); + EXPECT_EQ(strategy, Z_DEFAULT_STRATEGY); + + level = Z_NO_COMPRESSION; + strategy = Z_DEFAULT_STRATEGY; + zng_deflateSetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); +#else + PREFIX(deflateParams)(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); +#endif + + c_stream.next_in = compr; + diff = (unsigned int)(c_stream.next_out - compr); + c_stream.avail_in = diff; + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_OK); + + /* Switch back to compressing mode: */ +#ifndef ZLIB_COMPAT + level = -1; + strategy = -1; + zng_deflateGetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); + EXPECT_EQ(level, Z_NO_COMPRESSION); + EXPECT_EQ(strategy, Z_DEFAULT_STRATEGY); + + level = Z_BEST_COMPRESSION; + strategy = Z_FILTERED; + zng_deflateSetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); +#else + PREFIX(deflateParams)(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); +#endif + + c_stream.next_in = uncompr; + c_stream.avail_in = (unsigned int)uncompr_len; + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_OK); + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + + d_stream.next_in = compr; + d_stream.avail_in = (unsigned int)compr_len; + + err = PREFIX(inflateInit)(&d_stream); + EXPECT_EQ(err, Z_OK); + + do { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = uncompr_len; + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) + break; + EXPECT_EQ(err, Z_OK); + } while (err == Z_OK); + + err = PREFIX(inflateEnd)(&d_stream); + EXPECT_EQ(err, Z_OK); + + EXPECT_EQ(d_stream.total_out, (2 * uncompr_len) + diff); + + free(compr); + free(uncompr); +} diff --git a/test/test_deflate_pending.cc b/test/test_deflate_pending.cc new file mode 100644 index 0000000000..8ccedbf33d --- /dev/null +++ b/test/test_deflate_pending.cc @@ -0,0 +1,66 @@ +/* test_deflate_pending.cc - Test deflatePending() with small buffers */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include + +#include "test_shared.h" + +TEST(deflate, pending) { + PREFIX3(stream) c_stream; + uint8_t compr[128]; + z_size_t compr_len = sizeof(compr); + int *bits; + unsigned *ped; + int err; + + + bits = (int *)calloc(256, 1); + ASSERT_TRUE(bits != NULL); + ped = (unsigned *)calloc(256, 1); + ASSERT_TRUE(ped != NULL); + + memset(&c_stream, 0, sizeof(c_stream)); + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + EXPECT_EQ(err, Z_OK); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != hello_len && c_stream.total_out < compr_len) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_OK); + } + + err = PREFIX(deflatePending)(&c_stream, ped, bits); + EXPECT_EQ(err, Z_OK); + + EXPECT_GE(*bits, 0); + EXPECT_LE(*bits, 7); + + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + EXPECT_EQ(err, Z_OK); + } + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + + free(bits); + free(ped); +} diff --git a/test/test_deflate_prime.cc b/test/test_deflate_prime.cc new file mode 100644 index 0000000000..75dcf3177a --- /dev/null +++ b/test/test_deflate_prime.cc @@ -0,0 +1,91 @@ +/* test_deflate_prime.cc - Test deflatePrime() wrapping gzip around deflate stream */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include "test_shared_ng.h" + +#include + +TEST(deflate, prime) { + PREFIX3(stream) c_stream, d_stream; + uint8_t compr[128], uncompr[128]; + z_size_t compr_len = sizeof(compr), uncompr_len = sizeof(uncompr); + uint32_t crc = 0; + int err; + + memset(&c_stream, 0, sizeof(c_stream)); + memset(&d_stream, 0, sizeof(d_stream)); + + /* Raw deflate windowBits is -15 */ + err = PREFIX(deflateInit2)(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); + EXPECT_EQ(err, Z_OK); + + /* Gzip magic number */ + err = PREFIX(deflatePrime)(&c_stream, 16, 0x8b1f); + EXPECT_EQ(err, Z_OK); + /* Gzip compression method (deflate) */ + err = PREFIX(deflatePrime)(&c_stream, 8, 0x08); + EXPECT_EQ(err, Z_OK); + /* Gzip flags (one byte, using two odd bit calls) */ + err = PREFIX(deflatePrime)(&c_stream, 3, 0x0); + EXPECT_EQ(err, Z_OK); + err = PREFIX(deflatePrime)(&c_stream, 5, 0x0); + EXPECT_EQ(err, Z_OK); + /* Gzip modified time */ + err = deflate_prime_32(&c_stream, 0x0); + EXPECT_EQ(err, Z_OK); + /* Gzip extra flags */ + err = PREFIX(deflatePrime)(&c_stream, 8, 0x0); + EXPECT_EQ(err, Z_OK); + /* Gzip operating system */ + err = PREFIX(deflatePrime)(&c_stream, 8, 255); + EXPECT_EQ(err, Z_OK); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.avail_in = (uint32_t)hello_len; + c_stream.next_out = compr; + c_stream.avail_out = (uint32_t)compr_len; + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + + /* Gzip uncompressed data crc32 */ + crc = PREFIX(crc32)(0, (const uint8_t *)hello, (uint32_t)hello_len); + err = deflate_prime_32(&c_stream, crc); + EXPECT_EQ(err, Z_OK); + /* Gzip uncompressed data length */ + err = deflate_prime_32(&c_stream, (uint32_t)hello_len); + EXPECT_EQ(err, Z_OK); + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + + d_stream.next_in = compr; + d_stream.avail_in = (uint32_t)c_stream.total_out; + d_stream.next_out = uncompr; + d_stream.avail_out = (uint32_t)uncompr_len; + d_stream.total_in = 0; + d_stream.total_out = 0; + + /* Inflate with gzip header */ + err = PREFIX(inflateInit2)(&d_stream, MAX_WBITS + 32); + EXPECT_EQ(err, Z_OK); + + err = PREFIX(inflate)(&d_stream, Z_FINISH); + EXPECT_EQ(err, Z_BUF_ERROR); + + err = PREFIX(inflateEnd)(&d_stream); + EXPECT_EQ(err, Z_OK); + + EXPECT_STREQ((char *)uncompr, hello); +} diff --git a/test/test_deflate_quick_bi_valid.cc b/test/test_deflate_quick_bi_valid.cc new file mode 100644 index 0000000000..8ce4c229db --- /dev/null +++ b/test/test_deflate_quick_bi_valid.cc @@ -0,0 +1,80 @@ +/* Generated by fuzzing - test bi_valid handling in deflate_quick(). */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include + +#include "test_shared.h" + +#include + +TEST(deflate_quick, bi_valid) { + PREFIX3(stream) strm; + int err; + + memset(&strm, 0, sizeof(strm)); + + err = PREFIX(deflateInit2)(&strm, 1, Z_DEFLATED, 31, 1, Z_FILTERED); + EXPECT_EQ(err, Z_OK); + + z_const unsigned char next_in[554] = { + 0x8d, 0xff, 0xff, 0xff, 0xa2, 0x00, 0x00, 0xff, 0x00, 0x15, 0x1b, 0x1b, 0xa2, 0xa2, 0xaf, 0xa2, + 0xa2, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1b, 0x3f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0xab, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x1e, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x07, 0x01, 0x18, 0x00, 0x22, 0x00, + 0x00, 0x00, 0xfd, 0x39, 0xff, 0x00, 0x00, 0x00, 0x1b, 0xfd, 0x3b, 0x00, 0x68, 0x00, 0x00, 0x01, + 0xff, 0xff, 0xff, 0x57, 0xf8, 0x1e, 0x00, 0x00, 0xf2, 0xf2, 0xf2, 0xf2, 0xfa, 0xff, 0xff, 0xff, + 0xff, 0x7e, 0x00, 0x00, 0x4a, 0x00, 0xc5, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x01, 0x00, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x27, 0x4a, 0x4a, 0x4a, 0x32, + 0x00, 0xf9, 0xff, 0x00, 0x02, 0x9a, 0xff, 0x00, 0x00, 0x3f, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x08, 0x2f, 0x20, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7a, 0x7a, 0x9e, 0xff, 0xff, 0x00, 0x1b, 0x1b, 0x04, 0x00, 0x1b, 0x1b, + 0x1b, 0x1b, 0x00, 0x00, 0x00, 0xaf, 0xad, 0xaf, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x2e, 0xff, + 0xff, 0x2e, 0xc1, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x70, 0x00, 0x00, 0x00, 0xda, 0x67, 0x01, + 0x47, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x00, 0x3f, + 0x54, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x34, 0x3e, 0xc5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x00, 0x00, 0x00, 0x40, 0x1b, 0x1b, 0x88, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1f, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x50, 0x3e, 0x7a, 0x7a, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x87, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xff, 0x3d, 0x00, 0x11, 0x4d, 0x00, 0x00, 0x01, 0xd4, 0xd4, 0xd4, 0xd4, 0x2d, 0xd4, + 0xd4, 0xff, 0xff, 0xff, 0xfa, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0x00, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, + 0xd4, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00, 0xfe, 0xf9, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, + 0x16, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, + 0xff, 0x2b, 0x2b, 0x2b, 0x2b, 0x35, 0xd4, 0xd4, 0x47, 0x3f, 0xd4, 0xd4, 0xd6, 0xd4, 0xd4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0x4a, 0x4a, 0x4a, 0x4a, 0x71, 0x00, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1f, 0x1b, 0x1b, 0x1b, 0x57, 0x57, 0x57, 0x57, 0x00, 0x00, 0x1b, 0x08, 0x2b, 0x16, 0xc3, 0x00, + 0x00, 0x00, 0x29, 0x30, 0x03, 0xff, 0x03, 0x03, 0x03, 0x03, 0x07, 0x00, 0x00, 0x01, 0x0b, 0xff, + 0xff, 0xf5, 0xf5, 0xf5, 0x00, 0x00, 0xfe, 0xfa, 0x0f, 0x0f, 0x08, 0x00, 0xff, 0x00, 0x53, 0x3f, + 0x00, 0x04, 0x5d, 0xa8, 0x2e, 0xff, 0xff, 0x00, 0x2f, 0x2f, 0x05, 0xff, 0xff, 0xff, 0x2f, 0x2f, + 0x2f, 0x0a, 0x0a, 0x0a, 0x0a, 0x30, 0xff, 0xff, 0xff, 0xf0, 0x0a, 0x0a, 0x0a, 0x00, 0xff, 0x3f, + 0x4f, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x71, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x71, 0x71, 0x00, 0x71, 0x71, 0x71, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x3f, 0x00, 0xfa, 0x71, 0x71, 0x71, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x71, 0x71, 0x71, 0x71, 0x71}; + strm.next_in = next_in; + unsigned char next_out[1236]; + strm.next_out = next_out; + + strm.avail_in = 554; + strm.avail_out = 31; + + err = PREFIX(deflate)(&strm, Z_FINISH); + EXPECT_EQ(err, Z_OK); + + strm.avail_in = 0; + strm.avail_out = 498; + err = PREFIX(deflate)(&strm, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + + err = PREFIX(deflateEnd)(&strm); + EXPECT_EQ(err, Z_OK); +} diff --git a/test/test_deflate_quick_block_open.cc b/test/test_deflate_quick_block_open.cc new file mode 100644 index 0000000000..84a1ac8bbf --- /dev/null +++ b/test/test_deflate_quick_block_open.cc @@ -0,0 +1,94 @@ +/* Generated by fuzzing - test block_open handling in deflate_quick(). */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include + +#include "test_shared.h" + +#include + +TEST(deflate_quick, block_open) { + PREFIX3(stream) strm; + int err; + + memset(&strm, 0, sizeof(strm)); + err = PREFIX(deflateInit2)(&strm, 1, Z_DEFLATED, -MAX_WBITS, 1, Z_FILTERED); + EXPECT_EQ(err, Z_OK); + + z_const unsigned char next_in[495] = + "\x1d\x1d\x00\x00\x00\x4a\x4a\x4a\xaf\xaf\xaf\xaf\x4a\x4a\x4a\x4a" + "\x3f\x3e\xaf\xff\xff\xff\x11\xff\xff\xff\xff\xdf\x00\x00\x00\x01" + "\x3f\x7d\x00\x50\x00\x00\xc8\x01\x2b\x60\xc8\x00\x24\x06\xff\xff" + "\x4a\x4e\x4a\x7d\xc8\x01\xf1\x2b\x28\xb2\xb2\x60\x25\xc8\x06\x00" + "\x00\x00\x31\x00\x01\xb2\xb2\xb2\xff\xff\xfd\xb2\xb2\x40\xff\x7d" + "\x3b\x34\x3e\xff\xff\x4a\x4a\x01\xf1\xff\x02\xff\x3f\xff\x02\xff" + "\xff\xff\xbf\x0a\xff\x00\x01\x3f\xb3\xff\x26\x00\x00\x13\x00\xc8" + "\x3e\x3e\x3e\x4a\x76\x4a\x4a\x2e\x7d\x3e\x3e\x3e\x3e\x1d\x1d\x1d" + "\xfe\xea\xef\x80\x01\x00\x00\x40\x00\x00\xba\x00\x06\xfa\xb9\x11" + "\xbf\x98\xee\x45\x7e\x04\x00\xff\xff\xff\x67\xc3\xc3\xc3\xc3\x00" + "\x1d\x1d\xe1\xe3\x00\xc3\x1d\x98\x1d\x1d\x1d\x1d\x1d\x00\x00\x00" + "\x02\x00\x00\x00\xe8\x00\x00\x1d\x1d\x1d\xfa\x1e\x12\xff\xff\xff" + "\x00\x01\xa7\xff\xff\xff\x1d\x1d\x1d\x63\xff\xff\xff\x1f\x00\x00" + "\x10\x40\x00\x00\xad\xff\xff\x3f\x51\x00\xf8\xff\xff\x8a\x01\x05" + "\x00\x00\x03\x00\x00\xff\x00\x00\x00\x05\x40\x1f\x08\x0a\x00\xff" + "\xff\x01\x00\x12\x00\x00\x01\x00\x3f\x40\x1d\x1d\x1d\x1d\x1d\x1d" + "\x21\x00\x1d\x00\x00\x00\xe4\x00\x00\x00\x07\x00\x00\xe6\xe6\x34" + "\xe6\xe6\xe6\xe6\xff\x2b\xee\x1d\x1d\x1d\x93\x1d\x1d\x1d\xee\x2b" + "\xee\x01\x81\x1d\x00\x00\x58\x00\x00\x01\x14\x00\x1b\x00\x00\x2c" + "\x00\x00\x00\xdb\x00\x45\x7e\x00\x00\x00\xfb\xbd\x00\x06\x21\xd3" + "\x00\xff\xff\xff\xff\xff\x00\x49\x49\xc9\x49\x3d\x00\x34\x01\x00" + "\x00\x6a\x2b\x00\x00\x50\x40\xf0\xf0\xf0\xf0\xa3\xa3\xa3\xa3\xf0" + "\xf0\x06\xfa\xa9\x01\x10\xbf\x98\x9d\x2b\xee\x2d\x21\x01\xdb\x00" + "\x45\x10\x00\x00\x7e\x00\x00\xe7\x00\xff\xff\x00\xf6\x00\x00\x00" + "\xf9\x00\x00\x00\x11\x00\x00\x00\xe2\x00\x00\x00\x2d\x00\x00\x00" + "\x2f\x00\x3f\x54\x1d\x1d\x1d\x4c\x4c\x4c\x4c\x2a\x4c\x4c\x10\xff" + "\xff\x1a\x00\x00\x01\xff\x00\xff\xf9\x00\x3f\x53\xcc\xcc\xcc\xcc" + "\x6e\x00\x00\x01\xf8\xff\xff\xff\x49\x04\x2c\x01\x00\x1d\x00\x07" + "\x01\xff\x00\x00\x00\xf8\xff\x09\x00\x27\x00\x08\x21\x1c\x00\x00" + "\x00\x00\x1d\x05\x00\x00\x00\x2c\x53\x3f\x00\x01\x00\x00\xe6\xff" + "\xff\xff\x6a\x2b\xee\xe6\x6a\x2b\xee\x2b\xee\xee\x2b\xee"; + strm.next_in = next_in; + unsigned char next_out[1116]; + strm.next_out = next_out; + + strm.avail_in = sizeof(next_in); + while (1) { + strm.avail_out = (uint32_t)(next_out + sizeof(next_out) - strm.next_out); + if (strm.avail_out > 38) + strm.avail_out = 38; + err = PREFIX(deflate)(&strm, Z_FINISH); + if (err == Z_STREAM_END) + break; + EXPECT_EQ(err, Z_OK); + } + uint32_t compressed_size = (uint32_t)(strm.next_out - next_out); + + err = PREFIX(deflateEnd)(&strm); + EXPECT_EQ(err, Z_OK); + + memset(&strm, 0, sizeof(strm)); + err = PREFIX(inflateInit2)(&strm, -MAX_WBITS); + EXPECT_EQ(err, Z_OK); + + strm.next_in = next_out; + strm.avail_in = compressed_size; + unsigned char uncompressed[sizeof(next_in)]; + strm.next_out = uncompressed; + strm.avail_out = sizeof(uncompressed); + + err = PREFIX(inflate)(&strm, Z_NO_FLUSH); + EXPECT_EQ(err, Z_STREAM_END); + + err = PREFIX(inflateEnd)(&strm); + EXPECT_EQ(err, Z_OK); + + EXPECT_TRUE(memcmp(uncompressed, next_in, sizeof(uncompressed)) == 0); +} diff --git a/test/test_deflate_tune.cc b/test/test_deflate_tune.cc new file mode 100644 index 0000000000..9921ee6437 --- /dev/null +++ b/test/test_deflate_tune.cc @@ -0,0 +1,56 @@ +/* test_deflate_tune.cc - Test deflateTune() with small buffers */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include "test_shared.h" + +#include + +TEST(deflate, tune) { + PREFIX3(stream) c_stream; + uint8_t compr[128]; + z_size_t compr_len = sizeof(compr); + int err; + int good_length = 3; + int max_lazy = 5; + int nice_length = 18; + int max_chain = 6; + + memset(&c_stream, 0, sizeof(c_stream)); + + err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION); + EXPECT_EQ(err, Z_OK); + + err = PREFIX(deflateTune)(&c_stream, good_length, max_lazy,nice_length, max_chain); + EXPECT_EQ(err, Z_OK); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != hello_len && c_stream.total_out < compr_len) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_OK); + } + + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + EXPECT_EQ(err, Z_OK); + } + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); +} diff --git a/test/test_dict.cc b/test/test_dict.cc new file mode 100644 index 0000000000..8a882d5770 --- /dev/null +++ b/test/test_dict.cc @@ -0,0 +1,98 @@ +/* test_dict.cc - Test deflate() and inflate() with preset dictionary */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include "test_shared.h" + +#include + +/* Maximum dictionary size, according to inflateGetDictionary() description. */ +#define MAX_DICTIONARY_SIZE 32768 + +static const char dictionary[] = "hello"; + +TEST(dictionary, basic) { + PREFIX3(stream) c_stream, d_stream; + uint8_t compr[128], uncompr[128]; + z_size_t compr_len = sizeof(compr), uncompr_len = sizeof(uncompr); + uint32_t dict_adler = 0; + uint8_t check_dict[MAX_DICTIONARY_SIZE]; + uint32_t check_dict_len = 0; + int err; + + memset(&c_stream, 0, sizeof(c_stream)); + memset(&d_stream, 0, sizeof(d_stream)); + + err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION); + EXPECT_EQ(err, Z_OK); + + err = PREFIX(deflateSetDictionary)(&c_stream, + (const unsigned char *)dictionary, (int)sizeof(dictionary)); + EXPECT_EQ(err, Z_OK); + + dict_adler = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uint32_t)compr_len; + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.avail_in = (uint32_t)hello_len; + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + + compr_len = (z_size_t)c_stream.total_out; + + strcpy((char*)uncompr, "garbage garbage garbage"); + + d_stream.next_in = compr; + d_stream.avail_in = (unsigned int)compr_len; + + err = PREFIX(inflateInit)(&d_stream); + EXPECT_EQ(err, Z_OK); + + d_stream.next_out = uncompr; + d_stream.avail_out = (unsigned int)uncompr_len; + + for (;;) { + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) + break; + if (err == Z_NEED_DICT) { + EXPECT_EQ(d_stream.adler, dict_adler); + err = PREFIX(inflateSetDictionary)(&d_stream, (const unsigned char*)dictionary, + (uint32_t)sizeof(dictionary)); + EXPECT_EQ(d_stream.adler, dict_adler); + } + EXPECT_EQ(err, Z_OK); + } + + err = PREFIX(inflateGetDictionary)(&d_stream, NULL, &check_dict_len); + EXPECT_EQ(err, Z_OK); +#ifndef S390_DFLTCC_INFLATE + EXPECT_GE(check_dict_len, sizeof(dictionary)); +#endif + + err = PREFIX(inflateGetDictionary)(&d_stream, check_dict, &check_dict_len); + EXPECT_EQ(err, Z_OK); +#ifndef S390_DFLTCC_INFLATE + EXPECT_TRUE(memcmp(dictionary, check_dict, sizeof(dictionary)) == 0); +#endif + + err = PREFIX(inflateEnd)(&d_stream); + EXPECT_EQ(err, Z_OK); + + EXPECT_TRUE(strncmp((char*)uncompr, hello, sizeof(hello)) == 0); +} diff --git a/test/test_gzio.cc b/test/test_gzio.cc new file mode 100644 index 0000000000..032e3e1c51 --- /dev/null +++ b/test/test_gzio.cc @@ -0,0 +1,106 @@ +/* test_gzio.cc - Test read/write of .gz files */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include + +#include "test_shared.h" + +#define TESTFILE "foo.gz" + +TEST(gzip, readwrite) { +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); + GTEST_SKIP(); +#else + uint8_t compr[128], uncompr[128]; + uint32_t compr_len = sizeof(compr), uncompr_len = sizeof(uncompr); + size_t read; + int64_t pos; + gzFile file; + int err; + + Z_UNUSED(compr); + /* Write gz file with test data */ + file = PREFIX(gzopen)(TESTFILE, "wb"); + ASSERT_TRUE(file != NULL); + /* Write hello, hello! using gzputs and gzprintf */ + PREFIX(gzputc)(file, 'h'); + EXPECT_EQ(PREFIX(gzputs)(file, "ello"), 4); + EXPECT_EQ(PREFIX(gzprintf)(file, ", %s!", "hello"), 8); + /* Write string null-teriminator using gzseek */ + EXPECT_GE(PREFIX(gzseek)(file, 1L, SEEK_CUR), 0); + /* Write hello, hello! using gzfwrite using best compression level */ + EXPECT_EQ(PREFIX(gzsetparams)(file, Z_BEST_COMPRESSION, Z_DEFAULT_STRATEGY), Z_OK); + EXPECT_NE(PREFIX(gzfwrite)(hello, hello_len, 1, file), 0UL); + /* Flush compressed bytes to file */ + EXPECT_EQ(PREFIX(gzflush)(file, Z_SYNC_FLUSH), Z_OK); + compr_len = (uint32_t)PREFIX(gzoffset)(file); + EXPECT_GE(compr_len, 0UL); + PREFIX(gzclose)(file); + + /* Open gz file we previously wrote */ + file = PREFIX(gzopen)(TESTFILE, "rb"); + ASSERT_TRUE(file != NULL); + + /* Read uncompressed data - hello, hello! string twice */ + strcpy((char*)uncompr, "garbages"); + EXPECT_EQ(PREFIX(gzread)(file, uncompr, (unsigned)uncompr_len), (int)(hello_len + hello_len)); + EXPECT_STREQ((char*)uncompr, hello); + + /* Check position at the end of the gz file */ + EXPECT_EQ(PREFIX(gzeof)(file), 1); + + /* Seek backwards mid-string and check char reading with gzgetc and gzungetc */ + pos = PREFIX(gzseek)(file, -22L, SEEK_CUR); + EXPECT_EQ(pos, 6); + EXPECT_EQ(PREFIX(gztell)(file), pos); + EXPECT_EQ(PREFIX(gzgetc)(file), ' '); + EXPECT_EQ(PREFIX(gzungetc)(' ', file), ' '); + /* Read first hello, hello! string with gzgets */ + strcpy((char*)uncompr, "garbages"); + PREFIX(gzgets)(file, (char*)uncompr, (int)uncompr_len); + EXPECT_EQ(strlen((char*)uncompr), 7UL); /* " hello!" */ + EXPECT_STREQ((char*)uncompr, hello + 6); + + /* Seek to second hello, hello! string */ + pos = PREFIX(gzseek)(file, 14L, SEEK_SET); + EXPECT_EQ(pos, 14); + EXPECT_EQ(PREFIX(gztell)(file), pos); + + /* Check position not at end of file */ + EXPECT_EQ(PREFIX(gzeof)(file), 0); + /* Read first hello, hello! string with gzfread */ + strcpy((char*)uncompr, "garbages"); + read = PREFIX(gzfread)(uncompr, uncompr_len, 1, file); + EXPECT_STREQ((const char *)uncompr, hello); + + pos = PREFIX(gzoffset)(file); + EXPECT_GE(pos, 0); + EXPECT_EQ(pos, (compr_len + 10)); + + /* Trigger an error and clear it with gzclearerr */ + PREFIX(gzfread)(uncompr, (size_t)-1, (size_t)-1, file); + PREFIX(gzerror)(file, &err); + EXPECT_NE(err, 0); + + PREFIX(gzclearerr)(file); + PREFIX(gzerror)(file, &err); + EXPECT_EQ(err, 0); + + PREFIX(gzclose)(file); + + EXPECT_EQ(PREFIX(gzclose)(NULL), Z_STREAM_ERROR); + Z_UNUSED(read); +#endif +} diff --git a/test/test_inflate_adler32.cc b/test/test_inflate_adler32.cc new file mode 100644 index 0000000000..fb78bb1bfc --- /dev/null +++ b/test/test_inflate_adler32.cc @@ -0,0 +1,50 @@ +/* GH-1066 - inflate small amount of data and validate with adler32 checksum. */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include + +#include "test_shared.h" + +#include + +const char* original = "The quick brown fox jumped over the lazy dog"; + +z_const unsigned char compressed[] = { + 0x78, 0x9c, 0x0b, 0xc9, 0x48, 0x55, 0x28, 0x2c, 0xcd, 0x4c, 0xce, 0x56, 0x48, + 0x2a, 0xca, 0x2f, 0xcf, 0x53, 0x48, 0xcb, 0xaf, 0x50, 0xc8, 0x2a, 0xcd, 0x2d, + 0x48, 0x4d, 0x51, 0xc8, 0x2f, 0x4b, 0x2d, 0x52, 0x28, 0xc9, 0x48, 0x55, 0xc8, + 0x49, 0xac, 0xaa, 0x54, 0x48, 0xc9, 0x4f, 0x07, 0x00, 0x6b, 0x93, 0x10, 0x30 +}; + +TEST(inflate, adler32) { + unsigned char uncompressed[1024]; + PREFIX3(stream) strm; + + memset(&strm, 0, sizeof(strm)); + + int err = PREFIX(inflateInit2)(&strm, 32 + MAX_WBITS); + EXPECT_EQ(err, Z_OK); + + strm.next_in = compressed; + strm.avail_in = sizeof(compressed); + strm.next_out = uncompressed; + strm.avail_out = sizeof(uncompressed); + + err = PREFIX(inflate)(&strm, Z_NO_FLUSH); + EXPECT_EQ(err, Z_STREAM_END); + + EXPECT_EQ(strm.adler, 0x6b931030); + + err = PREFIX(inflateEnd)(&strm); + EXPECT_EQ(err, Z_OK); + + EXPECT_TRUE(memcmp(uncompressed, original, MIN(strm.total_out, strlen(original))) == 0); +} diff --git a/test/test_inflate_copy.cc b/test/test_inflate_copy.cc new file mode 100644 index 0000000000..02eea2648a --- /dev/null +++ b/test/test_inflate_copy.cc @@ -0,0 +1,31 @@ +/* test_inflate_copy.cc - Test copying inflate stream */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include "test_shared.h" + +#include + +TEST(inflate, copy_back_and_forth) { + PREFIX3(stream) d1_stream, d2_stream; + int err; + + memset(&d1_stream, 0, sizeof(d1_stream)); + err = PREFIX(inflateInit2)(&d1_stream, MAX_WBITS + 14); + ASSERT_EQ(err, Z_OK); + err = PREFIX(inflateCopy)(&d2_stream, &d1_stream); + ASSERT_EQ(err, Z_OK); + err = PREFIX(inflateEnd)(&d1_stream); + ASSERT_EQ(err, Z_OK); + err = PREFIX(inflateCopy)(&d1_stream, &d2_stream); + ASSERT_EQ(err, Z_OK); + err = PREFIX(inflateEnd)(&d1_stream); + ASSERT_EQ(err, Z_OK); + err = PREFIX(inflateEnd)(&d2_stream); + ASSERT_EQ(err, Z_OK); +} diff --git a/test/test_inflate_sync.cc b/test/test_inflate_sync.cc new file mode 100644 index 0000000000..a79d867e68 --- /dev/null +++ b/test/test_inflate_sync.cc @@ -0,0 +1,75 @@ +/* test_inflate_sync.cc - Test inflateSync using full flush deflate and corrupted data */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include "test_shared.h" + +#include + +TEST(inflate, sync) { + PREFIX3(stream) c_stream, d_stream; + uint8_t compr[128], uncompr[128]; + z_size_t compr_len = sizeof(compr), uncompr_len = sizeof(uncompr); + int err; + + memset(&c_stream, 0, sizeof(c_stream)); + + /* build compressed stream with full flush */ + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + EXPECT_EQ(err, Z_OK); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uint32_t)compr_len; + + err = PREFIX(deflate)(&c_stream, Z_FULL_FLUSH); + EXPECT_EQ(err, Z_OK); + + /* force an error in first compressed block */ + compr[3]++; + c_stream.avail_in = hello_len-3; + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + + compr_len = (z_size_t)c_stream.total_out; + + memset(&d_stream, 0, sizeof(d_stream)); + /* just read the zlib header */ + d_stream.next_in = compr; + d_stream.avail_in = 2; + + err = PREFIX(inflateInit)(&d_stream); + EXPECT_EQ(err, Z_OK); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uint32_t)uncompr_len; + + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_OK); + + /* read all compressed data, but skip damaged part */ + d_stream.avail_in = (uint32_t)compr_len-2; + err = PREFIX(inflateSync)(&d_stream); + EXPECT_EQ(err, Z_OK); + + err = PREFIX(inflate)(&d_stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + + err = PREFIX(inflateEnd)(&d_stream); + EXPECT_EQ(err, Z_OK); +} diff --git a/test/test_large_buffers.cc b/test/test_large_buffers.cc new file mode 100644 index 0000000000..3c1208140d --- /dev/null +++ b/test/test_large_buffers.cc @@ -0,0 +1,87 @@ +/* test_large_buffers.cc - Test deflate() and inflate() with large buffers */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include +#include + +#include + +#include "test_shared.h" + +#define COMPR_BUFFER_SIZE (48 * 1024) +#define UNCOMPR_BUFFER_SIZE (32 * 1024) +#define UNCOMPR_RAND_SIZE (8 * 1024) + +TEST(deflate, large_buffers) { + PREFIX3(stream) c_stream, d_stream; + uint8_t *compr, *uncompr; + uint32_t compr_len, uncompr_len; + int32_t i; + time_t now; + int err; + + memset(&c_stream, 0, sizeof(c_stream)); + memset(&d_stream, 0, sizeof(d_stream)); + + compr = (uint8_t *)calloc(1, COMPR_BUFFER_SIZE); + ASSERT_TRUE(compr != NULL); + uncompr = (uint8_t *)calloc(1, UNCOMPR_BUFFER_SIZE); + ASSERT_TRUE(uncompr != NULL); + + compr_len = COMPR_BUFFER_SIZE; + uncompr_len = UNCOMPR_BUFFER_SIZE; + + srand((unsigned)time(&now)); + for (i = 0; i < UNCOMPR_RAND_SIZE; i++) + uncompr[i] = (uint8_t)(rand() % 256); + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + EXPECT_EQ(err, Z_OK); + + c_stream.next_out = compr; + c_stream.avail_out = compr_len; + c_stream.next_in = uncompr; + c_stream.avail_in = uncompr_len; + + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_OK); + EXPECT_EQ(c_stream.avail_in, 0); + + err = PREFIX(deflate)(&c_stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + + d_stream.next_in = compr; + d_stream.avail_in = compr_len; + d_stream.next_out = uncompr; + + err = PREFIX(inflateInit)(&d_stream); + EXPECT_EQ(err, Z_OK); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = uncompr_len; + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + EXPECT_EQ(err, Z_OK); + } + + err = PREFIX(inflateEnd)(&d_stream); + EXPECT_EQ(err, Z_OK); + + EXPECT_EQ(d_stream.total_out, uncompr_len); + + free(compr); + free(uncompr); +} diff --git a/test/test_main.cc b/test/test_main.cc new file mode 100644 index 0000000000..994a3ef389 --- /dev/null +++ b/test/test_main.cc @@ -0,0 +1,22 @@ +/* test_test.cc - Main entry point for test framework */ + +#include + +#include "gtest/gtest.h" + +extern "C" { +# include "zbuild.h" +# include "test_cpu_features.h" +# ifndef DISABLE_RUNTIME_CPU_DETECTION + struct cpu_features test_cpu_features; +# endif +} + +GTEST_API_ int main(int argc, char **argv) { + printf("Running main() from %s\n", __FILE__); +#ifndef DISABLE_RUNTIME_CPU_DETECTION + cpu_check_features(&test_cpu_features); +#endif + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/test_raw.cc b/test/test_raw.cc new file mode 100644 index 0000000000..a013d4bb47 --- /dev/null +++ b/test/test_raw.cc @@ -0,0 +1,58 @@ +/* test_raw.cc - Test raw streams. */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include + +TEST(raw, basic) { + PREFIX3(stream) stream; + int err; + unsigned char plain[512]; + size_t i; + unsigned char compr[sizeof(plain)]; + unsigned int compr_len; + unsigned char plain_again[sizeof(plain)]; + + memset(&stream, 0, sizeof(stream)); + err = PREFIX(deflateInit2)(&stream, Z_BEST_SPEED, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + EXPECT_EQ(err, Z_OK); + + for (i = 0; i < sizeof(plain); i++) + plain[i] = (unsigned char)i; + stream.adler = 0x12345678; + stream.next_in = plain; + stream.avail_in = (uint32_t)sizeof(plain); + stream.next_out = compr; + stream.avail_out = (uint32_t)sizeof(compr); + err = PREFIX(deflate)(&stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + EXPECT_EQ(stream.adler, 0x12345678); + compr_len = sizeof(compr) - stream.avail_out; + + err = PREFIX(deflateEnd)(&stream); + EXPECT_EQ(err, Z_OK); + + memset(&stream, 0, sizeof(stream)); + err = PREFIX(inflateInit2)(&stream, -MAX_WBITS); + EXPECT_EQ(err, Z_OK); + + stream.adler = 0x87654321; + stream.next_in = compr; + stream.avail_in = compr_len; + stream.next_out = plain_again; + stream.avail_out = (unsigned int)sizeof(plain_again); + + err = PREFIX(inflate)(&stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_STREAM_END); + EXPECT_EQ(stream.adler, 0x87654321); + + err = PREFIX(inflateEnd)(&stream); + EXPECT_EQ(err, Z_OK); + + EXPECT_TRUE(memcmp(plain_again, plain, sizeof(plain)) == 0); +} diff --git a/test/test_shared.h b/test/test_shared.h new file mode 100644 index 0000000000..616f57342c --- /dev/null +++ b/test/test_shared.h @@ -0,0 +1,18 @@ +#ifndef TEST_SHARED_H +#define TEST_SHARED_H + +/* Test definitions that can be used in the original zlib build environment. */ + +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ +static const char hello[] = "hello, hello!"; +static const int hello_len = sizeof(hello); + +/* Clang static analyzer doesn't understand googletest's ASSERT_TRUE, so we need to tell that it's like assert() */ +#ifdef __clang_analyzer__ +# undef ASSERT_TRUE +# define ASSERT_TRUE assert +#endif + +#endif diff --git a/test/test_shared_ng.h b/test/test_shared_ng.h new file mode 100644 index 0000000000..81e451998f --- /dev/null +++ b/test/test_shared_ng.h @@ -0,0 +1,23 @@ +#ifndef TEST_SHARED_NG_H +#define TEST_SHARED_NG_H + +#include "test_shared.h" + +/* Test definitions that can only be used in the zlib-ng build environment. */ + +static inline int deflate_prime_32(PREFIX3(stream) *stream, uint32_t value) { + int err; + +#ifdef ZLIBNG_ENABLE_TESTS + err = PREFIX(deflatePrime)(stream, 32, value); +#else + /* zlib's deflatePrime() takes at most 16 bits */ + err = PREFIX(deflatePrime)(stream, 16, value & 0xffff); + if (err != Z_OK) return err; + err = PREFIX(deflatePrime)(stream, 16, value >> 16); +#endif + + return err; +} + +#endif diff --git a/test/test_small_buffers.cc b/test/test_small_buffers.cc new file mode 100644 index 0000000000..bb3449fd88 --- /dev/null +++ b/test/test_small_buffers.cc @@ -0,0 +1,69 @@ +/* test_small_buffers.cc - Test deflate() and inflate() with small buffers */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include "test_shared.h" + +#include + +TEST(deflate, small_buffers) { + PREFIX3(stream) c_stream, d_stream; + uint8_t compr[128], uncompr[128]; + z_size_t compr_len = sizeof(compr), uncompr_len = sizeof(uncompr); + int err; + + memset(&c_stream, 0, sizeof(c_stream)); + memset(&d_stream, 0, sizeof(d_stream)); + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + EXPECT_EQ(err, Z_OK); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != hello_len && c_stream.total_out < compr_len) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_OK); + } + /* Finish the stream, still forcing small buffers */ + for (;;) { + c_stream.avail_out = 1; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + EXPECT_EQ(err, Z_OK); + } + + err = PREFIX(deflateEnd)(&c_stream); + EXPECT_EQ(err, Z_OK); + + strcpy((char*)uncompr, "garbage"); + + d_stream.next_in = compr; + d_stream.next_out = uncompr; + + err = PREFIX(inflateInit)(&d_stream); + EXPECT_EQ(err, Z_OK); + + while (d_stream.total_out < uncompr_len && d_stream.total_in < compr_len) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + EXPECT_EQ(err, Z_OK); + } + + err = PREFIX(inflateEnd)(&d_stream); + EXPECT_EQ(err, Z_OK); + + EXPECT_STREQ((char*)uncompr, hello); +} diff --git a/test/test_small_window.cc b/test/test_small_window.cc new file mode 100644 index 0000000000..e351efac0d --- /dev/null +++ b/test/test_small_window.cc @@ -0,0 +1,67 @@ +/* test_small_window.cc - Test deflate() and inflate() with a small window and a preset dictionary */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include + +TEST(small_window, basic) { + PREFIX3(stream) stream; + int err; + unsigned char plain[128]; + unsigned char dictionary1[(1 << 9) - sizeof(plain) / 2]; + size_t i; + unsigned char compr[sizeof(plain)]; + unsigned int compr_len; + unsigned char plain_again[sizeof(plain)]; + + memset(&stream, 0, sizeof(stream)); + err = PREFIX(deflateInit2)(&stream, Z_BEST_COMPRESSION, Z_DEFLATED, -9, 8, Z_DEFAULT_STRATEGY); + EXPECT_EQ(err, Z_OK); + + /* Use a large dictionary that is loaded in two parts */ + memset(dictionary1, 'a', sizeof(dictionary1)); + err = PREFIX(deflateSetDictionary)(&stream, dictionary1, (unsigned int)sizeof(dictionary1)); + EXPECT_EQ(err, Z_OK); + for (i = 0; i < sizeof(plain); i++) + plain[i] = (unsigned char)i; + err = PREFIX(deflateSetDictionary)(&stream, plain, (unsigned int)sizeof(plain)); + EXPECT_EQ(err, Z_OK); + + stream.next_in = plain; + stream.avail_in = (uint32_t)sizeof(plain); + stream.next_out = compr; + stream.avail_out = (uint32_t)sizeof(compr); + err = PREFIX(deflate)(&stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + compr_len = sizeof(compr) - stream.avail_out; + + err = PREFIX(deflateEnd)(&stream); + EXPECT_EQ(err, Z_OK); + + memset(&stream, 0, sizeof(stream)); + err = PREFIX(inflateInit2)(&stream, -9); + EXPECT_EQ(err, Z_OK); + + err = PREFIX(inflateSetDictionary)(&stream, dictionary1, (unsigned int)sizeof(dictionary1)); + EXPECT_EQ(err, Z_OK); + err = PREFIX(inflateSetDictionary)(&stream, plain, (unsigned int)sizeof(plain)); + EXPECT_EQ(err, Z_OK); + + stream.next_in = compr; + stream.avail_in = compr_len; + stream.next_out = plain_again; + stream.avail_out = (unsigned int)sizeof(plain_again); + + err = PREFIX(inflate)(&stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_STREAM_END); + + err = PREFIX(inflateEnd)(&stream); + EXPECT_EQ(err, Z_OK); + + EXPECT_TRUE(memcmp(plain_again, plain, sizeof(plain)) == 0); +} diff --git a/test/test_version.cc b/test/test_version.cc new file mode 100644 index 0000000000..fda87904e0 --- /dev/null +++ b/test/test_version.cc @@ -0,0 +1,27 @@ +/* test_version.cc - Test zVersion() and zlibCompileFlags() */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include "test_shared.h" + +#include + +TEST(version, basic) { + static const char *my_version = PREFIX2(VERSION); + + EXPECT_EQ(zVersion()[0], my_version[0]); + EXPECT_STREQ(zVersion(), PREFIX2(VERSION)); + + printf("zlib-ng version %s = 0x%08lx, compile flags = 0x%lx\n", + ZLIBNG_VERSION, ZLIBNG_VERNUM, PREFIX(zlibCompileFlags)()); +} diff --git a/tools/config.sub b/tools/config.sub new file mode 100644 index 0000000000..dba175ae31 --- /dev/null +++ b/tools/config.sub @@ -0,0 +1,17 @@ +#!/bin/sh +# Canonicalize CHOST. +# In particular, converts Debian multiarch tuples into GNU triplets. +# See also +# https://wiki.debian.org/Multiarch/Tuples +# https://wiki.gentoo.org/wiki/CHOST +# If you need an architecture not listed here, file a bug at github.com/zlib-ng/zlib-ng +# and work around the problem by dropping libtool's much more comprehensive config.sub +# on top of this file, see +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +case "$1" in +*-*-linux-gnu*) echo $1;; +i686-linux-gnu*|x86_64-linux-gnu*) echo $1 | sed 's/-linux-gnu/-pc-linux-gnu/';; +*-linux-gnu*) echo $1 | sed 's/-linux-gnu/-unknown-linux-gnu/';; +*) echo $1;; +esac diff --git a/tools/makecrct.c b/tools/makecrct.c new file mode 100644 index 0000000000..9e65d24954 --- /dev/null +++ b/tools/makecrct.c @@ -0,0 +1,244 @@ +/* makecrct.c -- output crc32 tables + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h +*/ + +#include +#include +#include "zbuild.h" +#include "zutil.h" + +/* + The crc32 table header file contains tables for both 32-bit and 64-bit + z_word_t's, and so requires a 64-bit type be available. In that case, + z_word_t must be defined to be 64-bits. This code then also generates + and writes out the tables for the case that z_word_t is 32 bits. +*/ + +#define W 8 /* Need a 64-bit integer type in order to generate crc32 tables. */ + +#include "crc32_braid_p.h" + +static uint32_t crc_table[256]; +static z_word_t crc_big_table[256]; +static uint32_t x2n_table[32]; + +#include "crc32_braid_comb_p.h" + +static void make_crc_table(void); +static void print_crc_table(void); + +static void braid(uint32_t ltl[][256], z_word_t big[][256], int n, int w); + +static void write_table(const uint32_t *table, int k); +static void write_table32hi(const z_word_t *table, int k); +static void write_table64(const z_word_t *table, int k); + +/* ========================================================================= */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x^2+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x + (which is shifting right by one and adding x^32 mod p if the bit shifted out + is a one). We start with the highest power (least significant bit) of q and + repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all the + information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +static void make_crc_table(void) { + unsigned i, j, n; + uint32_t p; + + /* initialize the CRC of bytes tables */ + for (i = 0; i < 256; i++) { + p = i; + for (j = 0; j < 8; j++) + p = p & 1 ? (p >> 1) ^ POLY : p >> 1; + crc_table[i] = p; + crc_big_table[i] = ZSWAP64(p); + } + + /* initialize the x^2^n mod p(x) table */ + p = (uint32_t)1 << 30; /* x^1 */ + x2n_table[0] = p; + for (n = 1; n < 32; n++) + x2n_table[n] = p = multmodp(p, p); +} + +/* + Generate the little and big-endian braid tables for the given n and z_word_t + size w. Each array must have room for w blocks of 256 elements. + */ +static void braid(uint32_t ltl[][256], z_word_t big[][256], int n, int w) { + int k; + uint32_t i, p, q; + for (k = 0; k < w; k++) { + p = x2nmodp(((z_off64_t)n * w + 3 - k) << 3, 0); + ltl[k][0] = 0; + big[w - 1 - k][0] = 0; + for (i = 1; i < 256; i++) { + ltl[k][i] = q = multmodp(i << 24, p); + big[w - 1 - k][i] = ZSWAP64(q); + } + } +} + +/* + Write the 32-bit values in table[0..k-1] to out, five per line in + hexadecimal separated by commas. + */ +static void write_table(const uint32_t *table, int k) { + int n; + + for (n = 0; n < k; n++) + printf("%s0x%08" PRIx32 "%s", n == 0 || n % 5 ? "" : " ", + (uint32_t)(table[n]), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the high 32-bits of each value in table[0..k-1] to out, five per line + in hexadecimal separated by commas. + */ +static void write_table32hi(const z_word_t *table, int k) { + int n; + + for (n = 0; n < k; n++) + printf("%s0x%08" PRIx32 "%s", n == 0 || n % 5 ? "" : " ", + (uint32_t)(table[n] >> 32), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the 64-bit values in table[0..k-1] to out, three per line in + hexadecimal separated by commas. This assumes that if there is a 64-bit + type, then there is also a long long integer type, and it is at least 64 + bits. If not, then the type cast and format string can be adjusted + accordingly. + */ +static void write_table64(const z_word_t *table, int k) { + int n; + + for (n = 0; n < k; n++) + printf("%s0x%016" PRIx64 "%s", n == 0 || n % 3 ? "" : " ", + (uint64_t)(table[n]), + n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", ")); +} + +static void print_crc_table(void) { + int k, n; + uint32_t ltl[8][256]; + z_word_t big[8][256]; + + printf("#ifndef CRC32_BRAID_TBL_H_\n"); + printf("#define CRC32_BRAID_TBL_H_\n\n"); + printf("/* crc32_braid_tbl.h -- tables for braided CRC calculation\n"); + printf(" * Generated automatically by makecrct.c\n */\n\n"); + + /* print little-endian CRC table */ + printf("static const uint32_t crc_table[] = {\n"); + printf(" "); + write_table(crc_table, 256); + printf("};\n\n"); + + /* print big-endian CRC table for 64-bit z_word_t */ + printf("#ifdef W\n\n"); + printf("#if W == 8\n\n"); + printf("static const z_word_t crc_big_table[] = {\n"); + printf(" "); + write_table64(crc_big_table, 256); + printf("};\n\n"); + + /* print big-endian CRC table for 32-bit z_word_t */ + printf("#else /* W == 4 */\n\n"); + printf("static const z_word_t crc_big_table[] = {\n"); + printf(" "); + write_table32hi(crc_big_table, 256); + printf("};\n\n"); + printf("#endif\n\n"); + printf("#endif /* W */\n\n"); + + /* write out braid tables for each value of N */ + for (n = 1; n <= 6; n++) { + printf("#if N == %d\n", n); + + /* compute braid tables for this N and 64-bit word_t */ + braid(ltl, big, n, 8); + + /* write out braid tables for 64-bit z_word_t */ + printf("\n"); + printf("#if W == 8\n\n"); + printf("static const uint32_t crc_braid_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + printf(" {"); + write_table(ltl[k], 256); + printf("}%s", k < 7 ? ",\n" : ""); + } + printf("};\n\n"); + printf("static const z_word_t crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + printf(" {"); + write_table64(big[k], 256); + printf("}%s", k < 7 ? ",\n" : ""); + } + printf("};\n"); + + /* compute braid tables for this N and 32-bit word_t */ + braid(ltl, big, n, 4); + + /* write out braid tables for 32-bit z_word_t */ + printf("\n"); + printf("#else /* W == 4 */\n\n"); + printf("static const uint32_t crc_braid_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + printf(" {"); + write_table(ltl[k], 256); + printf("}%s", k < 3 ? ",\n" : ""); + } + printf("};\n\n"); + printf("static const z_word_t crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + printf(" {"); + write_table32hi(big[k], 256); + printf("}%s", k < 3 ? ",\n" : ""); + } + printf("};\n\n"); + printf("#endif /* W */\n\n"); + + printf("#endif /* N == %d */\n", n); + } + printf("\n"); + + /* write out zeros operator table */ + printf("static const uint32_t x2n_table[] = {\n"); + printf(" "); + write_table(x2n_table, 32); + printf("};\n"); + + printf("\n"); + printf("#endif /* CRC32_BRAID_TBL_H_ */\n"); +} + +// The output of this application can be piped out to recreate crc32 tables +int main(int argc, char *argv[]) { + Z_UNUSED(argc); + Z_UNUSED(argv); + + make_crc_table(); + print_crc_table(); + return 0; +} diff --git a/tools/makefixed.c b/tools/makefixed.c new file mode 100644 index 0000000000..7fe71e75ee --- /dev/null +++ b/tools/makefixed.c @@ -0,0 +1,89 @@ +#include +#include "zbuild.h" +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" + +// Build and return state with length and distance decoding tables and index sizes set to fixed code decoding. +void Z_INTERNAL buildfixedtables(struct inflate_state *state) { + static code *lenfix, *distfix; + static code fixed[544]; + + // build fixed huffman tables + unsigned sym, bits; + static code *next; + + // literal/length table + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + zng_inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + // distance table + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + zng_inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + + +// Create fixed tables on the fly and write out a inffixed_tbl.h file that is #include'd above. +// makefixed() writes those tables to stdout, which would be piped to inffixed_tbl.h. +void makefixed(void) { + unsigned low, size; + struct inflate_state state; + + memset(&state, 0, sizeof(state)); + buildfixedtables(&state); + puts("/* inffixed_tbl.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts("/* WARNING: this file should *not* be used by applications."); + puts(" * It is part of the implementation of this library and is"); + puts(" * subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf("static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) + printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) + break; + putchar(','); + } + puts("\n};"); + size = 1U << 5; + printf("\nstatic const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) + printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, state.distcode[low].val); + if (++low == size) + break; + putchar(','); + } + puts("\n};"); +} + +// The output of this application can be piped out to recreate inffixed_tbl.h +int main(void) { + makefixed(); + return 0; +} diff --git a/tools/maketrees.c b/tools/maketrees.c new file mode 100644 index 0000000000..2c32ccae08 --- /dev/null +++ b/tools/maketrees.c @@ -0,0 +1,147 @@ +/* maketrees.c -- output static huffman trees + * Copyright (C) 1995-2017 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include "zbuild.h" +#include "deflate.h" +#include "trees.h" + +static ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see zng_tr_init). + */ + +static ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use 5 bits.) + */ + +static unsigned char dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances 3 .. 258, + * the last 256 values correspond to the top 8 bits of the 15 bit distances. + */ + +static unsigned char length_code[STD_MAX_MATCH-STD_MIN_MATCH+1]; +/* length code for each normalized match length (0 == STD_MIN_MATCH) */ + +static int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = STD_MIN_MATCH) */ + +static int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + + +static void tr_static_init(void) { + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + uint16_t bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1 << extra_lbits[code]); n++) { + length_code[length++] = (unsigned char)code; + } + } + Assert(length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented in two different + * ways: code 284 + 5 bits or code 285, so we overwrite length_code[255] to use the best encoding: + */ + length_code[length-1] = (unsigned char)code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1 << extra_dbits[code]); n++) { + dist_code[dist++] = (unsigned char)code; + } + } + Assert(dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1 << (extra_dbits[code]-7)); n++) { + dist_code[256 + dist++] = (unsigned char)code; + } + } + Assert(dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) + bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the tree construction + * to get a canonical Huffman tree (longest code all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = PREFIX(bi_reverse)((unsigned)n, 5); + } +} + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +static void gen_trees_header(void) { + int i; + + printf("#ifndef TREES_TBL_H_\n"); + printf("#define TREES_TBL_H_\n\n"); + + printf("/* header created automatically with maketrees.c */\n\n"); + + printf("Z_INTERNAL const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + printf("{{%3u},{%u}}%s", static_ltree[i].Code, static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + printf("Z_INTERNAL const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + printf("{{%2u},{%u}}%s", static_dtree[i].Code, static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + printf("const unsigned char Z_INTERNAL zng_dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + printf("%2u%s", dist_code[i], SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + printf("const unsigned char Z_INTERNAL zng_length_code[STD_MAX_MATCH-STD_MIN_MATCH+1] = {\n"); + for (i = 0; i < STD_MAX_MATCH-STD_MIN_MATCH+1; i++) { + printf("%2u%s", length_code[i], SEPARATOR(i, STD_MAX_MATCH-STD_MIN_MATCH, 20)); + } + + printf("Z_INTERNAL const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + printf("%d%s", base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + printf("Z_INTERNAL const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + printf("%5d%s", base_dist[i], SEPARATOR(i, D_CODES-1, 10)); + } + + printf("#endif /* TREES_TBL_H_ */\n"); +} + +// The output of this application can be piped out to recreate trees.h +int main(void) { + tr_static_init(); + gen_trees_header(); + return 0; +} diff --git a/trees.c b/trees.c new file mode 100644 index 0000000000..9f2f49137f --- /dev/null +++ b/trees.c @@ -0,0 +1,818 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2024 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +#include "zbuild.h" +#include "deflate.h" +#include "trees.h" +#include "trees_emit.h" +#include "trees_tbl.h" + +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const int *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + unsigned int max_length; /* max bit length for the codes */ +}; + +static const static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +static const static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +static const static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +static void init_block (deflate_state *s); +static void pqdownheap (deflate_state *s, ct_data *tree, int k); +static void gen_bitlen (deflate_state *s, tree_desc *desc); +static void build_tree (deflate_state *s, tree_desc *desc); +static void scan_tree (deflate_state *s, ct_data *tree, int max_code); +static void send_tree (deflate_state *s, ct_data *tree, int max_code); +static int build_bl_tree (deflate_state *s); +static void send_all_trees (deflate_state *s, int lcodes, int dcodes, int blcodes); +static void compress_block (deflate_state *s, const ct_data *ltree, const ct_data *dtree); +static int detect_data_type (deflate_state *s); + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void Z_INTERNAL zng_tr_init(deflate_state *s) { + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +static void init_block(deflate_state *s) { + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) + s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) + s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) + s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->sym_next = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +static void pqdownheap(deflate_state *s, ct_data *tree, int k) { + /* tree: the tree to restore */ + /* k: node to move down */ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) + break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +static void gen_bitlen(deflate_state *s, tree_desc *desc) { + /* desc: the tree descriptor */ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const int *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + unsigned int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + unsigned int bits; /* bit length */ + int xbits; /* extra bits */ + uint16_t f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) + s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1u; + if (bits > max_length){ + bits = max_length; + overflow++; + } + tree[n].Len = (uint16_t)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) /* not a leaf node */ + continue; + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) + xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (unsigned long)f * (unsigned int)(bits + xbits); + if (stree) + s->static_len += (unsigned long)f * (unsigned int)(stree[n].Len + xbits); + } + if (overflow == 0) + return; + + Tracev((stderr, "\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length - 1; + while (s->bl_count[bits] == 0) + bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2u; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) + continue; + if (tree[m].Len != bits) { + Tracev((stderr, "code %d bits %d->%u\n", m, tree[m].Len, bits)); + s->opt_len += (unsigned long)(bits * tree[m].Freq); + s->opt_len -= (unsigned long)(tree[m].Len * tree[m].Freq); + tree[m].Len = (uint16_t)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +Z_INTERNAL void gen_codes(ct_data *tree, int max_code, uint16_t *bl_count) { + /* tree: the tree to decorate */ + /* max_code: largest code with non zero frequency */ + /* bl_count: number of codes at each bit length */ + uint16_t next_code[MAX_BITS+1]; /* next code value for each bit length */ + unsigned int code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits-1]) << 1; + next_code[bits] = (uint16_t)code; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert(code + bl_count[MAX_BITS]-1 == (1 << MAX_BITS)-1, "inconsistent bit counts"); + Tracev((stderr, "\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) + continue; + /* Now reverse the bits */ + tree[n].Code = PREFIX(bi_reverse)(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr, "\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n & 0xff) ? n : ' '), len, tree[n].Code, next_code[len]-1)); + } +} + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +static void build_tree(deflate_state *s, tree_desc *desc) { + /* desc: the tree descriptor */ + ct_data *tree = desc->dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0; + s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; + if (stree) + s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) + pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (unsigned char)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (uint16_t)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr, "\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +static void scan_tree(deflate_state *s, ct_data *tree, int max_code) { + /* tree: the tree to be scanned */ + /* max_code: and its largest code of non zero frequency */ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + uint16_t count = 0; /* repeat count of the current code */ + uint16_t max_count = 7; /* max repeat count */ + uint16_t min_count = 4; /* min repeat count */ + + if (nextlen == 0) + max_count = 138, min_count = 3; + + tree[max_code+1].Len = (uint16_t)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) + s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; + prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +static void send_tree(deflate_state *s, ct_data *tree, int max_code) { + /* tree: the tree to be scanned */ + /* max_code and its largest code of non zero frequency */ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) + max_count = 138, min_count = 3; + + // Temp local variables + uint32_t bi_valid = s->bi_valid; + uint64_t bi_buf = s->bi_buf; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { + send_code(s, curlen, s->bl_tree, bi_buf, bi_valid); + } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree, bi_buf, bi_valid); + count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree, bi_buf, bi_valid); + send_bits(s, count-3, 2, bi_buf, bi_valid); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree, bi_buf, bi_valid); + send_bits(s, count-3, 3, bi_buf, bi_valid); + + } else { + send_code(s, REPZ_11_138, s->bl_tree, bi_buf, bi_valid); + send_bits(s, count-11, 7, bi_buf, bi_valid); + } + count = 0; + prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } + + // Store back temp variables + s->bi_buf = bi_buf; + s->bi_valid = bi_valid; +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +static int build_bl_tree(deflate_state *s) { + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) + break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*((unsigned long)max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %lu, stat %lu", s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +static void send_all_trees(deflate_state *s, int lcodes, int dcodes, int blcodes) { + int rank; /* index in bl_order */ + + Assert(lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert(lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); + + // Temp local variables + uint32_t bi_valid = s->bi_valid; + uint64_t bi_buf = s->bi_buf; + + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5, bi_buf, bi_valid); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5, bi_buf, bi_valid); + send_bits(s, blcodes-4, 4, bi_buf, bi_valid); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2u ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3, bi_buf, bi_valid); + } + Tracev((stderr, "\nbl tree: sent %lu", s->bits_sent)); + + // Store back temp variables + s->bi_buf = bi_buf; + s->bi_valid = bi_valid; + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %lu", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %lu", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void Z_INTERNAL zng_tr_stored_block(deflate_state *s, char *buf, uint32_t stored_len, int last) { + /* buf: input block */ + /* stored_len: length of input block */ + /* last: one if this is the last block for a file */ + zng_tr_emit_tree(s, STORED_BLOCK, last); /* send block type */ + zng_tr_emit_align(s); /* align on byte boundary */ + cmpr_bits_align(s); + put_short(s, (uint16_t)stored_len); + put_short(s, (uint16_t)~stored_len); + cmpr_bits_add(s, 32); + sent_bits_add(s, 32); + if (stored_len) { + memcpy(s->pending_buf + s->pending, (unsigned char *)buf, stored_len); + s->pending += stored_len; + cmpr_bits_add(s, stored_len << 3); + sent_bits_add(s, stored_len << 3); + } +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +void Z_INTERNAL zng_tr_align(deflate_state *s) { + zng_tr_emit_tree(s, STATIC_TREES, 0); + zng_tr_emit_end_block(s, static_ltree, 0); + zng_tr_flush_bits(s); +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and write out the encoded block. + */ +void Z_INTERNAL zng_tr_flush_block(deflate_state *s, char *buf, uint32_t stored_len, int last) { + /* buf: input block, or NULL if too old */ + /* stored_len: length of input block */ + /* last: one if this is the last block for a file */ + unsigned long opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (UNLIKELY(s->sym_next == 0)) { + /* Emit an empty static tree block with no codes */ + opt_lenb = static_lenb = 0; + s->static_len = 7; + } else if (s->level > 0) { + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %lu, stat %lu", s->opt_len, s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %lu, stat %lu", s->opt_len, s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7) >> 3; + static_lenb = (s->static_len+3+7) >> 3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %u lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->sym_next / 3)); + + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) + opt_lenb = static_lenb; + + } else { + Assert(buf != NULL, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + if (stored_len+4 <= opt_lenb && buf != NULL) { + /* 4: two words for the lengths + * The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + zng_tr_stored_block(s, buf, stored_len, last); + + } else if (static_lenb == opt_lenb) { + zng_tr_emit_tree(s, STATIC_TREES, last); + compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); + cmpr_bits_add(s, s->static_len); + } else { + zng_tr_emit_tree(s, DYN_TREES, last); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); + compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); + cmpr_bits_add(s, s->opt_len); + } + Assert(s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and unsigned long implemented on 32 bits. + */ + init_block(s); + + if (last) { + zng_tr_emit_align(s); + } + Tracev((stderr, "\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*last)); +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +static void compress_block(deflate_state *s, const ct_data *ltree, const ct_data *dtree) { + /* ltree: literal tree */ + /* dtree: distance tree */ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned sx = 0; /* running index in symbol buffers */ + + if (s->sym_next != 0) { + do { +#ifdef LIT_MEM + dist = s->d_buf[sx]; + lc = s->l_buf[sx++]; +#else + dist = s->sym_buf[sx++] & 0xff; + dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; + lc = s->sym_buf[sx++]; +#endif + if (dist == 0) { + zng_emit_lit(s, ltree, lc); + } else { + zng_emit_dist(s, ltree, dtree, lc, dist); + } /* literal or match pair ? */ + + /* Check for no overlay of pending_buf on needed symbols */ +#ifdef LIT_MEM + Assert(s->pending < 2 * (s->lit_bufsize + sx), "pending_buf overflow"); +#else + Assert(s->pending < s->lit_bufsize + sx, "pending_buf overflow"); +#endif + } while (sx < s->sym_next); + } + + zng_emit_end_block(s, ltree, 0); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +static int detect_data_type(deflate_state *s) { + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long black_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>= 1) + if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("white-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +void Z_INTERNAL zng_tr_flush_bits(deflate_state *s) { + if (s->bi_valid >= 48) { + put_uint32(s, (uint32_t)s->bi_buf); + put_short(s, (uint16_t)(s->bi_buf >> 32)); + s->bi_buf >>= 48; + s->bi_valid -= 48; + } else if (s->bi_valid >= 32) { + put_uint32(s, (uint32_t)s->bi_buf); + s->bi_buf >>= 32; + s->bi_valid -= 32; + } + if (s->bi_valid >= 16) { + put_short(s, (uint16_t)s->bi_buf); + s->bi_buf >>= 16; + s->bi_valid -= 16; + } + if (s->bi_valid >= 8) { + put_byte(s, s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Reverse the first len bits of a code using bit manipulation + */ +Z_INTERNAL uint16_t PREFIX(bi_reverse)(unsigned code, int len) { + /* code: the value to invert */ + /* len: its bit length */ + Assert(len >= 1 && len <= 15, "code length must be 1-15"); +#define bitrev8(b) \ + (uint8_t)((((uint8_t)(b) * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32) + return (bitrev8(code >> 8) | (uint16_t)bitrev8(code) << 8) >> (16 - len); +} diff --git a/trees.h b/trees.h new file mode 100644 index 0000000000..e57f926489 --- /dev/null +++ b/trees.h @@ -0,0 +1,40 @@ +#ifndef TREES_H_ +#define TREES_H_ + +/* Constants */ + +#define DIST_CODE_LEN 512 +/* see definition of array dist_code in trees.c */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +static const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +static const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static const int extra_blbits[BL_CODES] /* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +static const unsigned char bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; + /* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + + +/* Function definitions */ +void gen_codes (ct_data *tree, int max_code, uint16_t *bl_count); + +#endif diff --git a/trees_emit.h b/trees_emit.h new file mode 100644 index 0000000000..b5295ee483 --- /dev/null +++ b/trees_emit.h @@ -0,0 +1,231 @@ +#ifndef TREES_EMIT_H_ +#define TREES_EMIT_H_ + +#include "zbuild.h" +#include "trees.h" + +#ifdef ZLIB_DEBUG +# include +# include +#endif + + +/* trees.h */ +extern Z_INTERNAL const ct_data static_ltree[L_CODES+2]; +extern Z_INTERNAL const ct_data static_dtree[D_CODES]; + +extern const unsigned char Z_INTERNAL zng_dist_code[DIST_CODE_LEN]; +extern const unsigned char Z_INTERNAL zng_length_code[STD_MAX_MATCH-STD_MIN_MATCH+1]; + +extern Z_INTERNAL const int base_length[LENGTH_CODES]; +extern Z_INTERNAL const int base_dist[D_CODES]; + +/* Bit buffer and deflate code stderr tracing */ +#ifdef ZLIB_DEBUG +# define send_bits_trace(s, value, length) { \ + Tracevv((stderr, " l %2d v %4llx ", (int)(length), (long long)(value))); \ + Assert(length > 0 && length <= BIT_BUF_SIZE, "invalid length"); \ + } +# define send_code_trace(s, c) \ + if (z_verbose > 2) { \ + fprintf(stderr, "\ncd %3d ", (c)); \ + } +#else +# define send_bits_trace(s, value, length) +# define send_code_trace(s, c) +#endif + +/* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (64 - bi_valid) bits from value, leaving (width - (64-bi_valid)) + * unused bits in value. + * + * NOTE: Static analyzers can't evaluate value of total_bits, so we + * also need to make sure bi_valid is within acceptable range, + * otherwise the shifts will overflow. + */ +#define send_bits(s, t_val, t_len, bi_buf, bi_valid) {\ + uint64_t val = (uint64_t)t_val;\ + uint32_t len = (uint32_t)t_len;\ + uint32_t total_bits = bi_valid + len;\ + send_bits_trace(s, val, len);\ + sent_bits_add(s, len);\ + if (total_bits < BIT_BUF_SIZE && bi_valid < BIT_BUF_SIZE) {\ + bi_buf |= val << bi_valid;\ + bi_valid = total_bits;\ + } else if (bi_valid >= BIT_BUF_SIZE) {\ + put_uint64(s, bi_buf);\ + bi_buf = val;\ + bi_valid = len;\ + } else {\ + bi_buf |= val << bi_valid;\ + put_uint64(s, bi_buf);\ + bi_buf = val >> (BIT_BUF_SIZE - bi_valid);\ + bi_valid = total_bits - BIT_BUF_SIZE;\ + }\ +} + +/* Send a code of the given tree. c and tree must not have side effects */ +#ifdef ZLIB_DEBUG +# define send_code(s, c, tree, bi_buf, bi_valid) { \ + send_code_trace(s, c); \ + send_bits(s, tree[c].Code, tree[c].Len, bi_buf, bi_valid); \ +} +#else +# define send_code(s, c, tree, bi_buf, bi_valid) \ + send_bits(s, tree[c].Code, tree[c].Len, bi_buf, bi_valid) +#endif + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +static void bi_windup(deflate_state *s) { + if (s->bi_valid > 56) { + put_uint64(s, s->bi_buf); + } else { + if (s->bi_valid > 24) { + put_uint32(s, (uint32_t)s->bi_buf); + s->bi_buf >>= 32; + s->bi_valid -= 32; + } + if (s->bi_valid > 8) { + put_short(s, (uint16_t)s->bi_buf); + s->bi_buf >>= 16; + s->bi_valid -= 16; + } + if (s->bi_valid > 0) { + put_byte(s, s->bi_buf); + } + } + s->bi_buf = 0; + s->bi_valid = 0; +} + +/* =========================================================================== + * Emit literal code + */ +static inline uint32_t zng_emit_lit(deflate_state *s, const ct_data *ltree, unsigned c) { + uint32_t bi_valid = s->bi_valid; + uint64_t bi_buf = s->bi_buf; + + send_code(s, c, ltree, bi_buf, bi_valid); + + s->bi_valid = bi_valid; + s->bi_buf = bi_buf; + + Tracecv(isgraph(c & 0xff), (stderr, " '%c' ", c)); + + return ltree[c].Len; +} + +/* =========================================================================== + * Emit match distance/length code + */ +static inline uint32_t zng_emit_dist(deflate_state *s, const ct_data *ltree, const ct_data *dtree, + uint32_t lc, uint32_t dist) { + uint32_t c, extra; + uint8_t code; + uint64_t match_bits; + uint32_t match_bits_len; + uint32_t bi_valid = s->bi_valid; + uint64_t bi_buf = s->bi_buf; + + /* Send the length code, len is the match length - STD_MIN_MATCH */ + code = zng_length_code[lc]; + c = code+LITERALS+1; + Assert(c < L_CODES, "bad l_code"); + send_code_trace(s, c); + + match_bits = ltree[c].Code; + match_bits_len = ltree[c].Len; + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + match_bits |= ((uint64_t)lc << match_bits_len); + match_bits_len += extra; + } + + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert(code < D_CODES, "bad d_code"); + send_code_trace(s, code); + + /* Send the distance code */ + match_bits |= ((uint64_t)dtree[code].Code << match_bits_len); + match_bits_len += dtree[code].Len; + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + match_bits |= ((uint64_t)dist << match_bits_len); + match_bits_len += extra; + } + + send_bits(s, match_bits, match_bits_len, bi_buf, bi_valid); + + s->bi_valid = bi_valid; + s->bi_buf = bi_buf; + + return match_bits_len; +} + +/* =========================================================================== + * Emit end block + */ +static inline void zng_emit_end_block(deflate_state *s, const ct_data *ltree, const int last) { + uint32_t bi_valid = s->bi_valid; + uint64_t bi_buf = s->bi_buf; + send_code(s, END_BLOCK, ltree, bi_buf, bi_valid); + s->bi_valid = bi_valid; + s->bi_buf = bi_buf; + Tracev((stderr, "\n+++ Emit End Block: Last: %u Pending: %u Total Out: %" PRIu64 "\n", + last, s->pending, (uint64_t)s->strm->total_out)); + Z_UNUSED(last); +} + +/* =========================================================================== + * Emit literal and count bits + */ +static inline void zng_tr_emit_lit(deflate_state *s, const ct_data *ltree, unsigned c) { + cmpr_bits_add(s, zng_emit_lit(s, ltree, c)); +} + +/* =========================================================================== + * Emit match and count bits + */ +static inline void zng_tr_emit_dist(deflate_state *s, const ct_data *ltree, const ct_data *dtree, + uint32_t lc, uint32_t dist) { + cmpr_bits_add(s, zng_emit_dist(s, ltree, dtree, lc, dist)); +} + +/* =========================================================================== + * Emit start of block + */ +static inline void zng_tr_emit_tree(deflate_state *s, int type, const int last) { + uint32_t bi_valid = s->bi_valid; + uint64_t bi_buf = s->bi_buf; + uint32_t header_bits = (type << 1) + last; + send_bits(s, header_bits, 3, bi_buf, bi_valid); + cmpr_bits_add(s, 3); + s->bi_valid = bi_valid; + s->bi_buf = bi_buf; + Tracev((stderr, "\n--- Emit Tree: Last: %u\n", last)); +} + +/* =========================================================================== + * Align bit buffer on a byte boundary and count bits + */ +static inline void zng_tr_emit_align(deflate_state *s) { + bi_windup(s); /* align on byte boundary */ + sent_bits_align(s); +} + +/* =========================================================================== + * Emit an end block and align bit buffer if last block + */ +static inline void zng_tr_emit_end_block(deflate_state *s, const ct_data *ltree, const int last) { + zng_emit_end_block(s, ltree, last); + cmpr_bits_add(s, 7); + if (last) + zng_tr_emit_align(s); +} + +#endif diff --git a/trees_tbl.h b/trees_tbl.h new file mode 100644 index 0000000000..a3912b7fd7 --- /dev/null +++ b/trees_tbl.h @@ -0,0 +1,132 @@ +#ifndef TREES_TBL_H_ +#define TREES_TBL_H_ + +/* header created automatically with maketrees.c */ + +Z_INTERNAL const ct_data static_ltree[L_CODES+2] = { +{{ 12},{8}}, {{140},{8}}, {{ 76},{8}}, {{204},{8}}, {{ 44},{8}}, +{{172},{8}}, {{108},{8}}, {{236},{8}}, {{ 28},{8}}, {{156},{8}}, +{{ 92},{8}}, {{220},{8}}, {{ 60},{8}}, {{188},{8}}, {{124},{8}}, +{{252},{8}}, {{ 2},{8}}, {{130},{8}}, {{ 66},{8}}, {{194},{8}}, +{{ 34},{8}}, {{162},{8}}, {{ 98},{8}}, {{226},{8}}, {{ 18},{8}}, +{{146},{8}}, {{ 82},{8}}, {{210},{8}}, {{ 50},{8}}, {{178},{8}}, +{{114},{8}}, {{242},{8}}, {{ 10},{8}}, {{138},{8}}, {{ 74},{8}}, +{{202},{8}}, {{ 42},{8}}, {{170},{8}}, {{106},{8}}, {{234},{8}}, +{{ 26},{8}}, {{154},{8}}, {{ 90},{8}}, {{218},{8}}, {{ 58},{8}}, +{{186},{8}}, {{122},{8}}, {{250},{8}}, {{ 6},{8}}, {{134},{8}}, +{{ 70},{8}}, {{198},{8}}, {{ 38},{8}}, {{166},{8}}, {{102},{8}}, +{{230},{8}}, {{ 22},{8}}, {{150},{8}}, {{ 86},{8}}, {{214},{8}}, +{{ 54},{8}}, {{182},{8}}, {{118},{8}}, {{246},{8}}, {{ 14},{8}}, +{{142},{8}}, {{ 78},{8}}, {{206},{8}}, {{ 46},{8}}, {{174},{8}}, +{{110},{8}}, {{238},{8}}, {{ 30},{8}}, {{158},{8}}, {{ 94},{8}}, +{{222},{8}}, {{ 62},{8}}, {{190},{8}}, {{126},{8}}, {{254},{8}}, +{{ 1},{8}}, {{129},{8}}, {{ 65},{8}}, {{193},{8}}, {{ 33},{8}}, +{{161},{8}}, {{ 97},{8}}, {{225},{8}}, {{ 17},{8}}, {{145},{8}}, +{{ 81},{8}}, {{209},{8}}, {{ 49},{8}}, {{177},{8}}, {{113},{8}}, +{{241},{8}}, {{ 9},{8}}, {{137},{8}}, {{ 73},{8}}, {{201},{8}}, +{{ 41},{8}}, {{169},{8}}, {{105},{8}}, {{233},{8}}, {{ 25},{8}}, +{{153},{8}}, {{ 89},{8}}, {{217},{8}}, {{ 57},{8}}, {{185},{8}}, +{{121},{8}}, {{249},{8}}, {{ 5},{8}}, {{133},{8}}, {{ 69},{8}}, +{{197},{8}}, {{ 37},{8}}, {{165},{8}}, {{101},{8}}, {{229},{8}}, +{{ 21},{8}}, {{149},{8}}, {{ 85},{8}}, {{213},{8}}, {{ 53},{8}}, +{{181},{8}}, {{117},{8}}, {{245},{8}}, {{ 13},{8}}, {{141},{8}}, +{{ 77},{8}}, {{205},{8}}, {{ 45},{8}}, {{173},{8}}, {{109},{8}}, +{{237},{8}}, {{ 29},{8}}, {{157},{8}}, {{ 93},{8}}, {{221},{8}}, +{{ 61},{8}}, {{189},{8}}, {{125},{8}}, {{253},{8}}, {{ 19},{9}}, +{{275},{9}}, {{147},{9}}, {{403},{9}}, {{ 83},{9}}, {{339},{9}}, +{{211},{9}}, {{467},{9}}, {{ 51},{9}}, {{307},{9}}, {{179},{9}}, +{{435},{9}}, {{115},{9}}, {{371},{9}}, {{243},{9}}, {{499},{9}}, +{{ 11},{9}}, {{267},{9}}, {{139},{9}}, {{395},{9}}, {{ 75},{9}}, +{{331},{9}}, {{203},{9}}, {{459},{9}}, {{ 43},{9}}, {{299},{9}}, +{{171},{9}}, {{427},{9}}, {{107},{9}}, {{363},{9}}, {{235},{9}}, +{{491},{9}}, {{ 27},{9}}, {{283},{9}}, {{155},{9}}, {{411},{9}}, +{{ 91},{9}}, {{347},{9}}, {{219},{9}}, {{475},{9}}, {{ 59},{9}}, +{{315},{9}}, {{187},{9}}, {{443},{9}}, {{123},{9}}, {{379},{9}}, +{{251},{9}}, {{507},{9}}, {{ 7},{9}}, {{263},{9}}, {{135},{9}}, +{{391},{9}}, {{ 71},{9}}, {{327},{9}}, {{199},{9}}, {{455},{9}}, +{{ 39},{9}}, {{295},{9}}, {{167},{9}}, {{423},{9}}, {{103},{9}}, +{{359},{9}}, {{231},{9}}, {{487},{9}}, {{ 23},{9}}, {{279},{9}}, +{{151},{9}}, {{407},{9}}, {{ 87},{9}}, {{343},{9}}, {{215},{9}}, +{{471},{9}}, {{ 55},{9}}, {{311},{9}}, {{183},{9}}, {{439},{9}}, +{{119},{9}}, {{375},{9}}, {{247},{9}}, {{503},{9}}, {{ 15},{9}}, +{{271},{9}}, {{143},{9}}, {{399},{9}}, {{ 79},{9}}, {{335},{9}}, +{{207},{9}}, {{463},{9}}, {{ 47},{9}}, {{303},{9}}, {{175},{9}}, +{{431},{9}}, {{111},{9}}, {{367},{9}}, {{239},{9}}, {{495},{9}}, +{{ 31},{9}}, {{287},{9}}, {{159},{9}}, {{415},{9}}, {{ 95},{9}}, +{{351},{9}}, {{223},{9}}, {{479},{9}}, {{ 63},{9}}, {{319},{9}}, +{{191},{9}}, {{447},{9}}, {{127},{9}}, {{383},{9}}, {{255},{9}}, +{{511},{9}}, {{ 0},{7}}, {{ 64},{7}}, {{ 32},{7}}, {{ 96},{7}}, +{{ 16},{7}}, {{ 80},{7}}, {{ 48},{7}}, {{112},{7}}, {{ 8},{7}}, +{{ 72},{7}}, {{ 40},{7}}, {{104},{7}}, {{ 24},{7}}, {{ 88},{7}}, +{{ 56},{7}}, {{120},{7}}, {{ 4},{7}}, {{ 68},{7}}, {{ 36},{7}}, +{{100},{7}}, {{ 20},{7}}, {{ 84},{7}}, {{ 52},{7}}, {{116},{7}}, +{{ 3},{8}}, {{131},{8}}, {{ 67},{8}}, {{195},{8}}, {{ 35},{8}}, +{{163},{8}}, {{ 99},{8}}, {{227},{8}} +}; + +Z_INTERNAL const ct_data static_dtree[D_CODES] = { +{{ 0},{5}}, {{16},{5}}, {{ 8},{5}}, {{24},{5}}, {{ 4},{5}}, +{{20},{5}}, {{12},{5}}, {{28},{5}}, {{ 2},{5}}, {{18},{5}}, +{{10},{5}}, {{26},{5}}, {{ 6},{5}}, {{22},{5}}, {{14},{5}}, +{{30},{5}}, {{ 1},{5}}, {{17},{5}}, {{ 9},{5}}, {{25},{5}}, +{{ 5},{5}}, {{21},{5}}, {{13},{5}}, {{29},{5}}, {{ 3},{5}}, +{{19},{5}}, {{11},{5}}, {{27},{5}}, {{ 7},{5}}, {{23},{5}} +}; + +const unsigned char Z_INTERNAL zng_dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const unsigned char Z_INTERNAL zng_length_code[STD_MAX_MATCH-STD_MIN_MATCH+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +Z_INTERNAL const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +Z_INTERNAL const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + +#endif /* TREES_TBL_H_ */ diff --git a/uncompr.c b/uncompr.c new file mode 100644 index 0000000000..311eca2b06 --- /dev/null +++ b/uncompr.c @@ -0,0 +1,80 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zutil.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. *sourceLen is + the byte length of the source buffer. Upon entry, *destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, + *destLen is the size of the decompressed data and *sourceLen is the number + of source bytes consumed. Upon return, source + *sourceLen points to the + first unused input byte. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, or + Z_DATA_ERROR if the input data was corrupted, including if the input data is + an incomplete zlib stream. +*/ +int Z_EXPORT PREFIX(uncompress2)(unsigned char *dest, z_uintmax_t *destLen, const unsigned char *source, z_uintmax_t *sourceLen) { + PREFIX3(stream) stream; + int err; + const unsigned int max = (unsigned int)-1; + z_uintmax_t len, left; + unsigned char buf[1]; /* for detection of incomplete stream when *destLen == 0 */ + + len = *sourceLen; + if (*destLen) { + left = *destLen; + *destLen = 0; + } else { + left = 1; + dest = buf; + } + + stream.next_in = (z_const unsigned char *)source; + stream.avail_in = 0; + stream.zalloc = NULL; + stream.zfree = NULL; + stream.opaque = NULL; + + err = PREFIX(inflateInit)(&stream); + if (err != Z_OK) return err; + + stream.next_out = dest; + stream.avail_out = 0; + + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (unsigned long)max ? max : (unsigned int)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = len > (unsigned long)max ? max : (unsigned int)len; + len -= stream.avail_in; + } + err = PREFIX(inflate)(&stream, Z_NO_FLUSH); + } while (err == Z_OK); + + *sourceLen -= len + stream.avail_in; + if (dest != buf) + *destLen = (z_size_t)stream.total_out; + else if (stream.total_out && err == Z_BUF_ERROR) + left = 1; + + PREFIX(inflateEnd)(&stream); + return err == Z_STREAM_END ? Z_OK : + err == Z_NEED_DICT ? Z_DATA_ERROR : + err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : + err; +} + +int Z_EXPORT PREFIX(uncompress)(unsigned char *dest, z_uintmax_t *destLen, const unsigned char *source, z_uintmax_t sourceLen) { + return PREFIX(uncompress2)(dest, destLen, source, &sourceLen); +} diff --git a/win32/Makefile.a64 b/win32/Makefile.a64 new file mode 100644 index 0000000000..3209f6a305 --- /dev/null +++ b/win32/Makefile.a64 @@ -0,0 +1,252 @@ +# Makefile for zlib using Microsoft (Visual) C +# zlib is copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler +# +# Usage: +# nmake -f win32/Makefile.a64 (standard build) +# nmake -f win32/Makefile.a64 LOC=-DFOO (nonstandard build) + +# The toplevel directory of the source tree. +# +TOP = . + +# optional build flags +LOC = + +# variables +STATICLIB = zlib.lib +SHAREDLIB = zlib1.dll +IMPLIB = zdll.lib +SYMBOL_PREFIX = + +CC = cl +LD = link +AR = lib +RC = rc +CP = copy /y +INCLUDES = -I$(TOP) -I$(TOP)/arch/arm -I$(TOP)/arch/generic +CFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi -Fd"zlib" $(LOC) $(INCLUDES) +WFLAGS = \ + -D_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1 \ + -D_CRT_SECURE_NO_DEPRECATE \ + -D_CRT_NONSTDC_NO_DEPRECATE \ + -DARM_FEATURES \ + -DARM_NEON_HASLD4 \ + # +LDFLAGS = -nologo -debug -incremental:no -opt:ref -manifest +ARFLAGS = -nologo +RCFLAGS = /dARM64 /r +DEFFILE = zlib.def +RCFILE = zlib1.rc +RESFILE = zlib1.res +WITH_GZFILEOP = yes +ZLIB_COMPAT = +SUFFIX = + +OBJS = \ + adler32.obj \ + adler32_c.obj \ + adler32_fold_c.obj \ + arm_features.obj \ + chunkset_c.obj \ + compare256_c.obj \ + compress.obj \ + cpu_features.obj \ + crc32.obj \ + crc32_braid_c.obj \ + crc32_braid_comb.obj \ + crc32_fold_c.obj \ + deflate.obj \ + deflate_fast.obj \ + deflate_huff.obj \ + deflate_medium.obj \ + deflate_quick.obj \ + deflate_rle.obj \ + deflate_slow.obj \ + deflate_stored.obj \ + functable.obj \ + infback.obj \ + inflate.obj \ + inftrees.obj \ + insert_string.obj \ + insert_string_roll.obj \ + slide_hash_c.obj \ + trees.obj \ + uncompr.obj \ + zutil.obj \ + # +!if "$(ZLIB_COMPAT)" != "" +WITH_GZFILEOP = yes +WFLAGS = $(WFLAGS) -DZLIB_COMPAT +DEFFILE = zlibcompat.def +!else +STATICLIB = zlib-ng.lib +SHAREDLIB = zlib-ng1.dll +IMPLIB = zngdll.lib +DEFFILE = zlib-ng.def +RCFILE = zlib-ng1.rc +RESFILE = zlib-ng1.res +SUFFIX = -ng +!endif + +!if "$(WITH_GZFILEOP)" != "" +WFLAGS = $(WFLAGS) -DWITH_GZFILEOP +OBJS = $(OBJS) gzlib.obj gzread.obj gzwrite.obj +!endif + +WFLAGS = $(WFLAGS) \ + -DARM_ACLE \ + -D__ARM_NEON__=1 \ + -DARM_NEON \ + -DARM_NOCHECK_NEON \ + # +OBJS = $(OBJS) crc32_acle.obj adler32_neon.obj chunkset_neon.obj compare256_neon.obj slide_hash_neon.obj + +# targets +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) \ + example.exe minigzip.exe example_d.exe minigzip_d.exe + +!if "$(SYMBOL_PREFIX)" != "" +zlib_name_mangling$(SUFFIX).h: zlib_name_mangling$(SUFFIX).h.in + cscript $(TOP)\win32\replace.vbs $(TOP)\zlib_name_mangling$(SUFFIX).h.in zlib_name_mangling$(SUFFIX).h "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" +!else +zlib_name_mangling$(SUFFIX).h: zlib_name_mangling.h.empty + $(CP) $(TOP)\zlib_name_mangling.h.empty zlib_name_mangling$(SUFFIX).h +!endif + +zlib$(SUFFIX).h: zlib$(SUFFIX).h.in + cscript $(TOP)\win32\replace.vbs $(TOP)\zlib$(SUFFIX).h.in zlib$(SUFFIX).h "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" + +gzread.c: gzread.c.in + cscript $(TOP)\win32\replace.vbs $(TOP)\gzread.c.in gzread.c "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" + +zconf: $(TOP)/zconf$(SUFFIX).h.in $(TOP)/zlib$(SUFFIX).h $(TOP)/zlib_name_mangling$(SUFFIX).h + $(CP) $(TOP)\zconf$(SUFFIX).h.in $(TOP)\zconf$(SUFFIX).h + +$(TOP)/win32/$(DEFFILE): $(TOP)/win32/$(DEFFILE).in + cscript $(TOP)\win32\replace.vbs $(TOP)/win32/$(DEFFILE).in $(TOP)/win32/$(DEFFILE) "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" + +$(STATICLIB): zconf $(OBJS) + $(AR) $(ARFLAGS) -out:$@ $(OBJS) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): zconf $(TOP)/win32/$(DEFFILE) $(OBJS) $(RESFILE) + $(LD) $(LDFLAGS) -def:$(TOP)/win32/$(DEFFILE) -dll -implib:$(IMPLIB) \ + -out:$@ -base:0x55A4C0000 $(OBJS) $(RESFILE) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;2 + +example.exe: example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + $(LD) $(LDFLAGS) example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip.exe: minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + $(LD) $(LDFLAGS) minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +example_d.exe: example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip_d.exe: minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +{$(TOP)}.c.obj: + $(CC) -c $(WFLAGS) $(CFLAGS) $< + +gzlib2.obj: gzlib.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h + $(CC) -c $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP -Fogzlib2.obj gzlib.c + +gzread2.obj: gzread.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h + $(CC) -c $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP -Fogzread2.obj gzread.c + +gzwrite2.obj: gzwrite.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h + $(CC) -c $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP -Fogzwrite2.obj gzwrite.c + +{$(TOP)/arch/arm}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/arch/generic}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/test}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP $< + +$(TOP)/zconf$(SUFFIX).h: zconf + +adler32.obj: $(TOP)/adler32.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/adler32_p.h +adler32_c.obj: $(TOP)/arch/generic/adler32_c.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/adler32_p.h +adler32_fold_c.obj: $(TOP)/arch/generic/adler32_fold_c.c $(TOP)/zbuild.h $(TOP)/functable.h +chunkset_c.obj: $(TOP)/arch/generic/chunkset_c.c $(TOP)/zbuild.h $(TOP)/chunkset_tpl.h $(TOP)/inffast_tpl.h +compare256_c.obj: $(TOP)/arch/generic/compare256_c.c $(TOP)/zbuild.h $(TOP)/zmemory.h $(TOP)/deflate.h $(TOP)/fallback_builtins.h $(TOP)/match_tpl.h +compress.obj: $(TOP)/compress.c $(TOP)/zbuild.h $(TOP)/zutil.h +cpu_features.obj: $(TOP)/cpu_features.c $(TOP)/cpu_features.h $(TOP)/zbuild.h +crc32.obj: $(TOP)/crc32.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/crc32_braid_tbl.h +crc32_braid_c.obj: $(TOP)/arch/generic/crc32_braid_c.c $(TOP)/zbuild.h $(TOP)/crc32_braid_p.h $(TOP)/crc32_braid_tbl.h +crc32_braid_comb.obj: $(TOP)/crc32_braid_comb.c $(TOP)/zutil.h $(TOP)/crc32_braid_p.h $(TOP)/crc32_braid_tbl.h $(TOP)/crc32_braid_comb_p.h +crc32_fold_c.obj: $(TOP)/arch/generic/crc32_fold_c.c $(TOP)/zbuild.h $(TOP)/crc32.h $(TOP)/functable.h $(TOP)/zutil.h +deflate.obj: $(TOP)/deflate.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_fast.obj: $(TOP)/deflate_fast.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_huff.obj: $(TOP)/deflate_huff.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_medium.obj: $(TOP)/deflate_medium.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_quick.obj: $(TOP)/deflate_quick.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h $(TOP)/trees_emit.h $(TOP)/zmemory.h +deflate_rle.obj: $(TOP)/deflate_rle.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h $(TOP)/compare256_rle.h +deflate_slow.obj: $(TOP)/deflate_slow.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_stored.obj: $(TOP)/deflate_stored.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +functable.obj: $(TOP)/functable.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/cpu_features.h $(TOP)/arch/arm/arm_features.h $(TOP)/arch_functions.h +gzlib.obj: $(TOP)/gzlib.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h +gzread.obj: $(TOP)/gzread.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h +gzwrite.obj: $(TOP)/gzwrite.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h +infback.obj: $(TOP)/infback.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/inftrees.h $(TOP)/inflate.h $(TOP)/inflate_p.h $(TOP)/functable.h +inflate.obj: $(TOP)/inflate.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/inftrees.h $(TOP)/inflate.h $(TOP)/inflate_p.h $(TOP)/functable.h $(TOP)/inffixed_tbl.h +inftrees.obj: $(TOP)/inftrees.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/inftrees.h +insert_string.obj: $(TOP)/insert_string.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/insert_string_tpl.h +insert_string_roll.obj: $(TOP)/insert_string_roll.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/insert_string_tpl.h +slide_hash_c.obj: $(TOP)/arch/generic/slide_hash_c.c $(TOP)/zbuild.h $(TOP)/deflate.h +slide_hash_neon.obj: $(TOP)/arch/arm/slide_hash_neon.c $(TOP)/arch/arm/neon_intrins.h $(TOP)/zbuild.h $(TOP)/deflate.h +trees.obj: $(TOP)/trees.c $(TOP)/trees.h $(TOP)/trees_emit.h $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/trees_tbl.h +uncompr.obj: $(TOP)/uncompr.c $(TOP)/zbuild.h $(TOP)/zutil.h +zutil.obj: $(TOP)/zutil.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/zutil_p.h + +$(RESFILE): $(TOP)/win32/$(RCFILE) + $(RC) $(RCFLAGS) /fo$@ $(TOP)/win32/$(RCFILE) + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +testdll: example_d.exe minigzip_d.exe + example_d + echo hello world | minigzip_d | minigzip_d -d + +example.obj: $(TOP)/test/example.c $(TOP)/zbuild.h $(TOP)/zlib$(SUFFIX).h $(TOP)/deflate.h $(TOP)/test/test_shared_ng.h + +minigzip.obj: $(TOP)/test/minigzip.c $(TOP)/zbuild.h $(TOP)/zlib$(SUFFIX).h + + +# cleanup +clean: + -del $(STATICLIB) + -del $(SHAREDLIB) + -del $(IMPLIB) + -del *.obj + -del *.res + -del *.exp + -del *.exe + -del *.pdb + -del *.manifest + +distclean: clean + -del zconf$(SUFFIX).h + -del zlib$(SUFFIX).h + -del zlib_name_mangling$(SUFFIX).h + -del $(TOP)\win32\zlib.def + -del $(TOP)\win32\zlibcompat.def + -del $(TOP)\win32\zlib-ng.def + -del gzread.c diff --git a/win32/Makefile.arm b/win32/Makefile.arm new file mode 100644 index 0000000000..54da045ffd --- /dev/null +++ b/win32/Makefile.arm @@ -0,0 +1,272 @@ +# Makefile for zlib using Microsoft (Visual) C +# zlib is copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler +# +# Usage: +# nmake -f win32/Makefile.arm (standard build) +# nmake -f win32/Makefile.arm LOC=-DFOO (nonstandard build) + +# The toplevel directory of the source tree. +# +TOP = . + +# optional build flags +LOC = + +# variables +STATICLIB = zlib.lib +SHAREDLIB = zlib1.dll +IMPLIB = zdll.lib +SYMBOL_PREFIX = + +CC = cl +LD = link +AR = lib +RC = rc +CP = copy /y +INCLUDES = -I$(TOP) -I$(TOP)/arch/arm -I$(TOP)/arch/generic +CFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi -Fd"zlib" $(LOC) $(INCLUDES) +WFLAGS = \ + -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1 \ + -D_CRT_SECURE_NO_DEPRECATE \ + -D_CRT_NONSTDC_NO_DEPRECATE \ + -DARM_FEATURES \ + -DARM_NEON_HASLD4 \ + # +LDFLAGS = -nologo -debug -incremental:no -opt:ref -manifest +ARFLAGS = -nologo +RCFLAGS = /dARM /r +DEFFILE = zlib.def +RCFILE = zlib1.rc +RESFILE = zlib1.res +WITH_GZFILEOP = yes +ZLIB_COMPAT = +WITH_ACLE = +WITH_NEON = +WITH_ARMV6 = +WITH_VFPV3 = +NEON_ARCH = /arch:VFPv4 +SUFFIX = + +OBJS = \ + adler32.obj \ + adler32_c.obj \ + adler32_fold_c.obj \ + arm_features.obj \ + chunkset_c.obj \ + compare256_c.obj \ + compress.obj \ + cpu_features.obj \ + crc32.obj \ + crc32_braid_c.obj \ + crc32_braid_comb.obj \ + crc32_fold_c.obj \ + deflate.obj \ + deflate_fast.obj \ + deflate_huff.obj \ + deflate_medium.obj \ + deflate_quick.obj \ + deflate_rle.obj \ + deflate_slow.obj \ + deflate_stored.obj \ + functable.obj \ + infback.obj \ + inflate.obj \ + inftrees.obj \ + insert_string.obj \ + insert_string_roll.obj \ + slide_hash_c.obj \ + trees.obj \ + uncompr.obj \ + zutil.obj \ + # +!if "$(ZLIB_COMPAT)" != "" +WITH_GZFILEOP = yes +WFLAGS = $(WFLAGS) -DZLIB_COMPAT +DEFFILE = zlibcompat.def +!else +STATICLIB = zlib-ng.lib +SHAREDLIB = zlib-ng1.dll +IMPLIB = zngdll.lib +DEFFILE = zlib-ng.def +RCFILE = zlib-ng1.rc +RESFILE = zlib-ng1.res +SUFFIX = -ng +!endif + +!if "$(WITH_GZFILEOP)" != "" +WFLAGS = $(WFLAGS) -DWITH_GZFILEOP +OBJS = $(OBJS) gzlib.obj gzread.obj gzwrite.obj +!endif + +!if "$(WITH_ACLE)" != "" +WFLAGS = $(WFLAGS) -DARM_ACLE +OBJS = $(OBJS) crc32_acle.obj +!endif +!if "$(WITH_VFPV3)" != "" +NEON_ARCH = /arch:VFPv3 +!endif +!if "$(WITH_NEON)" != "" +CFLAGS = $(CFLAGS) $(NEON_ARCH) +WFLAGS = $(WFLAGS) \ + -D__ARM_NEON__=1 \ + -DARM_NEON \ + -DARM_NOCHECK_NEON \ + # +OBJS = $(OBJS) adler32_neon.obj chunkset_neon.obj compare256_neon.obj slide_hash_neon.obj +!endif +!if "$(WITH_ARMV6)" != "" +WFLAGS = $(WFLAGS) \ + -DARM_SIMD \ + -DARM_NOCHECK_SIMD \ + # +OBJS = $(OBJS) slide_hash_armv6.obj +!endif + +# targets +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) \ + example.exe minigzip.exe example_d.exe minigzip_d.exe + +!if "$(SYMBOL_PREFIX)" != "" +zlib_name_mangling$(SUFFIX).h: zlib_name_mangling$(SUFFIX).h.in + cscript $(TOP)\win32\replace.vbs $(TOP)\zlib_name_mangling$(SUFFIX).h.in zlib_name_mangling$(SUFFIX).h "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" +!else +zlib_name_mangling$(SUFFIX).h: zlib_name_mangling.h.empty + $(CP) $(TOP)\zlib_name_mangling.h.empty zlib_name_mangling$(SUFFIX).h +!endif + +zlib$(SUFFIX).h: zlib$(SUFFIX).h.in + cscript $(TOP)\win32\replace.vbs $(TOP)\zlib$(SUFFIX).h.in zlib$(SUFFIX).h "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" + +gzread.c: gzread.c.in + cscript $(TOP)\win32\replace.vbs $(TOP)\gzread.c.in gzread.c "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" + +zconf: $(TOP)/zconf$(SUFFIX).h.in $(TOP)/zlib$(SUFFIX).h $(TOP)/zlib_name_mangling$(SUFFIX).h + $(CP) $(TOP)\zconf$(SUFFIX).h.in $(TOP)\zconf$(SUFFIX).h + +$(TOP)/win32/$(DEFFILE): $(TOP)/win32/$(DEFFILE).in + cscript $(TOP)\win32\replace.vbs $(TOP)/win32/$(DEFFILE).in $(TOP)/win32/$(DEFFILE) "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" + +$(STATICLIB): zconf $(OBJS) + $(AR) $(ARFLAGS) -out:$@ $(OBJS) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): zconf $(TOP)/win32/$(DEFFILE) $(OBJS) $(RESFILE) + $(LD) $(LDFLAGS) -def:$(TOP)/win32/$(DEFFILE) -dll -implib:$(IMPLIB) \ + -out:$@ -base:0x5A4C0000 $(OBJS) $(RESFILE) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;2 + +example.exe: example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + $(LD) $(LDFLAGS) example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip.exe: minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + $(LD) $(LDFLAGS) minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +example_d.exe: example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip_d.exe: minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +{$(TOP)}.c.obj: + $(CC) -c $(WFLAGS) $(CFLAGS) $< + +gzlib2.obj: gzlib.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h + $(CC) -c $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP -Fogzlib2.obj gzlib.c + +gzread2.obj: gzread.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h + $(CC) -c $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP -Fogzread2.obj gzread.c + +gzwrite2.obj: gzwrite.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h + $(CC) -c $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP -Fogzwrite2.obj gzwrite.c + +{$(TOP)/arch/arm}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/arch/generic}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/test}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP $< + +$(TOP)/zconf$(SUFFIX).h: zconf + +adler32.obj: $(TOP)/adler32.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/adler32_p.h +adler32_c.obj: $(TOP)/arch/generic/adler32_c.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/adler32_p.h +adler32_fold_c.obj: $(TOP)/arch/generic/adler32_fold_c.c $(TOP)/zbuild.h $(TOP)/functable.h +chunkset_c.obj: $(TOP)/arch/generic/chunkset_c.c $(TOP)/zbuild.h $(TOP)/chunkset_tpl.h $(TOP)/inffast_tpl.h +compare256_c.obj: $(TOP)/arch/generic/compare256_c.c $(TOP)/zbuild.h $(TOP)/zmemory.h $(TOP)/deflate.h $(TOP)/fallback_builtins.h $(TOP)/match_tpl.h +compress.obj: $(TOP)/compress.c $(TOP)/zbuild.h $(TOP)/zutil.h +cpu_features.obj: $(TOP)/cpu_features.c $(TOP)/cpu_features.h $(TOP)/zbuild.h +crc32.obj: $(TOP)/crc32.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/crc32_braid_tbl.h +crc32_braid_c.obj: $(TOP)/arch/generic/crc32_braid_c.c $(TOP)/zbuild.h $(TOP)/crc32_braid_p.h $(TOP)/crc32_braid_tbl.h +crc32_braid_comb.obj: $(TOP)/crc32_braid_comb.c $(TOP)/zutil.h $(TOP)/crc32_braid_p.h $(TOP)/crc32_braid_tbl.h $(TOP)/crc32_braid_comb_p.h +crc32_fold_c.obj: $(TOP)/arch/generic/crc32_fold_c.c $(TOP)/zbuild.h $(TOP)/crc32.h $(TOP)/functable.h $(TOP)/zutil.h +deflate.obj: $(TOP)/deflate.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_fast.obj: $(TOP)/deflate_fast.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_huff.obj: $(TOP)/deflate_huff.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_medium.obj: $(TOP)/deflate_medium.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_quick.obj: $(TOP)/deflate_quick.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h $(TOP)/trees_emit.h $(TOP)/zmemory.h +deflate_rle.obj: $(TOP)/deflate_rle.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h $(TOP)/compare256_rle.h +deflate_slow.obj: $(TOP)/deflate_slow.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_stored.obj: $(TOP)/deflate_stored.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +functable.obj: $(TOP)/functable.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/cpu_features.h $(TOP)/arch/arm/arm_features.h $(TOP)/arch_functions.h +gzlib.obj: $(TOP)/gzlib.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h +gzread.obj: $(TOP)/gzread.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h +gzwrite.obj: $(TOP)/gzwrite.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h +infback.obj: $(TOP)/infback.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/inftrees.h $(TOP)/inflate.h $(TOP)/inflate_p.h $(TOP)/functable.h +inflate.obj: $(TOP)/inflate.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/inftrees.h $(TOP)/inflate.h $(TOP)/inflate_p.h $(TOP)/functable.h $(TOP)/inffixed_tbl.h +inftrees.obj: $(TOP)/inftrees.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/inftrees.h +insert_string.obj: $(TOP)/insert_string.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/insert_string_tpl.h +insert_string_roll.obj: $(TOP)/insert_string_roll.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/insert_string_tpl.h +slide_hash_c.obj: $(TOP)/arch/generic/slide_hash_c.c $(TOP)/zbuild.h $(TOP)/deflate.h +trees.obj: $(TOP)/trees.c $(TOP)/trees.h $(TOP)/trees_emit.h $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/trees_tbl.h +uncompr.obj: $(TOP)/uncompr.c $(TOP)/zbuild.h $(TOP)/zutil.h +zutil.obj: $(TOP)/zutil.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/zutil_p.h + +$(RESFILE): $(TOP)/win32/$(RCFILE) + $(RC) $(RCFLAGS) /fo$@ $(TOP)/win32/$(RCFILE) + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +testdll: example_d.exe minigzip_d.exe + example_d + echo hello world | minigzip_d | minigzip_d -d + +example.obj: $(TOP)/test/example.c $(TOP)/zbuild.h $(TOP)/zlib$(SUFFIX).h $(TOP)/deflate.h $(TOP)/test/test_shared_ng.h + +minigzip.obj: $(TOP)/test/minigzip.c $(TOP)/zbuild.h $(TOP)/zlib$(SUFFIX).h + + +# cleanup +clean: + -del $(STATICLIB) + -del $(SHAREDLIB) + -del $(IMPLIB) + -del *.obj + -del *.res + -del *.exp + -del *.exe + -del *.pdb + -del *.manifest + +distclean: clean + -del zconf$(SUFFIX).h + -del zlib$(SUFFIX).h + -del zlib_name_mangling$(SUFFIX).h + -del $(TOP)\win32\zlib.def + -del $(TOP)\win32\zlibcompat.def + -del $(TOP)\win32\zlib-ng.def + -del gzread.c diff --git a/win32/Makefile.msc b/win32/Makefile.msc new file mode 100644 index 0000000000..62ca621aef --- /dev/null +++ b/win32/Makefile.msc @@ -0,0 +1,292 @@ +# Makefile for zlib using Microsoft (Visual) C +# zlib is copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler +# +# Usage: +# nmake -f win32/Makefile.msc (standard build) +# nmake -f win32/Makefile.msc LOC=-DFOO (nonstandard build) + +# The toplevel directory of the source tree. +# +TOP = . + +# optional build flags +LOC = + +# variables +STATICLIB = zlib.lib +SHAREDLIB = zlib1.dll +IMPLIB = zdll.lib +SYMBOL_PREFIX = + +CC = cl +CXX = cl +LD = link +AR = lib +RC = rc +CP = copy /y +INCLUDES = -I$(TOP) -I$(TOP)/arch/x86 -I$(TOP)/arch/generic +CFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi -Fd"zlib" $(LOC) $(INCLUDES) +CXXFLAGS = -nologo -EHsc -MD -W3 -O2 -Oy- -Zi -Fd"zlib" $(LOC) $(INCLUDES) +WFLAGS = \ + -D_CRT_SECURE_NO_DEPRECATE \ + -D_CRT_NONSTDC_NO_DEPRECATE \ + -DX86_FEATURES \ + -DX86_PCLMULQDQ_CRC \ + -DX86_SSE2 \ + -DX86_SSE42 \ + -DX86_SSSE3 \ + -DX86_AVX2 + +LDFLAGS = -nologo -debug -incremental:no -opt:ref -manifest +ARFLAGS = -nologo +RCFLAGS = /dWIN32 /r +DEFFILE = zlib.def +RCFILE = zlib1.rc +RESFILE = zlib1.res +WITH_GZFILEOP = yes +ZLIB_COMPAT = +SUFFIX = + +OBJS = \ + adler32.obj \ + adler32_c.obj \ + adler32_avx2.obj \ + adler32_avx512.obj \ + adler32_avx512_vnni.obj \ + adler32_sse42.obj \ + adler32_ssse3.obj \ + adler32_fold_c.obj \ + chunkset_c.obj \ + chunkset_avx2.obj \ + chunkset_sse2.obj \ + chunkset_ssse3.obj \ + compare256_c.obj \ + compare256_avx2.obj \ + compare256_sse2.obj \ + compress.obj \ + cpu_features.obj \ + crc32.obj \ + crc32_braid_c.obj \ + crc32_braid_comb.obj \ + crc32_fold_c.obj \ + crc32_pclmulqdq.obj \ + deflate.obj \ + deflate_fast.obj \ + deflate_huff.obj \ + deflate_medium.obj \ + deflate_quick.obj \ + deflate_rle.obj \ + deflate_slow.obj \ + deflate_stored.obj \ + functable.obj \ + infback.obj \ + inflate.obj \ + inftrees.obj \ + insert_string.obj \ + insert_string_roll.obj \ + slide_hash_c.obj \ + slide_hash_avx2.obj \ + slide_hash_sse2.obj \ + trees.obj \ + uncompr.obj \ + zutil.obj \ + x86_features.obj \ + # +!if "$(ZLIB_COMPAT)" != "" +WITH_GZFILEOP = yes +WFLAGS = $(WFLAGS) -DZLIB_COMPAT +DEFFILE = zlibcompat.def +!else +STATICLIB = zlib-ng.lib +SHAREDLIB = zlib-ng1.dll +IMPLIB = zngdll.lib +DEFFILE = zlib-ng.def +RCFILE = zlib-ng1.rc +RESFILE = zlib-ng1.res +SUFFIX = -ng +!endif + +!if "$(WITH_GZFILEOP)" != "" +WFLAGS = $(WFLAGS) -DWITH_GZFILEOP +OBJS = $(OBJS) gzlib.obj gzread.obj gzwrite.obj +!endif + +# targets +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) \ + example.exe minigzip.exe example_d.exe minigzip_d.exe + +!if "$(SYMBOL_PREFIX)" != "" +zlib_name_mangling$(SUFFIX).h: zlib_name_mangling$(SUFFIX).h.in + cscript $(TOP)\win32\replace.vbs $(TOP)\zlib_name_mangling$(SUFFIX).h.in zlib_name_mangling$(SUFFIX).h "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" +!else +zlib_name_mangling$(SUFFIX).h: zlib_name_mangling.h.empty + $(CP) $(TOP)\zlib_name_mangling.h.empty zlib_name_mangling$(SUFFIX).h +!endif + +zlib$(SUFFIX).h: zlib$(SUFFIX).h.in + cscript $(TOP)\win32\replace.vbs $(TOP)\zlib$(SUFFIX).h.in zlib$(SUFFIX).h "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" + +gzread.c: gzread.c.in + cscript $(TOP)\win32\replace.vbs $(TOP)\gzread.c.in gzread.c "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" + +zconf: $(TOP)/zconf$(SUFFIX).h.in $(TOP)/zlib$(SUFFIX).h $(TOP)/zlib_name_mangling$(SUFFIX).h + $(CP) $(TOP)\zconf$(SUFFIX).h.in $(TOP)\zconf$(SUFFIX).h + +$(TOP)/win32/$(DEFFILE): $(TOP)/win32/$(DEFFILE).in + cscript $(TOP)\win32\replace.vbs $(TOP)/win32/$(DEFFILE).in $(TOP)/win32/$(DEFFILE) "@ZLIB_SYMBOL_PREFIX@" "$(SYMBOL_PREFIX)" + +$(STATICLIB): zconf $(OBJS) + $(AR) $(ARFLAGS) -out:$@ $(OBJS) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): zconf $(TOP)/win32/$(DEFFILE) $(OBJS) $(RESFILE) + $(LD) $(LDFLAGS) -def:$(TOP)/win32/$(DEFFILE) -dll -implib:$(IMPLIB) \ + -out:$@ $(OBJS) $(RESFILE) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;2 + +depcheck.exe: depcheck.obj + $(LD) $(LDFLAGS) depcheck.obj + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +example.exe: example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + $(LD) $(LDFLAGS) example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip.exe: minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + $(LD) $(LDFLAGS) minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +example_d.exe: example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ example.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip_d.exe: minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ minigzip.obj gzlib2.obj gzread2.obj gzwrite2.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +{$(TOP)}.c.obj: + $(CC) -c $(WFLAGS) $(CFLAGS) $< + +gzlib2.obj: gzlib.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h + $(CC) -c $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP -Fogzlib2.obj gzlib.c + +gzread2.obj: gzread.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h + $(CC) -c $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP -Fogzread2.obj gzread.c + +gzwrite2.obj: gzwrite.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h + $(CC) -c $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP -Fogzwrite2.obj gzwrite.c + +{$(TOP)/arch/x86}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/arch/generic}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/test}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) -DWITH_GZFILEOP $< + +$(TOP)/zconf$(SUFFIX).h: zconf + +{$(TOP)/win32}.cpp.obj: + $(CXX) -c -I$(TOP) $(WFLAGS) $(CXXFLAGS) $< + +adler32.obj: $(TOP)/adler32.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/adler32_p.h +adler32_c.obj: $(TOP)/arch/generic/adler32_c.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/adler32_p.h +adler32_avx2.obj: $(TOP)/arch/x86/adler32_avx2.c $(TOP)/zbuild.h $(TOP)/adler32_p.h $(TOP)/arch/x86/adler32_avx2_p.h $(TOP)/arch/x86/x86_intrins.h +adler32_avx512.obj: $(TOP)/arch/x86/adler32_avx512.c $(TOP)/zbuild.h $(TOP)/arch_functions.h $(TOP)/adler32_p.h $(TOP)/arch/x86/adler32_avx512_p.h $(TOP)/arch/x86/x86_intrins.h +adler32_avx512_vnni.obj: $(TOP)/arch/x86/adler32_avx512_vnni.c $(TOP)/zbuild.h $(TOP)/arch_functions.h $(TOP)/adler32_p.h $(TOP)/arch/x86/adler32_avx512_p.h \ + $(TOP)/arch/x86/adler32_avx2_p.h $(TOP)/arch/x86/x86_intrins.h +adler32_sse42.obj: $(TOP)/arch/x86/adler32_sse42.c $(TOP)/zbuild.h $(TOP)/adler32_p.h \ + $(TOP)/arch/x86/adler32_ssse3_p.h +adler32_ssse3.obj: $(TOP)/arch/x86/adler32_ssse3.c $(TOP)/zbuild.h $(TOP)/adler32_p.h \ + $(TOP)/arch/x86/adler32_ssse3_p.h +adler32_fold_c.obj: $(TOP)/arch/generic/adler32_fold_c.c $(TOP)/zbuild.h $(TOP)/functable.h +chunkset_c.obj: $(TOP)/arch/generic/chunkset_c.c $(TOP)/zbuild.h $(TOP)/chunkset_tpl.h $(TOP)/inffast_tpl.h +chunkset_avx2.obj: $(TOP)/arch/x86/chunkset_avx2.c $(TOP)/zbuild.h $(TOP)/chunkset_tpl.h $(TOP)/inffast_tpl.h $(TOP)/arch/generic/chunk_permute_table.h +chunkset_sse2.obj: $(TOP)/arch/x86/chunkset_sse2.c $(TOP)/zbuild.h $(TOP)/chunkset_tpl.h $(TOP)/inffast_tpl.h +chunkset_ssse3.obj: $(TOP)/arch/x86/chunkset_ssse3.c $(TOP)/zbuild.h $(TOP)/chunkset_tpl.h $(TOP)/inffast_tpl.h $(TOP)/arch/generic/chunk_permute_table.h +compare256_c.obj: $(TOP)/arch/generic/compare256_c.c $(TOP)/zbuild.h $(TOP)/zmemory.h $(TOP)/deflate.h $(TOP)/fallback_builtins.h $(TOP)/match_tpl.h +compare256_avx2.obj: $(TOP)/arch/x86/compare256_avx2.c $(TOP)/zbuild.h $(TOP)/zmemory.h $(TOP)/deflate.h $(TOP)/fallback_builtins.h $(TOP)/match_tpl.h +compare256_sse2.obj: $(TOP)/arch/x86/compare256_sse2.c $(TOP)/zbuild.h $(TOP)/zmemory.h $(TOP)/deflate.h $(TOP)/fallback_builtins.h $(TOP)/match_tpl.h +compress.obj: $(TOP)/compress.c $(TOP)/zbuild.h $(TOP)/zutil.h +cpu_features.obj: $(TOP)/cpu_features.c $(TOP)/cpu_features.h $(TOP)/zbuild.h +crc32.obj: $(TOP)/crc32.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/crc32_braid_tbl.h +crc32_braid_c.obj: $(TOP)/arch/generic/crc32_braid_c.c $(TOP)/zbuild.h $(TOP)/crc32_braid_p.h $(TOP)/crc32_braid_tbl.h +crc32_braid_comb.obj: $(TOP)/crc32_braid_comb.c $(TOP)/zutil.h $(TOP)/crc32_braid_p.h $(TOP)/crc32_braid_tbl.h $(TOP)/crc32_braid_comb_p.h +crc32_fold_c.obj: $(TOP)/arch/generic/crc32_fold_c.c $(TOP)/zbuild.h $(TOP)/crc32.h $(TOP)/functable.h $(TOP)/zutil.h +crc32_pclmulqdq.obj: $(TOP)/arch/x86/crc32_pclmulqdq.c $(TOP)/arch/x86/crc32_pclmulqdq_tpl.h +deflate.obj: $(TOP)/deflate.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_fast.obj: $(TOP)/deflate_fast.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_huff.obj: $(TOP)/deflate_huff.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_medium.obj: $(TOP)/deflate_medium.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_quick.obj: $(TOP)/deflate_quick.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h $(TOP)/trees_emit.h $(TOP)/zmemory.h +deflate_rle.obj: $(TOP)/deflate_rle.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h $(TOP)/compare256_rle.h +deflate_slow.obj: $(TOP)/deflate_slow.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +deflate_stored.obj: $(TOP)/deflate_stored.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/deflate_p.h $(TOP)/functable.h +functable.obj: $(TOP)/functable.c $(TOP)/zbuild.h $(TOP)/functable.h $(TOP)/cpu_features.h $(TOP)/arch/x86/x86_features.h $(TOP)/arch_functions.h +gzlib.obj: $(TOP)/gzlib.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h +gzread.obj: $(TOP)/gzread.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h +gzwrite.obj: $(TOP)/gzwrite.c $(TOP)/zbuild.h $(TOP)/gzguts.h $(TOP)/zutil_p.h +infback.obj: $(TOP)/infback.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/inftrees.h $(TOP)/inflate.h $(TOP)/inflate_p.h $(TOP)/functable.h +inflate.obj: $(TOP)/inflate.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/inftrees.h $(TOP)/inflate.h $(TOP)/inflate_p.h $(TOP)/functable.h $(TOP)/inffixed_tbl.h +inftrees.obj: $(TOP)/inftrees.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/inftrees.h +insert_string.obj: $(TOP)/insert_string.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/insert_string_tpl.h +insert_string_roll.obj: $(TOP)/insert_string_roll.c $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/insert_string_tpl.h +slide_hash_c.obj: $(TOP)/arch/generic/slide_hash_c.c $(TOP)/zbuild.h $(TOP)/deflate.h +slide_hash_avx2.obj: $(TOP)/arch/x86/slide_hash_avx2.c $(TOP)/zbuild.h $(TOP)/deflate.h +slide_hash_sse2.obj: $(TOP)/arch/x86/slide_hash_sse2.c $(TOP)/zbuild.h $(TOP)/deflate.h +trees.obj: $(TOP)/trees.c $(TOP)/trees.h $(TOP)/trees_emit.h $(TOP)/zbuild.h $(TOP)/deflate.h $(TOP)/trees_tbl.h +uncompr.obj: $(TOP)/uncompr.c $(TOP)/zbuild.h $(TOP)/zutil.h +zutil.obj: $(TOP)/zutil.c $(TOP)/zbuild.h $(TOP)/zutil.h $(TOP)/zutil_p.h + +$(RESFILE): $(TOP)/win32/$(RCFILE) + $(RC) $(RCFLAGS) /fo$@ $(TOP)/win32/$(RCFILE) + +# testing +depcheck: depcheck.exe + depcheck win32\Makefile.msc . + depcheck win32\Makefile.arm . + depcheck win32\Makefile.a64 . + +test: example.exe minigzip.exe depcheck + example + echo hello world | minigzip | minigzip -d + +testdll: example_d.exe minigzip_d.exe + example_d + echo hello world | minigzip_d | minigzip_d -d + +depcheck.obj: $(TOP)/win32/depcheck.cpp + +example.obj: $(TOP)/test/example.c $(TOP)/zbuild.h $(TOP)/zlib$(SUFFIX).h $(TOP)/deflate.h $(TOP)/test/test_shared_ng.h + +minigzip.obj: $(TOP)/test/minigzip.c $(TOP)/zbuild.h $(TOP)/zlib$(SUFFIX).h + + +# cleanup +clean: + -del $(STATICLIB) + -del $(SHAREDLIB) + -del $(IMPLIB) + -del *.obj + -del *.res + -del *.exp + -del *.exe + -del *.pdb + -del *.manifest + +distclean: clean + -del zconf$(SUFFIX).h + -del zlib$(SUFFIX).h + -del zlib_name_mangling$(SUFFIX).h + -del $(TOP)\win32\zlib.def + -del $(TOP)\win32\zlibcompat.def + -del $(TOP)\win32\zlib-ng.def + -del gzread.c diff --git a/win32/depcheck.cpp b/win32/depcheck.cpp new file mode 100644 index 0000000000..f83bdd6852 --- /dev/null +++ b/win32/depcheck.cpp @@ -0,0 +1,321 @@ +/* depcheck.cpp - Dependency checker for NMake Makefiles + * Copyright (c) 2024 Mika T. Lindqvist + */ + +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) { + if (argc != 3) { + printf("Usage: depcheck Makefile \n"); + return -1; + } + std::filebuf fb; + if (fb.open (argv[1],std::ios::in)) { + std::istream is(&fb); + std::string makefile = argv[1]; + std::string l, tmp, tmp2; + while (is) { + std::getline(is, l); + while (l.back() == '\\') { + std::getline(is, tmp); + l.replace(l.length() - 1, 1, tmp); + } + size_t pos = l.find("obj:"); + if (pos != std::string::npos) { + std::string objfile = l.substr(0, pos+3); + printf("File: %s\n", objfile.c_str()); + std::vector files; + std::stringstream ss(l.substr(pos+4)); + while(getline(ss, tmp, ' ')){ + if (tmp != "" && tmp != "/") { + files.push_back(tmp); + } + } + for (auto it = files.begin(); it != files.end(); ++it) { + printf("Dependency: %s\n", (*it).c_str()); + } + if (!files.empty()) { + std::filebuf fb2; + std::string src = files[0]; + size_t pos2 = src.find("$(TOP)"); + if (pos2 != std::string::npos) { + src.replace(pos2, 6, argv[2]); + } + printf("Source: %s\n", src.c_str()); + if (fb2.open(src.c_str(),std::ios::in)) { + std::istream is2(&fb2); + std::vector includes; + while (is2) { + std::getline(is2, l); + pos = l.find("#"); + if (pos != std::string::npos) { + pos2 = l.find("include"); + size_t pos3 = l.find("\""); + if (pos2 != std::string::npos && pos3 != std::string::npos && pos2 > pos && pos3 > pos2) { + tmp = l.substr(pos3 + 1); + pos2 = tmp.find("\""); + if (pos2 != std::string::npos) { + tmp = tmp.substr(0, pos2); + } + pos2 = tmp.find("../"); + if (pos2 != std::string::npos) { + tmp = tmp.substr(3); + } + printf("Line: %s\n", tmp.c_str()); + int found = 0; + for (size_t i = 1; i < files.size(); i++) { + pos3 = files[i].find("$(SUFFIX)"); + if (pos3 != std::string::npos) { + tmp2 = files[i].substr(0, pos3).append(files[i].substr(pos3 + 9)); + printf("Comparing dependency \"%s\" and \"%s\"\n", tmp2.c_str(), tmp.c_str()); + if (tmp2 == tmp) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + printf("Comparing dependency \"%s\" and \"$(TOP)/%s\"\n", tmp2.c_str(), tmp.c_str()); + if (tmp2 == std::string("$(TOP)/").append(tmp)) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + + tmp2 = files[i].substr(0, pos3).append("-ng").append(files[i].substr(pos3 + 9)); + printf("Comparing dependency \"%s\" and \"%s\"\n", tmp2.c_str(), tmp.c_str()); + if (tmp2 == tmp) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + printf("Comparing dependency \"%s\" and \"$(TOP)/%s\"\n", tmp2.c_str(), tmp.c_str()); + if (tmp2 == std::string("$(TOP)/").append(tmp)) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + } else { + printf("Comparing dependency \"%s\" and \"%s\"\n", files[i].c_str(), tmp.c_str()); + if (files[i] == tmp) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + printf("Comparing dependency \"%s\" and \"$(TOP)/%s\"\n", files[i].c_str(), tmp.c_str()); + if (files[i] == std::string("$(TOP)/").append(tmp)) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + printf("Comparing dependency \"%s\" and \"$(TOP)/arch/%s\"\n", files[i].c_str(), tmp.c_str()); + if (files[i] == std::string("$(TOP)/arch/").append(tmp)) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + printf("Comparing dependency \"%s\" and \"$(TOP)/arch/generic/%s\"\n", files[i].c_str(), tmp.c_str()); + if (files[i] == std::string("$(TOP)/arch/generic/").append(tmp)) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + printf("Comparing dependency \"%s\" and \"$(TOP)/arch/arm/%s\"\n", files[i].c_str(), tmp.c_str()); + if (files[i] == std::string("$(TOP)/arch/arm/").append(tmp)) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + printf("Comparing dependency \"%s\" and \"$(TOP)/arch/x86/%s\"\n", files[i].c_str(), tmp.c_str()); + if (files[i] == std::string("$(TOP)/arch/x86/").append(tmp)) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + printf("Comparing dependency \"%s\" and \"$(TOP)/test/%s\"\n", files[i].c_str(), tmp.c_str()); + if (files[i] == std::string("$(TOP)/test/").append(tmp)) { + printf("Dependency %s OK\n", tmp.c_str()); + found = 1; + includes.push_back(tmp); + break; + } + } + } + // Skip irrelevant dependencies + if (tmp.substr(0, 9) == "arch/s390") found = 1; + if (tmp == "zlib-ng.h" && std::find(includes.begin(), includes.end(), "zlib.h") != includes.end()) found = 1; + if (found == 0) { + printf("%s: Dependency %s missing for %s!\n", makefile.c_str(), tmp.c_str(), objfile.c_str()); + return -1; + } + } + } + } + for (size_t i = 1; i < files.size(); i++) { + int found = 0; + tmp = files[i]; + printf("Dependency: %s\n", tmp.c_str()); + pos2 = tmp.find("$(TOP)"); + if (pos2 != std::string::npos) { + tmp = tmp.substr(7); + } + for (size_t j = 0; j < includes.size(); j++) { + pos2 = tmp.find("$(SUFFIX)"); + if (pos2 != std::string::npos) { + std::string tmp1 = tmp.substr(0, pos2).append(tmp.substr(pos2 + 9)); + printf("[%zd/%zd] Comparing dependency \"%s\" and \"%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == includes[j]) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == std::string("arch/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/generic/%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == std::string("arch/generic/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/arm/%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == std::string("arch/arm/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/x86/%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == std::string("arch/x86/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"test/%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == std::string("test/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + tmp1 = tmp.substr(0, pos2).append("-ng").append(tmp.substr(pos2 + 9)); + printf("[%zd/%zd] Comparing dependency \"%s\" and \"%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == includes[j]) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == std::string("arch/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/generic/%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == std::string("arch/generic/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/arm/%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == std::string("arch/arm/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/x86/%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == std::string("arch/x86/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"test/%s\"\n", j, includes.size(), tmp1.c_str(), includes[j].c_str()); + if (tmp1 == std::string("test/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + } else { + printf("[%zd/%zd] Comparing dependency \"%s\" and \"%s\"\n", j, includes.size(), tmp.c_str(), includes[j].c_str()); + if (tmp == includes[j]) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/%s\"\n", j, includes.size(), tmp.c_str(), includes[j].c_str()); + if (tmp == std::string("arch/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/generic/%s\"\n", j, includes.size(), tmp.c_str(), includes[j].c_str()); + if (tmp == std::string("arch/generic/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/arm/%s\"\n", j, includes.size(), tmp.c_str(), includes[j].c_str()); + if (tmp == std::string("arch/arm/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"arch/x86/%s\"\n", j, includes.size(), tmp.c_str(), includes[j].c_str()); + if (tmp == std::string("arch/x86/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + printf("[%zd/%zd] Comparing dependency \"%s\" and \"test/%s\"\n", j, includes.size(), tmp.c_str(), includes[j].c_str()); + if (tmp == std::string("test/").append(includes[j])) { + printf("Dependency %s OK\n", files[i].c_str()); + found = 1; + break; + } + } + } + // Skip indirect dependencies + if (tmp.find("arm_features.h") != std::string::npos + && std::find(includes.begin(), includes.end(), "cpu_features.h") != includes.end() + && (makefile.find(".arm") != std::string::npos + || makefile.find(".a64") != std::string::npos)) found = 1; + if (tmp.find("x86_features.h") != std::string::npos + && std::find(includes.begin(), includes.end(), "cpu_features.h") != includes.end() + && makefile.find(".msc") != std::string::npos) found = 1; + // + if (tmp.find("generic_functions.h") != std::string::npos + && std::find(includes.begin(), includes.end(), "arch_functions.h") != includes.end()) found = 1; + if (tmp.find("arm_functions.h") != std::string::npos + && std::find(includes.begin(), includes.end(), "arch_functions.h") != includes.end() + && (makefile.find(".arm") != std::string::npos + || makefile.find(".a64") != std::string::npos)) found = 1; + if (tmp.find("x86_functions.h") != std::string::npos + && std::find(includes.begin(), includes.end(), "arch_functions.h") != includes.end() + && makefile.find(".msc") != std::string::npos) found = 1; + if (found == 0) { + printf("%s: Dependency %s not needed for %s\n", makefile.c_str(), files[i].c_str(), objfile.c_str()); + return -1; + } + } + fb2.close(); + } + } + } + } + fb.close(); + } + return 0; +} diff --git a/win32/replace.vbs b/win32/replace.vbs new file mode 100644 index 0000000000..6779971d07 --- /dev/null +++ b/win32/replace.vbs @@ -0,0 +1,15 @@ +strInputFileName = Wscript.Arguments(0) +strOutputFileName = Wscript.Arguments(1) +strOldText = Wscript.Arguments(2) +strNewText = Wscript.Arguments(3) + +Set objFSO = CreateObject("Scripting.FileSystemObject") +Set objFile = objFSO.OpenTextFile(strInputFileName, 1) + +strText = objFile.ReadAll +objFile.Close +strNewText = Replace(strText, strOldText, strNewText) + +Set objFile = objFSO.OpenTextFile(strOutputFileName, 2, True) +objFile.Write strNewText +objFile.Close diff --git a/win32/zlib-ng.def.in b/win32/zlib-ng.def.in new file mode 100644 index 0000000000..53b2bc21f7 --- /dev/null +++ b/win32/zlib-ng.def.in @@ -0,0 +1,60 @@ +; zlib-ng data compression library +EXPORTS +; basic functions + @ZLIB_SYMBOL_PREFIX@zlibng_version + @ZLIB_SYMBOL_PREFIX@zng_deflate + @ZLIB_SYMBOL_PREFIX@zng_deflateEnd + @ZLIB_SYMBOL_PREFIX@zng_deflateInit + @ZLIB_SYMBOL_PREFIX@zng_deflateInit2 + @ZLIB_SYMBOL_PREFIX@zng_inflate + @ZLIB_SYMBOL_PREFIX@zng_inflateEnd + @ZLIB_SYMBOL_PREFIX@zng_inflateInit + @ZLIB_SYMBOL_PREFIX@zng_inflateInit2 + @ZLIB_SYMBOL_PREFIX@zng_inflateBackInit +; advanced functions + @ZLIB_SYMBOL_PREFIX@zng_deflateSetDictionary + @ZLIB_SYMBOL_PREFIX@zng_deflateGetDictionary + @ZLIB_SYMBOL_PREFIX@zng_deflateCopy + @ZLIB_SYMBOL_PREFIX@zng_deflateReset + @ZLIB_SYMBOL_PREFIX@zng_deflateParams + @ZLIB_SYMBOL_PREFIX@zng_deflateTune + @ZLIB_SYMBOL_PREFIX@zng_deflateBound + @ZLIB_SYMBOL_PREFIX@zng_deflatePending + @ZLIB_SYMBOL_PREFIX@zng_deflatePrime + @ZLIB_SYMBOL_PREFIX@zng_deflateSetHeader + @ZLIB_SYMBOL_PREFIX@zng_deflateSetParams + @ZLIB_SYMBOL_PREFIX@zng_deflateGetParams + @ZLIB_SYMBOL_PREFIX@zng_inflateSetDictionary + @ZLIB_SYMBOL_PREFIX@zng_inflateGetDictionary + @ZLIB_SYMBOL_PREFIX@zng_inflateSync + @ZLIB_SYMBOL_PREFIX@zng_inflateCopy + @ZLIB_SYMBOL_PREFIX@zng_inflateReset + @ZLIB_SYMBOL_PREFIX@zng_inflateReset2 + @ZLIB_SYMBOL_PREFIX@zng_inflatePrime + @ZLIB_SYMBOL_PREFIX@zng_inflateMark + @ZLIB_SYMBOL_PREFIX@zng_inflateGetHeader + @ZLIB_SYMBOL_PREFIX@zng_inflateBack + @ZLIB_SYMBOL_PREFIX@zng_inflateBackEnd + @ZLIB_SYMBOL_PREFIX@zng_zlibCompileFlags +; utility functions + @ZLIB_SYMBOL_PREFIX@zng_compress + @ZLIB_SYMBOL_PREFIX@zng_compress2 + @ZLIB_SYMBOL_PREFIX@zng_compressBound + @ZLIB_SYMBOL_PREFIX@zng_uncompress + @ZLIB_SYMBOL_PREFIX@zng_uncompress2 +; checksum functions + @ZLIB_SYMBOL_PREFIX@zng_adler32 + @ZLIB_SYMBOL_PREFIX@zng_adler32_z + @ZLIB_SYMBOL_PREFIX@zng_crc32 + @ZLIB_SYMBOL_PREFIX@zng_crc32_z + @ZLIB_SYMBOL_PREFIX@zng_adler32_combine + @ZLIB_SYMBOL_PREFIX@zng_crc32_combine +; various hacks, don't look :) + @ZLIB_SYMBOL_PREFIX@zng_zError + @ZLIB_SYMBOL_PREFIX@zng_inflateSyncPoint + @ZLIB_SYMBOL_PREFIX@zng_get_crc_table + @ZLIB_SYMBOL_PREFIX@zng_inflateUndermine + @ZLIB_SYMBOL_PREFIX@zng_inflateValidate + @ZLIB_SYMBOL_PREFIX@zng_inflateCodesUsed + @ZLIB_SYMBOL_PREFIX@zng_inflateResetKeep + @ZLIB_SYMBOL_PREFIX@zng_deflateResetKeep diff --git a/win32/zlib-ng1.rc b/win32/zlib-ng1.rc new file mode 100644 index 0000000000..f65cfa254e --- /dev/null +++ b/win32/zlib-ng1.rc @@ -0,0 +1,36 @@ +#include +#include "zlib-ng.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION ZLIBNG_VER_MAJOR,ZLIBNG_VER_MINOR,ZLIBNG_VER_REVISION,0 + PRODUCTVERSION ZLIBNG_VER_MAJOR,ZLIBNG_VER_MINOR,ZLIBNG_VER_REVISION,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS 1 +#else + FILEFLAGS 0 +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + BEGIN + VALUE "FileDescription", "zlib data compression library\0" + VALUE "FileVersion", ZLIBNG_VERSION "\0" + VALUE "InternalName", "zlib-ng1.dll\0" + VALUE "LegalCopyright", "(C) 1995-2024 Jean-loup Gailly & Mark Adler\0" + VALUE "OriginalFilename", "zlib-ng1.dll\0" + VALUE "ProductName", "zlib\0" + VALUE "ProductVersion", ZLIBNG_VERSION "\0" + VALUE "Comments", "For more information visit https://www.zlib.net/\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/win32/zlib.def.in b/win32/zlib.def.in new file mode 100644 index 0000000000..561a42f7f8 --- /dev/null +++ b/win32/zlib.def.in @@ -0,0 +1,64 @@ +; zlib data compression library +EXPORTS +; basic functions + @ZLIB_SYMBOL_PREFIX@zlibVersion + @ZLIB_SYMBOL_PREFIX@deflate + @ZLIB_SYMBOL_PREFIX@deflateEnd + @ZLIB_SYMBOL_PREFIX@inflate + @ZLIB_SYMBOL_PREFIX@inflateEnd +; advanced functions + @ZLIB_SYMBOL_PREFIX@deflateSetDictionary + @ZLIB_SYMBOL_PREFIX@deflateGetDictionary + @ZLIB_SYMBOL_PREFIX@deflateCopy + @ZLIB_SYMBOL_PREFIX@deflateReset + @ZLIB_SYMBOL_PREFIX@deflateParams + @ZLIB_SYMBOL_PREFIX@deflateTune + @ZLIB_SYMBOL_PREFIX@deflateBound + @ZLIB_SYMBOL_PREFIX@deflatePending + @ZLIB_SYMBOL_PREFIX@deflatePrime + @ZLIB_SYMBOL_PREFIX@deflateSetHeader + @ZLIB_SYMBOL_PREFIX@inflateSetDictionary + @ZLIB_SYMBOL_PREFIX@inflateGetDictionary + @ZLIB_SYMBOL_PREFIX@inflateSync + @ZLIB_SYMBOL_PREFIX@inflateCopy + @ZLIB_SYMBOL_PREFIX@inflateReset + @ZLIB_SYMBOL_PREFIX@inflateReset2 + @ZLIB_SYMBOL_PREFIX@inflatePrime + @ZLIB_SYMBOL_PREFIX@inflateMark + @ZLIB_SYMBOL_PREFIX@inflateGetHeader + @ZLIB_SYMBOL_PREFIX@inflateBack + @ZLIB_SYMBOL_PREFIX@inflateBackEnd + @ZLIB_SYMBOL_PREFIX@zlibCompileFlags +; utility functions + @ZLIB_SYMBOL_PREFIX@compress + @ZLIB_SYMBOL_PREFIX@compress2 + @ZLIB_SYMBOL_PREFIX@compressBound + @ZLIB_SYMBOL_PREFIX@uncompress + @ZLIB_SYMBOL_PREFIX@uncompress2 +; large file functions + @ZLIB_SYMBOL_PREFIX@adler32_combine64 + @ZLIB_SYMBOL_PREFIX@crc32_combine64 + @ZLIB_SYMBOL_PREFIX@crc32_combine_gen64 +; checksum functions + @ZLIB_SYMBOL_PREFIX@adler32 + @ZLIB_SYMBOL_PREFIX@adler32_z + @ZLIB_SYMBOL_PREFIX@crc32 + @ZLIB_SYMBOL_PREFIX@crc32_z + @ZLIB_SYMBOL_PREFIX@adler32_combine + @ZLIB_SYMBOL_PREFIX@crc32_combine + @ZLIB_SYMBOL_PREFIX@crc32_combine_gen + @ZLIB_SYMBOL_PREFIX@crc32_combine_op +; various hacks, don't look :) + @ZLIB_SYMBOL_PREFIX@deflateInit_ + @ZLIB_SYMBOL_PREFIX@deflateInit2_ + @ZLIB_SYMBOL_PREFIX@inflateInit_ + @ZLIB_SYMBOL_PREFIX@inflateInit2_ + @ZLIB_SYMBOL_PREFIX@inflateBackInit_ + @ZLIB_SYMBOL_PREFIX@zError + @ZLIB_SYMBOL_PREFIX@inflateSyncPoint + @ZLIB_SYMBOL_PREFIX@get_crc_table + @ZLIB_SYMBOL_PREFIX@inflateUndermine + @ZLIB_SYMBOL_PREFIX@inflateValidate + @ZLIB_SYMBOL_PREFIX@inflateCodesUsed + @ZLIB_SYMBOL_PREFIX@inflateResetKeep + @ZLIB_SYMBOL_PREFIX@deflateResetKeep diff --git a/win32/zlib1.rc b/win32/zlib1.rc new file mode 100644 index 0000000000..9bb9c18654 --- /dev/null +++ b/win32/zlib1.rc @@ -0,0 +1,36 @@ +#include +#include "zlib.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION ZLIB_VER_MAJOR,ZLIB_VER_MINOR,ZLIB_VER_REVISION,0 + PRODUCTVERSION ZLIB_VER_MAJOR,ZLIB_VER_MINOR,ZLIB_VER_REVISION,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS 1 +#else + FILEFLAGS 0 +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + BEGIN + VALUE "FileDescription", "zlib data compression library\0" + VALUE "FileVersion", ZLIB_VERSION "\0" + VALUE "InternalName", "zlib1.dll\0" + VALUE "LegalCopyright", "(C) 1995-2024 Jean-loup Gailly & Mark Adler\0" + VALUE "OriginalFilename", "zlib1.dll\0" + VALUE "ProductName", "zlib\0" + VALUE "ProductVersion", ZLIB_VERSION "\0" + VALUE "Comments", "For more information visit https://www.zlib.net/\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/win32/zlibcompat.def.in b/win32/zlibcompat.def.in new file mode 100644 index 0000000000..52a713cf03 --- /dev/null +++ b/win32/zlibcompat.def.in @@ -0,0 +1,97 @@ +; zlib data compression library +EXPORTS +; basic functions + @ZLIB_SYMBOL_PREFIX@zlibVersion + @ZLIB_SYMBOL_PREFIX@deflate + @ZLIB_SYMBOL_PREFIX@deflateEnd + @ZLIB_SYMBOL_PREFIX@inflate + @ZLIB_SYMBOL_PREFIX@inflateEnd +; advanced functions + @ZLIB_SYMBOL_PREFIX@deflateSetDictionary + @ZLIB_SYMBOL_PREFIX@deflateGetDictionary + @ZLIB_SYMBOL_PREFIX@deflateCopy + @ZLIB_SYMBOL_PREFIX@deflateReset + @ZLIB_SYMBOL_PREFIX@deflateParams + @ZLIB_SYMBOL_PREFIX@deflateTune + @ZLIB_SYMBOL_PREFIX@deflateBound + @ZLIB_SYMBOL_PREFIX@deflatePending + @ZLIB_SYMBOL_PREFIX@deflatePrime + @ZLIB_SYMBOL_PREFIX@deflateSetHeader + @ZLIB_SYMBOL_PREFIX@inflateSetDictionary + @ZLIB_SYMBOL_PREFIX@inflateGetDictionary + @ZLIB_SYMBOL_PREFIX@inflateSync + @ZLIB_SYMBOL_PREFIX@inflateCopy + @ZLIB_SYMBOL_PREFIX@inflateReset + @ZLIB_SYMBOL_PREFIX@inflateReset2 + @ZLIB_SYMBOL_PREFIX@inflatePrime + @ZLIB_SYMBOL_PREFIX@inflateMark + @ZLIB_SYMBOL_PREFIX@inflateGetHeader + @ZLIB_SYMBOL_PREFIX@inflateBack + @ZLIB_SYMBOL_PREFIX@inflateBackEnd + @ZLIB_SYMBOL_PREFIX@zlibCompileFlags +; utility functions + @ZLIB_SYMBOL_PREFIX@compress + @ZLIB_SYMBOL_PREFIX@compress2 + @ZLIB_SYMBOL_PREFIX@compressBound + @ZLIB_SYMBOL_PREFIX@uncompress + @ZLIB_SYMBOL_PREFIX@uncompress2 + @ZLIB_SYMBOL_PREFIX@gzopen + @ZLIB_SYMBOL_PREFIX@gzdopen + @ZLIB_SYMBOL_PREFIX@gzbuffer + @ZLIB_SYMBOL_PREFIX@gzsetparams + @ZLIB_SYMBOL_PREFIX@gzread + @ZLIB_SYMBOL_PREFIX@gzfread + @ZLIB_SYMBOL_PREFIX@gzwrite + @ZLIB_SYMBOL_PREFIX@gzfwrite + @ZLIB_SYMBOL_PREFIX@gzprintf + @ZLIB_SYMBOL_PREFIX@gzvprintf + @ZLIB_SYMBOL_PREFIX@gzputs + @ZLIB_SYMBOL_PREFIX@gzgets + @ZLIB_SYMBOL_PREFIX@gzputc + @ZLIB_SYMBOL_PREFIX@gzgetc + @ZLIB_SYMBOL_PREFIX@gzungetc + @ZLIB_SYMBOL_PREFIX@gzflush + @ZLIB_SYMBOL_PREFIX@gzseek + @ZLIB_SYMBOL_PREFIX@gzrewind + @ZLIB_SYMBOL_PREFIX@gztell + @ZLIB_SYMBOL_PREFIX@gzoffset + @ZLIB_SYMBOL_PREFIX@gzeof + @ZLIB_SYMBOL_PREFIX@gzdirect + @ZLIB_SYMBOL_PREFIX@gzclose + @ZLIB_SYMBOL_PREFIX@gzclose_r + @ZLIB_SYMBOL_PREFIX@gzclose_w + @ZLIB_SYMBOL_PREFIX@gzerror + @ZLIB_SYMBOL_PREFIX@gzclearerr +; large file functions + @ZLIB_SYMBOL_PREFIX@gzopen64 + @ZLIB_SYMBOL_PREFIX@gzseek64 + @ZLIB_SYMBOL_PREFIX@gztell64 + @ZLIB_SYMBOL_PREFIX@gzoffset64 + @ZLIB_SYMBOL_PREFIX@adler32_combine64 + @ZLIB_SYMBOL_PREFIX@crc32_combine64 + @ZLIB_SYMBOL_PREFIX@crc32_combine_gen64 +; checksum functions + @ZLIB_SYMBOL_PREFIX@adler32 + @ZLIB_SYMBOL_PREFIX@adler32_z + @ZLIB_SYMBOL_PREFIX@crc32 + @ZLIB_SYMBOL_PREFIX@crc32_z + @ZLIB_SYMBOL_PREFIX@adler32_combine + @ZLIB_SYMBOL_PREFIX@crc32_combine + @ZLIB_SYMBOL_PREFIX@crc32_combine_gen + @ZLIB_SYMBOL_PREFIX@crc32_combine_op +; various hacks, don't look :) + @ZLIB_SYMBOL_PREFIX@deflateInit_ + @ZLIB_SYMBOL_PREFIX@deflateInit2_ + @ZLIB_SYMBOL_PREFIX@inflateInit_ + @ZLIB_SYMBOL_PREFIX@inflateInit2_ + @ZLIB_SYMBOL_PREFIX@inflateBackInit_ + @ZLIB_SYMBOL_PREFIX@gzgetc_ + @ZLIB_SYMBOL_PREFIX@zError + @ZLIB_SYMBOL_PREFIX@inflateSyncPoint + @ZLIB_SYMBOL_PREFIX@get_crc_table + @ZLIB_SYMBOL_PREFIX@inflateUndermine + @ZLIB_SYMBOL_PREFIX@inflateValidate + @ZLIB_SYMBOL_PREFIX@inflateCodesUsed + @ZLIB_SYMBOL_PREFIX@inflateResetKeep + @ZLIB_SYMBOL_PREFIX@deflateResetKeep + @ZLIB_SYMBOL_PREFIX@gzopen_w diff --git a/zbuild.h b/zbuild.h new file mode 100644 index 0000000000..157ab6ffed --- /dev/null +++ b/zbuild.h @@ -0,0 +1,343 @@ +#ifndef _ZBUILD_H +#define _ZBUILD_H + +#define _POSIX_SOURCE 1 /* fileno */ +#ifndef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 200809L /* snprintf, posix_memalign, strdup */ +#endif +#ifndef _ISOC11_SOURCE +# define _ISOC11_SOURCE 1 /* aligned_alloc */ +#endif +#ifdef __OpenBSD__ +# define _BSD_SOURCE 1 +#endif + +#include +#include +#include +#include + +/* Determine compiler version of C Standard */ +#ifdef __STDC_VERSION__ +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +# if __STDC_VERSION__ >= 201112L +# ifndef STDC11 +# define STDC11 +# endif +# endif +#endif + +#ifndef Z_HAS_ATTRIBUTE +# if defined(__has_attribute) +# define Z_HAS_ATTRIBUTE(a) __has_attribute(a) +# else +# define Z_HAS_ATTRIBUTE(a) 0 +# endif +#endif + +#ifndef Z_FALLTHROUGH +# if Z_HAS_ATTRIBUTE(__fallthrough__) || (defined(__GNUC__) && (__GNUC__ >= 7)) +# define Z_FALLTHROUGH __attribute__((__fallthrough__)) +# else +# define Z_FALLTHROUGH do {} while(0) /* fallthrough */ +# endif +#endif + +#ifndef Z_TARGET +# if Z_HAS_ATTRIBUTE(__target__) +# define Z_TARGET(x) __attribute__((__target__(x))) +# else +# define Z_TARGET(x) +# endif +#endif + +/* This has to be first include that defines any types */ +#if defined(_MSC_VER) +# if defined(_WIN64) + typedef __int64 ssize_t; +# else + typedef long ssize_t; +# endif + +# if defined(_WIN64) + #define SSIZE_MAX _I64_MAX +# else + #define SSIZE_MAX LONG_MAX +# endif +#endif + +/* MS Visual Studio does not allow inline in C, only C++. + But it provides __inline instead, so use that. */ +#if defined(_MSC_VER) && !defined(inline) && !defined(__cplusplus) +# define inline __inline +#endif + +#if defined(ZLIB_COMPAT) +# define PREFIX(x) x +# define PREFIX2(x) ZLIB_ ## x +# define PREFIX3(x) z_ ## x +# define PREFIX4(x) x ## 64 +# define zVersion zlibVersion +#else +# define PREFIX(x) zng_ ## x +# define PREFIX2(x) ZLIBNG_ ## x +# define PREFIX3(x) zng_ ## x +# define PREFIX4(x) zng_ ## x +# define zVersion zlibng_version +# define z_size_t size_t +#endif + +/* In zlib-compat some functions and types use unsigned long, but zlib-ng use size_t */ +#if defined(ZLIB_COMPAT) +# define z_uintmax_t unsigned long +#else +# define z_uintmax_t size_t +#endif + +/* Minimum of a and b. */ +#define MIN(a, b) ((a) > (b) ? (b) : (a)) +/* Maximum of a and b. */ +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +/* Ignore unused variable warning */ +#define Z_UNUSED(var) (void)(var) + +#if defined(HAVE_VISIBILITY_INTERNAL) +# define Z_INTERNAL __attribute__((visibility ("internal"))) +#elif defined(HAVE_VISIBILITY_HIDDEN) +# define Z_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define Z_INTERNAL +#endif + +/* Symbol versioning helpers, allowing multiple versions of a function to exist. + * Functions using this must also be added to zlib-ng.map for each version. + * Double @@ means this is the default for newly compiled applications to link against. + * Single @ means this is kept for backwards compatibility. + * This is only used for Zlib-ng native API, and only on platforms supporting this. + */ +#if defined(HAVE_SYMVER) +# define ZSYMVER(func,alias,ver) __asm__(".symver " func ", " alias "@ZLIB_NG_" ver); +# define ZSYMVER_DEF(func,alias,ver) __asm__(".symver " func ", " alias "@@ZLIB_NG_" ver); +#else +# define ZSYMVER(func,alias,ver) +# define ZSYMVER_DEF(func,alias,ver) +#endif + +#ifndef __cplusplus +# define Z_REGISTER register +#else +# define Z_REGISTER +#endif + +/* Reverse the bytes in a value. Use compiler intrinsics when + possible to take advantage of hardware implementations. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1300) +# include +# pragma intrinsic(_byteswap_ulong) +# define ZSWAP16(q) _byteswap_ushort(q) +# define ZSWAP32(q) _byteswap_ulong(q) +# define ZSWAP64(q) _byteswap_uint64(q) + +#elif defined(__clang__) || (defined(__GNUC__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) +# define ZSWAP16(q) __builtin_bswap16(q) +# define ZSWAP32(q) __builtin_bswap32(q) +# define ZSWAP64(q) __builtin_bswap64(q) + +#elif defined(__GNUC__) && (__GNUC__ >= 2) && defined(__linux__) +# include +# define ZSWAP16(q) bswap_16(q) +# define ZSWAP32(q) bswap_32(q) +# define ZSWAP64(q) bswap_64(q) + +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +# include +# define ZSWAP16(q) bswap16(q) +# define ZSWAP32(q) bswap32(q) +# define ZSWAP64(q) bswap64(q) +#elif defined(__OpenBSD__) +# include +# define ZSWAP16(q) swap16(q) +# define ZSWAP32(q) swap32(q) +# define ZSWAP64(q) swap64(q) +#elif defined(__INTEL_COMPILER) +/* ICC does not provide a two byte swap. */ +# define ZSWAP16(q) ((((q) & 0xff) << 8) | (((q) & 0xff00) >> 8)) +# define ZSWAP32(q) _bswap(q) +# define ZSWAP64(q) _bswap64(q) + +#else +# define ZSWAP16(q) ((((q) & 0xff) << 8) | (((q) & 0xff00) >> 8)) +# define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) +# define ZSWAP64(q) \ + (((q & 0xFF00000000000000u) >> 56u) | \ + ((q & 0x00FF000000000000u) >> 40u) | \ + ((q & 0x0000FF0000000000u) >> 24u) | \ + ((q & 0x000000FF00000000u) >> 8u) | \ + ((q & 0x00000000FF000000u) << 8u) | \ + ((q & 0x0000000000FF0000u) << 24u) | \ + ((q & 0x000000000000FF00u) << 40u) | \ + ((q & 0x00000000000000FFu) << 56u)) +#endif + +/* Only enable likely/unlikely if the compiler is known to support it */ +#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__INTEL_COMPILER) || defined(__clang__) +# define LIKELY_NULL(x) __builtin_expect((x) != 0, 0) +# define LIKELY(x) __builtin_expect(!!(x), 1) +# define UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +# define LIKELY_NULL(x) x +# define LIKELY(x) x +# define UNLIKELY(x) x +#endif /* (un)likely */ + +#if defined(HAVE_ATTRIBUTE_ALIGNED) +# define ALIGNED_(x) __attribute__ ((aligned(x))) +#elif defined(_MSC_VER) +# define ALIGNED_(x) __declspec(align(x)) +#else +/* TODO: Define ALIGNED_ for your compiler */ +# define ALIGNED_(x) +#endif + +#ifdef HAVE_BUILTIN_ASSUME_ALIGNED +# define HINT_ALIGNED(p,n) __builtin_assume_aligned((void *)(p),(n)) +#else +# define HINT_ALIGNED(p,n) (p) +#endif +#define HINT_ALIGNED_16(p) HINT_ALIGNED((p),16) +#define HINT_ALIGNED_64(p) HINT_ALIGNED((p),64) +#define HINT_ALIGNED_4096(p) HINT_ALIGNED((p),4096) + +/* PADSZ returns needed bytes to pad bpos to pad size + * PAD_NN calculates pad size and adds it to bpos, returning the result. + * All take an integer or a pointer as bpos input. + */ +#define PADSZ(bpos, pad) (((pad) - ((uintptr_t)(bpos) % (pad))) % (pad)) +#define PAD_16(bpos) ((bpos) + PADSZ((bpos),16)) +#define PAD_64(bpos) ((bpos) + PADSZ((bpos),64)) +#define PAD_4096(bpos) ((bpos) + PADSZ((bpos),4096)) + +/* Diagnostic functions */ +#ifdef ZLIB_DEBUG +# include + extern int Z_INTERNAL z_verbose; + extern void Z_INTERNAL z_error(const char *m); +# define Assert(cond, msg) {int _cond = (cond); if (!_cond) z_error(msg);} +# define Trace(x) {if (z_verbose >= 0) fprintf x;} +# define Tracev(x) {if (z_verbose > 0) fprintf x;} +# define Tracevv(x) {if (z_verbose > 1) fprintf x;} +# define Tracec(c, x) {if (z_verbose > 0 && (c)) fprintf x;} +# define Tracecv(c, x) {if (z_verbose > 1 && (c)) fprintf x;} +#else +# define Assert(cond, msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c, x) +# define Tracecv(c, x) +#endif + +/* OPTIMAL_CMP values determine the comparison width: + * 64: Best for 64-bit architectures with unaligned access + * 32: Best for 32-bit architectures with unaligned access + * 16: Safe default for unknown architectures + * 8: Safe fallback for architectures without unaligned access + * Note: The unaligned access mentioned is cpu-support, this allows compiler or + * separate unaligned intrinsics to utilize safe unaligned access, without + * utilizing unaligned C pointers that are known to have undefined behavior. + */ +#if !defined(OPTIMAL_CMP) +# if defined(__x86_64__) || defined(_M_X64) || defined(__amd64__) || defined(_M_AMD64) +# define OPTIMAL_CMP 64 +# elif defined(__i386__) || defined(__i486__) || defined(__i586__) || \ + defined(__i686__) || defined(_X86_) || defined(_M_IX86) +# define OPTIMAL_CMP 32 +# elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) +# if defined(__ARM_FEATURE_UNALIGNED) || defined(_WIN32) +# define OPTIMAL_CMP 64 +# else +# define OPTIMAL_CMP 8 +# endif +# elif defined(__arm__) || defined(_M_ARM) +# if defined(__ARM_FEATURE_UNALIGNED) || defined(_WIN32) +# define OPTIMAL_CMP 32 +# else +# define OPTIMAL_CMP 8 +# endif +# elif defined(__powerpc64__) || defined(__ppc64__) +# define OPTIMAL_CMP 64 +# elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) +# define OPTIMAL_CMP 32 +# endif +#endif +#if !defined(OPTIMAL_CMP) +# define OPTIMAL_CMP 16 +#endif + +#if defined(__has_feature) +# if __has_feature(address_sanitizer) +# define Z_ADDRESS_SANITIZER 1 +# endif +#elif defined(__SANITIZE_ADDRESS__) +# define Z_ADDRESS_SANITIZER 1 +#endif + +/* + * __asan_loadN() and __asan_storeN() calls are inserted by compilers in order to check memory accesses. + * They can be called manually too, with the following caveats: + * gcc says: "warning: implicit declaration of function '...'" + * g++ says: "error: new declaration '...' ambiguates built-in declaration '...'" + * Accommodate both. + */ +#ifdef Z_ADDRESS_SANITIZER +#ifndef __cplusplus +void __asan_loadN(void *, long); +void __asan_storeN(void *, long); +#endif +#else +# define __asan_loadN(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0) +# define __asan_storeN(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0) +#endif + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# define Z_MEMORY_SANITIZER 1 +# include +# endif +#endif + +#ifndef Z_MEMORY_SANITIZER +# define __msan_check_mem_is_initialized(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0) +# define __msan_unpoison(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0) +#endif + +/* Notify sanitizer runtime about an upcoming read access. */ +#define instrument_read(a, size) do { \ + void *__a = (void *)(a); \ + long __size = size; \ + __asan_loadN(__a, __size); \ + __msan_check_mem_is_initialized(__a, __size); \ +} while (0) + +/* Notify sanitizer runtime about an upcoming write access. */ +#define instrument_write(a, size) do { \ + void *__a = (void *)(a); \ + long __size = size; \ + __asan_storeN(__a, __size); \ +} while (0) + +/* Notify sanitizer runtime about an upcoming read/write access. */ +#define instrument_read_write(a, size) do { \ + void *__a = (void *)(a); \ + long __size = size; \ + __asan_storeN(__a, __size); \ + __msan_check_mem_is_initialized(__a, __size); \ +} while (0) + +#endif diff --git a/zconf-ng.h.in b/zconf-ng.h.in new file mode 100644 index 0000000000..a1b5311b85 --- /dev/null +++ b/zconf-ng.h.in @@ -0,0 +1,176 @@ +/* zconf-ng.h -- configuration of the zlib-ng compression library + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef ZCONFNG_H +#define ZCONFNG_H + +#include "zlib_name_mangling-ng.h" + +#if !defined(_WIN32) && defined(__WIN32__) +# define _WIN32 +#endif + +/* Clang macro for detecting declspec support + * https://clang.llvm.org/docs/LanguageExtensions.html#has-declspec-attribute + */ +#ifndef __has_declspec_attribute +# define __has_declspec_attribute(x) 0 +#endif + +/* Always define z_const as const */ +#define z_const const + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# define MAX_MEM_LEVEL 9 +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MIN_WBITS +# define MIN_WBITS 8 /* 256 LZ77 window */ +#endif +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + +/* Type declarations */ + +#ifdef ZLIB_INTERNAL +# define Z_INTERNAL ZLIB_INTERNAL +#endif + +/* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +#if defined(ZLIB_DLL) && (defined(_WIN32) || (__has_declspec_attribute(dllexport) && __has_declspec_attribute(dllimport))) +# ifdef Z_INTERNAL +# define Z_EXTERN extern __declspec(dllexport) +# else +# define Z_EXTERN extern __declspec(dllimport) +# endif +#endif + +/* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +#if defined(ZLIB_WINAPI) && defined(_WIN32) +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define Z_EXPORT WINAPI +# define Z_EXPORTVA WINAPIV +#endif + +#ifndef Z_EXTERN +# define Z_EXTERN extern +#endif +#ifndef Z_EXPORT +# define Z_EXPORT +#endif +#ifndef Z_EXPORTVA +# define Z_EXPORTVA +#endif + +/* Conditional exports */ +#define ZNG_CONDEXPORT Z_EXPORT + +/* Fallback for something that includes us. */ +typedef unsigned char Byte; +typedef Byte Bytef; + +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +typedef char charf; +typedef int intf; +typedef uInt uIntf; +typedef uLong uLongf; + +typedef void const *voidpc; +typedef void *voidpf; +typedef void *voidp; + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by configure/cmake/etc */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef NEED_PTRDIFF_T /* may be set to #if 1 by configure/cmake/etc */ +typedef PTRDIFF_TYPE ptrdiff_t; +#endif + +#include /* for off_t */ + +#include /* for wchar_t and NULL */ + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && defined(WITH_GZFILEOP) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(__MSYS__) +# define z_off64_t _off64_t +# elif defined(_WIN32) && !defined(__GNUC__) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +#endif /* ZCONFNG_H */ diff --git a/zconf.h.in b/zconf.h.in new file mode 100644 index 0000000000..be8221fd86 --- /dev/null +++ b/zconf.h.in @@ -0,0 +1,206 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef ZCONF_H +#define ZCONF_H + +#include "zlib_name_mangling.h" + +#if !defined(_WIN32) && defined(__WIN32__) +# define _WIN32 +#endif + +/* Clang macro for detecting declspec support + * https://clang.llvm.org/docs/LanguageExtensions.html#has-declspec-attribute + */ +#ifndef __has_declspec_attribute +# define __has_declspec_attribute(x) 0 +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# define MAX_MEM_LEVEL 9 +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MIN_WBITS +# define MIN_WBITS 8 /* 256 LZ77 window */ +#endif +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + +/* Type declarations */ + + +#ifndef OF /* function prototypes */ +# define OF(args) args +#endif + +#ifdef ZLIB_INTERNAL +# define Z_INTERNAL ZLIB_INTERNAL +#endif + +/* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +#if defined(ZLIB_DLL) && (defined(_WIN32) || (__has_declspec_attribute(dllexport) && __has_declspec_attribute(dllimport))) +# ifdef Z_INTERNAL +# define Z_EXTERN extern __declspec(dllexport) +# else +# define Z_EXTERN extern __declspec(dllimport) +# endif +#endif + +/* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +#if defined(ZLIB_WINAPI) && defined(_WIN32) +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define Z_EXPORT WINAPI +# define Z_EXPORTVA WINAPIV +#endif + +#ifndef Z_EXTERN +# define Z_EXTERN extern +#endif +#ifndef Z_EXPORT +# define Z_EXPORT +#endif +#ifndef Z_EXPORTVA +# define Z_EXPORTVA +#endif + +/* Conditional exports */ +#define ZNG_CONDEXPORT Z_INTERNAL + +/* For backwards compatibility */ + +#ifndef ZEXTERN +# define ZEXTERN Z_EXTERN +#endif +#ifndef ZEXPORT +# define ZEXPORT Z_EXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA Z_EXPORTVA +#endif +#ifndef FAR +# define FAR +#endif + +/* Legacy zlib typedefs for backwards compatibility. Don't assume stdint.h is defined. */ +typedef unsigned char Byte; +typedef Byte Bytef; + +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +typedef char charf; +typedef int intf; +typedef uInt uIntf; +typedef uLong uLongf; + +typedef void const *voidpc; +typedef void *voidpf; +typedef void *voidp; + +typedef unsigned int z_crc_t; + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by configure/cmake/etc */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef NEED_PTRDIFF_T /* may be set to #if 1 by configure/cmake/etc */ +typedef PTRDIFF_TYPE ptrdiff_t; +#endif + +#include /* for off_t */ + +#include /* for wchar_t and NULL */ + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(__MSYS__) +# define z_off64_t _off64_t +# elif defined(_WIN32) && !defined(__GNUC__) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +typedef size_t z_size_t; + +#endif /* ZCONF_H */ diff --git a/zendian.h b/zendian.h new file mode 100644 index 0000000000..28177a609f --- /dev/null +++ b/zendian.h @@ -0,0 +1,60 @@ +/* zendian.h -- define BYTE_ORDER for endian tests + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef ENDIAN_H_ +#define ENDIAN_H_ + +/* First check whether the compiler knows the target __BYTE_ORDER__. */ +#if defined(__BYTE_ORDER__) +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# if !defined(LITTLE_ENDIAN) +# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +# endif +# if !defined(BYTE_ORDER) +# define BYTE_ORDER LITTLE_ENDIAN +# endif +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# if !defined(BIG_ENDIAN) +# define BIG_ENDIAN __ORDER_BIG_ENDIAN__ +# endif +# if !defined(BYTE_ORDER) +# define BYTE_ORDER BIG_ENDIAN +# endif +# endif +#elif defined(__MINGW32__) +# include +#elif defined(_WIN32) +# define LITTLE_ENDIAN 1234 +# define BIG_ENDIAN 4321 +# if defined(_M_IX86) || defined(_M_AMD64) || defined(_M_IA64) || defined (_M_ARM) || defined (_M_ARM64) || defined (_M_ARM64EC) +# define BYTE_ORDER LITTLE_ENDIAN +# else +# error Unknown endianness! +# endif +#elif defined(__linux__) +# include +#elif defined(__APPLE__) +# include +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) +# include +#elif defined(__sun) || defined(sun) +# include +# if !defined(LITTLE_ENDIAN) +# define LITTLE_ENDIAN 4321 +# endif +# if !defined(BIG_ENDIAN) +# define BIG_ENDIAN 1234 +# endif +# if !defined(BYTE_ORDER) +# if defined(_BIG_ENDIAN) +# define BYTE_ORDER BIG_ENDIAN +# else +# define BYTE_ORDER LITTLE_ENDIAN +# endif +# endif +#else +# include +#endif + +#endif diff --git a/zlib-config.cmake.in b/zlib-config.cmake.in new file mode 100644 index 0000000000..2e4ba4f230 --- /dev/null +++ b/zlib-config.cmake.in @@ -0,0 +1,12 @@ +set(ZLIB_VERSION @ZLIB_HEADER_VERSION@) + +@PACKAGE_INIT@ + +set_and_check(ZLIB_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set(ZLIB_INCLUDE_DIRS "${ZLIB_INCLUDE_DIR}") +set_and_check(ZLIB_LIB_DIR "@PACKAGE_LIB_INSTALL_DIR@") +set(ZLIB_LIBRARIES ZLIB::ZLIB) + +include("${CMAKE_CURRENT_LIST_DIR}/ZLIB.cmake") + +check_required_components(ZLIB) diff --git a/zlib-ng-config.cmake.in b/zlib-ng-config.cmake.in new file mode 100644 index 0000000000..f7564a905f --- /dev/null +++ b/zlib-ng-config.cmake.in @@ -0,0 +1,10 @@ +set(zlib-ng_VERSION @ZLIBNG_HEADER_VERSION@) + +@PACKAGE_INIT@ + +set_and_check(zlib-ng_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set_and_check(zlib-ng_LIB_DIR "@PACKAGE_LIB_INSTALL_DIR@") + +include("${CMAKE_CURRENT_LIST_DIR}/zlib-ng.cmake") + +check_required_components(zlib-ng) diff --git a/zlib-ng.h.in b/zlib-ng.h.in new file mode 100644 index 0000000000..93c7c86f26 --- /dev/null +++ b/zlib-ng.h.in @@ -0,0 +1,1871 @@ +#ifndef ZNGLIB_H_ +#define ZNGLIB_H_ +/* zlib-ng.h -- interface of the 'zlib-ng' compression library, forked from zlib. + + Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files https://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifdef ZLIB_H_ +# error Include zlib-ng.h for zlib-ng API or zlib.h for zlib-compat API but not both +#endif + +#ifndef RC_INVOKED +#include +#include + +#include "zconf-ng.h" + +#ifndef ZCONFNG_H +# error Missing zconf-ng.h add binary output directory to include directories +#endif +#endif /* RC_INVOKED */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIBNG_VERSION "2.2.4" +#define ZLIBNG_VERNUM 0x020204F0L /* MMNNRRSM: major minor revision status modified */ +#define ZLIBNG_VER_MAJOR 2 +#define ZLIBNG_VER_MINOR 2 +#define ZLIBNG_VER_REVISION 4 +#define ZLIBNG_VER_STATUS F /* 0=devel, 1-E=beta, F=Release (DEPRECATED) */ +#define ZLIBNG_VER_STATUSH 0xF /* Hex values: 0=devel, 1-E=beta, F=Release */ +#define ZLIBNG_VER_MODIFIED 0 /* non-zero if modified externally from zlib-ng */ + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef void *(*alloc_func) (void *opaque, unsigned int items, unsigned int size); +typedef void (*free_func) (void *opaque, void *address); + +struct internal_state; + +typedef struct zng_stream_s { + const uint8_t *next_in; /* next input byte */ + uint32_t avail_in; /* number of bytes available at next_in */ + size_t total_in; /* total number of input bytes read so far */ + + uint8_t *next_out; /* next output byte will go here */ + uint32_t avail_out; /* remaining free space at next_out */ + size_t total_out; /* total number of bytes output so far */ + + const char *msg; /* last error message, NULL if no error */ + struct internal_state *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + void *opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uint32_t adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + unsigned long reserved; /* reserved for future use */ +} zng_stream; + +typedef zng_stream *zng_streamp; /* Obsolete type, retained for compatibility only */ + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct zng_gz_header_s { + int32_t text; /* true if compressed data believed to be text */ + unsigned long time; /* modification time */ + int32_t xflags; /* extra flags (not used when writing a gzip file) */ + int32_t os; /* operating system */ + uint8_t *extra; /* pointer to extra field or NULL if none */ + uint32_t extra_len; /* extra field length (valid if extra != NULL) */ + uint32_t extra_max; /* space at extra (only when reading header) */ + uint8_t *name; /* pointer to zero-terminated file name or NULL */ + uint32_t name_max; /* space at name (only when reading header) */ + uint8_t *comment; /* pointer to zero-terminated comment or NULL */ + uint32_t comm_max; /* space at comment (only when reading header) */ + int32_t hcrc; /* true if there was or will be a header crc */ + int32_t done; /* true when done reading gzip header (not used when writing a gzip file) */ +} zng_gz_header; + +typedef zng_gz_header *zng_gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL NULL /* for compatibility with zlib, was for initializing zalloc, zfree, opaque */ + + + /* basic functions */ + +Z_EXTERN Z_EXPORT +const char *zlibng_version(void); +/* The application can compare zlibng_version and ZLIBNG_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib-ng.h header file used by the application. + */ + +Z_EXTERN Z_EXPORT +int32_t zng_deflateInit(zng_stream *strm, int32_t level); +/* + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. total_in, total_out, adler, and msg are initialized. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level. + msg is set to null if there is no error message. deflateInit does not perform + any compression: this will be done by deflate(). +*/ + + +Z_EXTERN Z_EXPORT +int32_t zng_deflate(zng_stream *strm, int32_t flush); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more output + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six when the flush marker begins, in order to avoid + repeated flush markers upon calling deflate() again when avail_out == 0. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL) or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +Z_EXTERN Z_EXPORT +int32_t zng_deflateEnd(zng_stream *strm); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +Z_EXTERN Z_EXPORT +int32_t zng_inflateInit(zng_stream *strm); +/* + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. total_in, total_out, adler, and + msg are initialized. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, or Z_STREAM_ERROR if the parameters are invalid, such as a null + pointer to the structure. msg is set to null if there is no error message. + inflateInit does not perform any decompression. Actual decompression will + be done by inflate(). So next_in, and avail_in, next_out, and avail_out + are unused and unchanged. The current implementation of inflateInit() + does not process any header information -- that is deferred until inflate() + is called. +*/ + + +Z_EXTERN Z_EXPORT +int32_t zng_inflate(zng_stream *strm, int32_t flush); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress is possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +Z_EXTERN Z_EXPORT +int32_t zng_inflateEnd(zng_stream *strm); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_deflateInit2(zng_stream *strm, int32_t level, int32_t method, int32_t windowBits, int32_t memLevel, int32_t strategy); +/* + This is another version of deflateInit with more compression options. The + fields zalloc, zfree and opaque must be initialized before by the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method). + msg is set to null if there is no error message. deflateInit2 does not perform + any compression: this will be done by deflate(). +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_deflateSetDictionary(zng_stream *strm, const uint8_t *dictionary, uint32_t dictLength); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_deflateGetDictionary(zng_stream *strm, uint8_t *dictionary, uint32_t *dictLength); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_deflateCopy(zng_stream *dest, zng_stream *source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_deflateReset(zng_stream *strm); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. total_in, total_out, adler, and msg are initialized. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_deflateParams(zng_stream *strm, int32_t level, int32_t strategy); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if there have been any deflate() calls since the + state was initialized or reset, then the input available so far is + compressed with the old level and strategy using deflate(strm, Z_BLOCK). + There are three approaches for the compression levels 0, 1..3, and 4..9 + respectively. The new level and strategy will take effect at the next call + of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_deflateTune(zng_stream *strm, int32_t good_length, int32_t max_lazy, int32_t nice_length, int32_t max_chain); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +Z_EXTERN Z_EXPORT +unsigned long zng_deflateBound(zng_stream *strm, unsigned long sourceLen); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_deflatePending(zng_stream *strm, uint32_t *pending, int32_t *bits); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +Z_EXTERN Z_EXPORT +int32_t zng_deflatePrime(zng_stream *strm, int32_t bits, int32_t value); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_deflateSetHeader(zng_stream *strm, zng_gz_headerp head); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided zng_gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not NULL, name and comment are terminated with + a zero byte, and that if extra is not NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to the current operating system, with no + extra, name, or comment fields. The gzip header is returned to the default + state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflateInit2(zng_stream *strm, int32_t windowBits); +/* + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will *not* automatically decode concatenated gzip members. + inflate() will return Z_STREAM_END at the end of the gzip member. The state + would need to be reset to continue decoding a subsequent gzip member. This + *must* be done if there is more data after a gzip member, in order for the + decompression to be compliant with the gzip standard (RFC 1952). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, or Z_STREAM_ERROR if the parameters are invalid, such as a null + pointer to the structure. msg is set to null if there is no error message. + inflateInit2 does not perform any decompression apart from possibly reading + the zlib header if present: actual decompression will be done by inflate(). + (So next_in and avail_in may be modified, but next_out and avail_out are + unused and unchanged.) The current implementation of inflateInit2() does not + process any header information -- that is deferred until inflate() is called. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflateSetDictionary(zng_stream *strm, const uint8_t *dictionary, uint32_t dictLength); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must ensure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflateGetDictionary(zng_stream *strm, uint8_t *dictionary, uint32_t *dictLength); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflateSync(zng_stream *strm); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflateCopy(zng_stream *dest, zng_stream *source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflateReset(zng_stream *strm); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + total_in, total_out, adler, and msg are initialized. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflateReset2(zng_stream *strm, int32_t windowBits); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL), or if + the windowBits parameter is invalid. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflatePrime(zng_stream *strm, int32_t bits, int32_t value); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +Z_EXTERN Z_EXPORT +long zng_inflateMark(zng_stream *strm); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflateGetHeader(zng_stream *strm, zng_gz_headerp head); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided zng_gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not NULL and the respective field is not + present in the header, then that field is set to NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflateBackInit(zng_stream *strm, int32_t windowBits, uint8_t *window); +/* + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated. +*/ + +typedef uint32_t (*in_func) (void *, const uint8_t * *); +typedef int32_t (*out_func) (void *, uint8_t *, uint32_t); + +Z_EXTERN Z_EXPORT +int32_t zng_inflateBack(zng_stream *strm, in_func in, void *in_desc, out_func out, void *out_desc); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is NULL, then in() will be called + immediately for input. If strm->next_in is not NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be NULL only if in() returned an error. If + strm->next_in is not NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_inflateBackEnd(zng_stream *strm); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +Z_EXTERN Z_EXPORT +unsigned long zng_zlibCompileFlags(void); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of unsigned int + 3.2: size of unsigned long + 5.4: size of void * (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed (not supported by zlib-ng) + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_compress(uint8_t *dest, size_t *destLen, const uint8_t *source, size_t sourceLen); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_compress2(uint8_t *dest, size_t *destLen, const uint8_t *source, size_t sourceLen, int32_t level); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +Z_EXTERN Z_EXPORT +size_t zng_compressBound(size_t sourceLen); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_uncompress(uint8_t *dest, size_t *destLen, const uint8_t *source, size_t sourceLen); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + + +Z_EXTERN Z_EXPORT +int32_t zng_uncompress2(uint8_t *dest, size_t *destLen, const uint8_t *source, size_t *sourceLen); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + +#ifdef WITH_GZFILEOP + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +Z_EXTERN Z_EXPORT +gzFile zng_gzopen(const char *path, const char *mode); +/* + Open the gzip (.gz) file at path for reading and decompressing, or + compressing and writing. The mode parameter is as in fopen ("rb" or "wb") + but can also include a compression level ("wb9") or a strategy: 'f' for + filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", + 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression + as in "wb9F". (See the description of deflateInit2 for more information + about the strategy parameter.) 'T' will request transparent writing or + appending with no compression and not using the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +Z_EXTERN Z_EXPORT +gzFile zng_gzdopen(int fd, const char *mode); +/* + Associate a gzFile with the file descriptor fd. File descriptors are + obtained from calls like open, dup, creat, pipe or fileno (if the file has + been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzbuffer(gzFile file, uint32_t size); +/* + Set the internal buffer size used by this library's functions for file to + size. The default buffer size is 8192 bytes. This function must be called + after gzopen() or gzdopen(), and before any other calls that read or write + the file. The buffer memory allocation is always deferred to the first read + or write. Three times that size in buffer space is allocated. A larger + buffer size of, for example, 64K or 128K bytes will noticeably increase the + speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzsetparams(gzFile file, int32_t level, int32_t strategy); +/* + Dynamically update the compression level and strategy for file. See the + description of deflateInit2 for the meaning of these parameters. Previously + provided data is flushed before applying the parameter changes. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzread(gzFile file, void *buf, uint32_t len); +/* + Read and decompress up to len uncompressed bytes from file into buf. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +Z_EXTERN Z_EXPORT +size_t zng_gzfread(void *buf, size_t size, size_t nitems, gzFile file); +/* + Read and decompress up to nitems items of size size from file into buf, + otherwise operating as gzread() does. This duplicates the interface of + stdio's fread(), with size_t request and return types. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevertheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, resetting and retrying on end-of-file, when size is not 1. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzwrite(gzFile file, void const *buf, uint32_t len); +/* + Compress and write the len uncompressed bytes at buf to file. gzwrite + returns the number of uncompressed bytes written or 0 in case of error. +*/ + +Z_EXTERN Z_EXPORT +size_t zng_gzfwrite(void const *buf, size_t size, size_t nitems, gzFile file); +/* + Compress and write nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +Z_EXTERN Z_EXPORTVA +int32_t zng_gzprintf(gzFile file, const char *format, ...); +/* + Convert, format, compress, and write the arguments (...) to file under + control of the string format, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf(), + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzputs(gzFile file, const char *s); +/* + Compress and write the given null-terminated string s to file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +Z_EXTERN Z_EXPORT +char * zng_gzgets(gzFile file, char *buf, int32_t len); +/* + Read and decompress bytes from file into buf, until len-1 characters are + read, or until a newline character is read and transferred to buf, or an + end-of-file condition is encountered. If any characters are read or if len + is one, the string is terminated with a null character. If no characters + are read due to an end-of-file or len is less than one, then the buffer is + left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzputc(gzFile file, int32_t c); +/* + Compress and write c, converted to an unsigned char, into file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzgetc(gzFile file); +/* + Read and decompress one byte from file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzungetc(int32_t c, gzFile file); +/* + Push c back onto the stream for file to be read as the first character on + the next read. At least one character of push-back is always allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzflush(gzFile file, int32_t flush); +/* + Flush all pending output to file. The parameter flush is as in the + deflate() function. The return value is the zlib error number (see function + gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +Z_EXTERN Z_EXPORT +z_off64_t zng_gzseek(gzFile file, z_off64_t offset, int whence); +/* + Set the starting position to offset relative to whence for the next gzread + or gzwrite on file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzrewind(gzFile file); +/* + Rewind file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). +*/ + +Z_EXTERN Z_EXPORT +z_off64_t zng_gztell(gzFile file); +/* + Return the starting position for the next gzread or gzwrite on file. + This position represents a number of bytes in the uncompressed data stream, + and is zero when starting, even if appending or reading a gzip stream from + the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +Z_EXTERN Z_EXPORT +z_off64_t zng_gzoffset(gzFile file); +/* + Return the current compressed (actual) read or write offset of file. This + offset includes the count of bytes that precede the gzip stream, for example + when appending or when using gzdopen() for reading. When reading, the + offset does not include as yet unused buffered input. This information can + be used for a progress indicator. On error, gzoffset() returns -1. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzeof(gzFile file); +/* + Return true (1) if the end-of-file indicator for file has been set while + reading, false (0) otherwise. Note that the end-of-file indicator is set + only if the read tried to go past the end of the input, but came up short. + Therefore, just like feof(), gzeof() may return false even if there is no + more data to read, in the event that the last read request was for the exact + number of bytes remaining in the input file. This will happen if the input + file size is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzdirect(gzFile file); +/* + Return true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzclose(gzFile file); +/* + Flush all pending output for file, if necessary, close file and + deallocate the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_gzclose_r(gzFile file); +Z_EXTERN Z_EXPORT +int32_t zng_gzclose_w(gzFile file); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +Z_EXTERN Z_EXPORT +const char * zng_gzerror(gzFile file, int32_t *errnum); +/* + Return the error message for the last error which occurred on file. + errnum is set to zlib error number. If an error occurred in the file system + and not in the compression library, errnum is set to Z_ERRNO and the + application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +Z_EXTERN Z_EXPORT +void zng_gzclearerr(gzFile file); +/* + Clear the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* WITH_GZFILEOP */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +Z_EXTERN Z_EXPORT +uint32_t zng_adler32(uint32_t adler, const uint8_t *buf, uint32_t len); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. An Adler-32 value is in the range of a 32-bit + unsigned integer. If buf is Z_NULL, this function returns the required + initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uint32_t adler = adler32(0L, NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +Z_EXTERN Z_EXPORT +uint32_t zng_adler32_z(uint32_t adler, const uint8_t *buf, size_t len); +/* + Same as adler32(), but with a size_t length. +*/ + +Z_EXTERN Z_EXPORT +uint32_t zng_adler32_combine(uint32_t adler1, uint32_t adler2, z_off64_t len2); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +Z_EXTERN Z_EXPORT +uint32_t zng_crc32(uint32_t crc, const uint8_t *buf, uint32_t len); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. + If buf is Z_NULL, this function returns the required initial value for the + crc. Pre- and post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the application. + + Usage example: + + uint32_t crc = crc32(0L, NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +Z_EXTERN Z_EXPORT +uint32_t zng_crc32_z(uint32_t crc, const uint8_t *buf, size_t len); +/* + Same as crc32(), but with a size_t length. +*/ + +Z_EXTERN Z_EXPORT +uint32_t zng_crc32_combine(uint32_t crc1, uint32_t crc2, z_off64_t len2); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. len2 must be non-negative. +*/ + +Z_EXTERN Z_EXPORT +uint32_t zng_crc32_combine_gen(z_off64_t len2); + +/* + Return the operator corresponding to length len2, to be used with + crc32_combine_op(). len2 must be non-negative. +*/ + +Z_EXTERN Z_EXPORT +uint32_t zng_crc32_combine_op(uint32_t crc1, uint32_t crc2, const uint32_t op); +/* + Give the same result as crc32_combine(), using op in place of len2. op is + is generated from len2 by crc32_combine_gen(). This will be faster than + crc32_combine() if the generated op is used more than once. +*/ + + /* various hacks, don't look :) */ + +#ifdef WITH_GZFILEOP + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +# define @ZLIB_SYMBOL_PREFIX@zng_gzgetc(g) ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (@ZLIB_SYMBOL_PREFIX@zng_gzgetc)(g)) + +#endif /* WITH_GZFILEOP */ + + +typedef enum { + Z_DEFLATE_LEVEL = 0, /* compression level, represented as an int */ + Z_DEFLATE_STRATEGY = 1, /* compression strategy, represented as an int */ + Z_DEFLATE_REPRODUCIBLE = 2, + /* + Whether reproducible compression results are required. Represented as an int, where 0 means that it is allowed + to trade reproducibility for e.g. improved performance or compression ratio, and non-0 means that + reproducibility is strictly required. Reproducibility is guaranteed only when using an identical zlib-ng build. + Default is 0. + */ +} zng_deflate_param; + +typedef struct { + zng_deflate_param param; /* parameter ID */ + void *buf; /* parameter value */ + size_t size; /* parameter value size */ + int32_t status; /* result of the last set/get call */ +} zng_deflate_param_value; + +Z_EXTERN Z_EXPORT +int32_t zng_deflateSetParams(zng_stream *strm, zng_deflate_param_value *params, size_t count); +/* + Sets the values of the given zlib-ng deflate stream parameters. All the buffers are copied internally, so the + caller still owns them after this function returns. Returns Z_OK if success. + + If the size of at least one of the buffers is too small to hold the entire value of the corresponding parameter, + or if the same parameter is specified multiple times, Z_BUF_ERROR is returned. The caller may inspect status fields + in order to determine which of the parameters caused this error. No other changes are performed. + + If the stream state is inconsistent or if at least one of the values cannot be updated, Z_STREAM_ERROR is + returned. The caller may inspect status fields in order to determine which of the parameters caused this error. + Parameters, whose status field is equal to Z_OK, have been applied successfully. If all status fields are not equal + to Z_STREAM_ERROR, then the error was caused by a stream state inconsistency. + + If there are no other errors, but at least one parameter is not supported by the current zlib-ng version, + Z_VERSION_ERROR is returned. The caller may inspect status fields in order to determine which of the parameters + caused this error. +*/ + +Z_EXTERN Z_EXPORT +int32_t zng_deflateGetParams(zng_stream *strm, zng_deflate_param_value *params, size_t count); +/* + Copies the values of the given zlib-ng deflate stream parameters into the user-provided buffers. Returns Z_OK if + success, Z_VERSION_ERROR if at least one parameter is not supported by the current zlib-ng version, Z_STREAM_ERROR + if the stream state is inconsistent, and Z_BUF_ERROR if the size of at least one buffer is too small to hold the + entire value of the corresponding parameter. +*/ + +/* undocumented functions */ +Z_EXTERN Z_EXPORT const char * zng_zError (int32_t); +Z_EXTERN Z_EXPORT int32_t zng_inflateSyncPoint (zng_stream *); +Z_EXTERN Z_EXPORT const uint32_t * zng_get_crc_table (void); +Z_EXTERN Z_EXPORT int32_t zng_inflateUndermine (zng_stream *, int32_t); +Z_EXTERN Z_EXPORT int32_t zng_inflateValidate (zng_stream *, int32_t); +Z_EXTERN Z_EXPORT unsigned long zng_inflateCodesUsed (zng_stream *); +Z_EXTERN Z_EXPORT int32_t zng_inflateResetKeep (zng_stream *); +Z_EXTERN Z_EXPORT int32_t zng_deflateResetKeep (zng_stream *); + +#ifdef WITH_GZFILEOP +# if defined(_WIN32) + Z_EXTERN Z_EXPORT gzFile zng_gzopen_w(const wchar_t *path, const char *mode); +# endif +Z_EXTERN Z_EXPORTVA int32_t zng_gzvprintf(gzFile file, const char *format, va_list va); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZNGLIB_H_ */ diff --git a/zlib-ng.map b/zlib-ng.map new file mode 100644 index 0000000000..64411ab105 --- /dev/null +++ b/zlib-ng.map @@ -0,0 +1,111 @@ +ZLIB_NG_2.1.0 { + global: + zng_deflateInit; + zng_deflateInit2; + zng_inflateBackInit; + zng_inflateInit; + zng_inflateInit2; + zlibng_version; +}; + +ZLIB_NG_2.0.0 { + global: + zng_adler32; + zng_adler32_combine; + zng_adler32_z; + zng_compress; + zng_compress2; + zng_compressBound; + zng_crc32; + zng_crc32_combine; + zng_crc32_combine_gen; + zng_crc32_combine_op; + zng_crc32_z; + zng_deflate; + zng_deflateBound; + zng_deflateCopy; + zng_deflateEnd; + zng_deflateGetDictionary; + zng_deflateGetParams; + zng_deflateInit_; + zng_deflateInit2_; + zng_deflateParams; + zng_deflatePending; + zng_deflatePrime; + zng_deflateReset; + zng_deflateResetKeep; + zng_deflateSetDictionary; + zng_deflateSetHeader; + zng_deflateSetParams; + zng_deflateTune; + zng_get_crc_table; + zng_inflate; + zng_inflateBack; + zng_inflateBackEnd; + zng_inflateBackInit_; + zng_inflateCodesUsed; + zng_inflateCopy; + zng_inflateEnd; + zng_inflateGetDictionary; + zng_inflateGetHeader; + zng_inflateInit_; + zng_inflateInit2_; + zng_inflateMark; + zng_inflatePrime; + zng_inflateReset; + zng_inflateReset2; + zng_inflateResetKeep; + zng_inflateSetDictionary; + zng_inflateSync; + zng_inflateSyncPoint; + zng_inflateUndermine; + zng_inflateValidate; + zng_uncompress; + zng_uncompress2; + zng_zError; + zng_zlibCompileFlags; + zng_vstring; + local: + zng_deflate_copyright; + zng_inflate_copyright; + zng_zcalloc; + zng_zcfree; + zng_z_errmsg; + gz_error; + _*; +}; + +ZLIB_NG_GZ_2.0.0 { + global: + zng_gzbuffer; + zng_gzclearerr; + zng_gzclose; + zng_gzclose_r; + zng_gzclose_w; + zng_gzdirect; + zng_gzdopen; + zng_gzeof; + zng_gzerror; + zng_gzflush; + zng_gzfread; + zng_gzfwrite; + zng_gzgetc; + zng_gzgets; + zng_gzoffset; + zng_gzopen; + zng_gzprintf; + zng_gzputc; + zng_gzputs; + zng_gzread; + zng_gzrewind; + zng_gzseek; + zng_gzsetparams; + zng_gztell; + zng_gzungetc; + zng_gzvprintf; + zng_gzwrite; +}; + +FAIL { + local: *; +}; diff --git a/zlib.h.in b/zlib.h.in new file mode 100644 index 0000000000..b8fa106ef1 --- /dev/null +++ b/zlib.h.in @@ -0,0 +1,1859 @@ +#ifndef ZLIB_H_ +#define ZLIB_H_ +/* zlib.h -- interface of the 'zlib-ng' compression library + Forked from and compatible with zlib 1.3.1 + + Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files https://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifdef ZNGLIB_H_ +# error Include zlib-ng.h for zlib-ng API or zlib.h for zlib-compat API but not both +#endif + +#ifndef RC_INVOKED +#include +#include + +#include "zconf.h" + +#ifndef ZCONF_H +# error Missing zconf.h add binary output directory to include directories +#endif +#endif /* RC_INVOKED */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIBNG_VERSION "2.2.4" +#define ZLIBNG_VERNUM 0x020204F0L /* MMNNRRSM: major minor revision status modified */ +#define ZLIBNG_VER_MAJOR 2 +#define ZLIBNG_VER_MINOR 2 +#define ZLIBNG_VER_REVISION 4 +#define ZLIBNG_VER_STATUS F /* 0=devel, 1-E=beta, F=Release (DEPRECATED) */ +#define ZLIBNG_VER_STATUSH 0xF /* Hex values: 0=devel, 1-E=beta, F=Release */ +#define ZLIBNG_VER_MODIFIED 0 /* non-zero if modified externally from zlib-ng */ + +#define ZLIB_VERSION "1.3.1.zlib-ng" +#define ZLIB_VERNUM 0x131f +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 3 +#define ZLIB_VER_REVISION 1 +#define ZLIB_VER_SUBREVISION 15 /* 15=fork (0xf) */ + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef void *(*alloc_func) (void *opaque, unsigned int items, unsigned int size); +typedef void (*free_func) (void *opaque, void *address); + +struct internal_state; + +typedef struct z_stream_s { + z_const unsigned char *next_in; /* next input byte */ + uint32_t avail_in; /* number of bytes available at next_in */ + unsigned long total_in; /* total number of input bytes read so far */ + + unsigned char *next_out; /* next output byte will go here */ + uint32_t avail_out; /* remaining free space at next_out */ + unsigned long total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + void *opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + unsigned long adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + unsigned long reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream *z_streamp; /* Obsolete type, retained for compatibility only */ + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + unsigned long time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + unsigned char *extra; /* pointer to extra field or NULL if none */ + unsigned int extra_len; /* extra field length (valid if extra != NULL) */ + unsigned int extra_max; /* space at extra (only when reading header) */ + unsigned char *name; /* pointer to zero-terminated file name or NULL */ + unsigned int name_max; /* space at name (only when reading header) */ + unsigned char *comment; /* pointer to zero-terminated comment or NULL */ + unsigned int comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used when writing a gzip file) */ +} gz_header; + +typedef gz_header *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for compatibility with zlib, was for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +Z_EXTERN const char * Z_EXPORT zlibVersion(void); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +Z_EXTERN int Z_EXPORT deflateInit (z_stream *strm, int level); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. total_in, total_out, adler, and msg are initialized. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +Z_EXTERN int Z_EXPORT deflate(z_stream *strm, int flush); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more output + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six when the flush marker begins, in order to avoid + repeated flush markers upon calling deflate() again when avail_out == 0. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL) or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +Z_EXTERN int Z_EXPORT deflateEnd(z_stream *strm); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +Z_EXTERN int Z_EXPORT inflateInit (z_stream *strm); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. total_in, total_out, adler, and + msg are initialized. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. +*/ + + +Z_EXTERN int Z_EXPORT inflate(z_stream *strm, int flush); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress is possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +Z_EXTERN int Z_EXPORT inflateEnd(z_stream *strm); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +Z_EXTERN int Z_EXPORT deflateInit2 (z_stream *strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy); + + This is another version of deflateInit with more compression options. The + fields zalloc, zfree and opaque must be initialized before by the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +Z_EXTERN int Z_EXPORT deflateSetDictionary(z_stream *strm, + const unsigned char *dictionary, + unsigned int dictLength); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +Z_EXTERN int Z_EXPORT deflateGetDictionary (z_stream *strm, unsigned char *dictionary, unsigned int *dictLength); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +Z_EXTERN int Z_EXPORT deflateCopy(z_stream *dest, z_stream *source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +Z_EXTERN int Z_EXPORT deflateReset(z_stream *strm); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. total_in, total_out, adler, and msg are initialized. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +Z_EXTERN int Z_EXPORT deflateParams(z_stream *strm, int level, int strategy); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if there have been any deflate() calls since the + state was initialized or reset, then the input available so far is + compressed with the old level and strategy using deflate(strm, Z_BLOCK). + There are three approaches for the compression levels 0, 1..3, and 4..9 + respectively. The new level and strategy will take effect at the next call + of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +Z_EXTERN int Z_EXPORT deflateTune(z_stream *strm, int good_length, int max_lazy, int nice_length, int max_chain); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +Z_EXTERN unsigned long Z_EXPORT deflateBound(z_stream *strm, unsigned long sourceLen); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +Z_EXTERN int Z_EXPORT deflatePending(z_stream *strm, uint32_t *pending, int *bits); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +Z_EXTERN int Z_EXPORT deflatePrime(z_stream *strm, int bits, int value); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +Z_EXTERN int Z_EXPORT deflateSetHeader(z_stream *strm, gz_headerp head); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not NULL, name and comment are terminated with + a zero byte, and that if extra is not NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to the current operating system, with no + extra, name, or comment fields. The gzip header is returned to the default + state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +Z_EXTERN int Z_EXPORT inflateInit2(z_stream *strm, int windowBits); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will *not* automatically decode concatenated gzip members. + inflate() will return Z_STREAM_END at the end of the gzip member. The state + would need to be reset to continue decoding a subsequent gzip member. This + *must* be done if there is more data after a gzip member, in order for the + decompression to be compliant with the gzip standard (RFC 1952). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +Z_EXTERN int Z_EXPORT inflateSetDictionary(z_stream *strm, const unsigned char *dictionary, unsigned int dictLength); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must ensure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +Z_EXTERN int Z_EXPORT inflateGetDictionary(z_stream *strm, unsigned char *dictionary, unsigned int *dictLength); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +Z_EXTERN int Z_EXPORT inflateSync(z_stream *strm); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +Z_EXTERN int Z_EXPORT inflateCopy(z_stream *dest, z_stream *source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +Z_EXTERN int Z_EXPORT inflateReset(z_stream *strm); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + total_in, total_out, adler, and msg are initialized. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +Z_EXTERN int Z_EXPORT inflateReset2(z_stream *strm, int windowBits); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL), or if + the windowBits parameter is invalid. +*/ + +Z_EXTERN int Z_EXPORT inflatePrime(z_stream *strm, int bits, int value); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +Z_EXTERN long Z_EXPORT inflateMark(z_stream *strm); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +Z_EXTERN int Z_EXPORT inflateGetHeader(z_stream *strm, gz_headerp head); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not NULL and the respective field is not + present in the header, then that field is set to NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +Z_EXTERN int Z_EXPORT inflateBackInit (z_stream *strm, int windowBits, unsigned char *window); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef uint32_t (*in_func) (void *, z_const unsigned char * *); +typedef int (*out_func) (void *, unsigned char *, uint32_t); + +Z_EXTERN int Z_EXPORT inflateBack(z_stream *strm, in_func in, void *in_desc, out_func out, void *out_desc); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is NULL, then in() will be called + immediately for input. If strm->next_in is not NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be NULL only if in() returned an error. If + strm->next_in is not NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +Z_EXTERN int Z_EXPORT inflateBackEnd(z_stream *strm); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +Z_EXTERN unsigned long Z_EXPORT zlibCompileFlags(void); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of unsigned int + 3.2: size of unsigned long + 5.4: size of void * (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed (not supported by zlib-ng) + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +Z_EXTERN int Z_EXPORT compress(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +Z_EXTERN int Z_EXPORT compress2(unsigned char *dest, unsigned long *destLen, const unsigned char *source, + unsigned long sourceLen, int level); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +Z_EXTERN unsigned long Z_EXPORT compressBound(unsigned long sourceLen); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +Z_EXTERN int Z_EXPORT uncompress(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + + +Z_EXTERN int Z_EXPORT uncompress2 (unsigned char *dest, unsigned long *destLen, + const unsigned char *source, unsigned long *sourceLen); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +Z_EXTERN gzFile Z_EXPORT gzopen(const char *path, const char *mode); + + Open the gzip (.gz) file at path for reading and decompressing, or + compressing and writing. The mode parameter is as in fopen ("rb" or "wb") + but can also include a compression level ("wb9") or a strategy: 'f' for + filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", + 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression + as in "wb9F". (See the description of deflateInit2 for more information + about the strategy parameter.) 'T' will request transparent writing or + appending with no compression and not using the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +Z_EXTERN gzFile Z_EXPORT gzdopen(int fd, const char *mode); +/* + Associate a gzFile with the file descriptor fd. File descriptors are + obtained from calls like open, dup, creat, pipe or fileno (if the file has + been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +Z_EXTERN int Z_EXPORT gzbuffer(gzFile file, unsigned size); +/* + Set the internal buffer size used by this library's functions for file to + size. The default buffer size is 8192 bytes. This function must be called + after gzopen() or gzdopen(), and before any other calls that read or write + the file. The buffer memory allocation is always deferred to the first read + or write. Three times that size in buffer space is allocated. A larger + buffer size of, for example, 64K or 128K bytes will noticeably increase the + speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +Z_EXTERN int Z_EXPORT gzsetparams(gzFile file, int level, int strategy); +/* + Dynamically update the compression level and strategy for file. See the + description of deflateInit2 for the meaning of these parameters. Previously + provided data is flushed before applying the parameter changes. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +Z_EXTERN int Z_EXPORT gzread(gzFile file, void *buf, unsigned len); +/* + Read and decompress up to len uncompressed bytes from file into buf. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +Z_EXTERN size_t Z_EXPORT gzfread (void *buf, size_t size, size_t nitems, gzFile file); +/* + Read and decompress up to nitems items of size size from file into buf, + otherwise operating as gzread() does. This duplicates the interface of + stdio's fread(), with size_t request and return types. If the library + defines size_t, then z_size_t is identical to size_t. If not, then z_size_t + is an unsigned integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevertheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, resetting and retrying on end-of-file, when size is not 1. +*/ + +Z_EXTERN int Z_EXPORT gzwrite(gzFile file, void const *buf, unsigned len); +/* + Compress and write the len uncompressed bytes at buf to file. gzwrite + returns the number of uncompressed bytes written or 0 in case of error. +*/ + +Z_EXTERN size_t Z_EXPORT gzfwrite(void const *buf, size_t size, size_t nitems, gzFile file); +/* + Compress and write nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +Z_EXTERN int Z_EXPORTVA gzprintf(gzFile file, const char *format, ...); +/* + Convert, format, compress, and write the arguments (...) to file under + control of the string format, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf(), + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +Z_EXTERN int Z_EXPORT gzputs(gzFile file, const char *s); +/* + Compress and write the given null-terminated string s to file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +Z_EXTERN char * Z_EXPORT gzgets(gzFile file, char *buf, int len); +/* + Read and decompress bytes from file into buf, until len-1 characters are + read, or until a newline character is read and transferred to buf, or an + end-of-file condition is encountered. If any characters are read or if len + is one, the string is terminated with a null character. If no characters + are read due to an end-of-file or len is less than one, then the buffer is + left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +Z_EXTERN int Z_EXPORT gzputc(gzFile file, int c); +/* + Compress and write c, converted to an unsigned char, into file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +Z_EXTERN int Z_EXPORT gzgetc(gzFile file); +/* + Read and decompress one byte from file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +Z_EXTERN int Z_EXPORT gzungetc(int c, gzFile file); +/* + Push c back onto the stream for file to be read as the first character on + the next read. At least one character of push-back is always allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +Z_EXTERN int Z_EXPORT gzflush(gzFile file, int flush); +/* + Flush all pending output to file. The parameter flush is as in the + deflate() function. The return value is the zlib error number (see function + gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +Z_EXTERN z_off_t Z_EXPORT gzseek (gzFile file, z_off_t offset, int whence); + + Set the starting position to offset relative to whence for the next gzread + or gzwrite on file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +Z_EXTERN int Z_EXPORT gzrewind(gzFile file); +/* + Rewind file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). +*/ + +/* +Z_EXTERN z_off_t Z_EXPORT gztell(gzFile file); + + Return the starting position for the next gzread or gzwrite on file. + This position represents a number of bytes in the uncompressed data stream, + and is zero when starting, even if appending or reading a gzip stream from + the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +Z_EXTERN z_off_t Z_EXPORT gzoffset(gzFile file); + + Return the current compressed (actual) read or write offset of file. This + offset includes the count of bytes that precede the gzip stream, for example + when appending or when using gzdopen() for reading. When reading, the + offset does not include as yet unused buffered input. This information can + be used for a progress indicator. On error, gzoffset() returns -1. +*/ + +Z_EXTERN int Z_EXPORT gzeof(gzFile file); +/* + Return true (1) if the end-of-file indicator for file has been set while + reading, false (0) otherwise. Note that the end-of-file indicator is set + only if the read tried to go past the end of the input, but came up short. + Therefore, just like feof(), gzeof() may return false even if there is no + more data to read, in the event that the last read request was for the exact + number of bytes remaining in the input file. This will happen if the input + file size is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +Z_EXTERN int Z_EXPORT gzdirect(gzFile file); +/* + Return true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +Z_EXTERN int Z_EXPORT gzclose(gzFile file); +/* + Flush all pending output for file, if necessary, close file and + deallocate the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +Z_EXTERN int Z_EXPORT gzclose_r(gzFile file); +Z_EXTERN int Z_EXPORT gzclose_w(gzFile file); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +Z_EXTERN const char * Z_EXPORT gzerror(gzFile file, int *errnum); +/* + Return the error message for the last error which occurred on file. + errnum is set to zlib error number. If an error occurred in the file system + and not in the compression library, errnum is set to Z_ERRNO and the + application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +Z_EXTERN void Z_EXPORT gzclearerr(gzFile file); +/* + Clear the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +Z_EXTERN unsigned long Z_EXPORT adler32(unsigned long adler, const unsigned char *buf, unsigned int len); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. An Adler-32 value is in the range of a 32-bit + unsigned integer. If buf is Z_NULL, this function returns the required + initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uint32_t adler = adler32(0L, NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +Z_EXTERN unsigned long Z_EXPORT adler32_z(unsigned long adler, const unsigned char *buf, size_t len); +/* + Same as adler32(), but with a size_t length. +*/ + +/* +Z_EXTERN unsigned long Z_EXPORT adler32_combine(unsigned long adler1, unsigned long adler2, z_off_t len2); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +Z_EXTERN unsigned long Z_EXPORT crc32(unsigned long crc, const unsigned char *buf, unsigned int len); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. + If buf is Z_NULL, this function returns the required initial value for the + crc. Pre- and post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the application. + + Usage example: + + uint32_t crc = crc32(0L, NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +Z_EXTERN unsigned long Z_EXPORT crc32_z(unsigned long crc, const unsigned char *buf, size_t len); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +Z_EXTERN unsigned long Z_EXPORT crc32_combine(unsigned long crc1, unsigned long crc2, z_off64_t len2); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. len2 must be non-negative. +*/ + +/* +Z_EXTERN unsigned long Z_EXPORT crc32_combine_gen(z_off_t len2); + + Return the operator corresponding to length len2, to be used with + crc32_combine_op(). len2 must be non-negative. +*/ + +Z_EXTERN unsigned long Z_EXPORT crc32_combine_op(unsigned long crc1, unsigned long crc2, + const unsigned long op); +/* + Give the same result as crc32_combine(), using op in place of len2. op is + is generated from len2 by crc32_combine_gen(). This will be faster than + crc32_combine() if the generated op is used more than once. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +Z_EXTERN int Z_EXPORT deflateInit_(z_stream *strm, int level, const char *version, int stream_size); +Z_EXTERN int Z_EXPORT inflateInit_(z_stream *strm, const char *version, int stream_size); +Z_EXTERN int Z_EXPORT deflateInit2_(z_stream *strm, int level, int method, int windowBits, int memLevel, + int strategy, const char *version, int stream_size); +Z_EXTERN int Z_EXPORT inflateInit2_(z_stream *strm, int windowBits, const char *version, int stream_size); +Z_EXTERN int Z_EXPORT inflateBackInit_(z_stream *strm, int windowBits, unsigned char *window, + const char *version, int stream_size); +#define @ZLIB_SYMBOL_PREFIX@deflateInit(strm, level) deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +#define @ZLIB_SYMBOL_PREFIX@inflateInit(strm) inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +#define @ZLIB_SYMBOL_PREFIX@deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm), (level), (method), (windowBits), (memLevel), \ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +#define @ZLIB_SYMBOL_PREFIX@inflateInit2(strm, windowBits) inflateInit2_((strm), (windowBits), ZLIB_VERSION, (int)sizeof(z_stream)) +#define @ZLIB_SYMBOL_PREFIX@inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), ZLIB_VERSION, (int)sizeof(z_stream)) + + +#ifndef Z_SOLO +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +Z_EXTERN int Z_EXPORT gzgetc_(gzFile file); /* backward compatibility */ +# define @ZLIB_SYMBOL_PREFIX@gzgetc(g) ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (@ZLIB_SYMBOL_PREFIX@gzgetc)(g)) + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + Z_EXTERN gzFile Z_EXPORT gzopen64(const char *, const char *); + Z_EXTERN z_off64_t Z_EXPORT gzseek64(gzFile, z_off64_t, int); + Z_EXTERN z_off64_t Z_EXPORT gztell64(gzFile); + Z_EXTERN z_off64_t Z_EXPORT gzoffset64(gzFile); + Z_EXTERN unsigned long Z_EXPORT adler32_combine64(unsigned long, unsigned long, z_off64_t); + Z_EXTERN unsigned long Z_EXPORT crc32_combine64(unsigned long, unsigned long, z_off64_t); + Z_EXTERN unsigned long Z_EXPORT crc32_combine_gen64(z_off64_t); +#endif +#endif + +#if !defined(Z_SOLO) && !defined(Z_INTERNAL) && defined(Z_WANT64) +# define @ZLIB_SYMBOL_PREFIX@gzopen @ZLIB_SYMBOL_PREFIX@gzopen64 +# define @ZLIB_SYMBOL_PREFIX@gzseek @ZLIB_SYMBOL_PREFIX@gzseek64 +# define @ZLIB_SYMBOL_PREFIX@gztell @ZLIB_SYMBOL_PREFIX@gztell64 +# define @ZLIB_SYMBOL_PREFIX@gzoffset @ZLIB_SYMBOL_PREFIX@gzoffset64 +# define @ZLIB_SYMBOL_PREFIX@adler32_combine @ZLIB_SYMBOL_PREFIX@adler32_combine64 +# define @ZLIB_SYMBOL_PREFIX@crc32_combine @ZLIB_SYMBOL_PREFIX@crc32_combine64 +# define @ZLIB_SYMBOL_PREFIX@crc32_combine_gen @ZLIB_SYMBOL_PREFIX@crc32_combine_gen64 +# ifndef Z_LARGE64 + Z_EXTERN gzFile Z_EXPORT @ZLIB_SYMBOL_PREFIX@gzopen64(const char *, const char *); + Z_EXTERN z_off_t Z_EXPORT @ZLIB_SYMBOL_PREFIX@gzseek64(gzFile, z_off_t, int); + Z_EXTERN z_off_t Z_EXPORT @ZLIB_SYMBOL_PREFIX@gztell64(gzFile); + Z_EXTERN z_off_t Z_EXPORT @ZLIB_SYMBOL_PREFIX@gzoffset64(gzFile); + Z_EXTERN unsigned long Z_EXPORT @ZLIB_SYMBOL_PREFIX@adler32_combine64(unsigned long, unsigned long, z_off_t); + Z_EXTERN unsigned long Z_EXPORT @ZLIB_SYMBOL_PREFIX@crc32_combine64(unsigned long, unsigned long, z_off_t); + Z_EXTERN unsigned long Z_EXPORT @ZLIB_SYMBOL_PREFIX@crc32_combine_gen64(z_off64_t); +# endif +#else +# ifndef Z_SOLO + Z_EXTERN gzFile Z_EXPORT @ZLIB_SYMBOL_PREFIX@gzopen(const char *, const char *); + Z_EXTERN z_off_t Z_EXPORT @ZLIB_SYMBOL_PREFIX@gzseek(gzFile, z_off_t, int); + Z_EXTERN z_off_t Z_EXPORT @ZLIB_SYMBOL_PREFIX@gztell(gzFile); + Z_EXTERN z_off_t Z_EXPORT @ZLIB_SYMBOL_PREFIX@gzoffset(gzFile); +# endif + Z_EXTERN unsigned long Z_EXPORT @ZLIB_SYMBOL_PREFIX@adler32_combine(unsigned long, unsigned long, z_off_t); + Z_EXTERN unsigned long Z_EXPORT @ZLIB_SYMBOL_PREFIX@crc32_combine(unsigned long, unsigned long, z_off_t); + Z_EXTERN unsigned long Z_EXPORT @ZLIB_SYMBOL_PREFIX@crc32_combine_gen(z_off_t); +#endif + +/* undocumented functions */ +Z_EXTERN const char * Z_EXPORT zError (int); +Z_EXTERN int Z_EXPORT inflateSyncPoint (z_stream *); +Z_EXTERN const uint32_t * Z_EXPORT get_crc_table (void); +Z_EXTERN int Z_EXPORT inflateUndermine (z_stream *, int); +Z_EXTERN int Z_EXPORT inflateValidate (z_stream *, int); +Z_EXTERN unsigned long Z_EXPORT inflateCodesUsed (z_stream *); +Z_EXTERN int Z_EXPORT inflateResetKeep (z_stream *); +Z_EXTERN int Z_EXPORT deflateResetKeep (z_stream *); + +#ifndef Z_SOLO +#if defined(_WIN32) + Z_EXTERN gzFile Z_EXPORT gzopen_w(const wchar_t *path, const char *mode); +#endif +Z_EXTERN int Z_EXPORTVA gzvprintf(gzFile file, const char *format, va_list va); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H_ */ diff --git a/zlib.map b/zlib.map new file mode 100644 index 0000000000..293e803729 --- /dev/null +++ b/zlib.map @@ -0,0 +1,98 @@ +ZLIB_1.2.0 { + global: + compressBound; + deflateBound; + inflateBack; + inflateBackEnd; + inflateBackInit_; + inflateCopy; + local: + deflate_copyright; + inflate_copyright; + zcalloc; + zcfree; + z_errmsg; + gz_error; + gz_intmax; + _*; +}; + +ZLIB_1.2.0.2 { + gzclearerr; + gzungetc; + zlibCompileFlags; +} ZLIB_1.2.0; + +ZLIB_1.2.0.8 { + deflatePrime; +} ZLIB_1.2.0.2; + +ZLIB_1.2.2 { + adler32_combine; + crc32_combine; + deflateSetHeader; + inflateGetHeader; +} ZLIB_1.2.0.8; + +ZLIB_1.2.2.3 { + deflateTune; + gzdirect; +} ZLIB_1.2.2; + +ZLIB_1.2.2.4 { + inflatePrime; +} ZLIB_1.2.2.3; + +ZLIB_1.2.3.3 { + adler32_combine64; + crc32_combine64; + gzopen64; + gzseek64; + gztell64; + inflateUndermine; +} ZLIB_1.2.2.4; + +ZLIB_1.2.3.4 { + inflateReset2; + inflateMark; +} ZLIB_1.2.3.3; + +ZLIB_1.2.3.5 { + gzbuffer; + gzoffset; + gzoffset64; + gzclose_r; + gzclose_w; +} ZLIB_1.2.3.4; + +ZLIB_1.2.5.1 { + deflatePending; +} ZLIB_1.2.3.5; + +ZLIB_1.2.5.2 { + deflateResetKeep; + gzgetc_; + inflateResetKeep; +} ZLIB_1.2.5.1; + +ZLIB_1.2.7.1 { + inflateGetDictionary; + gzvprintf; +} ZLIB_1.2.5.2; + +ZLIB_1.2.9 { + inflateCodesUsed; + inflateValidate; + uncompress2; + gzfread; + gzfwrite; + deflateGetDictionary; + adler32_z; + crc32_z; +} ZLIB_1.2.7.1; + +ZLIB_1.2.12 { + crc32_combine_gen; + crc32_combine_gen64; + crc32_combine_op; +} ZLIB_1.2.9; diff --git a/zlib.pc.cmakein b/zlib.pc.cmakein new file mode 100644 index 0000000000..df8bf9f051 --- /dev/null +++ b/zlib.pc.cmakein @@ -0,0 +1,14 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +symbol_prefix=@ZLIB_SYMBOL_PREFIX@ +libdir=@PC_LIB_INSTALL_DIR@ +sharedlibdir=${libdir} +includedir=@PC_INC_INSTALL_DIR@ + +Name: zlib@SUFFIX@ +Description: zlib-ng compression library +Version: @ZLIB_FULL_VERSION@ + +Requires: +Libs: -L${libdir} -L${sharedlibdir} -lz@SUFFIX@ +Cflags: -I${includedir} @PKG_CONFIG_CFLAGS@ diff --git a/zlib.pc.in b/zlib.pc.in new file mode 100644 index 0000000000..45b35989b1 --- /dev/null +++ b/zlib.pc.in @@ -0,0 +1,14 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +symbol_prefix=@symbol_prefix@ +libdir=@libdir@ +sharedlibdir=@sharedlibdir@ +includedir=@includedir@ + +Name: zlib@SUFFIX@ +Description: zlib-ng compression library +Version: @VERSION@ + +Requires: +Libs: -L${libdir} -L${sharedlibdir} -lz@SUFFIX@ +Cflags: -I${includedir} @PKG_CONFIG_CFLAGS@ diff --git a/zlib_name_mangling-ng.h.in b/zlib_name_mangling-ng.h.in new file mode 100644 index 0000000000..e90904a737 --- /dev/null +++ b/zlib_name_mangling-ng.h.in @@ -0,0 +1,178 @@ +/* zlib_name_mangling.h has been automatically generated from + * zlib_name_mangling.h.in because ZLIB_SYMBOL_PREFIX was set. + */ + +#ifndef ZLIB_NAME_MANGLING_H +#define ZLIB_NAME_MANGLING_H + +/* all linked symbols and init macros */ +#define zng__dist_code @ZLIB_SYMBOL_PREFIX@zng__dist_code +#define zng__length_code @ZLIB_SYMBOL_PREFIX@zng__length_code +#define zng__tr_align @ZLIB_SYMBOL_PREFIX@zng__tr_align +#define zng__tr_flush_bits @ZLIB_SYMBOL_PREFIX@zng__tr_flush_bits +#define zng__tr_flush_block @ZLIB_SYMBOL_PREFIX@zng__tr_flush_block +#define zng__tr_init @ZLIB_SYMBOL_PREFIX@zng__tr_init +#define zng__tr_stored_block @ZLIB_SYMBOL_PREFIX@zng__tr_stored_block +#define zng__tr_tally @ZLIB_SYMBOL_PREFIX@zng__tr_tally +#define zng_adler32 @ZLIB_SYMBOL_PREFIX@zng_adler32 +#define zng_adler32_combine @ZLIB_SYMBOL_PREFIX@zng_adler32_combine +#define zng_adler32_combine64 @ZLIB_SYMBOL_PREFIX@zng_adler32_combine64 +#define zng_adler32_z @ZLIB_SYMBOL_PREFIX@zng_adler32_z +#define zng_compress @ZLIB_SYMBOL_PREFIX@zng_compress +#define zng_compress2 @ZLIB_SYMBOL_PREFIX@zng_compress2 +#define zng_compressBound @ZLIB_SYMBOL_PREFIX@zng_compressBound +#define zng_crc32 @ZLIB_SYMBOL_PREFIX@zng_crc32 +#define zng_crc32_combine @ZLIB_SYMBOL_PREFIX@zng_crc32_combine +#define zng_crc32_combine64 @ZLIB_SYMBOL_PREFIX@zng_crc32_combine64 +#define zng_crc32_combine_gen @ZLIB_SYMBOL_PREFIX@zng_crc32_combine_gen +#define zng_crc32_combine_gen64 @ZLIB_SYMBOL_PREFIX@zng_crc32_combine_gen64 +#define zng_crc32_combine_op @ZLIB_SYMBOL_PREFIX@zng_crc32_combine_op +#define zng_crc32_z @ZLIB_SYMBOL_PREFIX@zng_crc32_z +#define zng_deflate @ZLIB_SYMBOL_PREFIX@zng_deflate +#define zng_deflateBound @ZLIB_SYMBOL_PREFIX@zng_deflateBound +#define zng_deflateCopy @ZLIB_SYMBOL_PREFIX@zng_deflateCopy +#define zng_deflateEnd @ZLIB_SYMBOL_PREFIX@zng_deflateEnd +#define zng_deflateGetDictionary @ZLIB_SYMBOL_PREFIX@zng_deflateGetDictionary +#define zng_deflateInit @ZLIB_SYMBOL_PREFIX@zng_deflateInit +#define zng_deflateInit2 @ZLIB_SYMBOL_PREFIX@zng_deflateInit2 +#define zng_deflateInit2_ @ZLIB_SYMBOL_PREFIX@zng_deflateInit2_ +#define zng_deflateInit_ @ZLIB_SYMBOL_PREFIX@zng_deflateInit_ +#define zng_deflateParams @ZLIB_SYMBOL_PREFIX@zng_deflateParams +#define zng_deflatePending @ZLIB_SYMBOL_PREFIX@zng_deflatePending +#define zng_deflatePrime @ZLIB_SYMBOL_PREFIX@zng_deflatePrime +#define zng_deflateReset @ZLIB_SYMBOL_PREFIX@zng_deflateReset +#define zng_deflateResetKeep @ZLIB_SYMBOL_PREFIX@zng_deflateResetKeep +#define zng_deflateSetDictionary @ZLIB_SYMBOL_PREFIX@zng_deflateSetDictionary +#define zng_deflateSetHeader @ZLIB_SYMBOL_PREFIX@zng_deflateSetHeader +#define zng_deflateTune @ZLIB_SYMBOL_PREFIX@zng_deflateTune +#define zng_deflate_copyright @ZLIB_SYMBOL_PREFIX@zng_deflate_copyright +#define zng_fill_window @ZLIB_SYMBOL_PREFIX@zng_fill_window +#define zng_fixedtables @ZLIB_SYMBOL_PREFIX@zng_fixedtables +#define zng_flush_pending @ZLIB_SYMBOL_PREFIX@zng_flush_pending +#define zng_get_crc_table @ZLIB_SYMBOL_PREFIX@zng_get_crc_table +#ifdef WITH_GZFILEOP +# define zng_gz_error @ZLIB_SYMBOL_PREFIX@zng_gz_error +# define zng_gz_strwinerror @ZLIB_SYMBOL_PREFIX@zng_gz_strwinerror +# define zng_gzbuffer @ZLIB_SYMBOL_PREFIX@zng_gzbuffer +# define zng_gzclearerr @ZLIB_SYMBOL_PREFIX@zng_gzclearerr +# define zng_gzclose @ZLIB_SYMBOL_PREFIX@zng_gzclose +# define zng_gzclose_r @ZLIB_SYMBOL_PREFIX@zng_gzclose_r +# define zng_gzclose_w @ZLIB_SYMBOL_PREFIX@zng_gzclose_w +# define zng_gzdirect @ZLIB_SYMBOL_PREFIX@zng_gzdirect +# define zng_gzdopen @ZLIB_SYMBOL_PREFIX@zng_gzdopen +# define zng_gzeof @ZLIB_SYMBOL_PREFIX@zng_gzeof +# define zng_gzerror @ZLIB_SYMBOL_PREFIX@zng_gzerror +# define zng_gzflush @ZLIB_SYMBOL_PREFIX@zng_gzflush +# define zng_gzfread @ZLIB_SYMBOL_PREFIX@zng_gzfread +# define zng_gzfwrite @ZLIB_SYMBOL_PREFIX@zng_gzfwrite +# define zng_gzgetc @ZLIB_SYMBOL_PREFIX@zng_gzgetc +# define zng_gzgetc_ @ZLIB_SYMBOL_PREFIX@zng_gzgetc_ +# define zng_gzgets @ZLIB_SYMBOL_PREFIX@zng_gzgets +# define zng_gzoffset @ZLIB_SYMBOL_PREFIX@zng_gzoffset +# define zng_gzoffset64 @ZLIB_SYMBOL_PREFIX@zng_gzoffset64 +# define zng_gzopen @ZLIB_SYMBOL_PREFIX@zng_gzopen +# define zng_gzopen64 @ZLIB_SYMBOL_PREFIX@zng_gzopen64 +# ifdef _WIN32 +# define zng_gzopen_w @ZLIB_SYMBOL_PREFIX@zng_gzopen_w +# endif +# define zng_gzprintf @ZLIB_SYMBOL_PREFIX@zng_gzprintf +# define zng_gzputc @ZLIB_SYMBOL_PREFIX@zng_gzputc +# define zng_gzputs @ZLIB_SYMBOL_PREFIX@zng_gzputs +# define zng_gzread @ZLIB_SYMBOL_PREFIX@zng_gzread +# define zng_gzrewind @ZLIB_SYMBOL_PREFIX@zng_gzrewind +# define zng_gzseek @ZLIB_SYMBOL_PREFIX@zng_gzseek +# define zng_gzseek64 @ZLIB_SYMBOL_PREFIX@zng_gzseek64 +# define zng_gzsetparams @ZLIB_SYMBOL_PREFIX@zng_gzsetparams +# define zng_gztell @ZLIB_SYMBOL_PREFIX@zng_gztell +# define zng_gztell64 @ZLIB_SYMBOL_PREFIX@zng_gztell64 +# define zng_gzungetc @ZLIB_SYMBOL_PREFIX@zng_gzungetc +# define zng_gzvprintf @ZLIB_SYMBOL_PREFIX@zng_gzvprintf +# define zng_gzwrite @ZLIB_SYMBOL_PREFIX@zng_gzwrite +#endif +#define zng_inflate @ZLIB_SYMBOL_PREFIX@zng_inflate +#define zng_inflateBack @ZLIB_SYMBOL_PREFIX@zng_inflateBack +#define zng_inflateBackEnd @ZLIB_SYMBOL_PREFIX@zng_inflateBackEnd +#define zng_inflateBackInit @ZLIB_SYMBOL_PREFIX@zng_inflateBackInit +#define zng_inflateBackInit_ @ZLIB_SYMBOL_PREFIX@zng_inflateBackInit_ +#define zng_inflateCodesUsed @ZLIB_SYMBOL_PREFIX@zng_inflateCodesUsed +#define zng_inflateCopy @ZLIB_SYMBOL_PREFIX@zng_inflateCopy +#define zng_inflateEnd @ZLIB_SYMBOL_PREFIX@zng_inflateEnd +#define zng_inflateGetDictionary @ZLIB_SYMBOL_PREFIX@zng_inflateGetDictionary +#define zng_inflateGetHeader @ZLIB_SYMBOL_PREFIX@zng_inflateGetHeader +#define zng_inflateInit @ZLIB_SYMBOL_PREFIX@zng_inflateInit +#define zng_inflateInit2 @ZLIB_SYMBOL_PREFIX@zng_inflateInit2 +#define zng_inflateInit2_ @ZLIB_SYMBOL_PREFIX@zng_inflateInit2_ +#define zng_inflateInit_ @ZLIB_SYMBOL_PREFIX@zng_inflateInit_ +#define zng_inflateMark @ZLIB_SYMBOL_PREFIX@zng_inflateMark +#define zng_inflatePrime @ZLIB_SYMBOL_PREFIX@zng_inflatePrime +#define zng_inflateReset @ZLIB_SYMBOL_PREFIX@zng_inflateReset +#define zng_inflateReset2 @ZLIB_SYMBOL_PREFIX@zng_inflateReset2 +#define zng_inflateResetKeep @ZLIB_SYMBOL_PREFIX@zng_inflateResetKeep +#define zng_inflateSetDictionary @ZLIB_SYMBOL_PREFIX@zng_inflateSetDictionary +#define zng_inflateSync @ZLIB_SYMBOL_PREFIX@zng_inflateSync +#define zng_inflateSyncPoint @ZLIB_SYMBOL_PREFIX@zng_inflateSyncPoint +#define zng_inflateUndermine @ZLIB_SYMBOL_PREFIX@zng_inflateUndermine +#define zng_inflateValidate @ZLIB_SYMBOL_PREFIX@zng_inflateValidate +#define zng_inflate_copyright @ZLIB_SYMBOL_PREFIX@zng_inflate_copyright +#define zng_inflate_ensure_window @ZLIB_SYMBOL_PREFIX@zng_inflate_ensure_window +#define zng_inflate_fast @ZLIB_SYMBOL_PREFIX@zng_inflate_fast +#define zng_inflate_table @ZLIB_SYMBOL_PREFIX@zng_inflate_table +#define zng_read_buf @ZLIB_SYMBOL_PREFIX@zng_read_buf +#define zng_uncompress @ZLIB_SYMBOL_PREFIX@zng_uncompress +#define zng_uncompress2 @ZLIB_SYMBOL_PREFIX@zng_uncompress2 +#define zng_zError @ZLIB_SYMBOL_PREFIX@zng_zError +#define zng_zcalloc @ZLIB_SYMBOL_PREFIX@zng_zcalloc +#define zng_zcfree @ZLIB_SYMBOL_PREFIX@zng_zcfree +#define zng_zlibCompileFlags @ZLIB_SYMBOL_PREFIX@zng_zlibCompileFlags +#define zng_zlibVersion @ZLIB_SYMBOL_PREFIX@zng_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +#define Byte @ZLIB_SYMBOL_PREFIX@Byte +#define Bytef @ZLIB_SYMBOL_PREFIX@Bytef +#define alloc_func @ZLIB_SYMBOL_PREFIX@alloc_func +#define charf @ZLIB_SYMBOL_PREFIX@charf +#define free_func @ZLIB_SYMBOL_PREFIX@free_func +#ifdef WITH_GZFILEOP +# define gzFile @ZLIB_SYMBOL_PREFIX@gzFile +#endif +#define gz_header @ZLIB_SYMBOL_PREFIX@gz_header +#define gz_headerp @ZLIB_SYMBOL_PREFIX@gz_headerp +#define in_func @ZLIB_SYMBOL_PREFIX@in_func +#define intf @ZLIB_SYMBOL_PREFIX@intf +#define out_func @ZLIB_SYMBOL_PREFIX@out_func +#define uInt @ZLIB_SYMBOL_PREFIX@uInt +#define uIntf @ZLIB_SYMBOL_PREFIX@uIntf +#define uLong @ZLIB_SYMBOL_PREFIX@uLong +#define uLongf @ZLIB_SYMBOL_PREFIX@uLongf +#define voidp @ZLIB_SYMBOL_PREFIX@voidp +#define voidpc @ZLIB_SYMBOL_PREFIX@voidpc +#define voidpf @ZLIB_SYMBOL_PREFIX@voidpf + +/* all zlib structs in zlib.h and zconf.h */ +#define zng_gz_header_s @ZLIB_SYMBOL_PREFIX@zng_gz_header_s +#define internal_state @ZLIB_SYMBOL_PREFIX@internal_state + +/* zlib-ng specific symbols */ +#define zng_deflate_param @ZLIB_SYMBOL_PREFIX@zng_deflate_param +#define zng_deflate_param_value @ZLIB_SYMBOL_PREFIX@zng_deflate_param_value +#define zng_deflateSetParams @ZLIB_SYMBOL_PREFIX@zng_deflateSetParams +#define zng_deflateGetParams @ZLIB_SYMBOL_PREFIX@zng_deflateGetParams + +#define zlibng_version @ZLIB_SYMBOL_PREFIX@zlibng_version +#define zng_vstring @ZLIB_SYMBOL_PREFIX@zng_vstring +#define zng_zError @ZLIB_SYMBOL_PREFIX@zng_zError + +#define zng_alloc_aligned @ZLIB_SYMBOL_PREFIX@zng_alloc_aligned +#define zng_free_aligned @ZLIB_SYMBOL_PREFIX@zng_free_aligned +#define zng_get_crc_table @ZLIB_SYMBOL_PREFIX@zng_get_crc_table +#define zng_inflateSyncPoint @ZLIB_SYMBOL_PREFIX@zng_inflateSyncPoint +#define zng_inflateUndermine @ZLIB_SYMBOL_PREFIX@zng_inflateUndermine +#define zng_inflateValidate @ZLIB_SYMBOL_PREFIX@zng_inflateValidate +#define zng_inflateCodesUsed @ZLIB_SYMBOL_PREFIX@zng_inflateCodesUsed +#define zng_inflateResetKeep @ZLIB_SYMBOL_PREFIX@zng_inflateResetKeep +#define zng_deflateResetKeep @ZLIB_SYMBOL_PREFIX@zng_deflateResetKeep + +#define zng_gzopen_w @ZLIB_SYMBOL_PREFIX@zng_gzopen_w +#define zng_gzvprintf @ZLIB_SYMBOL_PREFIX@zng_gzvprintf + +#endif /* ZLIB_NAME_MANGLING_H */ diff --git a/zlib_name_mangling.h.empty b/zlib_name_mangling.h.empty new file mode 100644 index 0000000000..b24cb834a6 --- /dev/null +++ b/zlib_name_mangling.h.empty @@ -0,0 +1,8 @@ +/* zlib_name_mangling.h has been automatically generated from + * zlib_name_mangling.h.empty because ZLIB_SYMBOL_PREFIX was NOT set. + */ + +#ifndef ZLIB_NAME_MANGLING_H +#define ZLIB_NAME_MANGLING_H + +#endif /* ZLIB_NAME_MANGLING_H */ diff --git a/zlib_name_mangling.h.in b/zlib_name_mangling.h.in new file mode 100644 index 0000000000..f496158181 --- /dev/null +++ b/zlib_name_mangling.h.in @@ -0,0 +1,170 @@ +/* zlib_name_mangling.h has been automatically generated from + * zlib_name_mangling.h.in because ZLIB_SYMBOL_PREFIX was set. + */ + +#ifndef ZLIB_NAME_MANGLING_H +#define ZLIB_NAME_MANGLING_H + +/* all linked symbols and init macros */ +#define _dist_code @ZLIB_SYMBOL_PREFIX@_dist_code +#define _length_code @ZLIB_SYMBOL_PREFIX@_length_code +#define _tr_align @ZLIB_SYMBOL_PREFIX@_tr_align +#define _tr_flush_bits @ZLIB_SYMBOL_PREFIX@_tr_flush_bits +#define _tr_flush_block @ZLIB_SYMBOL_PREFIX@_tr_flush_block +#define _tr_init @ZLIB_SYMBOL_PREFIX@_tr_init +#define _tr_stored_block @ZLIB_SYMBOL_PREFIX@_tr_stored_block +#define _tr_tally @ZLIB_SYMBOL_PREFIX@_tr_tally +#define adler32 @ZLIB_SYMBOL_PREFIX@adler32 +#define adler32_combine @ZLIB_SYMBOL_PREFIX@adler32_combine +#define adler32_combine64 @ZLIB_SYMBOL_PREFIX@adler32_combine64 +#define adler32_z @ZLIB_SYMBOL_PREFIX@adler32_z +#ifndef Z_SOLO +# define compress @ZLIB_SYMBOL_PREFIX@compress +# define compress2 @ZLIB_SYMBOL_PREFIX@compress2 +# define compressBound @ZLIB_SYMBOL_PREFIX@compressBound +#endif +#define crc32 @ZLIB_SYMBOL_PREFIX@crc32 +#define crc32_combine @ZLIB_SYMBOL_PREFIX@crc32_combine +#define crc32_combine64 @ZLIB_SYMBOL_PREFIX@crc32_combine64 +#define crc32_combine_gen @ZLIB_SYMBOL_PREFIX@crc32_combine_gen +#define crc32_combine_gen64 @ZLIB_SYMBOL_PREFIX@crc32_combine_gen64 +#define crc32_combine_op @ZLIB_SYMBOL_PREFIX@crc32_combine_op +#define crc32_z @ZLIB_SYMBOL_PREFIX@crc32_z +#define deflate @ZLIB_SYMBOL_PREFIX@deflate +#define deflateBound @ZLIB_SYMBOL_PREFIX@deflateBound +#define deflateCopy @ZLIB_SYMBOL_PREFIX@deflateCopy +#define deflateEnd @ZLIB_SYMBOL_PREFIX@deflateEnd +#define deflateGetDictionary @ZLIB_SYMBOL_PREFIX@deflateGetDictionary +#define deflateInit @ZLIB_SYMBOL_PREFIX@deflateInit +#define deflateInit2 @ZLIB_SYMBOL_PREFIX@deflateInit2 +#define deflateInit2_ @ZLIB_SYMBOL_PREFIX@deflateInit2_ +#define deflateInit_ @ZLIB_SYMBOL_PREFIX@deflateInit_ +#define deflateParams @ZLIB_SYMBOL_PREFIX@deflateParams +#define deflatePending @ZLIB_SYMBOL_PREFIX@deflatePending +#define deflatePrime @ZLIB_SYMBOL_PREFIX@deflatePrime +#define deflateReset @ZLIB_SYMBOL_PREFIX@deflateReset +#define deflateResetKeep @ZLIB_SYMBOL_PREFIX@deflateResetKeep +#define deflateSetDictionary @ZLIB_SYMBOL_PREFIX@deflateSetDictionary +#define deflateSetHeader @ZLIB_SYMBOL_PREFIX@deflateSetHeader +#define deflateTune @ZLIB_SYMBOL_PREFIX@deflateTune +#define deflate_copyright @ZLIB_SYMBOL_PREFIX@deflate_copyright +#define fill_window @ZLIB_SYMBOL_PREFIX@fill_window +#define fixedtables @ZLIB_SYMBOL_PREFIX@fixedtables +#define flush_pending @ZLIB_SYMBOL_PREFIX@flush_pending +#define get_crc_table @ZLIB_SYMBOL_PREFIX@get_crc_table +#ifndef Z_SOLO +# define gz_error @ZLIB_SYMBOL_PREFIX@gz_error +# define gz_strwinerror @ZLIB_SYMBOL_PREFIX@gz_strwinerror +# define gzbuffer @ZLIB_SYMBOL_PREFIX@gzbuffer +# define gzclearerr @ZLIB_SYMBOL_PREFIX@gzclearerr +# define gzclose @ZLIB_SYMBOL_PREFIX@gzclose +# define gzclose_r @ZLIB_SYMBOL_PREFIX@gzclose_r +# define gzclose_w @ZLIB_SYMBOL_PREFIX@gzclose_w +# define gzdirect @ZLIB_SYMBOL_PREFIX@gzdirect +# define gzdopen @ZLIB_SYMBOL_PREFIX@gzdopen +# define gzeof @ZLIB_SYMBOL_PREFIX@gzeof +# define gzerror @ZLIB_SYMBOL_PREFIX@gzerror +# define gzflush @ZLIB_SYMBOL_PREFIX@gzflush +# define gzfread @ZLIB_SYMBOL_PREFIX@gzfread +# define gzfwrite @ZLIB_SYMBOL_PREFIX@gzfwrite +# define gzgetc @ZLIB_SYMBOL_PREFIX@gzgetc +# define gzgetc_ @ZLIB_SYMBOL_PREFIX@gzgetc_ +# define gzgets @ZLIB_SYMBOL_PREFIX@gzgets +# define gzoffset @ZLIB_SYMBOL_PREFIX@gzoffset +# define gzoffset64 @ZLIB_SYMBOL_PREFIX@gzoffset64 +# define gzopen @ZLIB_SYMBOL_PREFIX@gzopen +# define gzopen64 @ZLIB_SYMBOL_PREFIX@gzopen64 +# ifdef _WIN32 +# define gzopen_w @ZLIB_SYMBOL_PREFIX@gzopen_w +# endif +# define gzprintf @ZLIB_SYMBOL_PREFIX@gzprintf +# define gzputc @ZLIB_SYMBOL_PREFIX@gzputc +# define gzputs @ZLIB_SYMBOL_PREFIX@gzputs +# define gzread @ZLIB_SYMBOL_PREFIX@gzread +# define gzrewind @ZLIB_SYMBOL_PREFIX@gzrewind +# define gzseek @ZLIB_SYMBOL_PREFIX@gzseek +# define gzseek64 @ZLIB_SYMBOL_PREFIX@gzseek64 +# define gzsetparams @ZLIB_SYMBOL_PREFIX@gzsetparams +# define gztell @ZLIB_SYMBOL_PREFIX@gztell +# define gztell64 @ZLIB_SYMBOL_PREFIX@gztell64 +# define gzungetc @ZLIB_SYMBOL_PREFIX@gzungetc +# define gzvprintf @ZLIB_SYMBOL_PREFIX@gzvprintf +# define gzwrite @ZLIB_SYMBOL_PREFIX@gzwrite +#endif +#define inflate @ZLIB_SYMBOL_PREFIX@inflate +#define inflateBack @ZLIB_SYMBOL_PREFIX@inflateBack +#define inflateBackEnd @ZLIB_SYMBOL_PREFIX@inflateBackEnd +#define inflateBackInit @ZLIB_SYMBOL_PREFIX@inflateBackInit +#define inflateBackInit_ @ZLIB_SYMBOL_PREFIX@inflateBackInit_ +#define inflateCodesUsed @ZLIB_SYMBOL_PREFIX@inflateCodesUsed +#define inflateCopy @ZLIB_SYMBOL_PREFIX@inflateCopy +#define inflateEnd @ZLIB_SYMBOL_PREFIX@inflateEnd +#define inflateGetDictionary @ZLIB_SYMBOL_PREFIX@inflateGetDictionary +#define inflateGetHeader @ZLIB_SYMBOL_PREFIX@inflateGetHeader +#define inflateInit @ZLIB_SYMBOL_PREFIX@inflateInit +#define inflateInit2 @ZLIB_SYMBOL_PREFIX@inflateInit2 +#define inflateInit2_ @ZLIB_SYMBOL_PREFIX@inflateInit2_ +#define inflateInit_ @ZLIB_SYMBOL_PREFIX@inflateInit_ +#define inflateMark @ZLIB_SYMBOL_PREFIX@inflateMark +#define inflatePrime @ZLIB_SYMBOL_PREFIX@inflatePrime +#define inflateReset @ZLIB_SYMBOL_PREFIX@inflateReset +#define inflateReset2 @ZLIB_SYMBOL_PREFIX@inflateReset2 +#define inflateResetKeep @ZLIB_SYMBOL_PREFIX@inflateResetKeep +#define inflateSetDictionary @ZLIB_SYMBOL_PREFIX@inflateSetDictionary +#define inflateSync @ZLIB_SYMBOL_PREFIX@inflateSync +#define inflateSyncPoint @ZLIB_SYMBOL_PREFIX@inflateSyncPoint +#define inflateUndermine @ZLIB_SYMBOL_PREFIX@inflateUndermine +#define inflateValidate @ZLIB_SYMBOL_PREFIX@inflateValidate +#define inflate_copyright @ZLIB_SYMBOL_PREFIX@inflate_copyright +#define inflate_ensure_window @ZLIB_SYMBOL_PREFIX@inflate_ensure_window +#define inflate_fast @ZLIB_SYMBOL_PREFIX@inflate_fast +#define inflate_table @ZLIB_SYMBOL_PREFIX@inflate_table +#define read_buf @ZLIB_SYMBOL_PREFIX@read_buf +#ifndef Z_SOLO +# define uncompress @ZLIB_SYMBOL_PREFIX@uncompress +# define uncompress2 @ZLIB_SYMBOL_PREFIX@uncompress2 +#endif +#define zError @ZLIB_SYMBOL_PREFIX@zError +#ifndef Z_SOLO +# define zcalloc @ZLIB_SYMBOL_PREFIX@zcalloc +# define zcfree @ZLIB_SYMBOL_PREFIX@zcfree +#endif +#define zlibCompileFlags @ZLIB_SYMBOL_PREFIX@zlibCompileFlags +#define zlibVersion @ZLIB_SYMBOL_PREFIX@zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +#define Byte @ZLIB_SYMBOL_PREFIX@Byte +#define Bytef @ZLIB_SYMBOL_PREFIX@Bytef +#define alloc_func @ZLIB_SYMBOL_PREFIX@alloc_func +#define charf @ZLIB_SYMBOL_PREFIX@charf +#define free_func @ZLIB_SYMBOL_PREFIX@free_func +#ifndef Z_SOLO +# define gzFile @ZLIB_SYMBOL_PREFIX@gzFile +#endif +#define gz_header @ZLIB_SYMBOL_PREFIX@gz_header +#define gz_headerp @ZLIB_SYMBOL_PREFIX@gz_headerp +#define in_func @ZLIB_SYMBOL_PREFIX@in_func +#define intf @ZLIB_SYMBOL_PREFIX@intf +#define out_func @ZLIB_SYMBOL_PREFIX@out_func +#define uInt @ZLIB_SYMBOL_PREFIX@uInt +#define uIntf @ZLIB_SYMBOL_PREFIX@uIntf +#define uLong @ZLIB_SYMBOL_PREFIX@uLong +#define uLongf @ZLIB_SYMBOL_PREFIX@uLongf +#define voidp @ZLIB_SYMBOL_PREFIX@voidp +#define voidpc @ZLIB_SYMBOL_PREFIX@voidpc +#define voidpf @ZLIB_SYMBOL_PREFIX@voidpf + +/* all zlib structs in zlib.h and zconf.h */ +#define gz_header_s @ZLIB_SYMBOL_PREFIX@gz_header_s +#define internal_state @ZLIB_SYMBOL_PREFIX@internal_state + +/* all zlib structs in zutil.h */ +#define z_errmsg @ZLIB_SYMBOL_PREFIX@z_errmsg +#define z_vstring @ZLIB_SYMBOL_PREFIX@z_vstring +#define zlibng_version @ZLIB_SYMBOL_PREFIX@zlibng_version + +/* zlib-ng specific symbols */ +#define zng_alloc_aligned @ZLIB_SYMBOL_PREFIX@zng_alloc_aligned +#define zng_free_aligned @ZLIB_SYMBOL_PREFIX@zng_free_aligned + +#endif /* ZLIB_NAME_MANGLING_H */ diff --git a/zmemory.h b/zmemory.h new file mode 100644 index 0000000000..fc850a7227 --- /dev/null +++ b/zmemory.h @@ -0,0 +1,99 @@ +/* zmemory.h -- Private inline functions used internally in zlib-ng + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef _ZMEMORY_H +#define _ZMEMORY_H + +#if defined(__GNUC__) && (__GNUC__ >= 4) +# define HAVE_MAY_ALIAS +#endif + +static inline uint16_t zng_memread_2(const void *ptr) { +#if defined(HAVE_MAY_ALIAS) + typedef struct { uint16_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint16_t; + return ((const unaligned_uint16_t *)ptr)->val; +#else + uint16_t val; + memcpy(&val, ptr, sizeof(val)); + return val; +#endif +} + +static inline uint32_t zng_memread_4(const void *ptr) { +#if defined(HAVE_MAY_ALIAS) + typedef struct { uint32_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint32_t; + return ((const unaligned_uint32_t *)ptr)->val; +#else + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + return val; +#endif +} + +static inline uint64_t zng_memread_8(const void *ptr) { +#if defined(HAVE_MAY_ALIAS) + typedef struct { uint64_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint64_t; + return ((const unaligned_uint64_t *)ptr)->val; +#else + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + return val; +#endif +} + +static inline void zng_memwrite_2(void *ptr, uint16_t val) { +#if defined(HAVE_MAY_ALIAS) + typedef struct { uint16_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint16_t; + ((unaligned_uint16_t *)ptr)->val = val; +#else + memcpy(ptr, &val, sizeof(val)); +#endif +} + +static inline void zng_memwrite_4(void *ptr, uint32_t val) { +#if defined(HAVE_MAY_ALIAS) + typedef struct { uint32_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint32_t; + ((unaligned_uint32_t *)ptr)->val = val; +#else + memcpy(ptr, &val, sizeof(val)); +#endif +} + +static inline void zng_memwrite_8(void *ptr, uint64_t val) { +#if defined(HAVE_MAY_ALIAS) + typedef struct { uint64_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint64_t; + ((unaligned_uint64_t *)ptr)->val = val; +#else + memcpy(ptr, &val, sizeof(val)); +#endif +} + +/* Use zng_memread_* instead of memcmp to avoid older compilers not converting memcmp + calls to unaligned comparisons when unaligned access is supported. Use memcmp only when + unaligned support is not available to avoid an extra call to memcpy. */ +static inline int32_t zng_memcmp_2(const void *src0, const void *src1) { +#if defined(HAVE_MAY_ALIAS) + return zng_memread_2(src0) != zng_memread_2(src1); +#else + return memcmp(src0, src1, 2); +#endif +} + +static inline int32_t zng_memcmp_4(const void *src0, const void *src1) { +#if defined(HAVE_MAY_ALIAS) + return zng_memread_4(src0) != zng_memread_4(src1); +#else + return memcmp(src0, src1, 4); +#endif +} + +static inline int32_t zng_memcmp_8(const void *src0, const void *src1) { +#if defined(HAVE_MAY_ALIAS) + return zng_memread_8(src0) != zng_memread_8(src1); +#else + return memcmp(src0, src1, 8); +#endif +} + +#endif diff --git a/zutil.c b/zutil.c new file mode 100644 index 0000000000..99818c3a7b --- /dev/null +++ b/zutil.c @@ -0,0 +1,111 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2017 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zbuild.h" +#include "zutil_p.h" +#include "zutil.h" + +z_const char * const PREFIX(z_errmsg)[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; + +const char PREFIX3(vstring)[] = + " zlib-ng 2.2.4"; + +#ifdef ZLIB_COMPAT +const char * Z_EXPORT zlibVersion(void) { + return ZLIB_VERSION; +} +#else +const char * Z_EXPORT zlibng_version(void) { + return ZLIBNG_VERSION; +} +#endif + +unsigned long Z_EXPORT PREFIX(zlibCompileFlags)(void) { + unsigned long flags; + + flags = 0; + switch ((int)(sizeof(unsigned int))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(unsigned long))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(void *))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef ZLIB_DEBUG + flags += 1 << 8; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif + /* Bit 13 reserved for DYNAMIC_CRC_TABLE */ +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif + return flags; +} + +#ifdef ZLIB_DEBUG +# include +# ifndef verbose +# define verbose 0 +# endif +int Z_INTERNAL z_verbose = verbose; + +void Z_INTERNAL z_error(const char *m) { + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * Z_EXPORT PREFIX(zError)(int err) { + return ERR_MSG(err); +} + +void Z_INTERNAL *PREFIX(zcalloc)(void *opaque, unsigned items, unsigned size) { + Z_UNUSED(opaque); + return zng_alloc((size_t)items * (size_t)size); +} + +void Z_INTERNAL PREFIX(zcfree)(void *opaque, void *ptr) { + Z_UNUSED(opaque); + zng_free(ptr); +} diff --git a/zutil.h b/zutil.h new file mode 100644 index 0000000000..a6284502d0 --- /dev/null +++ b/zutil.h @@ -0,0 +1,140 @@ +#ifndef ZUTIL_H_ +#define ZUTIL_H_ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +typedef unsigned char uch; /* Included for compatibility with external code only */ +typedef uint16_t ush; /* Included for compatibility with external code only */ +typedef unsigned long ulg; + +extern z_const char * const PREFIX(z_errmsg)[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) PREFIX(z_errmsg)[(err) < -6 || (err) > 2 ? 9 : 2 - (err)] + +#define ERR_RETURN(strm, err) return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#define MAX_BITS 15 +/* all codes must not exceed MAX_BITS bits */ +#define MAX_DIST_EXTRA_BITS 13 +/* maximum number of extra distance bits */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define STD_MIN_MATCH 3 +#define STD_MAX_MATCH 258 +/* The minimum and maximum match lengths mandated by the deflate standard */ + +#define WANT_MIN_MATCH 4 +/* The minimum wanted match length, affects deflate_quick, deflate_fast, deflate_medium and deflate_slow */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + +#define ADLER32_INITIAL_VALUE 1 /* initial adler-32 hash value */ +#define CRC32_INITIAL_VALUE 0 /* initial crc-32 hash value */ + +#define ZLIB_WRAPLEN 6 /* zlib format overhead */ +#define GZIP_WRAPLEN 18 /* gzip format overhead */ + +#define DEFLATE_HEADER_BITS 3 +#define DEFLATE_EOBS_BITS 15 +#define DEFLATE_PAD_BITS 6 +#define DEFLATE_BLOCK_OVERHEAD ((DEFLATE_HEADER_BITS + DEFLATE_EOBS_BITS + DEFLATE_PAD_BITS) >> 3) +/* deflate block overhead: 3 bits for block start + 15 bits for block end + padding to nearest byte */ + +#define DEFLATE_QUICK_LIT_MAX_BITS 9 +#define DEFLATE_QUICK_OVERHEAD(x) ((x * (DEFLATE_QUICK_LIT_MAX_BITS - 8) + 7) >> 3) +/* deflate_quick worst-case overhead: 9 bits per literal, round up to next byte (+7) */ + + + /* target dependencies */ + +#ifdef AMIGA +# define OS_CODE 1 +#endif + +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 5 +#endif + +#ifdef OS2 +# define OS_CODE 6 +#endif + +#if defined(MACOS) +# define OS_CODE 7 +#endif + +#ifdef __acorn +# define OS_CODE 13 +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 3 /* assume Unix */ +#endif + + /* macros */ + +#define CHECK_VER_STSIZE(_ver,_stsize) ((_ver) == NULL || (_ver)[0] != PREFIX2(VERSION)[0] || (_stsize) != (int32_t)sizeof(PREFIX3(stream))) + + /* memory allocation functions */ + +void Z_INTERNAL *PREFIX(zcalloc)(void *opaque, unsigned items, unsigned size); +void Z_INTERNAL PREFIX(zcfree)(void *opaque, void *ptr); + +typedef void *zng_calloc_func(void *opaque, unsigned items, unsigned size); +typedef void zng_cfree_func(void *opaque, void *ptr); + +#endif /* ZUTIL_H_ */ diff --git a/zutil_p.h b/zutil_p.h new file mode 100644 index 0000000000..835e12f4de --- /dev/null +++ b/zutil_p.h @@ -0,0 +1,46 @@ +/* zutil_p.h -- Private inline functions used internally in zlib-ng + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef ZUTIL_P_H +#define ZUTIL_P_H + +#if defined(__APPLE__) || defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_ALIGNED_ALLOC) +# include +#elif defined(__FreeBSD__) +# include +# include +#else +# include +#endif + +/* Function to allocate 16 or 64-byte aligned memory */ +static inline void *zng_alloc(size_t size) { +#ifdef HAVE_ALIGNED_ALLOC + /* Size must be a multiple of alignment */ + size = (size + (64 - 1)) & ~(64 - 1); + return (void *)aligned_alloc(64, size); /* Defined in C11 */ +#elif defined(HAVE_POSIX_MEMALIGN) + void *ptr; + return posix_memalign(&ptr, 64, size) ? NULL : ptr; +#elif defined(_WIN32) + return (void *)_aligned_malloc(size, 64); +#elif defined(__APPLE__) + /* Fallback for when posix_memalign and aligned_alloc are not available. + * On macOS, it always aligns to 16 bytes. */ + return (void *)malloc(size); +#else + return (void *)memalign(64, size); +#endif +} + +/* Function that can free aligned memory */ +static inline void zng_free(void *ptr) { +#if defined(_WIN32) + _aligned_free(ptr); +#else + free(ptr); +#endif +} + +#endif

  • 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℞AMkzQ=&V-bWaym-?9j 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%0ARD|WAUa-^)bZn# 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