20#include "../../include/zxc_dict.h"
21#include "../../include/zxc_error.h"
26#if defined(ZXC_DISABLE_SIMD) && !defined(ZXC_ONLY_DEFAULT)
27#define ZXC_ONLY_DEFAULT
37#if (defined(__x86_64__) || defined(_M_X64)) && !defined(_MSC_VER) && !defined(ZXC_ONLY_DEFAULT)
41#if defined(__linux__) && (defined(__arm__) || defined(_M_ARM)) && !defined(ZXC_ONLY_DEFAULT)
46#if __has_include(<asm/hwcap.h>)
51#define HWCAP_NEON (1 << 12)
61int zxc_decompress_chunk_wrapper_default(
const zxc_cctx_t* RESTRICT ctx,
62 const uint8_t* RESTRICT src,
const size_t src_sz,
63 uint8_t* RESTRICT dst,
const size_t dst_cap,
64 const uint64_t block_index);
65int zxc_decompress_chunk_wrapper_dict_default(
const zxc_cctx_t* RESTRICT ctx,
66 const uint8_t* RESTRICT src,
const size_t src_sz,
67 uint8_t* RESTRICT dst,
const size_t dst_cap,
68 const uint64_t block_index);
69int zxc_decompress_chunk_wrapper_safe_default(
const zxc_cctx_t* RESTRICT ctx,
70 const uint8_t* RESTRICT src,
const size_t src_sz,
71 uint8_t* RESTRICT dst,
const size_t dst_cap,
72 const uint64_t block_index);
74#ifndef ZXC_ONLY_DEFAULT
75#if defined(__x86_64__) || defined(_M_X64)
76int zxc_decompress_chunk_wrapper_avx2(
const zxc_cctx_t* RESTRICT ctx,
const uint8_t* RESTRICT src,
77 const size_t src_sz, uint8_t* RESTRICT dst,
78 const size_t dst_cap,
const uint64_t block_index);
79int zxc_decompress_chunk_wrapper_dict_avx2(
const zxc_cctx_t* RESTRICT ctx,
80 const uint8_t* RESTRICT src,
const size_t src_sz,
81 uint8_t* RESTRICT dst,
const size_t dst_cap,
82 const uint64_t block_index);
83int zxc_decompress_chunk_wrapper_avx512(
const zxc_cctx_t* RESTRICT ctx,
const uint8_t* RESTRICT src,
84 const size_t src_sz, uint8_t* RESTRICT dst,
85 const size_t dst_cap,
const uint64_t block_index);
86int zxc_decompress_chunk_wrapper_dict_avx512(
const zxc_cctx_t* RESTRICT ctx,
87 const uint8_t* RESTRICT src,
const size_t src_sz,
88 uint8_t* RESTRICT dst,
const size_t dst_cap,
89 const uint64_t block_index);
90int zxc_decompress_chunk_wrapper_safe_avx2(
const zxc_cctx_t* RESTRICT ctx,
91 const uint8_t* RESTRICT src,
const size_t src_sz,
92 uint8_t* RESTRICT dst,
const size_t dst_cap,
93 const uint64_t block_index);
94int zxc_decompress_chunk_wrapper_safe_avx512(
const zxc_cctx_t* RESTRICT ctx,
95 const uint8_t* RESTRICT src,
const size_t src_sz,
96 uint8_t* RESTRICT dst,
const size_t dst_cap,
97 const uint64_t block_index);
98#elif defined(__arm__) || defined(_M_ARM)
99int zxc_decompress_chunk_wrapper_neon32(
const zxc_cctx_t* RESTRICT ctx,
const uint8_t* RESTRICT src,
100 const size_t src_sz, uint8_t* RESTRICT dst,
101 const size_t dst_cap,
const uint64_t block_index);
102int zxc_decompress_chunk_wrapper_dict_neon32(
const zxc_cctx_t* RESTRICT ctx,
103 const uint8_t* RESTRICT src,
const size_t src_sz,
104 uint8_t* RESTRICT dst,
const size_t dst_cap,
105 const uint64_t block_index);
106int zxc_decompress_chunk_wrapper_safe_neon32(
const zxc_cctx_t* RESTRICT ctx,
107 const uint8_t* RESTRICT src,
const size_t src_sz,
108 uint8_t* RESTRICT dst,
const size_t dst_cap,
109 const uint64_t block_index);
114int zxc_compress_chunk_wrapper_default(
zxc_cctx_t* RESTRICT ctx,
const uint8_t* RESTRICT src,
115 const size_t src_sz, uint8_t* RESTRICT dst,
116 const size_t dst_cap,
const uint64_t block_index);
121int zxc_huf_build_code_lengths_default(
const uint32_t* RESTRICT freq, uint8_t* RESTRICT code_len,
122 void* RESTRICT scratch,
int max_code_len);
123size_t zxc_huf_calc_size_default(
const uint32_t* RESTRICT freq,
const uint8_t* RESTRICT code_len,
125int zxc_huf_encode_section_default(
const uint8_t* RESTRICT literals,
size_t n_literals,
126 const uint32_t* RESTRICT freq,
const uint8_t* RESTRICT code_len,
127 uint8_t* RESTRICT dst,
size_t dst_cap);
128int zxc_huf_decode_section_default(
const uint8_t* RESTRICT payload,
size_t payload_size,
129 uint8_t* RESTRICT dst,
size_t n, uint8_t* RESTRICT scratch);
130int zxc_huf_encode_section_dict_default(
const uint8_t* RESTRICT literals,
size_t n_literals,
131 const uint32_t* RESTRICT freq,
132 const uint8_t* RESTRICT code_len,
134 const uint32_t* RESTRICT codes, uint8_t* RESTRICT dst,
136int zxc_huf_decode_section_dict_default(
const uint8_t* RESTRICT payload,
size_t payload_size,
137 uint8_t* RESTRICT dst,
size_t n,
139 uint8_t* RESTRICT scratch);
140size_t zxc_huf_calc_size_dict_default(
const uint32_t* RESTRICT freq,
141 const uint8_t* RESTRICT code_len,
143void zxc_huf_pack_lengths_default(
const uint8_t* RESTRICT code_len, uint8_t* RESTRICT out);
144int zxc_huf_unpack_lengths_default(
const uint8_t* RESTRICT in, uint8_t* RESTRICT code_len);
146#if defined(__x86_64__) || defined(_M_X64)
147int zxc_compress_chunk_wrapper_avx2(
zxc_cctx_t* RESTRICT ctx,
const uint8_t* RESTRICT src,
148 const size_t src_sz, uint8_t* RESTRICT dst,
149 const size_t dst_cap,
const uint64_t block_index);
150int zxc_compress_chunk_wrapper_avx512(
zxc_cctx_t* RESTRICT ctx,
const uint8_t* RESTRICT src,
151 const size_t src_sz, uint8_t* RESTRICT dst,
152 const size_t dst_cap,
const uint64_t block_index);
153#elif defined(__arm__) || defined(_M_ARM)
154int zxc_compress_chunk_wrapper_neon32(
zxc_cctx_t* RESTRICT ctx,
const uint8_t* RESTRICT src,
155 const size_t src_sz, uint8_t* RESTRICT dst,
156 const size_t dst_cap,
const uint64_t block_index);
163#if (defined(__x86_64__) || defined(_M_X64)) && !defined(ZXC_ONLY_DEFAULT)
166static inline void zxc_cpuid(
const uint32_t leaf,
const uint32_t sub, uint32_t regs[4]) {
169 __cpuidex(r, (
int)leaf, (
int)sub);
170 regs[0] = (uint32_t)r[0];
171 regs[1] = (uint32_t)r[1];
172 regs[2] = (uint32_t)r[2];
173 regs[3] = (uint32_t)r[3];
175 __cpuid_count(leaf, sub, regs[0], regs[1], regs[2], regs[3]);
180static inline uint64_t zxc_xgetbv0(
void) {
187 __asm__
volatile(
".byte 0x0f, 0x01, 0xd0" :
"=a"(lo),
"=d"(hi) :
"c"(0));
188 return ((uint64_t)hi << 32) | lo;
195 const size_t, uint8_t* RESTRICT,
const size_t,
const uint64_t);
198 uint8_t* RESTRICT,
const size_t,
const uint64_t);
200#ifndef ZXC_ONLY_DEFAULT
228#if defined(__x86_64__) || defined(_M_X64)
237 zxc_cpuid(0, 0, regs);
238 const uint32_t max_leaf = regs[0];
240 zxc_cpuid(1, 0, regs);
241 if (regs[3] & (1U << 26)) sse2 = 1;
242 if ((regs[2] & (1U << 27)) && max_leaf >= 7) {
243 const uint64_t xcr0 = zxc_xgetbv0();
244 if ((xcr0 & 0x6) == 0x6) {
245 zxc_cpuid(7, 0, regs);
246 const int bmi1 = (regs[1] >> 3) & 1;
247 const int bmi2 = (regs[1] >> 8) & 1;
248 if (regs[1] & (1U << 5)) avx2 = 1;
250 if ((regs[1] & (1U << 16)) && (regs[1] & (1U << 30)) && (regs[2] & (1U << 1)) &&
251 (regs[2] & (1U << 6)) && (xcr0 & 0xE0) == 0xE0)
256 zxc_cpuid(0x80000001U, 0, regs);
257 bmi_lzcnt = bmi1 && bmi2 && ((regs[2] >> 5) & 1);
261 if (avx512 && bmi_lzcnt) {
263 }
else if (avx2 && bmi_lzcnt) {
269#elif defined(__aarch64__) || defined(_M_ARM64)
273#elif defined(__arm__) || defined(_M_ARM)
275#if defined(__linux__)
276 const unsigned long hwcaps = getauxval(AT_HWCAP);
277 if (hwcaps & HWCAP_NEON) {
284#if defined(__ARM_NEON)
317#define ZXC_VARIANT_SET(sfx) \
318 static const zxc_variant_set_t zxc_variants##sfx = {zxc_decompress_chunk_wrapper##sfx, \
319 zxc_decompress_chunk_wrapper_dict##sfx, \
320 zxc_compress_chunk_wrapper##sfx}
323#ifndef ZXC_ONLY_DEFAULT
324#if defined(__x86_64__) || defined(_M_X64)
327#elif defined(__arm__) || defined(_M_ARM)
331#undef ZXC_VARIANT_SET
333#ifdef ZXC_ONLY_DEFAULT
336 return &zxc_variants_default;
347#if defined(__x86_64__) || defined(_M_X64)
350#elif defined(__arm__) || defined(_M_ARM)
357 return &zxc_variants_default;
369#if ZXC_USE_C11_ATOMICS
380#if ZXC_USE_C11_ATOMICS
381 const zxc_variant_set_t* v = atomic_load_explicit(&
zxc_variants_ptr, memory_order_acquire);
390#ifdef ZXC_ONLY_DEFAULT
393 return zxc_decompress_chunk_wrapper_safe_default;
404#if defined(__x86_64__) || defined(_M_X64)
405 if (v == &zxc_variants_avx512) f = zxc_decompress_chunk_wrapper_safe_avx512;
406 if (v == &zxc_variants_avx2) f = zxc_decompress_chunk_wrapper_safe_avx2;
407#elif defined(__arm__) || defined(_M_ARM)
408 if (v == &zxc_variants_neon32) f = zxc_decompress_chunk_wrapper_safe_neon32;
412#if ZXC_USE_C11_ATOMICS
423#if ZXC_USE_C11_ATOMICS
435 const size_t src_sz, uint8_t* RESTRICT dst,
const size_t dst_cap,
436 const uint64_t block_index) {
441 return (ctx->dict_size ? v->decompress_dict : v->decompress)(ctx, src, src_sz, dst, dst_cap,
457 const uint8_t* RESTRICT src,
458 const size_t src_sz, uint8_t* RESTRICT dst,
459 const size_t dst_cap,
460 const uint64_t block_index) {
466 const size_t src_sz, uint8_t* RESTRICT dst,
const size_t dst_cap,
467 const uint64_t block_index) {
468 return zxc_variants()->compress(ctx, src, src_sz, dst, dst_cap, block_index);
491 void* RESTRICT scratch,
const int max_code_len) {
492 return zxc_huf_build_code_lengths_default(freq, code_len, scratch, max_code_len);
497 const int with_header) {
498 return zxc_huf_calc_size_default(freq, code_len, with_header);
502 const uint32_t* RESTRICT freq,
const uint8_t* RESTRICT code_len,
503 uint8_t* RESTRICT dst,
const size_t dst_cap) {
504 return zxc_huf_encode_section_default(literals, n_literals, freq, code_len, dst, dst_cap);
508 uint8_t* RESTRICT dst,
const size_t n, uint8_t* RESTRICT scratch) {
509 return zxc_huf_decode_section_default(payload, payload_size, dst, n, scratch);
513 const uint32_t* RESTRICT freq,
const uint8_t* RESTRICT code_len,
515 const uint32_t* RESTRICT codes, uint8_t* RESTRICT dst,
516 const size_t dst_cap) {
517 return zxc_huf_encode_section_dict_default(literals, n_literals, freq, code_len, tree, codes,
522 uint8_t* RESTRICT dst,
const size_t n,
524 return zxc_huf_decode_section_dict_default(payload, payload_size, dst, n, tree, scratch);
529 return zxc_huf_calc_size_dict_default(freq, code_len, tree);
539 zxc_huf_pack_lengths_default(code_len, out);
549 return zxc_huf_unpack_lengths_default(in, code_len);
568 const size_t block_size,
const int checksum_enabled,
569 const uint32_t did,
const int seekable) {
572 if (UNLIKELY(h < 0))
return h;
573 size_t off = (size_t)h;
576 .
block_type = ZXC_BLOCK_EOF, .block_flags = 0, .reserved = 0, .comp_size = 0};
578 if (UNLIKELY(e < 0))
return e;
584 if (UNLIKELY(t < 0))
return t;
589 if (UNLIKELY(f < 0))
return f;
590 return (int64_t)(off + (size_t)f);
603 const uint8_t* RESTRICT blocks,
604 const uint8_t*
const blocks_end,
605 const uint64_t num_blocks,
606 const int checksum_enabled) {
612 if (UNLIKELY(h < 0))
return h;
613 uint8_t* p = dst + h;
617 for (uint64_t i = 0; i < num_blocks; i++) {
622 const size_t left = (size_t)(blocks_end - blocks);
625 const size_t size = (size_t)
zxc_le32(blocks + 3) + trailer;
633 return (int64_t)(p - dst);
643int64_t
zxc_compress(
const void* RESTRICT src,
const size_t src_size,
void* RESTRICT dst,
648 const int seekable = opts ? opts->
seekable : 0;
651 const uint8_t* dict = opts ? (
const uint8_t*)opts->
dict : NULL;
658 const uint32_t did = (dict && dict_size > 0) ?
zxc_dict_id(dict, dict_size, dict_huf) : 0;
660 if (UNLIKELY(src_size == 0))
664 const uint8_t* ip = (
const uint8_t*)src;
665 uint8_t* op = (uint8_t*)dst;
666 const uint8_t* op_start = op;
667 const uint8_t* op_end = op + dst_capacity;
670 const size_t eff_chunk =
673 if (UNLIKELY(
zxc_cctx_init(&ctx, eff_chunk, 1, level, checksum_enabled, dict_size) !=
ZXC_OK))
686 if (dict_input) ZXC_MEMCPY(dict_input, dict, dict_size);
691 if (UNLIKELY(h_val < 0)) {
699 uint32_t* seek_comp = NULL;
700 uint64_t seek_count = 0;
702 const size_t block_count = src_size / block_size;
703 if (UNLIKELY(block_count + 2 > SIZE_MAX /
sizeof(uint32_t))) {
709 seek_comp = (uint32_t*)
ZXC_MALLOC((block_count + 2) *
sizeof(uint32_t));
711 if (UNLIKELY(!seek_comp)) {
720 for (uint64_t bi = 0; pos < src_size; bi++) {
721 const size_t chunk_len = (src_size - pos > block_size) ? block_size : (src_size - pos);
722 const size_t rem_cap = (size_t)(op_end - op);
726 ZXC_MEMCPY(dict_input + dict_size, ip + pos, chunk_len);
732 if (UNLIKELY(res < 0)) {
739 if (seekable) seek_comp[seek_count++] = (uint32_t)res;
750 const size_t rem_cap = (size_t)(op_end - op);
752 .
block_type = ZXC_BLOCK_EOF, .block_flags = 0, .reserved = 0, .comp_size = 0};
755 if (UNLIKELY(eof_val < 0)) {
764 const size_t st_cap = (size_t)(op_end - op);
767 if (UNLIKELY(st_val < 0))
return st_val;
772 op, (
size_t)(op_end - op), (uint64_t)(op - op_start), src_size, digest, checksum_enabled);
773 if (UNLIKELY(footer_val < 0))
return footer_val;
776 return (int64_t)(op - op_start);
780static int64_t zxc_decompress_oneshot(
const uint8_t* src,
size_t src_size, uint8_t* dst,
785 uint8_t* dst,
size_t dst_capacity,
791 uint8_t* dst,
size_t dst_capacity,
807 size_t* footer_len) {
828 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
832 uint8_t probe_dst[1];
833 return zxc_decompress_oneshot(src, src_size, probe_dst, 0, opts);
843int64_t
zxc_decompress(
const void* RESTRICT src,
const size_t src_size,
void* RESTRICT dst,
850 if (UNLIKELY(!dst || dst_capacity == 0))
853 return zxc_decompress_oneshot((
const uint8_t*)src, src_size, (uint8_t*)dst, dst_capacity, opts);
886 const int has_seek,
const size_t footer_len) {
888 const uint64_t per_block =
890 const uint64_t seek_table =
893 seek_table + (uint64_t)footer_len;
894 return (uint64_t)chunk_size + nblocks * per_block + trailing +
920 uint64_t* margin, uint64_t* floor) {
922 size_t footer_len = 0;
927 if (UNLIKELY(rc !=
ZXC_OK))
959 if (UNLIKELY(
zxc_inplace_probe((
const uint8_t*)src, src_size, &dsize, &margin, &floor) !=
962 if (UNLIKELY(margin > (uint64_t)SIZE_MAX || dsize > (uint64_t)SIZE_MAX - margin))
return 0;
963 const uint64_t by_payload = dsize + margin;
965 if (UNLIKELY(floor > (uint64_t)SIZE_MAX - (uint64_t)src_size))
return 0;
966 const uint64_t by_placement = (uint64_t)src_size + floor;
968 return (
size_t)(by_payload > by_placement ? by_payload : by_placement);
986 const uint8_t** comp) {
987 if (UNLIKELY(!buffer || comp_size < ZXC_FRAME_MIN_SIZE || comp_size > buffer_capacity))
989 const uint8_t*
const c = (
const uint8_t*)buffer + (buffer_capacity - comp_size);
994 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
995 if (UNLIKELY(dsize > (uint64_t)buffer_capacity || (uint64_t)buffer_capacity - dsize < margin))
1015 const uint8_t* comp = NULL;
1017 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
1021 buffer_capacity, opts, 1, NULL);
1033 if (UNLIKELY(!src))
return 0;
1050 const uint8_t*
const p = (
const uint8_t*)src;
1063 const size_t info_size) {
1078 const size_t info_size) {
1083 const int rc =
zxc_scan_frame(&scan, src_size, &start, &got, NULL);
1111 size_t last_block_size;
1114 int stored_checksum;
1115 int stored_seekable;
1116 size_t stored_block_size;
1129 int* RESTRICT cached,
const uint8_t* RESTRICT dict_huf) {
1138 }
else if (*cached) {
1147 if (UNLIKELY(!cctx))
return NULL;
1153 cctx->stored_seekable = opts ? opts->
seekable : 0;
1158 zxc_cctx_init(&cctx->inner, cctx->stored_block_size, 1, cctx->stored_level,
1159 cctx->stored_checksum, 0) !=
ZXC_OK)) {
1164 cctx->last_block_size = cctx->stored_block_size;
1165 cctx->initialized = 1;
1179 if (UNLIKELY(!cctx))
return;
1182 if (cctx->owns_workspace)
return;
1196 void* RESTRICT dst,
const size_t dst_capacity,
1199 if (UNLIKELY(!dst || dst_capacity == 0 || (src_size > 0 && !src)))
return ZXC_ERROR_NULL_INPUT;
1201 const int checksum_enabled = opts ? opts->
checksum_enabled : cctx->stored_checksum;
1202 const int seekable = opts ? opts->
seekable : cctx->stored_seekable;
1206 const uint8_t* dict = opts ? (
const uint8_t*)opts->
dict : NULL;
1217 if (UNLIKELY(cctx->owns_workspace && block_size != cctx->last_block_size))
1219 if (UNLIKELY(cctx->owns_workspace && level >=
ZXC_LEVEL_DENSITY && !cctx->inner.opt_scratch))
1222 cctx->stored_level = level;
1223 cctx->stored_block_size = block_size;
1224 cctx->stored_checksum = checksum_enabled;
1225 cctx->stored_seekable = seekable;
1228 const size_t eff_chunk =
1230 const uint32_t did = (dict && dict_size > 0) ?
zxc_dict_id(dict, dict_size, dict_huf) : 0;
1234 if (UNLIKELY(src_size == 0))
1240 if (UNLIKELY(!cctx->initialized || cctx->last_block_size != eff_chunk ||
1242 (dict_size > 0 && !cctx->inner.dict_buffer))) {
1243 if (cctx->initialized) {
1245 cctx->initialized = 0;
1248 if (UNLIKELY(
zxc_cctx_init(&cctx->inner, eff_chunk, 1, level, checksum_enabled,
1252 cctx->last_block_size = eff_chunk;
1253 cctx->initialized = 1;
1254 cctx->huf_cached = 0;
1257 cctx->inner.compression_level = level;
1258 cctx->inner.checksum_enabled = checksum_enabled;
1268 uint8_t*
const dict_input = dict_size > 0 ? ctx->
dict_buffer : NULL;
1269 if (dict_input) ZXC_MEMCPY(dict_input, dict, dict_size);
1271 uint8_t* op = (uint8_t*)dst;
1272 const uint8_t*
const op_start = op;
1273 const uint8_t*
const op_end = op + dst_capacity;
1274 const uint8_t*
const ip = (
const uint8_t*)src;
1278 if (UNLIKELY(h_val < 0))
return h_val;
1281 uint64_t digest = 0;
1284 for (; pos < src_size; bi++) {
1285 const size_t chunk_len = (src_size - pos > block_size) ? block_size : (src_size - pos);
1286 const size_t rem_cap = (size_t)(op_end - op);
1290 ZXC_MEMCPY(dict_input + dict_size, ip + pos, chunk_len);
1296 if (UNLIKELY(res < 0))
return res;
1305 uint8_t*
const eof_at = op;
1306 const size_t rem_cap = (size_t)(op_end - op);
1308 .
block_type = ZXC_BLOCK_EOF, .block_flags = 0, .reserved = 0, .comp_size = 0};
1310 if (UNLIKELY(eof_val < 0))
return eof_val;
1316 op, (
size_t)(op_end - op), op_start + h_val, eof_at, bi, checksum_enabled);
1317 if (UNLIKELY(st_val < 0))
return st_val;
1322 op, (
size_t)(op_end - op), (uint64_t)(op - op_start), src_size, digest, checksum_enabled);
1323 if (UNLIKELY(footer_val < 0))
return footer_val;
1326 return (int64_t)(op - op_start);
1339 size_t last_block_size;
1340 size_t last_dict_size;
1361 if (UNLIKELY(!dctx))
return;
1364 if (dctx->owns_workspace)
return;
1384 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
1385 if (UNLIKELY(dctx->owns_workspace && (info.
uses_dict || dict_size != 0)))
1398 void* RESTRICT dst,
const size_t dst_capacity,
1404 if (UNLIKELY(!dst || dst_capacity == 0))
return zxc_dctx_probe(dctx, src, src_size, opts);
1406 dst_capacity, opts);
1420 const uint8_t* comp = NULL;
1422 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
1435 const int checksum,
const uint8_t* dict_huf) {
1436 if (UNLIKELY(!dctx->initialized || dctx->last_block_size != chunk_size ||
1437 dctx->last_dict_size != dict_size)) {
1438 if (dctx->initialized) {
1440 dctx->initialized = 0;
1443 if (UNLIKELY(
zxc_cctx_init(&dctx->inner, chunk_size, 0, 0, checksum, dict_size) !=
ZXC_OK))
1446 dctx->last_block_size = chunk_size;
1447 dctx->last_dict_size = dict_size;
1448 dctx->initialized = 1;
1449 dctx->huf_cached = 0;
1451 dctx->inner.checksum_enabled = checksum;
1469 uint8_t* dst,
const size_t dst_capacity,
1471 size_t* frame_end) {
1473 const uint8_t* dict = opts ? (
const uint8_t*)opts->
dict : NULL;
1477 const uint8_t* ip = (
const uint8_t*)src;
1478 const uint8_t*
const ip_end = ip + src_size;
1479 uint8_t* op = (uint8_t*)dst;
1480 const uint8_t*
const op_start = op;
1481 const uint8_t*
const op_end = op + dst_capacity;
1482 size_t runtime_chunk_size = 0;
1483 int file_has_checksums = 0;
1484 int file_has_seek = 0;
1485 uint32_t header_dict_id = 0;
1488 &header_dict_id, &file_has_seek);
1489 if (UNLIKELY(hrc !=
ZXC_OK))
return hrc;
1493 if (UNLIKELY(dctx->owns_workspace && runtime_chunk_size != dctx->last_block_size))
1496 if (UNLIKELY(dctx->owns_workspace && (header_dict_id != 0 || dict_size != 0)))
1500 if (header_dict_id != 0) {
1502 if (UNLIKELY(
zxc_dict_id(dict, dict_size, dict_huf) != header_dict_id))
1516 uint8_t* dict_dec = NULL;
1518 uint64_t block_index = 0;
1519 uint64_t digest = 0;
1523 const size_t rem_src = (size_t)(ip_end - ip);
1528 if (UNLIKELY(bh.
block_type == ZXC_BLOCK_EOF)) {
1533 const uint64_t total_out = (uint64_t)(op - op_start);
1535 if (file_has_seek) {
1536 uint64_t sek_bytes = 0;
1538 runtime_chunk_size, &sek_bytes);
1539 if (UNLIKELY(src_rc !=
ZXC_OK))
return src_rc;
1541 if (UNLIKELY(sek_bytes > (uint64_t)(src_size - pos)))
1543 pos += (size_t)sek_bytes;
1546 uint64_t stored_digest = 0;
1549 if (UNLIKELY(frc !=
ZXC_OK))
return frc;
1550 if (checksum_enabled && file_has_checksums && UNLIKELY(stored_digest != digest))
1556 else if (UNLIKELY(pos != src_size))
1567 if (UNLIKELY(!ctx_ready)) {
1568 const int crc =
zxc_dctx_carve(dctx, runtime_chunk_size, dict_size,
1569 file_has_checksums && checksum_enabled, dict_huf);
1570 if (UNLIKELY(crc !=
ZXC_OK))
return crc;
1572 if (dict_dec) ZXC_MEMCPY(dict_dec, dict, dict_size);
1579 const size_t rem_cap = (size_t)(op_end - op);
1580 size_t room = rem_cap;
1582 const size_t ahead = ip > op ? (size_t)(ip - op) : 0;
1583 if (ahead < room) room = ahead;
1586 const uint8_t* bounce = NULL;
1591 bounce = dict_dec + dict_size;
1592 }
else if (LIKELY(room >= work_sz)) {
1599 if (bounce && LIKELY(res > 0)) {
1602 if (UNLIKELY((
size_t)res > room))
1604 ZXC_MEMCPY(op, bounce, (
size_t)res);
1606 if (UNLIKELY(res < 0))
return res;
1608 if (checksum_enabled && file_has_checksums)
1617 return (int64_t)(op - op_start);
1622 uint8_t* dst,
const size_t dst_capacity,
1629 size_t frame_size = 0;
1631 dst_capacity - out, opts, 0, &frame_size);
1632 if (UNLIKELY(res < 0))
return res;
1636 if (UNLIKELY(rc < 0))
return rc;
1638 return (int64_t)out;
1642static int64_t zxc_decompress_oneshot(
const uint8_t* src,
const size_t src_size, uint8_t* dst,
1643 const size_t dst_capacity,
1646 ZXC_MEMSET(&dctx, 0,
sizeof(dctx));
1669 void* RESTRICT dst,
const size_t dst_capacity,
1675 void* RESTRICT dst,
const size_t dst_capacity,
1677 if (UNLIKELY(!cctx || !src || !dst || src_size == 0 || dst_capacity == 0))
1685 const int checksum_enabled = opts ? opts->
checksum_enabled : cctx->stored_checksum;
1693 const uint8_t* b_dict = opts ? (
const uint8_t*)opts->
dict : NULL;
1696 const size_t base_block_size = (block_size > min_bs) ? block_size : min_bs;
1697 const size_t effective_block_size =
1706 if (UNLIKELY(cctx->owns_workspace && effective_block_size != cctx->last_block_size))
1708 if (UNLIKELY(cctx->owns_workspace && level >=
ZXC_LEVEL_DENSITY && !cctx->inner.opt_scratch))
1711 cctx->stored_level = level;
1712 cctx->stored_block_size = base_block_size;
1713 cctx->stored_checksum = checksum_enabled;
1718 if (UNLIKELY(!cctx->initialized || cctx->last_block_size != effective_block_size ||
1720 (b_dict_size > 0 && !cctx->inner.dict_buffer))) {
1721 if (cctx->initialized) {
1724 cctx->initialized = 0;
1728 if (UNLIKELY(
zxc_cctx_init(&cctx->inner, effective_block_size, 1, level, checksum_enabled,
1732 cctx->last_block_size = effective_block_size;
1733 cctx->initialized = 1;
1734 cctx->huf_cached = 0;
1736 cctx->inner.compression_level = level;
1737 cctx->inner.checksum_enabled = checksum_enabled;
1740 cctx->inner.dict_size = b_dict_size;
1746 if (b_dict && b_dict_size > 0) {
1748 uint8_t*
const combined = cctx->inner.dict_buffer;
1749 ZXC_MEMCPY(combined, b_dict, b_dict_size);
1750 ZXC_MEMCPY(combined + b_dict_size, src, src_size);
1752 (uint8_t*)dst, dst_capacity, block_index);
1755 dst_capacity, block_index);
1757 if (UNLIKELY(res < 0))
return res;
1758 return (int64_t)res;
1767 const size_t src_size, uint8_t* RESTRICT dst,
1768 const size_t dst_capacity,
const size_t carved) {
1772 if (UNLIKELY(res < 0))
return res;
1775 ZXC_MEMCPY(dst, ctx->work_buf, (
size_t)res);
1787 const size_t src_size, uint8_t* RESTRICT dst,
1788 const size_t dst_capacity,
const size_t dict_size,
1789 const int checksum_enabled,
const int strict) {
1792 const size_t carved = dctx->last_block_size;
1799 const size_t cap = dst_capacity < work_sz ? dst_capacity : work_sz;
1801 }
else if (dst_capacity >= work_sz) {
1816 const size_t dict_size,
const int checksum_enabled) {
1817 if (LIKELY(dctx->initialized && dctx->last_block_size == block_size &&
1818 dctx->last_dict_size == dict_size)) {
1819 dctx->inner.checksum_enabled = checksum_enabled;
1822 if (dctx->initialized) {
1824 dctx->initialized = 0;
1827 if (UNLIKELY(
zxc_cctx_init(&dctx->inner, block_size, 0, 0, checksum_enabled, dict_size) !=
1831 dctx->last_block_size = block_size;
1832 dctx->last_dict_size = dict_size;
1833 dctx->initialized = 1;
1834 dctx->huf_cached = 0;
1849 void* RESTRICT dst,
const size_t dst_capacity,
1862 const uint8_t* dict = opts ? (
const uint8_t*)opts->
dict : NULL;
1865 if (UNLIKELY(dctx->owns_workspace))
1867 dst_capacity, dict_size, checksum_enabled, 0);
1871 const int rc =
zxc_dctx_prepare(dctx, block_size, dict_size, checksum_enabled);
1872 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
1884 if (dict && dict_size > 0) {
1887 ZXC_MEMCPY(dec_buf, dict, dict_size);
1890 if (LIKELY(res > 0)) {
1892 ZXC_MEMCPY(dst, dec_buf + dict_size, (
size_t)res);
1903 if (UNLIKELY(res < 0))
return res;
1904 return (int64_t)res;
1917 void* RESTRICT dst,
const size_t dst_capacity,
1924 if (UNLIKELY(dctx->owns_workspace))
1934 const uint8_t type = ((
const uint8_t*)src)[0];
1936 if (type == ZXC_BLOCK_RAW) {
1943 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
1944 dctx->inner.dict_size = 0;
1947 &dctx->inner, (
const uint8_t*)src, src_size, (uint8_t*)dst, dst_capacity, 0);
1948 if (UNLIKELY(res < 0))
return res;
1949 return (int64_t)res;
1963#define ZXC_STATIC_CCTX_HDR_SIZE ZXC_ALIGN_CL(sizeof(struct zxc_cctx_s))
1964#define ZXC_STATIC_DCTX_HDR_SIZE ZXC_ALIGN_CL(sizeof(struct zxc_dctx_s))
1975 if (UNLIKELY(level < ZXC_LEVEL_FASTEST || level >
ZXC_LEVEL_ULTRA))
return 0;
1977 if (UNLIKELY(inner_sz == 0))
return 0;
1978 return ZXC_STATIC_CCTX_HDR_SIZE + inner_sz;
1983 if (UNLIKELY(!workspace || !opts))
return NULL;
1987 const int checksum_enabled = opts->checksum_enabled;
1990 if (UNLIKELY(level < ZXC_LEVEL_FASTEST || level >
ZXC_LEVEL_ULTRA))
return NULL;
1993 if (UNLIKELY(inner_sz == 0))
return NULL;
1994 if (UNLIKELY(workspace_size < ZXC_STATIC_CCTX_HDR_SIZE + inner_sz))
return NULL;
1997 ZXC_MEMSET(cctx, 0,
sizeof(*cctx));
1999 uint8_t*
const inner_ws = (uint8_t*)workspace + ZXC_STATIC_CCTX_HDR_SIZE;
2001 checksum_enabled, 0, 0) !=
ZXC_OK))
2004 cctx->owns_workspace = 1;
2005 cctx->initialized = 1;
2006 cctx->last_block_size = block_size;
2007 cctx->stored_level = level;
2008 cctx->stored_block_size = block_size;
2009 cctx->stored_checksum = checksum_enabled;
2010 cctx->stored_seekable = opts->seekable;
2024 if (UNLIKELY(inner_sz == 0))
return 0;
2025 return ZXC_STATIC_DCTX_HDR_SIZE + inner_sz;
2029 const size_t block_size) {
2030 if (UNLIKELY(!workspace))
return NULL;
2034 if (UNLIKELY(inner_sz == 0))
return NULL;
2035 if (UNLIKELY(workspace_size < ZXC_STATIC_DCTX_HDR_SIZE + inner_sz))
return NULL;
2038 ZXC_MEMSET(dctx, 0,
sizeof(*dctx));
2040 uint8_t*
const inner_ws = (uint8_t*)workspace + ZXC_STATIC_DCTX_HDR_SIZE;
2047 dctx->owns_workspace = 1;
2048 dctx->initialized = 1;
2049 dctx->last_block_size = block_size;
struct zxc_cctx_s zxc_cctx
Opaque reusable compression context (see zxc_create_cctx).
int64_t zxc_compress_block(zxc_cctx *cctx, const void *src, const size_t src_size, void *dst, const size_t dst_capacity, const zxc_compress_opts_t *opts)
Compresses a single block (no file framing), reusing cctx.
struct zxc_dctx_s zxc_dctx
Opaque reusable decompression context (see zxc_create_dctx).
int64_t zxc_decompress_block_safe(zxc_dctx *dctx, const void *src, const size_t src_size, void *dst, const size_t dst_capacity, const zxc_decompress_opts_t *opts)
Safe-variant block decompressor: accepts dst_capacity == uncompressed_size.
int64_t zxc_decompress_block(zxc_dctx *dctx, const void *src, const size_t src_size, void *dst, const size_t dst_capacity, const zxc_decompress_opts_t *opts)
Decompresses a single block (no file framing), reusing dctx.
#define ZXC_BLOCK_SIZE_MAX
Maximum allowed block size (2 MB = 2^21).
#define ZXC_BLOCK_SIZE_DEFAULT
Default block size (512 KB).
int64_t zxc_decompress(const void *src, const size_t src_size, void *dst, const size_t dst_capacity, const zxc_decompress_opts_t *opts)
Decompresses an entire buffer in one call.
int zxc_get_frame_info(const void *src, const size_t src_size, zxc_frame_info_t *info, const size_t info_size)
Reads a frame's header and footer, without decoding.
uint64_t zxc_get_decompressed_size(const void *src, const size_t src_size)
Reads the decompressed size from a ZXC-compressed buffer.
int64_t zxc_compress(const void *src, const size_t src_size, void *dst, const size_t dst_capacity, const zxc_compress_opts_t *opts)
Compresses an entire buffer in one call.
int64_t zxc_decompress_inplace(void *buffer, const size_t buffer_capacity, const size_t comp_size, const zxc_decompress_opts_t *opts)
Decompresses in place, inside a single caller-owned buffer.
size_t zxc_decompress_inplace_bound(const void *src, const size_t src_size)
Minimum single-buffer size for a safe in-place decode of src.
uint32_t zxc_get_dict_id(const void *src, const size_t src_size)
Reads the dictionary id from a compressed archive's file header.
int zxc_get_last_frame_info(const void *src, const size_t src_size, zxc_frame_info_t *info, const size_t info_size)
Reads the frame that ends src, without decoding.
zxc_cctx * zxc_create_cctx(const zxc_compress_opts_t *opts)
Creates a reusable compression context.
int64_t zxc_compress_cctx(zxc_cctx *cctx, const void *src, const size_t src_size, void *dst, const size_t dst_capacity, const zxc_compress_opts_t *opts)
Compresses data using a reusable context.
void zxc_free_cctx(zxc_cctx *cctx)
Releases a reusable compression context.
zxc_dctx * zxc_create_dctx(void)
Creates a reusable decompression context.
int64_t zxc_decompress_dctx(zxc_dctx *dctx, const void *src, const size_t src_size, void *dst, const size_t dst_capacity, const zxc_decompress_opts_t *opts)
Decompresses a framed archive into dst, reusing dctx.
int64_t zxc_decompress_inplace_dctx(zxc_dctx *dctx, void *buffer, const size_t buffer_capacity, const size_t comp_size, const zxc_decompress_opts_t *opts)
Decompresses in place inside one caller buffer, reusing dctx.
void zxc_free_dctx(zxc_dctx *dctx)
Releases a reusable decompression context.
uint32_t zxc_dict_id(const void *dict, size_t dict_size, const void *huf_lengths)
Computes the dictionary ID for the given content and optional table.
#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_BAD_MAGIC
Invalid magic word in file header.
@ ZXC_ERROR_OVERFLOW
Buffer overflow detected during processing.
@ ZXC_ERROR_CORRUPT_DATA
Corrupted compressed data.
@ ZXC_ERROR_NULL_INPUT
Required input pointer is NULL.
@ ZXC_ERROR_DICT_MISMATCH
Provided dictionary ID does not match the file header.
@ ZXC_ERROR_MEMORY
Memory allocation failure.
@ ZXC_ERROR_BAD_HEADER
Corrupted or invalid header (checksum mismatch).
@ ZXC_ERROR_DST_TOO_SMALL
Destination buffer too small.
@ ZXC_ERROR_SRC_TOO_SMALL
Source buffer too small or truncated input.
@ ZXC_ERROR_DICT_REQUIRED
File requires a dictionary but none was provided.
@ ZXC_ERROR_DICT_UNSUPPORTED
Dictionary not supported by this context's workspace.
@ ZXC_ERROR_BAD_CHECKSUM
A block's decoded bytes fail its checksum, or the archive digest mismatches.
@ ZXC_ERROR_BAD_LEVEL
Compression level not supported by this context's workspace.
@ ZXC_OK
Success (no error).
@ ZXC_ERROR_BAD_BLOCK_SIZE
Invalid block size.
@ ZXC_ERROR_DICT_TOO_LARGE
Dictionary exceeds maximum allowed size.
#define ZXC_MALLOC(size)
Heap allocator.
#define ZXC_SEEK_GROUP
Blocks per group.
#define ZXC_ALWAYS_INLINE
Forces a function to be inlined (fallback for non-GCC/Clang/MSVC compilers).
static uint64_t zxc_seek_table_bytes(const uint64_t nblocks)
Byte size of the groups for nblocks blocks, in 64 bits.
#define ZXC_SEEK_SIZE_ENTRY
One block's on-disk size, u32.
#define ZXC_CALLOC(nmemb, size)
Zero-initialised heap allocator.
#define ZXC_FREE(ptr)
Heap deallocator.
#define ZXC_FILE_FLAG_HAS_DICTIONARY
Bit flag in the Flags byte indicating a dictionary is required (bit 6).
#define ZXC_BLOCK_HEADER_SIZE
Block header size: Type(1)+Flags(1)+Reserved(1)+Checksum(1)+CompSize(4).
#define ZXC_NOINLINE
Prevents inlining (best-effort no-op fallback for unknown compilers).
#define ZXC_BLOCK_CHECKSUM_SIZE
Size of the per-block checksum field in bytes.
#define ZXC_SEEK_ANCHOR_SIZE
Group anchor: offset of its first block, u64.
#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_DEFAULT
Recommended default: better ratio and decode speed than LZ4.
@ ZXC_LEVEL_DENSITY
Higher density: adds Huffman-coded literals on top of COMPACT.
int64_t zxc_write_seek_table(uint8_t *dst, const size_t dst_capacity, const uint32_t *comp_sizes, const uint64_t num_blocks)
Writes a seek table to the destination buffer.
size_t zxc_seek_table_size(const uint64_t num_blocks)
Returns the encoded size of a seek table for the given block count.
size_t zxc_static_dctx_workspace_size(const size_t block_size)
Workspace size needed for a static decompression context.
size_t zxc_static_cctx_workspace_size(const size_t block_size, const int level)
Workspace size needed for a static compression context.
zxc_dctx * zxc_init_static_dctx(void *workspace, const size_t workspace_size, const size_t block_size)
Initialises a decompression context inside a caller-supplied workspace.
zxc_cctx * zxc_init_static_cctx(void *workspace, const size_t workspace_size, const zxc_compress_opts_t *opts)
Initialises a compression context inside a caller-supplied workspace.
Compression / decompression context.
size_t work_buf_cap
Capacity of the work buffer.
uint8_t * work_buf
Padded scratch buffer for buffer-API decompression.
uint8_t * dict_buffer
[dict | data] concat scratch carved from memory_block when dict_size > 0 (NULL otherwise).
size_t dict_size
Dictionary prefill size (0 = no dictionary).
int checksum_enabled
1 if checksum calculation/verification is enabled.
int seekable
1 to append a seek table for random-access decompression.
const void * dict
Pre-trained dictionary content (NULL = none).
int checksum_enabled
1 to append the block checksums and archive digest, 0 to disable.
What zxc_scan_container learns about a container.
int uses_dict
A frame bound to a dictionary.
uint64_t dsize
Sum of the stored decompressed sizes.
Options for decompression.
int checksum_enabled
1 to verify the block checksums and archive digest, 0 to skip.
size_t dict_size
Dictionary size in bytes (0 = none).
const void * dict
Pre-trained dictionary content (NULL = none).
What a frame's header and footer declare, read without decoding.
uint8_t has_checksum
1 when blocks carry checksums and the footer a digest.
size_t block_size
Block size, 4 KB to 2 MB.
uint64_t decompressed_size
Source bytes the frame decodes to.
uint8_t has_seek_table
1 when a seek table precedes the footer.
A PivCo code tree: its canonical shape, by depth.
Where a container scan reads from: memory, or a positioned callback (the FILE* size query).
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)
Serialises a ZXC file header into dst.
int zxc_read_block_header(const uint8_t *src, const size_t src_size, zxc_block_header_t *bh)
Parses and validates a block header from src.
void zxc_cctx_free(zxc_cctx_t *ctx)
Releases all resources owned by a compression context.
int zxc_write_block_header(uint8_t *dst, const size_t dst_capacity, const zxc_block_header_t *bh)
Serialises a block header (8 bytes) into dst.
int zxc_scan_container(const zxc_scan_src_t *src, const 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_...
int zxc_seek_table_header(uint8_t *dst, const size_t dst_capacity, const uint64_t num_blocks)
Writes a seek table's block header for num_blocks entries.
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)
Partitions a caller-supplied workspace into a ready-to-use context.
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)
Parses and validates a ZXC file header from src.
int zxc_scan_frame(const zxc_scan_src_t *src, const 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...
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.
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 workspace byte count required for the given parameters.
int zxc_container_next(const zxc_scan_src_t *src, const uint64_t pos)
Tells whether a frame starts at pos.
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,...
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 compression / decompression context, allocating the persistent buffer with ZXC_ALIGNED_...
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 file footer: the archive digest when checksum_enabled, then the two sizes and their length...
int zxc_cctx_attach_dict_huf(zxc_cctx_t *ctx, const uint8_t *lengths)
Attach the shared dictionary literal Huffman table to a context.
int zxc_check_file_footer(const uint8_t *footer, const size_t avail, const zxc_footer_layout_t *l, const uint64_t src_size, uint64_t *digest)
Checks a footer against the one the frame implies.
int zxc_check_seek_header(const uint8_t *hdr, const size_t avail, const uint64_t total_out, const size_t block_size, uint64_t *sek_bytes)
Checks the SEK block header the file header announced, on the avail bytes present.
static _Atomic zxc_decompress_func_t zxc_decompress_safe_ptr
The _safe decoder in use, NULL until the first call.
static int64_t zxc_static_decompress_block(zxc_dctx *dctx, const uint8_t *src, const size_t src_size, uint8_t *dst, const size_t dst_capacity, const size_t dict_size, const int checksum_enabled, const int strict)
Block decode on a static dctx: the carved block is the effective capacity.
#define ZXC_VARIANT_SET(sfx)
Defines the constant variant set of suffix sfx.
static int zxc_ctx_sync_dict_huf(zxc_cctx_t *inner, uint8_t *cache, int *cached, const uint8_t *dict_huf)
Attaches the shared literal table to inner; NULL detaches.
static int zxc_decompress_chunk_wrapper_safe_public(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)
Internal safe-decompression dispatcher (strict dst_capacity == uncompressed_size).
static int64_t zxc_write_seek_table_from_blocks(uint8_t *dst, const size_t dst_capacity, const uint8_t *blocks, const uint8_t *const blocks_end, const uint64_t num_blocks, const int checksum_enabled)
Writes the seek table of the num_blocks blocks in [blocks, blocks_end), sizes read back from their he...
static const zxc_variant_set_t * zxc_select_variants(void)
Detects the CPU tier and returns the matching variant set.
int(* zxc_decompress_func_t)(const zxc_cctx_t *, const uint8_t *, const size_t, uint8_t *, const size_t, const uint64_t)
Function pointer type for the chunk decompressor.
size_t zxc_huf_calc_size(const uint32_t *freq, const uint8_t *code_len, const int with_header)
Un-suffixed forwarders for the PivCo section codec (tests, tools).
zxc_cpu_feature_t
Detected CPU SIMD capability level.
@ ZXC_CPU_GENERIC
Scalar-only fallback.
@ ZXC_CPU_SSE2
x86 SSE2 available (no AVX2); x86-64 baseline, served by _default (no dedicated variant).
@ ZXC_CPU_AVX512
x86-64 AVX-512F+BW available.
@ ZXC_CPU_AVX2
x86-64 AVX2 available.
@ ZXC_CPU_NEON
ARM NEON available (dedicated variant on 32-bit ARM only; AArch64 baseline, served by _default there)...
static int64_t zxc_dctx_probe(const zxc_dctx *dctx, const uint8_t *src, const size_t src_size, const zxc_decompress_opts_t *opts)
Answers a no-destination decode on a reusable context.
static uint64_t zxc_inplace_margin(const uint64_t dsize, const size_t chunk_size, const int has_cs, const int has_seek, const size_t footer_len)
Bytes an in-place decode needs on top of the decompressed size.
static int zxc_inplace_prepare(const void *buffer, const size_t buffer_capacity, const size_t comp_size, const zxc_decompress_opts_t *opts, const uint8_t **comp)
Argument and buffer checks shared by the in-place entry points.
int(* zxc_compress_func_t)(zxc_cctx_t *, const uint8_t *, const size_t, uint8_t *, const size_t, const uint64_t)
Function pointer type for the chunk compressor.
static int64_t zxc_decode_bounce(zxc_cctx_t *ctx, const uint8_t *src, const size_t src_size, uint8_t *dst, const size_t dst_capacity, const size_t carved)
Block decode through work_buf, for a dst too tight for the speculative writes, then copied out.
static int64_t zxc_dctx_decode_frame(zxc_dctx *dctx, const uint8_t *src, size_t src_size, uint8_t *dst, size_t dst_capacity, const zxc_decompress_opts_t *opts, int inplace, size_t *frame_end)
The frame walk behind every buffer decode: zxc_decompress(), its no-destination probe,...
int zxc_huf_decode_section_dict(const uint8_t *payload, const size_t payload_size, uint8_t *dst, const size_t n, const zxc_pivco_tree_t *tree, uint8_t *scratch)
Decode a PivCo dict section against a prebuilt dict tree.
static int64_t zxc_write_empty_frame(uint8_t *dst, const size_t dst_capacity, const size_t block_size, const int checksum_enabled, const uint32_t did, const int seekable)
Writes the whole archive an empty source produces: file header, EOF block, the empty seek table when ...
int zxc_huf_build_code_lengths(const uint32_t *freq, uint8_t *code_len, void *scratch, const int max_code_len)
Build length-limited per-symbol Huffman code lengths from frequencies.
static const zxc_variant_set_t * zxc_variants(void)
The variant set in use, selected on the first call.
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 const zxc_variant_set_t * zxc_variants_resolve(void)
First call: selects and publishes.
int zxc_huf_encode_section_dict(const uint8_t *literals, const 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, const size_t dst_cap)
Encode a PivCo section against a prebuilt dict tree/codes (no header).
int64_t zxc_compress_block_at(zxc_cctx *cctx, const void *src, const size_t src_size, void *dst, const size_t dst_capacity, const zxc_compress_opts_t *opts, const uint64_t block_index)
zxc_compress_block, its checksum seeded with block_index (public entry: 0).
static int64_t zxc_dctx_decode_container(zxc_dctx *dctx, const uint8_t *src, size_t src_size, uint8_t *dst, size_t dst_capacity, const zxc_decompress_opts_t *opts)
The container walk behind zxc_decompress() and zxc_decompress_dctx().
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)
Public compression dispatcher.
static int zxc_inplace_probe(const uint8_t *comp, const size_t comp_size, uint64_t *dsize, uint64_t *margin, uint64_t *floor)
Shared archive probe for the in-place entry points: validates the magic + file header,...
static zxc_cpu_feature_t zxc_detect_cpu_features(void)
Probes the running CPU for SIMD support.
static int zxc_buffer_frame_info(const uint8_t *src, const size_t src_size, zxc_frame_info_t *info, size_t *footer_len)
Validates a frame without decoding it: the check of zxc_read_frame_info() on a whole buffer,...
static int64_t zxc_probe_without_dst(const uint8_t *src, const size_t src_size, const zxc_decompress_opts_t *opts, const zxc_container_info_t *scanned)
Answers a decode request that carries no destination.
static const zxc_variant_set_t *_Atomic zxc_variants_ptr
The selection, NULL until the first call.
static zxc_decompress_func_t zxc_decompress_safe_variant(void)
The _safe decoder in use, selected on the first call.
static int zxc_dctx_prepare(zxc_dctx *dctx, const size_t block_size, const size_t dict_size, const int checksum_enabled)
Recarves a heap dctx when block_size or dict_size changed; otherwise only refreshes the checksum flag...
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)
Public decompression dispatcher.
static int zxc_dctx_carve(zxc_dctx *dctx, const size_t chunk_size, const size_t dict_size, const int checksum, const uint8_t *dict_huf)
Readies dctx for a frame: re-carves the inner buffers when the block or dictionary size changed (the ...
int zxc_huf_decode_section(const uint8_t *payload, const size_t payload_size, uint8_t *dst, const size_t n, uint8_t *scratch)
Decode a PivCo literal section into dst (exactly n bytes).
void zxc_huf_pack_lengths(const uint8_t *code_len, uint8_t *out)
Pack per-symbol code lengths into the 128-byte nibble header.
int zxc_huf_encode_section(const uint8_t *literals, const size_t n_literals, const uint32_t *freq, const uint8_t *code_len, uint8_t *dst, const size_t dst_cap)
Encode a PivCo literal section (128-byte lengths header + payload).
int zxc_huf_unpack_lengths(const uint8_t *in, uint8_t *code_len)
Unpack and validate a 128-byte packed lengths header.
static zxc_decompress_func_t zxc_decompress_safe_resolve(void)
First call: the _safe decoder of the selected set, published.
Internal definitions, constants, SIMD helpers, and utility functions.
static uint32_t zxc_le32(const void *p)
Reads a little-endian 32-bit value from a possibly unaligned address.
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.
static void zxc_store_le64(void *p, const uint64_t v)
Writes a 64-bit value little-endian to a possibly unaligned address.
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.
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.
#define ZXC_OPTS_DICT_HUF(o)
Shared literal Huffman table, gated on dict the same way.
#define ZXC_FRAME_MIN_SIZE
Smallest frame: header, the EOF block and the shortest footer.
#define ZXC_OPTS_LEVEL(o, dflt)
Compression level, 0 meaning the default, clamped to the highest level the encoder implements.
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 void zxc_store_le32(void *p, const uint32_t v)
Writes a 32-bit value little-endian to a possibly unaligned address.
#define ZXC_OPTS_DICT_SIZE(o)
Dictionary length from a (possibly NULL) options struct.
#define ZXC_OPTS_BLOCK_SIZE(o, dflt)
Block size, 0 meaning the default.
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 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.