This document covers both the recommended wrapper API and the lower-level API.
The wrapper API lives in include/loxc_simple.h. It is the fastest path for
common use cases.
loxc_ctx_t *loxc_open(const char *table_path);Loads a .loxctab into a module owned directly by the returned context. It
does not register that module globally. Opening the same table repeatedly, or
opening tables with duplicate module names/IDs, creates independent contexts.
void loxc_close(loxc_ctx_t *ctx);Frees the context's owned runtime module and releases the wrapper context. Contexts may be closed in any order without affecting other contexts.
int loxc_compress_file(loxc_ctx_t *ctx, const char *input_path,
const char *output_path, int embed_table);Compresses a file to .loxc. Use embed_table = 1 for self-contained output.
int loxc_decompress_file(loxc_ctx_t *ctx, const char *input_path,
const char *output_path);Decompresses a .loxc file to disk. For embedded .loxc input, ctx may be
NULL.
loxc_buffer_t loxc_compress_buffer(loxc_ctx_t *ctx,
const void *data, size_t len,
int embed_table);Compresses an in-memory buffer and returns an owned output buffer. The loaded
table generation selects the codec: v2 retains its existing representation;
v3 emits the table's MATRIX4 or MATRIX8 grammar and never uses the legacy
rank/CONTINUE payload. embed_table has the same meaning for both generations.
Generated static modules carry the same explicit generation field. Generated
v2 modules retain their callbacks; generated v3 modules expose the same
semantic matrix view as runtime-loaded v3 and call the shared buffer codec.
Static v3 modules do not retain serialized .loxctab bytes, so embedded-table
output requires a runtime-loaded module. Ordinary static compression and
decompression have no loader or filesystem dependency.
loxc_buffer_t loxc_decompress_buffer(loxc_ctx_t *ctx,
const void *data, size_t len);Decompresses an in-memory .loxc buffer and returns an owned output buffer.
For embedded input, ctx may be NULL.
For v3, the container declares the exact payload size and expected uncompressed byte count. Dictionary expansion is bounded by that count. The whole-payload decoder rejects truncation, extra semantic symbols, malformed paths, output overflow, and nonzero final padding; callers do not finish padding separately.
void loxc_buffer_free(loxc_buffer_t *buf);Frees the owned memory inside a loxc_buffer_t and resets the structure.
const char *loxc_strerror(int error_code);Maps LOXC_ERR_* values to human-readable strings.
int loxc_check_file(const char *path);Validates that a file looks like a readable .loxc container.
int loxc_check_file_ex(const char *path, loxc_check_file_result_t *out_result);Validates a .loxc file and, when out_result is not NULL, returns parsed
metadata about the container:
rc: the validation resultos_errno: host errno from open failuresfile_size: observed file size when availableheader_size: parsed header sizeembedded: non-zero for embedded-table containersmodule_id,version,flags,strategy_idpayload_len,level_count,uncompressed_len,table_fingerprint- v3 framed metadata:
table_size,container_revision,frame_header_size
loxc_ctx_t *loxc_open_module(const char *registered_module_name);After a module's registration function succeeds, this creates a simple
context. Generated/static descriptors have process lifetime and are borrowed;
closing the context does not unregister them. Runtime-loaded registered
modules are cloned from their owned table image, so the context remains valid
after the source module is unregistered and unloaded. File compression and
decompression use the same bounded streaming engine as loxc_open().
loxc_compress_file() dispatches explicitly by module generation. V2 modules
retain the legacy v2 single-payload file path. V3 runtime-loaded and generated
modules write framed revision 1 with direct Phase 1 matrix payloads. Embedded
mode requires a runtime-loaded module that retains canonical .loxctab bytes;
generated modules remain external-table/static semantics unless their
deployment also supplies a table image.
loxc_decompress_file() dispatches by the explicit container version. V3
frames are decoded by the canonical whole-payload decoder, including exact
uncompressed expansion, semantic-bit exhaustion, and zero-padding validation.
The global fingerprint must match the exact matrix placement. Embedded v3
files may be decoded with a null context because their one global table is
loaded once for all frames.
The configuration fields max_table_size, max_input_size,
max_output_size, max_file_size, and max_frame_count bound cumulative
stream work. File output uses a temporary path and is published only after a
complete successful stream.
#include "loxc_simple.h"
loxc_ctx_t *ctx = loxc_open("modules/loxc_demo.loxctab");
loxc_buffer_t compressed = loxc_compress_buffer(ctx, data, len, 0);
loxc_buffer_t restored =
loxc_decompress_buffer(ctx, compressed.data, compressed.size);
loxc_buffer_free(&compressed);
loxc_buffer_free(&restored);
loxc_close(ctx);The advanced API is declared in include/loxc.h and include/loxc_tab.h.
int loxc_module_register(const loxc_module_t *module);Registers a module in the global registry.
Returns:
LOXC_OKon success- an error code on failure
int loxc_compress(const char *module_name,
const char *input, size_t input_len,
uint8_t *output, size_t *output_capacity,
size_t *output_actual);Compresses text using a registered module.
Notes:
output_capacityis both input and outputoutput_actualreceives the produced size- runtime-loaded modules dispatch explicitly by
.loxctabgeneration - v3 uses canonical matrix paths and deterministic longest dictionary match
- an unmatched byte uses the table's unique RAW path
int loxc_compress_with_options(const char *module_name,
const char *input, size_t input_len,
uint8_t *output, size_t *output_capacity,
size_t *output_actual,
int embed_table);Same as loxc_compress, with optional embedded-table output.
int loxc_module_get_table_blob(const loxc_module_t *module,
const uint8_t **out_blob,
size_t *out_size);Returns the raw .loxctab blob for runtime-loaded modules.
int loxc_decompress(const uint8_t *input, size_t input_len,
char *output, size_t *output_capacity,
size_t *output_actual);Decompresses a .loxc payload back into text.
Behavior:
- embedded files auto-load their own table
- external files require the matching module to be registered
- v3 requires the same matrix-aware fingerprint, strategy, and generation
- identical symbols with different matrix placement are not interchangeable
- v3 decoding owns exact-output-length and zero-padding validation
LOXC_OKLOXC_ERR_NULLLOXC_ERR_TRUNCATEDLOXC_ERR_OVERFLOWLOXC_ERR_INVALID_MAGICLOXC_ERR_SYMBOL_NOT_FOUNDLOXC_ERR_INVALID_FORMATLOXC_ERR_MODULE_NOT_FOUNDLOXC_ERR_REGISTRY_FULLLOXC_ERR_DUPLICATE_MODULELOXC_ERR_INVALID_MODULE
For v3 buffers, malformed/truncated paths normally return
LOXC_ERR_INVALID_FORMAT or LOXC_ERR_TRUNCATED; insufficient capacity
returns LOXC_ERR_OVERFLOW; a missing RAW fallback returns
LOXC_ERR_SYMBOL_NOT_FOUND; and module, strategy, generation, or fingerprint
mismatches return the corresponding invalid-module/magic error. Existing v2
error behavior is unchanged.
loxc_module_t *m = loxc_module_load_from_file("modules/loxc_demo.loxctab");
loxc_module_register(m);
uint8_t out[4096];
size_t out_cap = sizeof(out);
size_t out_len = 0;
loxc_compress("demo", "hello", 5, out, &out_cap, &out_len);
loxc_module_unload(m);