17#include "../../include/zxc_buffer.h"
18#include "../../include/zxc_error.h"
64 size_t off_pivco_dctx;
71 size_t off_split_hist;
106 size_t* RESTRICT sz_pivco) {
141 const int level,
const size_t dict_size,
142 const int defer_entropy_scratch) {
143 zxc_cctx_layout_t layout = {0};
154 layout.off_work = layout.total;
156 layout.off_lit_dctx = layout.total;
163 if (!defer_entropy_scratch) {
167 layout.sz_tok_dctx = sz_tok;
168 layout.off_tok_dctx = layout.total;
170 layout.sz_pivco_dctx = sz_pivco;
171 layout.off_pivco_dctx = layout.total;
176 const uint32_t offset_bits =
zxc_log2_u32((uint32_t)chunk_size);
177 layout.max_seq = max_seq;
183 const size_t sz_seq_union = layout.max_seq *
sizeof(uint32_t);
184 const size_t vbyte_len = (offset_bits + 6) / 7;
185 const size_t sz_extras = layout.max_seq * 2 * vbyte_len;
198 const size_t dp_needed = sz_dp + sz_pl + sz_po + sz_bm;
203 layout.off_hash_pos = layout.total;
205 layout.off_hash_tags = layout.total;
207 layout.off_chain = layout.total;
209 layout.off_seq_union = layout.total;
211 layout.off_split_hist = layout.total;
213 layout.off_extras = layout.total;
215 layout.off_lit_cctx = layout.total;
220 layout.off_opt = layout.total;
230 layout.off_dict = layout.total;
232 layout.off_dict_huf = layout.total;
246 const size_t dict_size) {
247 if (UNLIKELY(chunk_size == 0))
return 0;
261 const size_t workspace_size,
const size_t chunk_size,
const int mode,
262 const int level,
const int checksum_enabled,
const size_t dict_size,
263 const int defer_entropy_scratch) {
266 const zxc_cctx_layout_t layout =
271 ctx->checksum_enabled = checksum_enabled;
272 ctx->chunk_size = chunk_size;
273 const uint32_t offset_bits =
zxc_log2_u32((uint32_t)chunk_size);
274 ctx->offset_bits = offset_bits;
275 ctx->offset_mask = (uint32_t)((1ULL << offset_bits) - 1);
276 ctx->max_epoch = (uint32_t)(1ULL << (32 - offset_bits));
281 uint8_t*
const mem = (uint8_t*)workspace;
285 ctx->dict_size = dict_size;
287 ctx->dict_buffer = mem + layout.off_dict;
288 ctx->dict_buffer_cap = layout.sz_dict;
293 ctx->work_buf = mem + layout.off_work;
295 ctx->lit_buffer = mem + layout.off_lit_dctx;
297 if (layout.sz_pivco_dctx) {
298 ctx->tok_buffer = mem + layout.off_tok_dctx;
299 ctx->tok_buffer_cap = layout.sz_tok_dctx;
300 ctx->pivco_scratch = mem + layout.off_pivco_dctx;
301 ctx->pivco_scratch_cap = layout.sz_pivco_dctx;
306 ctx->hash_table = (uint32_t*)(mem + layout.off_hash_pos);
307 ctx->hash_tags = mem + layout.off_hash_tags;
308 ctx->chain_table = (uint16_t*)(mem + layout.off_chain);
309 ctx->buf_sequences = (uint32_t*)(mem + layout.off_seq_union);
310 ctx->buf_offsets = (uint16_t*)(mem + layout.off_seq_union);
311 ctx->buf_tokens = mem + layout.off_seq_union + layout.max_seq *
sizeof(uint16_t);
312 ctx->buf_split = ctx->buf_tokens + layout.max_seq;
314 ctx->buf_extras = mem + layout.off_extras;
315 ctx->literals = mem + layout.off_lit_cctx;
317 ctx->opt_scratch = mem + layout.off_opt;
318 ctx->opt_scratch_cap = layout.sz_opt;
321 ctx->compression_level = level;
324 ZXC_MEMSET(ctx->hash_table, 0, layout.sz_hash_pos);
325 ZXC_MEMSET(ctx->hash_tags, 0, layout.sz_hash_tags);
340 const int level,
const int checksum_enabled,
const size_t dict_size) {
344 const int defer_entropy = (mode == 0);
353 checksum_enabled, dict_size, defer_entropy);
354 if (UNLIKELY(rc !=
ZXC_OK)) {
361 ctx->memory_block = mem;
455 ctx->dict_huf_tree_ok = 0;
456 if (!lengths)
return ZXC_OK;
466 if (UNLIKELY(empty || !ctx->dict_huf))
return ZXC_OK;
470 ctx->dict_huf->code_len);
471 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
472 ctx->dict_huf_tree_ok = 1;
487 const int has_checksum,
const uint32_t dict_id,
const int has_seek) {
502 ZXC_MEMSET(dst + 7, 0, 7);
517 size_t* RESTRICT out_block_size,
int* RESTRICT out_has_checksum,
518 uint32_t* RESTRICT out_dict_id,
int* RESTRICT out_has_seek) {
534 if (out_block_size) {
535 const uint8_t code = src[5];
539 *out_block_size = (size_t)1U << code;
551 if (UNLIKELY(off > src->size || (uint64_t)len > src->size - off))
553 if (src->read_at)
return src->read_at(src, off, dst, len);
554 ZXC_MEMCPY(dst, src->data + off, len);
559 if (pos == src->size)
return 0;
560 uint8_t m[
sizeof(uint32_t)];
561 if (src->size - pos >=
sizeof(m)) {
563 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
575 const size_t n = end <
sizeof(h) ? (
size_t)end :
sizeof(h);
580 rc =
zxc_scan_read(src, end -
sizeof(tail), tail,
sizeof(tail));
581 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
586 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
589 const uint64_t at = end - frame;
591 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
596 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
603 const size_t n = src->size <
sizeof(h) ? (
size_t)src->size :
sizeof(h);
605 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
615 ZXC_MEMSET(info, 0,
sizeof(*info));
618 const size_t n = src->size <
sizeof(h) ? (
size_t)src->size :
sizeof(h);
622 if (UNLIKELY(hrc !=
ZXC_OK))
return hrc;
624 uint64_t end = src->size;
629 if (UNLIKELY(rc !=
ZXC_OK))
return rc;
655 if (UNLIKELY(hrc !=
ZXC_OK))
return hrc;
661 if (UNLIKELY(frc !=
ZXC_OK))
return frc;
668 ZXC_MEMSET(info, 0,
sizeof(*info));
677 if (footer_len) *footer_len = flen;
688 dst[0] = bh->block_type;
712 bh->block_type = src[0];
714 bh->reserved = src[2];
716 bh->header_checksum = src[7];
750 .
block_type = ZXC_BLOCK_EOF, .block_flags = 0, .reserved = 0, .comp_size = 0};
758 const size_t block_size, uint64_t* sek_bytes) {
763 const size_t m = avail <
sizeof(want) ? avail :
sizeof(want);
771 const uint32_t* RESTRICT sizes,
const uint32_t cnt) {
778 return (
size_t)(p - dst);
787 const uint64_t num_blocks) {
794 if (UNLIKELY(hdr_res < 0))
return hdr_res;
795 uint8_t* p = dst + hdr_res;
802 return (int64_t)(p - dst);
807 for (
size_t i = 0; i < n; i++, v >>= 8) dst[i] = (uint8_t)v;
813 for (
size_t i = n; i > 0; i--) v = (v << 8) | src[i - 1];
819 const uint64_t digest) {
821 uint8_t* p = dst + l->
skip;
825 p[l->
nf] = (uint8_t)((l->
nd - 1) | (l->
nf - 1) << 4);
833 const uint64_t src_size,
const uint64_t digest,
834 const int checksum_enabled) {
848 const uint64_t src_size, uint64_t* digest) {
851 const size_t n = avail < l->
len ? avail : l->
len;
852 if (n > l->
skip && memcmp(footer + l->
skip, want + l->
skip, n - l->
skip) != 0)
866 uint64_t* compressed_size,
size_t* sizes_len) {
868 const uint8_t L = end[-1];
870 const size_t nd = (size_t)(L & 0x07U) + 1;
871 const size_t nf = (size_t)(L >> 4) + 1;
872 const size_t need = nd + nf + 1;
882 *compressed_size = f;
898 dst[8] = gh->enc_lit;
899 dst[9] = gh->enc_tok;
900 dst[10] = gh->enc_mlen;
901 dst[11] = gh->enc_off;
914 gh->enc_lit = src[8];
915 gh->enc_tok = src[9];
916 gh->enc_mlen = src[10];
917 gh->enc_off = src[11];
927 return ((enc_lit != ZXC_SECTION_ENCODING_RAW) ?
sizeof(uint32_t) : 0) +
928 ((enc_tok == ZXC_SECTION_ENCODING_HUFFMAN) ?
sizeof(uint32_t) : 0);
942 const uint32_t tok_comp) {
951 if (gh->enc_lit != ZXC_SECTION_ENCODING_RAW) {
953 p +=
sizeof(uint32_t);
955 if (gh->enc_tok == ZXC_SECTION_ENCODING_HUFFMAN) {
967 uint32_t* RESTRICT tok_comp) {
978 if (gh->enc_lit != ZXC_SECTION_ENCODING_RAW) {
980 p +=
sizeof(uint32_t);
982 *lit_comp = gh->n_literals;
984 *tok_comp = (gh->enc_tok == ZXC_SECTION_ENCODING_HUFFMAN) ?
zxc_le32(p) : gh->n_sequences;
1032 if (UNLIKELY(input_size > (SIZE_MAX - (SIZE_MAX >> 8))))
return 0;
1088 if (UNLIKELY(src_size == 0))
return 0;
1105 return "ZXC_ERROR_MEMORY";
1107 return "ZXC_ERROR_DST_TOO_SMALL";
1109 return "ZXC_ERROR_SRC_TOO_SMALL";
1111 return "ZXC_ERROR_BAD_MAGIC";
1113 return "ZXC_ERROR_BAD_VERSION";
1115 return "ZXC_ERROR_BAD_HEADER";
1117 return "ZXC_ERROR_BAD_CHECKSUM";
1119 return "ZXC_ERROR_CORRUPT_DATA";
1121 return "ZXC_ERROR_BAD_OFFSET";
1123 return "ZXC_ERROR_OVERFLOW";
1125 return "ZXC_ERROR_IO";
1127 return "ZXC_ERROR_NULL_INPUT";
1129 return "ZXC_ERROR_BAD_BLOCK_TYPE";
1131 return "ZXC_ERROR_BAD_BLOCK_SIZE";
1133 return "ZXC_ERROR_DICT_REQUIRED";
1135 return "ZXC_ERROR_DICT_MISMATCH";
1137 return "ZXC_ERROR_DICT_TOO_LARGE";
1139 return "ZXC_ERROR_BAD_LEVEL";
1141 return "ZXC_ERROR_DICT_UNSUPPORTED";
1143 return "ZXC_UNKNOWN_ERROR";
uint64_t zxc_compress_block_bound(const size_t input_size)
Returns the maximum compressed size for a single block (no file framing).
uint64_t zxc_estimate_cctx_size(const size_t src_size, const int level)
Estimates the total buffer bytes allocated inside a cctx for a block.
uint64_t zxc_decompress_block_bound(const size_t uncompressed_size)
Returns the minimum dst_capacity required by zxc_decompress_block().
#define ZXC_BLOCK_SIZE_MAX_LOG2
log2(ZXC_BLOCK_SIZE_MAX) - exponent code for maximum block size.
#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).
size_t zxc_frame_info_size(void)
Returns sizeof(zxc_frame_info_t) for ABI-safe mirroring.
uint64_t zxc_compress_bound(const size_t input_size)
Returns the maximum compressed size for a given input size.
#define ZXC_HUF_TABLE_SIZE
Size of a packed literal Huffman code-lengths table (256 symbols, 4 bits each): the shared table in a...
const char * zxc_error_name(const int code)
Returns a human-readable string for the given error code.
zxc_error_t
Error codes returned by ZXC library functions.
@ ZXC_ERROR_BAD_MAGIC
Invalid magic word in file header.
@ ZXC_ERROR_BAD_VERSION
Unsupported file format version.
@ ZXC_ERROR_BAD_BLOCK_TYPE
Unknown or unexpected block type.
@ ZXC_ERROR_OVERFLOW
Buffer overflow detected during processing.
@ ZXC_ERROR_BAD_OFFSET
Invalid match offset during decompression.
@ ZXC_ERROR_CORRUPT_DATA
Corrupted compressed data.
@ ZXC_ERROR_NULL_INPUT
Required input pointer is NULL.
@ ZXC_ERROR_IO
Read/write/seek failure on file.
@ 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_FILE_FORMAT_VERSION
Current on-disk file format version.
#define ZXC_FILE_FLAG_HAS_CHECKSUM
Bit flag in the Flags byte indicating checksum presence (bit 7).
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_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_ALIGNED_FREE(ptr)
Counterpart deallocator for ZXC_ALIGNED_MALLOC.
#define ZXC_CHECKSUM_RAPIDHASH
Checksum algorithm id for RapidHash (default, sole implementation).
#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_ALIGNED_MALLOC(size, alignment)
Cache-line-aligned allocator.
#define ZXC_LZ_HASH_SIZE
Maximum number of entries in the hash table.
#define ZXC_FILE_CHECKSUM_ALGO_MASK
Mask for the checksum algorithm id (bits 0-3).
#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_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_GHI_HEADER_BINARY_SIZE
Binary size of a GHI block sub-header.
#define ZXC_BLOCK_HEADER_SIZE
Block header size: Type(1)+Flags(1)+Reserved(1)+Checksum(1)+CompSize(4).
#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_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_CACHE_LINE_SIZE
Assumed CPU cache line size for alignment.
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_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_FASTEST
Fastest compression; lowest ratio.
@ ZXC_LEVEL_DENSITY
Higher density: adds Huffman-coded literals on top of COMPACT.
const char * zxc_version_string(void)
Returns the human-readable library version string.
int zxc_default_level(void)
Returns the default compression level.
int zxc_max_level(void)
Returns the maximum supported compression level.
int zxc_min_level(void)
Returns the minimum supported compression level.
int64_t zxc_write_seek_table(uint8_t *dst, const size_t dst_capacity, const uint32_t *comp_sizes, const uint64_t num_blocks)
Serialises a seek table (a ZXC_BLOCK_SEK block) into dst.
size_t zxc_seek_table_size(const uint64_t num_blocks)
Byte size of a seek table holding num_blocks blocks: header, then groups.
#define ZXC_LIB_VERSION_STR
Human-readable version string in "MAJOR.MINOR.PATCH" form (e.g.
Compression / decompression context.
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.
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).
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 dict_huf_tree_ok
1 when *dict_huf is built and valid.
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).
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.
Options for decompression.
Frame-constant dictionary Huffman state, prebuilt once at attach.
What a frame's header and footer declare, read without decoding.
uint8_t format_version
Format version of the frame.
uint64_t digest
Archive digest; 0 when has_checksum is 0.
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.
uint32_t dict_id
Dictionary the frame needs; 0 for none.
uint8_t has_seek_table
1 when a seek table precedes the footer.
uint64_t compressed_size
Compressed bytes of the frame, footer included.
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_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)
Serialises a GLO block header followed by its section descriptors.
int zxc_read_frame_info(const uint8_t *header, const uint8_t *tail, const size_t tail_len, const uint64_t total, zxc_frame_info_t *info, size_t *footer_len)
Validates a frame from its header and the end of its bytes.
static uint64_t zxc_load_le_n(const uint8_t *src, const size_t n)
Loads n little-endian bytes.
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_parse_file_footer(const uint8_t *end, const size_t avail, uint64_t *src_size, uint64_t *compressed_size, size_t *sizes_len)
Parses the two sizes back from the end of a frame.
static size_t zxc_cctx_max_seq(const size_t chunk_size)
Worst-case sequence count for one block.
int zxc_cctx_alloc_entropy_scratch(zxc_cctx_t *ctx)
Lazily allocates the deferred decode-side entropy scratch.
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.
static void zxc_read_gnr_header(const uint8_t *src, zxc_gnr_header_t *gh)
Reads the 12-byte GLO/GHI sub-header shared by both block types.
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.
static void zxc_write_gnr_header(uint8_t *dst, const zxc_gnr_header_t *gh)
Writes the 12-byte GLO/GHI sub-header shared by both block types.
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.
size_t zxc_decompress_opts_size(void)
Returns sizeof(zxc_decompress_opts_t) for ABI-safe allocation.
int zxc_read_ghi_header(const uint8_t *src, const size_t len, zxc_gnr_header_t *gh)
Parses a GHI block header from src.
static void zxc_dctx_entropy_sizes(const size_t chunk_size, size_t *sz_tok, size_t *sz_pivco)
Decode-side entropy scratch sizes for one block: token scratch (worst-case sequence count + wild-read...
int zxc_write_ghi_header(uint8_t *dst, const size_t rem, const zxc_gnr_header_t *gh)
Serialises a GHI block header.
size_t zxc_seek_write_group(uint8_t *dst, uint64_t *anchor, const uint32_t *sizes, const uint32_t cnt)
Writes one group (*anchor, then cnt sizes) into dst, which holds ZXC_SEEK_GROUP_BYTES,...
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)
Parses a GLO block header and its section descriptors from src.
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_...
static void zxc_store_le_n(uint8_t *dst, uint64_t v, const size_t n)
Stores the low n bytes of v, little-endian.
static int zxc_scan_read(const zxc_scan_src_t *src, const uint64_t off, void *dst, const size_t len)
Reads a byte range of a scan source, refusing ranges past its end.
static size_t zxc_glo_desc_size(const uint8_t enc_lit, const uint8_t enc_tok)
Size of the GLO section descriptors, implied by the encoding fields.
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...
static zxc_cctx_layout_t compute_cctx_layout(const size_t chunk_size, const int mode, const int level, const size_t dict_size, const int defer_entropy_scratch)
Computes the single-allocation memory layout for a compression / decompression context.
int zxc_cctx_attach_dict_huf(zxc_cctx_t *ctx, const uint8_t *lengths)
Attach the shared dictionary literal Huffman table to a context.
size_t zxc_compress_opts_size(void)
Returns sizeof(zxc_compress_opts_t) for ABI-safe allocation.
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 void zxc_encode_footer(uint8_t *dst, const zxc_footer_layout_t *l, const uint64_t src_size, const uint64_t digest)
Encodes the l footer: digest, the two sizes, then L.
int zxc_huf_dict_tree_build(const uint8_t *packed_lengths, zxc_pivco_tree_t *tree, uint32_t *codes, uint8_t *code_len)
Prebuild a dict table's decode/encode state (tree-at-attach).
Internal definitions, constants, SIMD helpers, and utility functions.
#define ZXC_PIVCO_SCRATCH_PAD
Extra scratch slack required past n by the PivCo decoder.
static uint64_t zxc_le64(const void *p)
Reads a little-endian 64-bit value from a possibly unaligned address.
static uint32_t zxc_le32(const void *p)
Reads a little-endian 32-bit value from a possibly unaligned address.
#define ZXC_HUF_NUDGE_SCRATCH_SIZE
Scratch size (bytes) for zxc_huf_nudge_code_lengths: builder's, then workspace.
static void zxc_store_le64(void *p, const uint64_t v)
Writes a 64-bit value little-endian to a possibly unaligned address.
static uint32_t zxc_log2_u32(const uint32_t v)
Integer log-base-2 for a 32-bit value.
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_FRAME_MIN_SIZE
Smallest frame: header, the EOF block and the shortest footer.
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.
static uint16_t zxc_hash16(const uint8_t *p)
Computes the 2-byte checksum for file and dictionary headers.
static uint8_t zxc_hash8(const uint8_t *p)
Computes the 1-byte checksum for block headers.
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.
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.
static size_t zxc_uint_bytes(const uint64_t v)
Fewest little-endian bytes, 1 to 8, that hold v.
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...
#define ZXC_FOOTER_MAX_SIZE_WITH_DIGEST
Most bytes a footer spans: the digest and the two longest sizes.
static void zxc_file_header_sign(uint8_t *h)
Writes the file header checksum (bytes 14-15) over the other 14 bytes.
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.
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.