How to Integrate the Kanzi C++ API for Compression into Your Application

To integrate the Kanzi C++ API for compression, link your application against libkanzi, include kanzi/api/Compressor.hpp, configure a cData struct with your desired transform and entropy codec, and execute the initCompressor(), compress(), and disposeCompressor() sequence to process data blocks.

The Kanzi C++ library (flanglet/kanzi-cpp) provides a modular, high-performance lossless compression pipeline designed for modern C++ applications. Whether you require a stable ABI through the C API or prefer direct C++ class instantiation, integrating Kanzi requires understanding its transform-entropy architecture and proper initialization workflow.

Understanding the Kanzi Compression Architecture

Kanzi implements a clear pipeline that processes data through distinct stages to maximize compression efficiency.

The Pipeline Flow


Input → Transform(s) → Entropy Encoder → CompressedOutputStream → File/Memory

  • Transforms (e.g., LZ, BWT, RLT) increase data redundancy before encoding. Implementations reside in src/transform/ (see LZCodec.cpp, BWT.cpp, ZRLT.cpp).
  • Entropy codecs (Huffman, ANS0/1, Range, FPAQ) convert transformed symbols into bit-streams. These live in src/entropy/ (e.g., HuffmanEncoder.cpp, FPAQEncoder.cpp).
  • CompressedOutputStream (src/io/CompressedOutputStream.hpp) buffers data, writes block headers (unless headerless mode is enabled), and forwards encoded bits to a file descriptor.
  • Context (src/Context.hpp) serves as the central configuration holder, storing parameters such as block size, thread count, transform/entropy names, checksum mode, and headerless flags. All high-level objects (BlockCompressor, BlockDecompressor, and the C API) read settings from a Context instance.

The C API Wrapper

The C API (src/api/Compressor.hpp, src/api/Compressor.cpp) provides an ABI-stable wrapper around the C++ pipeline. This avoids exposing template-heavy internals while granting full control over compression options. The typical compress flow involves:

  1. Fill a cData structure with parameters (transform, entropy, block size, jobs, checksum, headerless).
  2. Call initCompressor(&cData, FILE* dst, &cContext*), which creates a CompressedOutputStream, validates names, and stores the pointer in an opaque cContext.
  3. For each block, invoke compress(cContext, src, inSize, &outSize), which transforms, entropy-encodes, and writes the data.
  4. Call disposeCompressor(&cContext, &writtenBytes) to flush pending data and free resources.

For pure C++ projects, you can bypass the C wrapper and instantiate BlockCompressor directly (see src/app/BlockCompressor.hpp). This class builds a Context internally and exposes compress(uint64& written) to process entire input streams.

Step-by-Step Integration Guide

Clone the repository and build the static (libkanzi.a) or shared (libkanzi.so/.dll) library using the provided CMake configuration. Link your target with kanzi (static) or kanzi_shared (shared) and include the Threads::Threads dependency.

Key file: CMakeLists.txtlink

Include the Public Headers

For the C API:

#include <kanzi/api/Compressor.hpp>

For the C++ class API:

#include <kanzi/app/BlockCompressor.hpp>

Headers are installed under include/kanzi/… when running make install.

Key files: src/api/Compressor.hpplink, src/app/BlockCompressor.hpplink

Configure Compression Parameters

Fill a cData struct (C API) or Context object (C++). Example configuration for the C API:

kanzi::cData params{};
strcpy(params.transform, "LZ");        // Transform chain
strcpy(params.entropy,   "ANS0");      // Entropy codec
params.blockSize = 1 << 16;            // 64 KiB blocks
params.jobs      = 1;                  // Thread count
params.checksum  = 32;                 // 32-bit checksum per block
params.headerless = 0;                 // Standard headered stream

Key file: src/api/Compressor.hpplink

Initialize and Compress

Initialize the compressor:

kanzi::cContext* ctx = nullptr;
if (kanzi::initCompressor(&params, outFile, &ctx) != 0) {
    // Handle error
}

Compress data blocks in a loop:

size_t outSize = 0;
kanzi::compress(ctx, srcBuffer, srcSize, &outSize);

Key file: src/api/Compressor.cpplink

Finalize and Cleanup

Call disposeCompressor to flush remaining data and retrieve total bytes written:

size_t totalWritten = 0;
kanzi::disposeCompressor(&ctx, &totalWritten);

The output file now contains a valid Kanzi bit-stream (or raw blocks if headerless was enabled).

Code Examples

Minimal C API Example

// compress_demo.cpp
#include <cstdio>
#include <cstring>
#include <kanzi/api/Compressor.hpp>

int main()
{
    FILE* out = fopen("example.knz", "wb");
    if (!out) return 1;

    kanzi::cData params{};
    strcpy(params.transform, "LZ");
    strcpy(params.entropy, "ANS0");
    params.blockSize = 1 << 16;
    params.jobs = 1;
    params.checksum = 32;
    params.headerless = 0;

    kanzi::cContext* ctx = nullptr;
    if (kanzi::initCompressor(&params, out, &ctx) != 0) {
        fclose(out);
        return 2;
    }

    const char* txt = "The quick brown fox jumps over the lazy dog.";
    size_t txtSize = strlen(txt);
    size_t outSize = 0;

    if (kanzi::compress(ctx, 
                        reinterpret_cast<const unsigned char*>(txt), 
                        txtSize, 
                        &outSize) != 0) {
        kanzi::disposeCompressor(&ctx, nullptr);
        fclose(out);
        return 3;
    }

    size_t flushed = 0;
    kanzi::disposeCompressor(&ctx, &flushed);
    fclose(out);
    return 0;
}

