ZXC 0.15.0
High-performance asymmetric lossless compression library
Loading...
Searching...
No Matches
zxc_internal.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * ZXC - High-performance lossless compression
4 *
5 * Copyright (c) Bertrand Lebonnois and contributors.
6 */
7
26#ifndef ZXC_INTERNAL_H
27#define ZXC_INTERNAL_H
28
29#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L)
30#error "libzxc requires C11 or later (MSVC: /std:c11)"
31#endif
32
33#include "zxc_deps.h" /* libc deps: <assert.h>, <limits.h>, <stdint.h>, <stdlib.h>, <string.h>,
34 and the ZXC_MALLOC / ZXC_ALIGNED_MALLOC macros.
35 Vendor this file to retarget non-libc environments. */
36
37#include "../../include/zxc_buffer.h"
38#include "../../include/zxc_constants.h"
39#include "../../include/zxc_error.h"
40#include "../../include/zxc_seekable.h"
41#include "rapidhash.h"
42
43#ifdef __cplusplus
44extern "C" {
45#endif
46
61#if !defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__)
62#include <stdatomic.h>
63#define ZXC_ATOMIC _Atomic
64#define ZXC_USE_C11_ATOMICS 1
65#else
66#define ZXC_ATOMIC volatile
67#define ZXC_USE_C11_ATOMICS 0
68#endif
/* end of Atomic Qualifier */
70
98#ifndef ZXC_DISABLE_SIMD
99#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
100#include <immintrin.h>
101#include <nmmintrin.h>
102#if defined(__AVX512F__) && defined(__AVX512BW__)
103#ifndef ZXC_USE_AVX512
104#define ZXC_USE_AVX512
105#endif
106#endif
107#if defined(__AVX2__)
108#ifndef ZXC_USE_AVX2
109#define ZXC_USE_AVX2
110#endif
111#endif
112#if defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
113#ifndef ZXC_USE_SSE2
114#define ZXC_USE_SSE2
115#endif
116#endif
117#elif (defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(_M_ARM64) || \
118 defined(ZXC_USE_NEON32) || defined(ZXC_USE_NEON64))
119#if !defined(_MSC_VER)
120#include <arm_acle.h>
121#endif
122#include <arm_neon.h>
123#if defined(__aarch64__) || defined(_M_ARM64)
124#ifndef ZXC_USE_NEON64
125#define ZXC_USE_NEON64
126#endif
127#else
128#ifndef ZXC_USE_NEON32
129#define ZXC_USE_NEON32
130#endif
131#endif
132#endif
133#endif /* ZXC_DISABLE_SIMD */
/* end of SIMD Intrinsics */
135
143#if defined(__GNUC__) || defined(__clang__)
148#define LIKELY(x) (__builtin_expect(!!(x), 1))
149
154#define UNLIKELY(x) (__builtin_expect(!!(x), 0))
155
159#define RESTRICT __restrict__
160
165#define ZXC_PREFETCH_READ(ptr) __builtin_prefetch((const void*)(ptr), 0, 3)
166
170#define ZXC_MEMCPY(dst, src, n) __builtin_memcpy(dst, src, n)
171
175#define ZXC_MEMSET(dst, val, n) __builtin_memset(dst, val, n)
176
181#define ZXC_ALIGN(x) __attribute__((aligned(x)))
182
186#define ZXC_ALWAYS_INLINE inline __attribute__((always_inline))
187
191#define ZXC_NOINLINE __attribute__((__noinline__))
192
199#define ZXC_COLD __attribute__((cold))
200
201#elif defined(_MSC_VER)
202#include <intrin.h>
203#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64)
204#include <xmmintrin.h>
205#define ZXC_PREFETCH_READ(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
206#else
207#define ZXC_PREFETCH_READ(ptr) __prefetch((const void*)(ptr))
208#endif
209#define LIKELY(x) (x)
210#define UNLIKELY(x) (x)
211#define RESTRICT __restrict
212#pragma intrinsic(memcpy, memset)
213#define ZXC_MEMCPY(dst, src, n) memcpy(dst, src, n)
214#define ZXC_MEMSET(dst, val, n) memset(dst, val, n)
215
220#define ZXC_ALIGN(x) __declspec(align(x))
221
225#define ZXC_ALWAYS_INLINE __forceinline
226
230#define ZXC_NOINLINE __declspec(noinline)
232#define ZXC_COLD
233#pragma intrinsic(_BitScanReverse)
234#else
235#define LIKELY(x) (x)
236#define UNLIKELY(x) (x)
237#define RESTRICT
238#define ZXC_PREFETCH_READ(ptr)
239#define ZXC_MEMCPY(dst, src, n) memcpy(dst, src, n)
240#define ZXC_MEMSET(dst, val, n) memset(dst, val, n)
241
245#define ZXC_ALWAYS_INLINE inline
246
250#define ZXC_NOINLINE
251#define ZXC_COLD
252
257#define ZXC_ALIGN(x) _Alignas(x)
258#endif
/* end of Compiler Abstractions */
260
261// Heap allocator and cache-line-aligned allocator macros are now defined
262// in @c zxc_deps.h (included at the top of this header), so non-libc
263// targets can override them by vendoring that single file.
264
272#ifndef ZXC_LITTLE_ENDIAN
273#if defined(_WIN32) || defined(__LITTLE_ENDIAN__) || \
274 (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
275#define ZXC_LITTLE_ENDIAN
276#elif defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
277#define ZXC_BIG_ENDIAN
278#else
279#warning "Endianness not detected, defaulting to little-endian"
280#define ZXC_LITTLE_ENDIAN
281#endif
282#endif
/* end of Endianness Detection */
284
290#ifdef ZXC_BIG_ENDIAN
291#if defined(__GNUC__) || defined(__clang__)
292#define ZXC_BSWAP16(x) __builtin_bswap16(x)
293#define ZXC_BSWAP32(x) __builtin_bswap32(x)
294#define ZXC_BSWAP64(x) __builtin_bswap64(x)
295#elif defined(_MSC_VER)
296#define ZXC_BSWAP16(x) _byteswap_ushort(x)
297#define ZXC_BSWAP32(x) _byteswap_ulong(x)
298#define ZXC_BSWAP64(x) _byteswap_uint64(x)
299#else
300#define ZXC_BSWAP16(x) ((uint16_t)(((x) >> 8) | ((x) << 8)))
301#define ZXC_BSWAP32(x) \
302 ((uint32_t)(((x) >> 24) | (((x) >> 8) & 0xFF00) | (((x) << 8) & 0xFF0000) | ((x) << 24)))
303#define ZXC_BSWAP64(x) \
304 ((uint64_t)(((uint64_t)ZXC_BSWAP32((uint32_t)(x)) << 32) | ZXC_BSWAP32((uint32_t)((x) >> 32))))
305#endif
306#endif
/* end of Byte-Swap Helpers */
308
318static inline int zxc_magic_prefix_ok(const uint8_t* p, const size_t n) {
319 static const uint8_t magic[4] = {(uint8_t)ZXC_MAGIC_WORD, (uint8_t)(ZXC_MAGIC_WORD >> 8),
320 (uint8_t)(ZXC_MAGIC_WORD >> 16),
321 (uint8_t)(ZXC_MAGIC_WORD >> 24)};
322 for (size_t i = 0; i < n && i < sizeof(magic); i++)
323 if (p[i] != magic[i]) return 0;
324 return 1;
325}
328#define ZXC_FILE_FORMAT_VERSION 9
329
331#define ZXC_PAD_SIZE 32
345#define ZXC_BLOCK_LIT_SLACK 32
357#define ZXC_DECOMPRESS_TAIL_PAD (ZXC_PAD_SIZE * 66)
359#define ZXC_CACHE_LINE_SIZE 64
361#define ZXC_ALIGNMENT_MASK ((size_t)ZXC_CACHE_LINE_SIZE - 1)
363#define ZXC_ALIGN_CL(x) (((x) + ZXC_ALIGNMENT_MASK) & ~(size_t)ZXC_ALIGNMENT_MASK)
364static_assert((ZXC_CACHE_LINE_SIZE & ZXC_ALIGNMENT_MASK) == 0,
365 "ZXC_CACHE_LINE_SIZE must be a power of two");
366
372#define ZXC_BITMAP_WORDS(n_bits) (((n_bits) + 63) / 64)
373
375#define ZXC_FILE_FLAG_HAS_CHECKSUM 0x80U
377#define ZXC_FILE_FLAG_HAS_DICTIONARY 0x40U
380#define ZXC_FILE_FLAG_HAS_SEEK_TABLE 0x20U
382#define ZXC_FILE_CHECKSUM_ALGO_MASK 0x0FU
386 "a file flag overlaps the checksum algorithm id");
387
393#define ZXC_DICT_VERSION 2
396#define ZXC_DICT_KGRAM_LEN ZXC_LZ_MIN_MATCH_LEN
398#define ZXC_DICT_HASH_BITS 16
400#define ZXC_DICT_MAX_SEGMENTS (1U << 16)
404#define ZXC_DICT_SAMPLE_TARGET (1U << 19)
406#define ZXC_DICT_HASH_SIZE (1U << ZXC_DICT_HASH_BITS)
408#define ZXC_DICT_HUF_TRAIN_BLOCK 4096U
411#define ZXC_DICT_HUF_SAMPLE_BUDGET (8U << 20)
412
414#define ZXC_BLOCK_HEADER_SIZE 8
416#define ZXC_BLOCK_CHECKSUM_SIZE 4
418#define ZXC_GLO_HEADER_BINARY_SIZE 12
420#define ZXC_GHI_HEADER_BINARY_SIZE 12
422#define ZXC_GLO_DESC_MAX_SIZE (2 * sizeof(uint32_t))
423
432#define ZXC_BLOCK_FORMAT_OVERHEAD 68
433static_assert(ZXC_BLOCK_FORMAT_OVERHEAD >=
435 "ZXC_BLOCK_FORMAT_OVERHEAD must cover sub-header, descriptors and slack");
436
438#define ZXC_CHECKSUM_RAPIDHASH 0
439
449#define ZXC_SEEK_GROUP 64U
451#define ZXC_SEEK_ANCHOR_SIZE 8U
453#define ZXC_SEEK_SIZE_ENTRY 4U
455#define ZXC_SEEK_GROUP_BYTES (ZXC_SEEK_ANCHOR_SIZE + ZXC_SEEK_GROUP * ZXC_SEEK_SIZE_ENTRY)
456
458static ZXC_ALWAYS_INLINE uint64_t zxc_seek_group_count(const uint64_t nblocks) {
459 return (nblocks + ZXC_SEEK_GROUP - 1) / ZXC_SEEK_GROUP;
460}
461
463static ZXC_ALWAYS_INLINE uint32_t zxc_seek_group_len(const uint64_t nblocks, const uint64_t g) {
464 const uint64_t left = nblocks - g * ZXC_SEEK_GROUP;
465 return left < ZXC_SEEK_GROUP ? (uint32_t)left : ZXC_SEEK_GROUP;
466}
467
469static ZXC_ALWAYS_INLINE uint64_t zxc_seek_table_bytes(const uint64_t nblocks) {
471}
472
475static ZXC_ALWAYS_INLINE uint32_t zxc_seek_size_field(const uint64_t table_bytes) {
476#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM64) || defined(_M_ARM64EC))
477 // MSVC 19.51 ARM64 /O2 sees the table size as 4u and compiles this fold into
478 // `ror w, #30` on the low half of u, dropping the high word: tables of 4 GiB
479 // and more get a wrong field. A volatile copy hides that shape. Once per table.
480 const volatile uint64_t t = table_bytes;
481 return (uint32_t)(t ^ (t >> 32));
482#else
483 return (uint32_t)(table_bytes ^ (table_bytes >> 32));
484#endif
485}
486
/* end of Seekable Format Constants */
488
493#define ZXC_TOKEN_LIT_BITS 4
495#define ZXC_TOKEN_ML_BITS 4
497#define ZXC_TOKEN_LL_MASK ((1U << ZXC_TOKEN_LIT_BITS) - 1)
499#define ZXC_TOKEN_ML_MASK ((1U << ZXC_TOKEN_ML_BITS) - 1)
500static_assert(ZXC_TOKEN_LIT_BITS == 4 && ZXC_TOKEN_ML_BITS == 4,
501 "the GLO decoder reads its tokens as two nibbles");
508#define ZXC_SEQ_LL_BITS 8
510#define ZXC_SEQ_ML_BITS 8
512#define ZXC_SEQ_OFF_BITS 16
514#define ZXC_SEQ_LL_MASK ((1U << ZXC_SEQ_LL_BITS) - 1)
516#define ZXC_SEQ_ML_MASK ((1U << ZXC_SEQ_ML_BITS) - 1)
518#define ZXC_SEQ_OFF_MASK ((1U << ZXC_SEQ_OFF_BITS) - 1)
519static_assert(ZXC_SEQ_LL_BITS + ZXC_SEQ_ML_BITS + ZXC_SEQ_OFF_BITS == 32,
520 "a GHI sequence is one 32-bit word");
526#define ZXC_LIT_RLE_FLAG 0x80U
528#define ZXC_LIT_LEN_MASK (ZXC_LIT_RLE_FLAG - 1)
543#define ZXC_LZ_HASH_BITS 15
545#define ZXC_LZ_HASH_SIZE (1U << ZXC_LZ_HASH_BITS)
547#define ZXC_LZ_WINDOW_SIZE (1U << 16)
549#define ZXC_LZ_WINDOW_MASK (ZXC_LZ_WINDOW_SIZE - 1U)
551#define ZXC_LZ_MIN_MATCH_LEN 5
560#define ZXC_MAX_VARINT_VALUE ((uint32_t)(ZXC_BLOCK_SIZE_MAX - 1U))
561static_assert(ZXC_MAX_VARINT_VALUE < (1U << 21), "varint values must fit the 3-byte form");
565 "ZXC_BLOCK_SIZE_DEFAULT must be a power of two within the block size range");
566static_assert((ZXC_LZ_WINDOW_SIZE & ZXC_LZ_WINDOW_MASK) == 0,
567 "ZXC_LZ_WINDOW_SIZE must be a power of two (ring mask)");
568static_assert(ZXC_LZ_WINDOW_SIZE <= (1U << ZXC_SEQ_OFF_BITS),
569 "chain_table holds window positions in 16 bits");
570
586static ZXC_ALWAYS_INLINE uint32_t zxc_read_varint(const uint8_t** ptr, const uint8_t* end) {
587 const uint8_t* p = *ptr;
588 if (UNLIKELY(p >= end)) return 0;
589
590 const uint32_t b0 = p[0];
591
592 // 1 Byte: 0xxxxxxx (7 bits) -> val < 128 (2^7)
593 if (LIKELY(b0 < 0x80)) {
594 *ptr = p + 1;
595 return b0;
596 }
597
598 // 2 Bytes: 10xxxxxx xxxxxxxx (14 bits) -> val < 16384 (2^14)
599 if (LIKELY(b0 < 0xC0)) {
600 if (UNLIKELY(p + 1 >= end)) {
601 *ptr = end;
602 return 0;
603 }
604 *ptr = p + 2;
605 return (b0 & 0x3F) | ((uint32_t)p[1] << 6);
606 }
607
608 // 3 Bytes: 110xxxxx xxxxxxxx xxxxxxxx (21 bits) -> val < 2^21. The longest
609 // a legitimate varint can be: values are (ll - MASK) or (ml - MASK), always
610 // strictly below block_size_max = 2^21.
611 if (LIKELY(b0 < 0xE0)) {
612 if (UNLIKELY(p + 2 >= end)) {
613 *ptr = end;
614 return 0;
615 }
616 *ptr = p + 3;
617 return (b0 & 0x1F) | ((uint32_t)p[1] << 5) | ((uint32_t)p[2] << 13);
618 }
619
620 // extra encoding: out-of-spec for the current format, reject.
621 *ptr = end;
622 return 0;
623}
624
630#define ZXC_GLO_MAX_INLINE_OUT_PER_SEQ ((ZXC_TOKEN_LL_MASK - 1U) + ZXC_GLO_MAX_INLINE_ML) /* 33 */
633#define ZXC_GLO_INLINE_ML_CODE (ZXC_TOKEN_ML_MASK - 1U) /* 14 */
639#define ZXC_GLO_MAX_INLINE_ML (ZXC_GLO_INLINE_ML_CODE + ZXC_LZ_MIN_MATCH_LEN) /* 19 */
640#define ZXC_GHI_MAX_INLINE_OUT_PER_SEQ \
641 ((ZXC_SEQ_LL_MASK - 1U) + (ZXC_SEQ_ML_MASK - 1U) + ZXC_LZ_MIN_MATCH_LEN) /* 513 */
643#define ZXC_LZ_OFFSET_BIAS 1
645#define ZXC_LZ_MAX_DIST (ZXC_LZ_WINDOW_SIZE - 1)
646static_assert(ZXC_GLO_MAX_INLINE_ML <= ZXC_PAD_SIZE, "an inline GLO match is one 32-byte store");
648 "a biased offset must fit the 16-bit wire field");
649static_assert(4 * ZXC_GHI_MAX_INLINE_OUT_PER_SEQ + ZXC_PAD_SIZE <= ZXC_DECOMPRESS_TAIL_PAD,
650 "ZXC_DECOMPRESS_TAIL_PAD must hold a 4x GHI batch and its wild-copy overshoot");
651static_assert(ZXC_DICT_SIZE_MAX <= ZXC_LZ_MAX_DIST, "a dictionary must stay within offset reach");
652
660#define ZXC_LZ_MINDIST 32
661
667#define ZXC_LZ_MINDIST_PROBE_PER_KB 1024
668#define ZXC_LZ_MINDIST_PROBE_MIN 16
669#define ZXC_LZ_MINDIST_PROBE_MAX 64
670
677#define ZXC_LZ_MINDIST_MAX_SHORT_PCT 20
680#define ZXC_LZ_SEARCH_MARGIN (sizeof(uint64_t))
689#define ZXC_OPT_MATCH_COST_BASE ((uint32_t)(3U * CHAR_BIT))
692#define ZXC_OPT_LONG_MATCH_SKIP ((size_t)256)
694 "covered positions relax only the first two match cost classes");
699#define ZXC_OPT_LIT_SAMPLE_MIN 1024
700
709#define ZXC_HASH_GOLDEN64 0x9E3779B97F4A7C15ULL
711#define ZXC_HASH_XORSHIFT64 0x2545F4914F6CDD1DULL
713#define ZXC_HASH_MULT32 0x2D35182DU
715#define ZXC_HASH_MULT64 0xD2D84A61D2D84A61ULL
738#define ZXC_HUF_MAX_CODE_LEN_ULTRA 11
743#define ZXC_HUF_MAX_CODE_LEN_DENSITY 8
745#define ZXC_HUF_NUM_SYMBOLS 256
747 "the decoder accepts code lengths up to ZXC_HUF_MAX_CODE_LEN_ULTRA only");
749 "code lengths are packed one nibble per symbol");
750
752#define ZXC_PIVCO_MAX_NODES (2 * ZXC_HUF_NUM_SYMBOLS - 1)
755#define ZXC_PIVCO_NODE_SLOTS (ZXC_PIVCO_MAX_NODES + 1)
759#define ZXC_PIVCO_UNPACK_FLAT_SIMD_MAX 6
760
762#define ZXC_PIVCO_COVERED 0xFFU
763
779typedef struct {
780 uint16_t node_base[ZXC_HUF_MAX_CODE_LEN_ULTRA + 2];
781 uint16_t leaf_base[ZXC_HUF_MAX_CODE_LEN_ULTRA + 2];
782 int16_t base[ZXC_HUF_MAX_CODE_LEN_ULTRA + 1];
783 int max_depth;
784 uint8_t syms[ZXC_HUF_NUM_SYMBOLS];
785 uint8_t flat_d[ZXC_PIVCO_NODE_SLOTS];
787
796typedef struct {
798 uint32_t codes[ZXC_HUF_NUM_SYMBOLS];
799 uint8_t code_len[ZXC_HUF_NUM_SYMBOLS];
804#define ZXC_RLE_MARGIN_SHIFT 5
808#define ZXC_HUF_MARGIN_SHIFT 5
809
825#define ZXC_HUF_NUDGE_LAMBDA_Q8 26
828#define ZXC_HUF_NUDGE_BITS_PERMIL 1015
831#define ZXC_HUF_NUDGE_MERGE_Q8 230
836#define ZXC_HUF_NUDGE_DEEP_FLAT_PENALTY 24
840#define ZXC_HUF_NUDGE_LEVEL_COST 64
862#define ZXC_SS_TAX(n, prem_q8) (((size_t)(n) * (size_t)(prem_q8)) >> 8)
877static inline int zxc_ss_prem_rle_q8(const int level) {
878 return (level >= ZXC_LEVEL_DENSITY) ? 1 : (256 >> ZXC_RLE_MARGIN_SHIFT);
879}
896static inline int zxc_ss_prem_huf_q8(const int level) {
897 return (level >= ZXC_LEVEL_DENSITY) ? 4 : (256 >> ZXC_HUF_MARGIN_SHIFT);
898}
911#define ZXC_HUF_MIN_LITERALS 139
921static inline int zxc_level_clamp(const int level) {
922 return (level > ZXC_LEVEL_ULTRA) ? ZXC_LEVEL_ULTRA : level;
923}
924
930#define ZXC_OPTS_DICT_SIZE(o) (((o) && (o)->dict) ? (o)->dict_size : (size_t)0)
932#define ZXC_OPTS_DICT_HUF(o) \
933 (((o) && (o)->dict && (o)->dict_size > 0) ? (const uint8_t*)(o)->dict_huf : NULL)
936#define ZXC_OPTS_LEVEL(o, dflt) zxc_level_clamp(((o) && (o)->level > 0) ? (o)->level : (dflt))
938#define ZXC_OPTS_BLOCK_SIZE(o, dflt) (((o) && (o)->block_size > 0) ? (o)->block_size : (dflt))
950#define ZXC_GLO_SPLIT_CTX_BITS 8
953#define ZXC_GLO_SPLIT_MIN_MISPREDICT_PCT 80
956typedef uint32_t zxc_glo_split_hist_t[4][2][1U << ZXC_GLO_SPLIT_CTX_BITS];
957static_assert(ZXC_GLO_SPLIT_CTX_BITS <= CHAR_BIT, "a context is recorded in one byte of buf_split");
965static inline int zxc_huf_enc_max_code_len(const int level) {
967}
968
975typedef struct {
976 uint32_t weight;
977 int16_t left;
978 int16_t right;
979 int16_t sym;
981
983typedef struct {
984 int8_t lvl;
985 int16_t idx;
987
989typedef struct {
990 uint32_t w;
991 int16_t sym;
993
996#define ZXC_HUF_PM_LEVEL_BOUND (2 * ZXC_HUF_NUM_SYMBOLS)
997
1002#define ZXC_HUF_BUILD_SCRATCH_SIZE \
1003 ((size_t)ZXC_HUF_MAX_CODE_LEN_ULTRA * (size_t)ZXC_HUF_PM_LEVEL_BOUND * \
1004 sizeof(zxc_huf_pm_item_t) + \
1005 8U + (size_t)ZXC_HUF_MAX_CODE_LEN_ULTRA * sizeof(int) + 8U + \
1006 (size_t)ZXC_HUF_MAX_CODE_LEN_ULTRA * (size_t)ZXC_HUF_PM_LEVEL_BOUND * \
1007 sizeof(zxc_huf_pm_frame_t))
1008
1011#define ZXC_HUF_NUDGE_DP_M 64
1012
1016typedef struct {
1017 uint64_t pf[ZXC_HUF_NUM_SYMBOLS + 1];
1018 uint64_t pf_rank[ZXC_HUF_NUM_SYMBOLS + 1];
1019 uint64_t pfg[ZXC_HUF_NUDGE_DP_M + 1];
1020 uint64_t jcur[(ZXC_HUF_NUDGE_DP_M + 1) * (ZXC_HUF_NUDGE_DP_M + 1)];
1021 uint64_t jnxt[(ZXC_HUF_NUDGE_DP_M + 1) * (ZXC_HUF_NUDGE_DP_M + 1)];
1023 uint8_t arrive[(ZXC_HUF_MAX_CODE_LEN_ULTRA + 1) * (ZXC_HUF_NUDGE_DP_M + 1) *
1024 (ZXC_HUF_NUDGE_DP_M + 1)];
1026 int16_t sym_order[ZXC_HUF_NUM_SYMBOLS];
1027 uint8_t cand[4][ZXC_HUF_NUM_SYMBOLS];
1029
1031#define ZXC_HUF_NUDGE_SCRATCH_OFF ZXC_ALIGN_CL(ZXC_HUF_BUILD_SCRATCH_SIZE)
1033#define ZXC_HUF_NUDGE_SCRATCH_SIZE (ZXC_HUF_NUDGE_SCRATCH_OFF + sizeof(zxc_huf_nudge_ws_t))
1034
1041static ZXC_ALWAYS_INLINE void zxc_opt_dp_sizes(const size_t chunk_size, size_t* RESTRICT sz_dp,
1042 size_t* RESTRICT sz_pl, size_t* RESTRICT sz_po,
1043 size_t* RESTRICT sz_bm) {
1044 *sz_dp = ZXC_ALIGN_CL((chunk_size + 1) * sizeof(uint32_t));
1045 *sz_pl = ZXC_ALIGN_CL((chunk_size + 1) * sizeof(uint16_t));
1046 *sz_po = ZXC_ALIGN_CL((chunk_size + 1) * sizeof(uint16_t));
1047 *sz_bm = ZXC_ALIGN_CL(ZXC_BITMAP_WORDS(chunk_size + 1) * sizeof(uint64_t));
1048}
1049
1059static ZXC_ALWAYS_INLINE uint32_t zxc_log2_u32(const uint32_t v) {
1060#ifdef _MSC_VER
1061 unsigned long index;
1062 return (v == 0) ? 0 : (_BitScanReverse(&index, v) ? index : 0);
1063#else
1064 return (v == 0) ? 0 : (uint32_t)(31 - __builtin_clz(v));
1065#endif
1066}
1067
1073static ZXC_ALWAYS_INLINE size_t zxc_block_size_ceil(const size_t v) {
1074 uint64_t x = (uint64_t)v - 1;
1075 x |= x >> 1;
1076 x |= x >> 2;
1077 x |= x >> 4;
1078 x |= x >> 8;
1079 x |= x >> 16;
1080 x |= x >> 32;
1081 x++;
1082 const size_t bs = (size_t)x;
1083 return (bs < ZXC_BLOCK_SIZE_MIN) ? ZXC_BLOCK_SIZE_MIN : bs;
1084}
1085
1092static ZXC_ALWAYS_INLINE int zxc_validate_block_size(const size_t bs) {
1093 return bs >= ZXC_BLOCK_SIZE_MIN && bs <= ZXC_BLOCK_SIZE_MAX && (bs & (bs - 1)) == 0;
1094}
/* end of File Format Constants */
1098
1108typedef struct {
1112
1117
1123
1128
1133
1136 uint32_t step_base;
1137
1141 uint32_t step_shift;
1142
1146 uint32_t min_offset;
1147
1151 uint8_t split_max;
1153
1164 // The distance floor stops at level 5: the slow levels keep every distance.
1165 // Match splitting at levels 3-5 only: 1-2 are GHI, 6-7 keep every escape.
1166 // search_depth, sufficient_len, use_lazy, lazy_attempts, lazy_len_threshold, step_base,
1167 // step_shift, min_offset, split_max
1168 static const zxc_lz77_params_t table[7] = {
1169 {3, 16, 0, 0, 0, 4, 4, ZXC_LZ_MINDIST, 0}, // fallback
1170 {3, 16, 0, 0, 0, 4, 4, ZXC_LZ_MINDIST, 0}, // level 1
1171 {3, 18, 0, 0, 0, 3, 6, ZXC_LZ_MINDIST, 0}, // level 2
1172 {3, 16, 1, 4, 128, 1, 4, ZXC_LZ_MINDIST, 33}, // level 3
1173 {3, 18, 1, 4, 128, 1, 5, ZXC_LZ_MINDIST, 24}, // level 4
1174 {64, 256, 1, 16, 128, 1, 8, ZXC_LZ_MINDIST, 23}, // level 5
1175 {64, 256, 0, 0, 0, 1, 8, 1, 0} // level 6
1176 };
1177 return (level >= ZXC_LEVEL_ULTRA)
1178 ? (zxc_lz77_params_t){128, 256, 0, 0, 0, 1, 8, 1, 0}
1179 : table[level < ZXC_LEVEL_FASTEST ? ZXC_LEVEL_FASTEST : level];
1180}
1181
1198typedef enum {
1199 ZXC_BLOCK_RAW = 0,
1200 ZXC_BLOCK_GLO = 1,
1201 ZXC_BLOCK_GHI = 2,
1202 ZXC_BLOCK_SEK = 254,
1203 ZXC_BLOCK_EOF = 255
1205
1224typedef enum {
1225 ZXC_SECTION_ENCODING_RAW = 0,
1226 ZXC_SECTION_ENCODING_RLE = 1,
1227 ZXC_SECTION_ENCODING_HUFFMAN = 2,
1228 ZXC_SECTION_ENCODING_HUFFMAN_DICT = 3
1230
1254typedef struct {
1255 uint32_t n_sequences; // Number of sequences
1256 uint32_t n_literals; // Number of literals
1257 uint8_t enc_lit; // Literal stream encoding
1258 uint8_t enc_tok; // Token section encoding (GLO only)
1259 uint8_t enc_mlen; // Reserved (see above)
1260 uint8_t enc_off; // Offset stream width (GLO only; ignored on decode in GHI)
1262
1279static ZXC_ALWAYS_INLINE uint16_t zxc_le16(const void* p) {
1280 uint16_t v;
1281 ZXC_MEMCPY(&v, p, sizeof(v));
1282#ifdef ZXC_BIG_ENDIAN
1283 return ZXC_BSWAP16(v);
1284#else
1285 return v;
1286#endif
1287}
1288
1298static ZXC_ALWAYS_INLINE uint32_t zxc_le32(const void* p) {
1299 uint32_t v;
1300 ZXC_MEMCPY(&v, p, sizeof(v));
1301#ifdef ZXC_BIG_ENDIAN
1302 return ZXC_BSWAP32(v);
1303#else
1304 return v;
1305#endif
1306}
1307
1320static ZXC_ALWAYS_INLINE int zxc_block_is_short_dist_bound(const uint8_t* const blk,
1321 const size_t size) {
1322 const size_t d_max = ZXC_LZ_MINDIST;
1323 // Too small to sample, and too small to gain: keep every distance.
1324 if (size < d_max + sizeof(uint32_t)) return 1;
1325
1326 size_t want = size / ZXC_LZ_MINDIST_PROBE_PER_KB;
1327 if (want < ZXC_LZ_MINDIST_PROBE_MIN) want = ZXC_LZ_MINDIST_PROBE_MIN;
1328 if (want > ZXC_LZ_MINDIST_PROBE_MAX) want = ZXC_LZ_MINDIST_PROBE_MAX;
1329 size_t stride = size / want;
1330 if (stride < d_max) stride = d_max;
1331
1332 const size_t planned = (size - sizeof(uint32_t) - d_max) / stride + 1;
1333 const size_t bar = (size_t)ZXC_LZ_MINDIST_MAX_SHORT_PCT * planned;
1334
1335 size_t samples = 0;
1336 size_t hits = 0;
1337 for (size_t i = d_max; i + sizeof(uint32_t) <= size; i += stride) {
1338 const uint32_t cur = zxc_le32(blk + i);
1339 samples++;
1340 for (size_t d = 1; d < d_max; d++) {
1341 if (zxc_le32(blk + i - d) == cur) {
1342 hits++;
1343 break;
1344 }
1345 }
1346 if (hits * 100U > bar) return 1; // can only rise
1347 if ((hits + (planned - samples)) * 100U <= bar) return 0; // out of reach
1348 }
1349 return hits * 100U > bar;
1350}
1351
1361static ZXC_ALWAYS_INLINE uint64_t zxc_le64(const void* p) {
1362 uint64_t v;
1363 ZXC_MEMCPY(&v, p, sizeof(v));
1364#ifdef ZXC_BIG_ENDIAN
1365 return ZXC_BSWAP64(v);
1366#else
1367 return v;
1368#endif
1369}
1370
1380static ZXC_ALWAYS_INLINE void zxc_store_le16(void* p, const uint16_t v) {
1381#ifdef ZXC_BIG_ENDIAN
1382 const uint16_t s = ZXC_BSWAP16(v);
1383 ZXC_MEMCPY(p, &s, sizeof(s));
1384#else
1385 ZXC_MEMCPY(p, &v, sizeof(v));
1386#endif
1387}
1388
1398static ZXC_ALWAYS_INLINE void zxc_store_le32(void* p, const uint32_t v) {
1399#ifdef ZXC_BIG_ENDIAN
1400 const uint32_t s = ZXC_BSWAP32(v);
1401 ZXC_MEMCPY(p, &s, sizeof(s));
1402#else
1403 ZXC_MEMCPY(p, &v, sizeof(v));
1404#endif
1405}
1406
1416static ZXC_ALWAYS_INLINE void zxc_store_le64(void* p, const uint64_t v) {
1417#ifdef ZXC_BIG_ENDIAN
1418 const uint64_t s = ZXC_BSWAP64(v);
1419 ZXC_MEMCPY(p, &s, sizeof(s));
1420#else
1421 ZXC_MEMCPY(p, &v, sizeof(v));
1422#endif
1423}
1424
1437static ZXC_ALWAYS_INLINE uint8_t zxc_hash8(const uint8_t* p) {
1438 const uint64_t h = (zxc_le64(p) ^ ZXC_HASH_GOLDEN64) * ZXC_HASH_GOLDEN64;
1439
1440 return (uint8_t)(h >> 56);
1441}
1442
1456static ZXC_ALWAYS_INLINE uint16_t zxc_hash16(const uint8_t* p) {
1457 const uint64_t h1 = (zxc_le64(p) ^ ZXC_HASH_MULT64) * ZXC_HASH_MULT64;
1458
1459 return (uint16_t)(((h1 + zxc_le64(p + 8) + ZXC_HASH_GOLDEN64) * ZXC_HASH_GOLDEN64) >> 48);
1460}
1461
1468 zxc_store_le16(h + 14, 0);
1469 zxc_store_le16(h + 14, zxc_hash16(h));
1470}
1471
1481static ZXC_ALWAYS_INLINE void zxc_copy16(void* dst, const void* src) {
1482#if defined(ZXC_USE_AVX2) || defined(ZXC_USE_AVX512) || defined(ZXC_USE_SSE2)
1483 // x86 SSE2/AVX2/AVX512: Single 128-bit unaligned load/store
1484 _mm_storeu_si128((__m128i*)dst, _mm_loadu_si128((const __m128i*)src));
1485#elif defined(ZXC_USE_NEON64) || defined(ZXC_USE_NEON32)
1486 vst1q_u8((uint8_t*)dst, vld1q_u8((const uint8_t*)src));
1487#else
1488 ZXC_MEMCPY(dst, src, 16);
1489#endif
1490}
1491
1500static ZXC_ALWAYS_INLINE void zxc_copy32(void* dst, const void* src) {
1501#if defined(ZXC_USE_AVX2) || defined(ZXC_USE_AVX512)
1502 // AVX2/AVX512: Single 256-bit (32 byte) unaligned load/store
1503 _mm256_storeu_si256((__m256i*)dst, _mm256_loadu_si256((const __m256i*)src));
1504#elif defined(ZXC_USE_SSE2)
1505 const __m128i a = _mm_loadu_si128((const __m128i*)src);
1506 const __m128i b = _mm_loadu_si128((const __m128i*)((const uint8_t*)src + 16));
1507 _mm_storeu_si128((__m128i*)dst, a);
1508 _mm_storeu_si128((__m128i*)((uint8_t*)dst + 16), b);
1509#elif defined(ZXC_USE_NEON64) || defined(ZXC_USE_NEON32)
1510 const uint8x16_t a = vld1q_u8((const uint8_t*)src);
1511 const uint8x16_t b = vld1q_u8((const uint8_t*)src + 16);
1512 vst1q_u8((uint8_t*)dst, a);
1513 vst1q_u8((uint8_t*)dst + 16, b);
1514#else
1515 ZXC_MEMCPY(dst, src, 32);
1516#endif
1517}
1518
1528static ZXC_ALWAYS_INLINE int zxc_ctz32(const uint32_t x) {
1529 if (x == 0) return 32;
1530#if defined(__GNUC__) || defined(__clang__)
1531 return __builtin_ctz(x);
1532#elif defined(_MSC_VER)
1533 unsigned long r;
1534 _BitScanForward(&r, x);
1535 return (int)r;
1536#else
1537 // Fallback De Bruijn (32 bits)
1538 static const int DeBruijn32[32] = {0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20,
1539 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19,
1540 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
1541 return DeBruijn32[((uint32_t)((x & (0U - x)) * 0x077CB531U)) >> 27];
1542#endif
1543}
1544
1554static ZXC_ALWAYS_INLINE int zxc_ctz64(const uint64_t x) {
1555 if (x == 0) return 64;
1556#if defined(__GNUC__) || defined(__clang__)
1557 return __builtin_ctzll(x);
1558#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
1559 unsigned long r;
1560 _BitScanForward64(&r, x);
1561 return (int)r;
1562#elif defined(_MSC_VER)
1563 // Use two 32-bit scans to avoid fragile 64-bit De Bruijn multiplication.
1564 unsigned long r;
1565 const uint32_t lo = (uint32_t)x;
1566 if (_BitScanForward(&r, lo)) return (int)r;
1567 _BitScanForward(&r, (uint32_t)(x >> 32));
1568 return 32 + (int)r;
1569#else
1570 // Fallback De Bruijn for non-GCC/non-MSVC compilers
1571 static const int Debruijn64[64] = {
1572 0, 1, 48, 2, 57, 49, 28, 3, 61, 58, 50, 42, 38, 29, 17, 4, 62, 55, 59, 36, 53, 51,
1573 43, 22, 45, 39, 33, 30, 24, 18, 12, 5, 63, 47, 56, 27, 60, 41, 37, 16, 54, 35, 52, 21,
1574 44, 32, 23, 11, 46, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6};
1575 return Debruijn64[((x & (0ULL - x)) * 0x03F79D71B4CA8B09ULL) >> 58];
1576#endif
1577}
1578
1581static ZXC_ALWAYS_INLINE uint64_t zxc_seek_block_count(const uint64_t total_decomp,
1582 const size_t block_size) {
1583 // A shift, block_size being a header power of two: no 64-bit division on 32-bit
1584 // hosts. Not (total + bs - 1) >> s, which wraps near 2^64 on a forged footer.
1585 if (UNLIKELY(!block_size)) return 0;
1586 const int s = zxc_ctz32((uint32_t)block_size);
1587 return (total_decomp >> s) + ((total_decomp & (block_size - 1)) != 0);
1588}
1589
1590// ============================================================================
1591// COMPRESSION CONTEXT & STRUCTS
1592// ============================================================================
1593
1594// INTERNAL API
1595// ------------
1596
1613static ZXC_ALWAYS_INLINE uint32_t zxc_checksum(const void* RESTRICT input, const size_t len,
1614 const uint64_t seed, const uint8_t hash_method) {
1615 (void)hash_method; /* single algorithm for now; extend when adding more */
1616 const uint64_t hash = rapidhash_withSeed(input, len, seed);
1617
1618 return (uint32_t)(hash ^ (hash >> (sizeof(uint32_t) * CHAR_BIT)));
1619}
1620
1633static ZXC_ALWAYS_INLINE uint64_t zxc_digest_combine(const uint64_t acc,
1634 const uint32_t block_checksum) {
1635 const uint64_t a = acc ^ ((uint64_t)block_checksum + 1U) * ZXC_HASH_GOLDEN64;
1636 const uint64_t b = ZXC_HASH_XORSHIFT64;
1637#if defined(__SIZEOF_INT128__)
1638 const __uint128_t r = (__uint128_t)a * b;
1639 return (uint64_t)r ^ (uint64_t)(r >> 64);
1640#else
1641 const uint64_t alo = (uint32_t)a, ahi = a >> 32, blo = (uint32_t)b, bhi = b >> 32;
1642 const uint64_t lolo = alo * blo, lohi = alo * bhi, hilo = ahi * blo, hihi = ahi * bhi;
1643 const uint64_t cross = (lolo >> 32) + (uint32_t)lohi + (uint32_t)hilo;
1644 const uint64_t hi = hihi + (lohi >> 32) + (hilo >> 32) + (cross >> 32);
1645 const uint64_t lo = (cross << 32) | (uint32_t)lolo;
1646 return lo ^ hi;
1647#endif
1648}
1649
1664int zxc_write_glo_header_and_desc(uint8_t* RESTRICT dst, const size_t rem,
1665 const zxc_gnr_header_t* RESTRICT gh, const uint32_t lit_comp,
1666 const uint32_t tok_comp);
1667
1681int zxc_read_glo_header_and_desc(const uint8_t* RESTRICT src, const size_t len,
1682 zxc_gnr_header_t* RESTRICT gh, uint32_t* RESTRICT lit_comp,
1683 uint32_t* RESTRICT tok_comp);
1684
1693int zxc_write_ghi_header(uint8_t* RESTRICT dst, const size_t rem,
1694 const zxc_gnr_header_t* RESTRICT gh);
1695
1704int zxc_read_ghi_header(const uint8_t* RESTRICT src, const size_t len,
1705 zxc_gnr_header_t* RESTRICT gh);
1706
1707// ============================================================================
1708// Huffman codec for the GLO literal stream (level >= 6).
1709//
1710// On-disk layout, decoder geometry and tunables: see
1711// @ref ZXC_HUF_MAX_CODE_LEN_ULTRA and the surrounding "Huffman Codec Constants"
1712// group above.
1713// ============================================================================
1714
1733int zxc_huf_build_code_lengths(const uint32_t* RESTRICT freq, uint8_t* RESTRICT code_len,
1734 void* RESTRICT scratch, int max_code_len);
1735
1767int zxc_huf_nudge_code_lengths(const uint32_t* RESTRICT freq, uint8_t* RESTRICT code_len,
1768 void* RESTRICT scratch, size_t scratch_cap, int max_code_len);
1769
1777void zxc_huf_nudge_cost(const uint8_t* RESTRICT code_len, const uint32_t* RESTRICT freq,
1778 uint64_t* RESTRICT bits, uint64_t* RESTRICT touches);
1779
1790void zxc_huf_pack_lengths(const uint8_t* RESTRICT code_len, uint8_t* RESTRICT out);
1791
1804int zxc_huf_unpack_lengths(const uint8_t* RESTRICT in, uint8_t* RESTRICT code_len);
1805
1806// --------------------------------------------------------------------------
1807// PivCo-Huffman section codec (enc 2/3)
1808//
1809// Layout from PivCo-Huffman by Marcin Zukowski
1810// (https://github.com/MarcinZukowski/pivco-huffman); implemented
1811// independently here. See zxc_huffman.c for the codec.
1812//
1813// Same code bits as canonical Huffman, reordered by tree LEVEL: for each
1814// internal node in BFS order, its branch bits (one per symbol routed through
1815// it, LSB-first, byte-aligned). No size fields - the decoder derives every run
1816// length from the root count and popcounts. Decoding is bottom-up level merges,
1817// shuffle-parallel and gather-free.
1818// --------------------------------------------------------------------------
1819
1821#define ZXC_PIVCO_SCRATCH_PAD 32
1822
1825size_t zxc_huf_calc_size(const uint32_t* RESTRICT freq, const uint8_t* RESTRICT code_len,
1826 int with_header);
1827
1829int zxc_huf_encode_section(const uint8_t* RESTRICT literals, size_t n_literals,
1830 const uint32_t* RESTRICT freq, const uint8_t* RESTRICT code_len,
1831 uint8_t* RESTRICT dst, size_t dst_cap);
1832
1835int zxc_huf_dict_tree_build(const uint8_t* RESTRICT packed_lengths, zxc_pivco_tree_t* RESTRICT tree,
1836 uint32_t* RESTRICT codes, uint8_t* RESTRICT code_len);
1837
1839size_t zxc_huf_calc_size_dict(const uint32_t* RESTRICT freq, const uint8_t* RESTRICT code_len,
1840 const zxc_pivco_tree_t* RESTRICT tree);
1841
1843int zxc_huf_encode_section_dict(const uint8_t* RESTRICT literals, size_t n_literals,
1844 const uint32_t* RESTRICT freq, const uint8_t* RESTRICT code_len,
1845 const zxc_pivco_tree_t* RESTRICT tree,
1846 const uint32_t* RESTRICT codes, uint8_t* RESTRICT dst,
1847 size_t dst_cap);
1848
1851int zxc_huf_decode_section(const uint8_t* RESTRICT payload, size_t payload_size,
1852 uint8_t* RESTRICT dst, size_t n, uint8_t* RESTRICT scratch);
1853
1855int zxc_huf_decode_section_dict(const uint8_t* RESTRICT payload, size_t payload_size,
1856 uint8_t* RESTRICT dst, size_t n,
1857 const zxc_pivco_tree_t* RESTRICT tree, uint8_t* RESTRICT scratch);
1858
1859// ---------------------------------------------------------------------------
1860// Compression / decompression context.
1861//
1862// The context owns the working buffers (hash table, sequence buffers, scratch)
1863// that encoder and decoder reuse across blocks. It stays private - the public
1864// APIs already wrap it opaquely - so the layout can evolve (cache-line
1865// placement, extra scratch arenas) without breaking the ABI.
1866// ---------------------------------------------------------------------------
1867
1884typedef struct {
1885 // Hot zone: random access / high frequency.
1886 // Kept at the start to ensure they reside in the first cache line (64 bytes).
1887 uint32_t* hash_table;
1888 uint8_t* hash_tags;
1889 uint16_t* chain_table;
1891 uint32_t epoch;
1893 // Warm zone: sequential access per sequence.
1894 uint32_t* buf_sequences;
1895 uint8_t* buf_tokens;
1896 uint16_t* buf_offsets;
1897 uint8_t* buf_extras;
1898 uint8_t* buf_split;
1900 uint8_t* literals;
1902 // Cold zone: configuration / scratch / resizeable.
1903 uint8_t* lit_buffer;
1905 uint8_t* work_buf;
1907 uint8_t* tok_buffer;
1912 uint8_t* pivco_scratch;
1918 uint8_t* opt_scratch;
1925 size_t dict_size;
1926 uint8_t* dict_buffer;
1934 uint32_t* lit_freq_acc;
1938 // Block-size derived parameters (computed once at init).
1939 size_t chunk_size;
1940 uint32_t offset_bits;
1941 uint32_t offset_mask;
1942 uint32_t max_epoch;
1943} zxc_cctx_t;
1944
1963int zxc_cctx_init(zxc_cctx_t* ctx, const size_t chunk_size, const int mode, const int level,
1964 const int checksum_enabled, const size_t dict_size);
1965
1977int zxc_cctx_attach_dict_huf(zxc_cctx_t* RESTRICT ctx, const uint8_t* RESTRICT lengths);
1978
1994size_t zxc_cctx_compute_workspace_size(const size_t chunk_size, const int mode, const int level,
1995 const size_t dict_size);
1996
2029int zxc_cctx_init_in_workspace(zxc_cctx_t* RESTRICT ctx, void* RESTRICT workspace,
2030 const size_t workspace_size, const size_t chunk_size, const int mode,
2031 const int level, const int checksum_enabled, const size_t dict_size,
2032 const int defer_entropy_scratch);
2033
2045
2054void zxc_cctx_free(zxc_cctx_t* ctx);
2055
2071int zxc_decompress_chunk_wrapper(const zxc_cctx_t* RESTRICT ctx, const uint8_t* RESTRICT src,
2072 const size_t src_sz, uint8_t* RESTRICT dst, const size_t dst_cap,
2073 const uint64_t block_index);
2074int zxc_decompress_chunk_wrapper_dict(const zxc_cctx_t* RESTRICT ctx, const uint8_t* RESTRICT src,
2075 const size_t src_sz, uint8_t* RESTRICT dst,
2076 const size_t dst_cap, const uint64_t block_index);
2078int zxc_decompress_chunk_wrapper_safe(const zxc_cctx_t* RESTRICT ctx, const uint8_t* RESTRICT src,
2079 const size_t src_sz, uint8_t* RESTRICT dst,
2080 const size_t dst_cap, const uint64_t block_index);
2081
2096int zxc_compress_chunk_wrapper(zxc_cctx_t* RESTRICT ctx, const uint8_t* RESTRICT src,
2097 const size_t src_sz, uint8_t* RESTRICT dst, const size_t dst_cap,
2098 const uint64_t block_index);
2099
2101int64_t zxc_compress_block_at(zxc_cctx* cctx, const void* RESTRICT src, size_t src_size,
2102 void* RESTRICT dst, size_t dst_capacity,
2103 const zxc_compress_opts_t* opts, uint64_t block_index);
2104
2105// ---------------------------------------------------------------------------
2106// Internal frame primitives.
2107//
2108// Read/write the ZXC file header, block header and footer. Kept internal:
2109// exposing them would freeze on-disk details (block_flags layout, footer
2110// composition) that stay free to evolve until the format is declared stable.
2111// ---------------------------------------------------------------------------
2112
2119typedef struct {
2120 uint8_t block_type;
2121 uint8_t block_flags;
2122 uint8_t reserved;
2124 uint32_t comp_size;
2126
2143int zxc_write_file_header(uint8_t* RESTRICT dst, const size_t dst_capacity, const size_t chunk_size,
2144 const int has_checksum, const uint32_t dict_id, const int has_seek);
2145
2167int zxc_read_file_header(const uint8_t* RESTRICT src, const size_t src_size, size_t* out_block_size,
2168 int* out_has_checksum, uint32_t* out_dict_id, int* out_has_seek);
2169
2172static inline int zxc_short_input_verdict(const uint8_t* p, const size_t n) {
2173 size_t chunk = 0;
2175 &chunk, NULL, NULL, NULL);
2176 return rc != ZXC_OK ? rc : ZXC_ERROR_SRC_TOO_SMALL;
2177}
2178
2179// ---------------------------------------------------------------------------
2180// Container scan: frames back to back, measured without decoding (FORMAT.md,
2181// Sec 2.1).
2182// ---------------------------------------------------------------------------
2183
2189typedef struct zxc_scan_src_s {
2192 int (*read_at)(const struct zxc_scan_src_s* src, uint64_t off, void* dst, size_t len);
2193 const uint8_t* data;
2194 void* ctx;
2195 uint64_t size;
2197
2199static ZXC_ALWAYS_INLINE zxc_scan_src_t zxc_scan_src_mem(const uint8_t* data, const size_t size) {
2200 zxc_scan_src_t src = {NULL, data, NULL, (uint64_t)size};
2201 return src;
2202}
2203
2205typedef struct {
2206 uint64_t dsize;
2207 uint64_t frames;
2208 uint32_t first_dict_id;
2211
2222int zxc_container_next(const zxc_scan_src_t* src, uint64_t pos);
2223
2235int zxc_scan_frame(const zxc_scan_src_t* src, uint64_t end, uint64_t* start, zxc_frame_info_t* info,
2236 size_t* footer_len);
2237
2243int zxc_scan_whole_frame(const zxc_scan_src_t* src, zxc_frame_info_t* info, size_t* footer_len);
2244
2255int zxc_scan_container(const zxc_scan_src_t* src, size_t req_chunk, zxc_container_info_t* info);
2256
2271int zxc_write_block_header(uint8_t* RESTRICT dst, const size_t dst_capacity,
2272 const zxc_block_header_t* bh);
2273
2288int zxc_read_block_header(const uint8_t* RESTRICT src, const size_t src_size,
2289 zxc_block_header_t* bh);
2290
2302static ZXC_ALWAYS_INLINE size_t zxc_uint_bytes(const uint64_t v) {
2303 size_t n = 1;
2304 while (n < sizeof(uint64_t) && (v >> (8 * n)) != 0) n++;
2305 return n;
2306}
2307
2309typedef struct {
2310 size_t skip;
2311 size_t nd;
2312 size_t nf;
2313 size_t len;
2316
2324 const uint64_t src_size,
2325 const int checksum_enabled) {
2327 l.skip = checksum_enabled ? (size_t)ZXC_FILE_DIGEST_SIZE : 0U;
2328 l.nd = zxc_uint_bytes(src_size);
2329 const uint64_t base = prefix + l.skip + l.nd + 1;
2330 l.nf = 1;
2331 while (zxc_uint_bytes(base + l.nf) > l.nf) l.nf++;
2332 l.compressed_size = base + l.nf;
2333 l.len = l.skip + l.nd + l.nf + 1;
2334 return l;
2335}
2336
2344int zxc_write_file_footer(uint8_t* RESTRICT dst, const size_t dst_capacity, const uint64_t prefix,
2345 const uint64_t src_size, const uint64_t digest,
2346 const int checksum_enabled);
2347
2362int zxc_check_file_footer(const uint8_t* footer, size_t avail, const zxc_footer_layout_t* l,
2363 uint64_t src_size, uint64_t* digest);
2364
2378int zxc_parse_file_footer(const uint8_t* end, size_t avail, uint64_t* src_size,
2379 uint64_t* compressed_size, size_t* sizes_len);
2380
2382#define ZXC_FOOTER_MAX_SIZE_WITH_DIGEST (ZXC_FILE_DIGEST_SIZE + ZXC_FILE_FOOTER_MAX_SIZE)
2383
2385#define ZXC_FRAME_MIN_SIZE (ZXC_FILE_HEADER_SIZE + ZXC_BLOCK_HEADER_SIZE + ZXC_FILE_FOOTER_MIN_SIZE)
2386
2390static inline size_t zxc_frame_tail_len(const uint64_t total) {
2391 const uint64_t body = total - (ZXC_FILE_HEADER_SIZE + ZXC_BLOCK_HEADER_SIZE);
2393}
2394
2407int zxc_read_frame_info(const uint8_t* header, const uint8_t* tail, size_t tail_len, uint64_t total,
2408 zxc_frame_info_t* info, size_t* footer_len);
2409
2411static ZXC_ALWAYS_INLINE void zxc_frame_info_copy(zxc_frame_info_t* info, const size_t info_size,
2412 const zxc_frame_info_t* got) {
2413 ZXC_MEMCPY(info, got, info_size < sizeof(*got) ? info_size : sizeof(*got));
2414}
2432static ZXC_ALWAYS_INLINE int zxc_footer_dsize_plausible(const uint64_t dsize,
2433 const size_t chunk_size,
2434 const uint64_t comp_size) {
2435 return zxc_seek_block_count(dsize, chunk_size) <= comp_size / ZXC_BLOCK_HEADER_SIZE;
2436}
2437
2448int zxc_seek_table_header(uint8_t* dst, size_t dst_capacity, uint64_t num_blocks);
2449
2457int zxc_check_eof_header(const uint8_t* hdr);
2458
2475int zxc_check_seek_header(const uint8_t* hdr, size_t avail, uint64_t total_out, size_t block_size,
2476 uint64_t* sek_bytes);
2477
2478// ---------------------------------------------------------------------------
2479// Seekable cross-TU hooks (defined in zxc_seekable.c, consumed by the
2480// FILE*-flavored open helper in zxc_driver.c).
2481// -------------------------------------------------------------------------
2482
2497
2503size_t zxc_seek_write_group(uint8_t* RESTRICT dst, uint64_t* RESTRICT anchor,
2504 const uint32_t* RESTRICT sizes, uint32_t cnt);
2505
/* end of internal */
2507
2508#ifdef __cplusplus
2509}
2510#endif
2511
2512#endif // ZXC_INTERNAL_H
struct zxc_cctx_s zxc_cctx
Opaque reusable compression context (see zxc_create_cctx).
Definition zxc_buffer.h:327
#define ZXC_BLOCK_SIZE_MAX
Maximum allowed block size (2 MB = 2^21).
#define ZXC_BLOCK_SIZE_MIN
Minimum allowed block size (4 KB = 2^12).
#define ZXC_BLOCK_SIZE_DEFAULT
Default block size (512 KB).
#define ZXC_DICT_SIZE_MAX
Maximum dictionary content size in bytes (64 KB - 1).
#define ZXC_HUF_TABLE_SIZE
Size of a packed literal Huffman code-lengths table (256 symbols, 4 bits each): the shared table in a...
@ ZXC_ERROR_SRC_TOO_SMALL
Source buffer too small or truncated input.
Definition zxc_error.h:45
@ ZXC_OK
Success (no error).
Definition zxc_error.h:38
#define ZXC_MAGIC_WORD
Magic word opening every frame, stored little-endian (F5 2E B0 9C).
#define ZXC_FILE_DIGEST_SIZE
Archive digest, opening the footer when the header sets HAS_CHECKSUM.
#define ZXC_FILE_HEADER_SIZE
File header size: Magic(4) + Version(1) + Chunk(1) + Flags(1) + Reserved(7) + Checksum(2).
#define ZXC_FILE_FLAG_HAS_CHECKSUM
Bit flag in the Flags byte indicating checksum presence (bit 7).
#define ZXC_SEQ_OFF_MASK
Mask to extract Offset from a GHI sequence.
static int zxc_ss_prem_rle_q8(const int level)
Per-level RLE-vs-RAW decode premium (Q8) for the space-speed selector.
static uint32_t zxc_seek_group_len(const uint64_t nblocks, const uint64_t g)
Blocks in group g of nblocks: ZXC_SEEK_GROUP, fewer for the last.
#define ZXC_BITMAP_WORDS(n_bits)
Number of uint64_t words needed to hold a bitmap of n_bits.
#define ZXC_SEEK_GROUP
Blocks per group.
#define ZXC_ALIGN_CL(x)
Round x up to the next cache-line boundary.
#define ZXC_GLO_HEADER_BINARY_SIZE
Binary size of a GLO block sub-header.
#define ZXC_ALWAYS_INLINE
Forces a function to be inlined (fallback for non-GCC/Clang/MSVC compilers).
#define ZXC_OPT_LONG_MATCH_SKIP
Threshold above which find_best_match is skipped at intra-match positions, keeping the parser O(N) on...
#define ZXC_HASH_GOLDEN64
Golden-ratio prime: header hashes and the digest spread.
#define ZXC_ALIGNMENT_MASK
Bitmask for cache-line alignment checks.
#define ZXC_LZ_MAX_DIST
Maximum allowed offset distance.
#define ZXC_BLOCK_FORMAT_OVERHEAD
Worst-case format overhead inside a single block beyond the outer 8-byte block header and the optiona...
static uint64_t zxc_seek_table_bytes(const uint64_t nblocks)
Byte size of the groups for nblocks blocks, in 64 bits.
#define ZXC_MAX_VARINT_VALUE
Maximum legitimate value a varint can decode to.
#define ZXC_HUF_MAX_CODE_LEN_ULTRA
Maximum Huffman code length, in bits: the ceiling the decoder's on-wire validation accepts (and the l...
static int zxc_ss_prem_huf_q8(const int level)
Per-level Huffman/PivCo-vs-RAW decode premium (Q8) for the space-speed selector.
#define ZXC_TOKEN_ML_MASK
Mask to extract Match Length from a GLO token.
static uint64_t zxc_seek_group_count(const uint64_t nblocks)
Groups holding nblocks blocks; the last one may be partial.
#define ZXC_FILE_CHECKSUM_ALGO_MASK
Mask for the checksum algorithm id (bits 0-3).
#define ZXC_SEQ_ML_BITS
Bits for Match Length in a GHI sequence.
#define ZXC_LZ_MINDIST
Match distance floor the encoder holds to at levels 1 to 5, sized to the decoder's widest match-copy ...
#define ZXC_SEEK_SIZE_ENTRY
One block's on-disk size, u32.
#define ZXC_LZ_MIN_MATCH_LEN
Minimum match length for an LZ77 match.
#define ZXC_GLO_DESC_MAX_SIZE
Widest GLO section descriptors: the literal and token section sizes.
#define ZXC_LZ_WINDOW_SIZE
Sliding window size (64 KB).
#define ZXC_PAD_SIZE
Safety padding appended to buffers to tolerate overruns.
#define ZXC_FILE_FLAG_HAS_DICTIONARY
Bit flag in the Flags byte indicating a dictionary is required (bit 6).
static uint32_t zxc_seek_size_field(const uint64_t table_bytes)
SEK header size field: table_bytes with its high half folded onto the low one.
#define ZXC_LZ_OFFSET_BIAS
Base bias added to encoded offsets (stored = actual - bias).
#define ZXC_BLOCK_HEADER_SIZE
Block header size: Type(1)+Flags(1)+Reserved(1)+Checksum(1)+CompSize(4).
#define ZXC_HUF_MAX_CODE_LEN_DENSITY
Encoder code-length cap for levels up to ZXC_LEVEL_DENSITY (below ZXC_LEVEL_ULTRA): shallow 8-bit tre...
#define ZXC_FILE_FLAG_HAS_SEEK_TABLE
Bit flag in the Flags byte: a SEK block sits between the EOF block and the footer (bit 5).
#define ZXC_HUF_MARGIN_SHIFT
Huffman margin shift: source of the legacy below-ULTRA premium used by zxc_ss_prem_huf_q8 (the frozen...
#define ZXC_BLOCK_LIT_SLACK
Readable bytes a GLO/GHI payload guarantees after its literal section.
#define ZXC_GLO_MAX_INLINE_ML
Longest match a GLO sequence carries without a varint extension.
#define ZXC_HASH_MULT64
Second multiplier of the 16-byte header hash (zxc_hash16).
#define ZXC_TOKEN_ML_BITS
Bits for Match Length in a GLO token.
#define ZXC_SEQ_OFF_BITS
Bits for Offset in a GHI sequence.
#define ZXC_HASH_XORSHIFT64
Vigna's xorshift* multiplier: the 5-byte LZ hash and the digest fold.
#define ZXC_SEQ_LL_BITS
Bits for Literal Length in a GHI sequence.
static uint32_t zxc_read_varint(const uint8_t **ptr, const uint8_t *end)
Reads a Prefix Varint encoded integer.
#define ZXC_PIVCO_NODE_SLOTS
Node-indexed array size: every node, plus a slot for the lone-symbol root's missing child.
#define ZXC_RLE_MARGIN_SHIFT
RLE margin shift: source of the legacy below-ULTRA premium used by zxc_ss_prem_rle_q8 (256 >> shift r...
#define ZXC_SEEK_ANCHOR_SIZE
Group anchor: offset of its first block, u64.
#define ZXC_LZ_MINDIST_PROBE_PER_KB
Probe sampling: one position per KB, clamped.
#define ZXC_CACHE_LINE_SIZE
Assumed CPU cache line size for alignment.
#define ZXC_LZ_WINDOW_MASK
Mask for ring-buffer indexing into chain_table (power-of-two window).
#define ZXC_LZ_MINDIST_MAX_SHORT_PCT
Short-distance hit rate, in percent, above which a block keeps its short match distances.
static int zxc_magic_prefix_ok(const uint8_t *p, const size_t n)
Whether the first n bytes (up to 4) at p agree with the magic word, so a frame may start there: the c...
#define ZXC_TOKEN_LIT_BITS
Bits for Literal Length in a GLO token.
#define ZXC_HUF_NUM_SYMBOLS
Alphabet size: one entry per possible byte value.
#define ZXC_DECOMPRESS_TAIL_PAD
Tail padding required on the decompression destination buffer.
@ ZXC_LEVEL_ULTRA
Maximum density: Huffman-coded literals and sequence tokens.
@ ZXC_LEVEL_FASTEST
Fastest compression; lowest ratio.
@ ZXC_LEVEL_DENSITY
Higher density: adds Huffman-coded literals on top of COMPACT.
struct zxc_seekable_s zxc_seekable
Opaque handle for a seekable ZXC archive.
On-disk header structure for a ZXC block (8 bytes, little-endian).
uint8_t reserved
Reserved for future protocol extensions.
uint32_t comp_size
Compressed size excluding this header.
uint8_t block_type
Block type (see zxc_block_type_t).
uint8_t header_checksum
Header integrity checksum (1 byte).
uint8_t block_flags
Flags (e.g., checksum presence).
Compression / decompression context.
uint32_t offset_mask
(1U << offset_bits) - 1
uint32_t * lit_freq_acc
Trainer hook: when non-NULL, the GLO encoder accumulates post-LZ literal byte frequencies here (256 e...
uint8_t * hash_tags
Split tag table for fast match rejection (8-bit tags).
zxc_dict_huf_state_t * dict_huf
Tree-at-attach state (PivCo tree + codes + code lengths), carved from the workspace only when dict_si...
uint8_t * buf_split
Match-splitting scratch, one byte per sequence.
size_t lit_buffer_cap
Current capacity of the scratch buffer.
void * memory_block
Single allocation block owner.
size_t opt_scratch_cap
Current capacity of opt_scratch in bytes.
size_t work_buf_cap
Capacity of the work buffer.
void * entropy_block
Lazy allocation backing tok_buffer + pivco_scratch (heap decode contexts, first entropy block only).
size_t pivco_scratch_cap
Capacity of pivco_scratch in bytes.
int compression_level
Compression level.
uint32_t epoch
Current epoch for lazy hash table invalidation.
uint32_t * buf_sequences
Buffer for sequence records (packed: LL(8)|ML(8)|Offset(16)).
uint8_t * lit_buffer
Scratch buffer for literals (RLE / Huffman).
uint8_t * work_buf
Padded scratch buffer for buffer-API decompression.
uint32_t * hash_table
Hash table for LZ77 match positions (epoch|pos).
uint32_t offset_bits
log2(chunk_size) - governs epoch_mark shift.
size_t chunk_size
Effective block size in bytes.
size_t tok_buffer_cap
Capacity of tok_buffer in bytes.
uint8_t * buf_tokens
Buffer for token sequences.
uint8_t * buf_extras
Buffer for extra lengths (vbytes for LL/ML).
uint8_t * dict_buffer
[dict | data] concat scratch carved from memory_block when dict_size > 0 (NULL otherwise).
uint8_t * pivco_scratch
Level ping-pong scratch for PivCo decode.
zxc_glo_split_hist_t * buf_split_hist
Match-splitting escape histograms.
size_t dict_size
Dictionary prefill size (0 = no dictionary).
uint8_t * literals
Buffer for literal bytes.
uint8_t * opt_scratch
Optimal-parser DP scratch (level >= 6 only, lazy-allocated, packs dp/parent_len/parent_off/actions).
uint16_t * chain_table
Chain table for collision resolution.
int checksum_enabled
1 if checksum calculation/verification is enabled.
int dict_huf_tree_ok
1 when *dict_huf is built and valid.
uint32_t max_epoch
1U << (32 - offset_bits)
uint8_t * tok_buffer
Decode scratch for a Huffman-coded GLO token section (enc_tok == HUFFMAN); NULL on compress.
uint16_t * buf_offsets
Buffer for offsets.
size_t dict_buffer_cap
Capacity of dict_buffer in bytes (0 = none).
Options for compression.
Definition zxc_opts.h:58
What zxc_scan_container learns about a container.
int uses_dict
A frame bound to a dictionary.
uint64_t frames
ZXC frames.
uint64_t dsize
Sum of the stored decompressed sizes.
uint32_t first_dict_id
Dictionary id of the first frame, 0 without one.
Frame-constant dictionary Huffman state, prebuilt once at attach.
zxc_pivco_tree_t tree
PivCo tree from the shared literal table.
What a frame's header and footer declare, read without decoding.
Definition zxc_buffer.h:235
Header specific to General (LZ-based) compression blocks.
uint32_t n_sequences
The total count of LZ sequences in the block.
uint8_t enc_mlen
Reserved, written 0 and ignored on decode.
uint8_t enc_off
GLO only: width of the offset stream (1 = 1-byte, 0 = 2-byte).
uint32_t n_literals
The total count of literal bytes.
uint8_t enc_tok
GLO only: encoding of the token section, whose bytes each pack a literal length and a match length ni...
uint8_t enc_lit
Encoding method used for the literal stream.
Workspace of zxc_huf_nudge_code_lengths: tables and DP planes, once a 10 KiB frame and a per-block al...
Trace-back stack frame for the package-merge code-length recovery.
int16_t idx
Item index within that level.
int8_t lvl
Package-merge level being traced back.
Boundary package-merge work item.
int16_t right
Right child index, or -1 for a leaf.
int16_t sym
Symbol index for a leaf, or -1 for an internal node.
int16_t left
Left child index, or -1 for a leaf.
uint32_t weight
Accumulated weight (summed frequency) of the package.
A live symbol and its weight, the package-merge sort key.
uint32_t w
Frequency.
int16_t sym
Byte value.
Search parameters for LZ77 compression levels.
int lazy_attempts
Maximum number of candidates explored during lazy evaluation (same semantics as search_depth but appl...
int search_depth
Maximum number of candidates explored in the hash chain per position.
int use_lazy
Enable lazy matching.
int lazy_len_threshold
Skip lazy evaluation when the current match length already reaches this threshold: a match this long ...
uint32_t step_shift
Acceleration factor for step size: step = step_base + (distance >> step_shift).
uint8_t split_max
Longest match re-emitted as inline pieces (zxc_glo_split_block), in the token's units (length - ZXC_L...
int sufficient_len
"Good enough" match length: once a match reaches this threshold the chain walk stops immediately,...
uint32_t min_offset
Shortest match distance the parser may emit; 1 = unconstrained.
uint32_t step_base
Base step size when advancing through unmatched literals.
A PivCo code tree: its canonical shape, by depth.
void * ctx
Opaque state for read_at.
uint64_t size
Container size in bytes.
int(* read_at)(const struct zxc_scan_src_s *src, uint64_t off, void *dst, size_t len)
Reads len bytes at off; NULL reads from data.
const uint8_t * data
Container bytes when read_at is NULL.
Where a container scan reads from: memory, or a positioned callback (the FILE* size query).
Single point of override for the C-library dependencies of libzxc.
static uint64_t zxc_le64(const void *p)
Reads a little-endian 64-bit value from a possibly unaligned address.
zxc_block_type_t
Block types, i.e.
int zxc_write_file_header(uint8_t *dst, const size_t dst_capacity, const size_t chunk_size, const int has_checksum, const uint32_t dict_id, const int has_seek)
Writes the standard ZXC file header into dst.
Definition zxc_common.c:486
static int zxc_ctz32(const uint32_t x)
Counts trailing zeros, returning 32 for a zero input.
int zxc_write_glo_header_and_desc(uint8_t *dst, const size_t rem, const zxc_gnr_header_t *gh, const uint32_t lit_comp, const uint32_t tok_comp)
Writes a GLO sub-header followed by its section descriptors.
Definition zxc_common.c:940
size_t zxc_huf_calc_size(const uint32_t *freq, const uint8_t *code_len, int with_header)
Exact encoded size (bytes) of a PivCo section for this histogram and code lengths; includes the 128-b...
#define ZXC_HUF_NUDGE_DP_M
Slot-ledger DP bound, coarse symbols per plane axis; the nudge groups symbols to stay under it.
int zxc_read_block_header(const uint8_t *src, const size_t src_size, zxc_block_header_t *bh)
Reads and parses a ZXC block header from src.
Definition zxc_common.c:703
void zxc_cctx_free(zxc_cctx_t *ctx)
Releases the internal buffers owned by a context.
Definition zxc_common.c:400
static uint32_t zxc_le32(const void *p)
Reads a little-endian 32-bit value from a possibly unaligned address.
int zxc_write_block_header(uint8_t *dst, const size_t dst_capacity, const zxc_block_header_t *bh)
Encodes a block header into dst.
Definition zxc_common.c:684
#define ZXC_GLO_SPLIT_CTX_BITS
Longest escape history a context keys on; small blocks shorten it (down to 2 bits) towards 16 samples...
static void zxc_copy32(void *dst, const void *src)
Copies 32 bytes from source to destination using SIMD when available.
int zxc_parse_file_footer(const uint8_t *end, size_t avail, uint64_t *src_size, uint64_t *compressed_size, size_t *sizes_len)
Parses the sizes back from the end of a frame.
Definition zxc_common.c:865
int zxc_huf_encode_section_dict(const uint8_t *literals, size_t n_literals, const uint32_t *freq, const uint8_t *code_len, const zxc_pivco_tree_t *tree, const uint32_t *codes, uint8_t *dst, size_t dst_cap)
Encode a PivCo section against a prebuilt dict tree/codes (no header).
static int zxc_huf_enc_max_code_len(const int level)
Encoder Huffman code-length cap for a compression level: levels below ZXC_LEVEL_ULTRA use ZXC_HUF_MAX...
static void zxc_frame_info_copy(zxc_frame_info_t *info, const size_t info_size, const zxc_frame_info_t *got)
Copies the fields of got that fit the caller's info_size bytes.
static int zxc_validate_block_size(const size_t bs)
Validates a block size.
static zxc_scan_src_t zxc_scan_src_mem(const uint8_t *data, const size_t size)
A scan source over size bytes of memory at data.
int zxc_scan_frame(const zxc_scan_src_t *src, uint64_t end, uint64_t *start, zxc_frame_info_t *info, size_t *footer_len)
Measures the frame ending at end without decoding: its footer's compressed size gives where it starts...
Definition zxc_common.c:569
int zxc_huf_encode_section(const uint8_t *literals, size_t n_literals, const uint32_t *freq, const uint8_t *code_len, uint8_t *dst, size_t dst_cap)
Encode a PivCo literal section (128-byte lengths header + payload).
int zxc_cctx_alloc_entropy_scratch(zxc_cctx_t *ctx)
Lazily allocates the decode-side entropy scratch (tok_buffer + pivco_scratch) for a heap context init...
Definition zxc_common.c:373
int zxc_cctx_init_in_workspace(zxc_cctx_t *ctx, void *workspace, const size_t workspace_size, const size_t chunk_size, const int mode, const int level, const int checksum_enabled, const size_t dict_size, const int defer_entropy_scratch)
Initialises a compression / decompression context inside a caller-supplied workspace.
Definition zxc_common.c:260
int zxc_seek_table_header(uint8_t *dst, size_t dst_capacity, uint64_t num_blocks)
Writes a seek table's block header for num_blocks entries.
Definition zxc_common.c:738
int zxc_container_next(const zxc_scan_src_t *src, uint64_t pos)
Tells whether a frame starts at pos.
Definition zxc_common.c:558
int zxc_check_seek_header(const uint8_t *hdr, size_t avail, uint64_t total_out, size_t block_size, uint64_t *sek_bytes)
Checks the SEK block header the file header announced, on the avail bytes present.
Definition zxc_common.c:757
int zxc_read_file_header(const uint8_t *src, const size_t src_size, size_t *out_block_size, int *out_has_checksum, uint32_t *out_dict_id, int *out_has_seek)
Validates and reads the ZXC file header from src.
Definition zxc_common.c:516
int zxc_huf_decode_section_dict(const uint8_t *payload, size_t payload_size, uint8_t *dst, size_t n, const zxc_pivco_tree_t *tree, uint8_t *scratch)
Decode a PivCo dict section against a prebuilt dict tree.
static void zxc_store_le64(void *p, const uint64_t v)
Writes a 64-bit value little-endian to a possibly unaligned address.
static int zxc_level_clamp(const int level)
Clamps a resolved compression level to the supported ceiling.
static zxc_lz77_params_t zxc_get_lz77_params(const int level)
Retrieves LZ77 compression parameters based on the specified compression level.
void zxc_seekable_attach_owned_ctx(zxc_seekable *s, void *ctx)
Hands ownership of a heap-allocated reader context to a seekable handle.
int zxc_huf_build_code_lengths(const uint32_t *freq, uint8_t *code_len, void *scratch, int max_code_len)
Build length-limited canonical Huffman code lengths from a frequency table.
static uint32_t zxc_log2_u32(const uint32_t v)
Integer log-base-2 for a 32-bit value.
int zxc_scan_whole_frame(const zxc_scan_src_t *src, zxc_frame_info_t *info, size_t *footer_len)
The frame that must span all of src: zxc_get_frame_info() and its FILE* twin.
Definition zxc_common.c:601
static uint64_t zxc_digest_combine(const uint64_t acc, const uint32_t block_checksum)
Folds a data block's 32-bit checksum into the running archive digest.
size_t zxc_cctx_compute_workspace_size(const size_t chunk_size, const int mode, const int level, const size_t dict_size)
Returns the byte count that zxc_cctx_init would allocate for the given parameters.
Definition zxc_common.c:245
static size_t zxc_block_size_ceil(const size_t v)
Branchless bit_ceil: smallest power of two >= v, clamped to ZXC_BLOCK_SIZE_MIN.
static uint64_t zxc_seek_block_count(const uint64_t total_decomp, const size_t block_size)
Blocks in total_decomp bytes of block_size: the seek table's entry count, which the SEK header's fiel...
static uint16_t zxc_le16(const void *p)
Reads a little-endian 16-bit value from a possibly unaligned address.
size_t zxc_huf_calc_size_dict(const uint32_t *freq, const uint8_t *code_len, const zxc_pivco_tree_t *tree)
zxc_huf_calc_size for a dict section: prebuilt tree, no header.
static uint16_t zxc_hash16(const uint8_t *p)
Computes the 2-byte checksum for file and dictionary headers.
void zxc_huf_nudge_cost(const uint8_t *code_len, const uint32_t *freq, uint64_t *bits, uint64_t *touches)
Modeled (bits, level-touches) decode cost of one code-length vector.
static void zxc_store_le16(void *p, const uint16_t v)
Writes a 16-bit value little-endian to a possibly unaligned address.
static uint8_t zxc_hash8(const uint8_t *p)
Computes the 1-byte checksum for block headers.
int zxc_read_ghi_header(const uint8_t *src, const size_t len, zxc_gnr_header_t *gh)
Reads a GHI sub-header from a buffer.
int zxc_decompress_chunk_wrapper_dict(const zxc_cctx_t *ctx, const uint8_t *src, const size_t src_sz, uint8_t *dst, const size_t dst_cap, const uint64_t block_index)
Public dictionary chunk decoder.
int zxc_compress_chunk_wrapper(zxc_cctx_t *ctx, const uint8_t *src, const size_t src_sz, uint8_t *dst, const size_t dst_cap, const uint64_t block_index)
Compresses one chunk through the runtime ISA dispatch.
int zxc_check_file_footer(const uint8_t *footer, size_t avail, const zxc_footer_layout_t *l, uint64_t src_size, uint64_t *digest)
Checks the footer a sequential reader reaches against l, the one the frame implies,...
Definition zxc_common.c:847
static int zxc_footer_dsize_plausible(const uint64_t dsize, const size_t chunk_size, const uint64_t comp_size)
Whether a footer's decompressed size is reachable for this archive.
int zxc_read_frame_info(const uint8_t *header, const uint8_t *tail, size_t tail_len, uint64_t total, zxc_frame_info_t *info, size_t *footer_len)
Validates a frame from its header and the end of its bytes: the one check behind zxc_get_frame_info()...
Definition zxc_common.c:648
uint32_t zxc_glo_split_hist_t[4][2][1U<< 8]
zxc_glo_split_analyze's escape histograms: four rotating lanes of [escape][context] counts,...
static void zxc_store_le32(void *p, const uint32_t v)
Writes a 32-bit value little-endian to a possibly unaligned address.
int zxc_write_ghi_header(uint8_t *dst, const size_t rem, const zxc_gnr_header_t *gh)
Writes a GHI sub-header.
Definition zxc_common.c:997
int zxc_read_glo_header_and_desc(const uint8_t *src, const size_t len, zxc_gnr_header_t *gh, uint32_t *lit_comp, uint32_t *tok_comp)
Reads a GLO sub-header and its section descriptors from a source buffer.
Definition zxc_common.c:965
static size_t zxc_uint_bytes(const uint64_t v)
Fewest little-endian bytes, 1 to 8, that hold v.
int zxc_huf_decode_section(const uint8_t *payload, size_t payload_size, uint8_t *dst, size_t n, uint8_t *scratch)
Decode a PivCo literal section into dst (exactly n bytes).
int zxc_huf_nudge_code_lengths(const uint32_t *freq, uint8_t *code_len, void *scratch, size_t scratch_cap, int max_code_len)
Optionally reshape freshly built code lengths for faster PivCo decode.
int zxc_check_eof_header(const uint8_t *hdr)
Checks an EOF block header against its one valid form: type 255, every other field zero,...
Definition zxc_common.c:748
static int zxc_ctz64(const uint64_t x)
Counts trailing zeros, returning 64 for a zero input.
static void zxc_copy16(void *dst, const void *src)
Copies exactly 16 bytes as one vector move where the ISA has one.
static int zxc_block_is_short_dist_bound(const uint8_t *const blk, const size_t size)
Reports whether a block leans on back-references shorter than ZXC_LZ_MINDIST.
static size_t zxc_frame_tail_len(const uint64_t total)
Bytes zxc_read_frame_info() takes from the end of total bytes (at least ZXC_FRAME_MIN_SIZE): all of t...
int zxc_cctx_init(zxc_cctx_t *ctx, const size_t chunk_size, const int mode, const int level, const int checksum_enabled, const size_t dict_size)
Initialises a ZXC compression / decompression context in place.
Definition zxc_common.c:339
int zxc_scan_container(const zxc_scan_src_t *src, size_t req_chunk, zxc_container_info_t *info)
Measures a whole container without decoding: frames from the last back to the first through zxc_scan_...
Definition zxc_common.c:613
#define ZXC_FOOTER_MAX_SIZE_WITH_DIGEST
Most bytes a footer spans: the digest and the two longest sizes.
size_t zxc_seek_write_group(uint8_t *dst, uint64_t *anchor, const uint32_t *sizes, uint32_t cnt)
Writes one group (*anchor, then cnt sizes) into dst, which holds ZXC_SEEK_GROUP_BYTES,...
Definition zxc_common.c:770
int zxc_decompress_chunk_wrapper(const zxc_cctx_t *ctx, const uint8_t *src, const size_t src_sz, uint8_t *dst, const size_t dst_cap, const uint64_t block_index)
Decompresses one chunk through the runtime ISA dispatch.
static void zxc_file_header_sign(uint8_t *h)
Writes the file header checksum (bytes 14-15) over the other 14 bytes.
int zxc_write_file_footer(uint8_t *dst, const size_t dst_capacity, const uint64_t prefix, const uint64_t src_size, const uint64_t digest, const int checksum_enabled)
Writes the footer of a frame whose first prefix bytes precede it.
Definition zxc_common.c:832
int64_t zxc_compress_block_at(zxc_cctx *cctx, const void *src, size_t src_size, void *dst, size_t dst_capacity, const zxc_compress_opts_t *opts, uint64_t block_index)
zxc_compress_block, its checksum seeded with block_index (public entry: 0).
static zxc_footer_layout_t zxc_footer_layout(const uint64_t prefix, const uint64_t src_size, const int checksum_enabled)
The footer of a frame whose first prefix bytes precede it.
static uint32_t zxc_checksum(const void *input, const size_t len, const uint64_t seed, const uint8_t hash_method)
Calculates a 32-bit hash for a given input buffer.
int zxc_cctx_attach_dict_huf(zxc_cctx_t *ctx, const uint8_t *lengths)
Attach the shared dictionary literal table to an initialised context.
Definition zxc_common.c:453
static int zxc_short_input_verdict(const uint8_t *p, const size_t n)
The verdict on n bytes too short for a frame: the header speaks first, then ZXC_ERROR_SRC_TOO_SMALL.
void zxc_huf_pack_lengths(const uint8_t *code_len, uint8_t *out)
Pack per-symbol code lengths into the 128-byte (4-bit nibble) header.
int zxc_decompress_chunk_wrapper_safe(const zxc_cctx_t *ctx, const uint8_t *src, const size_t src_sz, uint8_t *dst, const size_t dst_cap, const uint64_t block_index)
Exact-capacity variant for the safe block API; dispatch table only.
static void zxc_opt_dp_sizes(const size_t chunk_size, size_t *sz_dp, size_t *sz_pl, size_t *sz_po, size_t *sz_bm)
The four DP partitions the optimal parser carves out of opt_scratch.
int zxc_huf_dict_tree_build(const uint8_t *packed_lengths, zxc_pivco_tree_t *tree, uint32_t *codes, uint8_t *code_len)
Unpack a dict table's packed lengths and prebuild its tree, codes and code lengths,...
int zxc_huf_unpack_lengths(const uint8_t *in, uint8_t *code_len)
Unpack and structurally validate a 128-byte packed lengths header.
zxc_section_encoding_t
Specifies the encoding methods used for internal data sections.