Implementation details:

  • cData fields are validated and rewritten by initCompressor (see lines 96-108 in Compressor.cpp).
  • Block sizes are automatically rounded to multiples of 16 (pData->blockSize = (pData->blockSize + 15) & -16).
  • Error codes are defined in src/Error.hpp.

Pure C++ Class API Example

// cpp_compress_demo.cpp
#include <fstream>
#include <kanzi/app/BlockCompressor.hpp>
#include <kanzi/Context.hpp>

int main()
{
    kanzi::Context ctx;
    ctx.putString("transform", "LZ");
    ctx.putString("entropy", "ANS0");
    ctx.putInt("blockSize", 1 << 16);
    ctx.putInt("jobs", 4);
    ctx.putInt("checksum", 32);
    ctx.putInt("headerless", 0);
    ctx.putString("outputName", "example_cpp.knz");
    ctx.putString("inputName", "input.txt");

    kanzi::BlockCompressor compressor(ctx);
    uint64_t written = 0;
    
    int result = compressor.compress(written);
    return (result == 0) ? 0 : 1;
}

Notes:

  • BlockCompressor reads inputName and outputName from the Context. If omitted, it defaults to stdin/stdout.
  • The heavy lifting (transform selection, entropy encoder creation) occurs inside BlockCompressor::compress (see src/app/BlockCompressor.cpp around line 1125).

Python Integration via C API

The repository includes a Python wrapper demonstrating cross-language usage:

from kanzi import Compressor, KanziError
import tempfile

def compress_bytes(data: bytes) -> bytes:
    with tempfile.NamedTemporaryFile(delete=False) as tmp:
        with Compressor(tmp.name,
                       transform=b"LZ",
                       entropy=b"ANS0",
                       block_size=1<<16,
                       jobs=1,
                       checksum=32,
                       headerless=0) as c:
            c.compress(data)
        
        with open(tmp.name, "rb") as f:
            return f.read()

This wrapper internally invokes the C functions defined in src/api/Compressor.cpp.

Key Implementation Files

Category File Purpose Link
Public C API src/api/Compressor.hpp Declares cData, cContext, initCompressor(), compress(), disposeCompressor() View
src/api/Compressor.cpp Implements C API wrapper, creates CompressedOutputStream, validates parameters View
src/api/Decompressor.hpp/cpp Symmetric decompression API Decompressor.hpp
C++ Class API src/app/BlockCompressor.hpp High-level C++ interface using Context View
src/app/BlockCompressor.cpp Core compression logic, multi-threading support View
I/O Layer src/io/CompressedOutputStream.hpp/cpp Block buffering, header writing, bit-packing CompressedOutputStream.hpp
Configuration src/Context.hpp Key-value store for compression parameters View
Error Handling src/Error.hpp Error code definitions for API returns View

Summary

  • Link against libkanzi (static or shared) built via the provided CMakeLists.txt, ensuring you link Threads::Threads for multi-threading support.
  • Choose your API layer: Use kanzi/api/Compressor.hpp for stable C ABI compatibility across compilers, or kanzi/app/BlockCompressor.hpp for direct C++ integration with Context-based configuration.
  • Configure via cData or Context: Set transform (e.g., "LZ", "BWT"), entropy (e.g., "ANS0", "Huffman"), blockSize (rounded to multiples of 16), jobs (thread count), and headerless mode.
  • Execute the lifecycle: initCompressor()compress() (loop for blocks) → disposeCompressor() to flush buffers and retrieve total bytes written.
  • Handle errors: Check return codes against definitions in src/Error.hpp; validation of transform/entropy names occurs during initCompressor.

Frequently Asked Questions

Should I use the C API or the C++ BlockCompressor class?

Use the C API (src/api/Compressor.hpp) when you need ABI stability across different compiler versions or when binding to other languages like Python. The cData struct and opaque cContext pointer provide a clean, stable interface. Use the C++ BlockCompressor class (src/app/BlockCompressor.hpp) for native C++ projects where you want direct access to the Context object and prefer object-oriented resource management without extern "C" linkage overhead.

How do I enable multi-threaded compression?

Set the jobs parameter in your cData struct (C API) or call ctx.putInt("jobs", 4) in your Context object (C++ API). The BlockCompressor implementation in src/app/BlockCompressor.cpp handles thread pool creation and block-level parallelism automatically. Note that you must link against Threads::Threads in your CMake configuration to support concurrent execution.

Can I compress data without headers for custom protocols?

Yes. Set params.headerless = 1 (C API) or ctx.putInt("headerless", 1) (C++ API). In headerless mode, CompressedOutputStream (defined in src/io/CompressedOutputStream.hpp) skips writing the Kanzi file signature and block metadata. You must manually track block sizes and checksums if your protocol requires them, as the decompressor will need identical parameters to decode the raw bit-stream correctly.

What error codes does the C API return?

The C API returns integer error codes defined in src/Error.hpp. Common values include ERR_OK (0) for success, ERR_INVALID_PARAM for malformed transform or entropy names, and ERR_IO for file operation failures. During initCompressor, the library validates cData fields and rewrites them (e.g., rounding blockSize to multiples of 16) before allocating the cContext structure. Always check return values before proceeding to compress() calls.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →