# How to Perform Partial Decompression in Kanzi Using `--from` and `--to` Options

> Quickly extract specific blocks from Kanzi archives with partial decompression. Use --from and --to options to target desired data efficiently, saving time and resources.

- Repository: [flanglet/kanzi-cpp](https://github.com/flanglet/kanzi-cpp)
- Tags: how-to-guide
- Published: 2026-03-02

---

**Run Kanzi in decompression mode (`-d`) and specify the range with `--from=<firstBlock>` (inclusive) and `--to=<lastBlock+1>` (exclusive) to extract only specific blocks without processing the entire archive.**

The kanzi-cpp compression library supports granular block-level decompression through command-line range specifiers. Partial decompression in Kanzi allows you to extract targeted segments from large archives, reducing I/O overhead and processing time when you need only a subset of the data.

## Command-Line Syntax for Block Range Extraction

To extract a specific range, invoke Kanzi with the decompression flag and both range boundaries. Block IDs are **1-indexed**, and the `--to` value is **exclusive** (the block matching `--to` is not decompressed).

```bash
kanzi -d -i archive.knz -o out.txt --from=5 --to=11

```

This command decompresses **blocks 5 through 10** (inclusive) from `archive.knz` into [`out.txt`](https://github.com/flanglet/kanzi-cpp/blob/main/out.txt). Omitting `--from` defaults to block `1`, while omitting `--to` processes until the end of the file.

## How Block Range Filtering Works

The implementation propagates range parameters through three architectural layers, from CLI parsing to low-level bitstream decoding.

### Stage 1: Argument Parsing in [`src/app/Kanzi.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/Kanzi.cpp)

The `parseArguments` function detects range specifiers using string prefix comparisons and validates that the current mode is decompression (`mode == "d"`).

```cpp
if ((arg.compare(0, 7, "--from=") == 0) && (ctx == -1)) { … }
if ((arg.compare(0, 5, "--to=") == 0) && (ctx == -1)) { … }

```

The numeric arguments are converted via `toInt(arg, from)` and `toInt(arg, to)`, then stored in the global `Context` map:

```cpp
map.putInt("from", from);   // Defaults to -1 if not set
map.putInt("to",   to);

```

If either value is non-numeric or less than or equal to zero, the parser returns `Error::ERR_INVALID_PARAM`.

### Stage 2: Context Propagation in [`src/app/BlockDecompressor.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/BlockDecompressor.cpp)

When instantiating a `BlockDecompressor`, the constructor receives the same `Context` object containing the range values. In **info mode** (`-y`), the constructor explicitly overrides user input to force a no-output run on a single block:

```cpp
_ctx.putInt("from", 1);
_ctx.putInt("to",   1);

```

In standard decompression mode, the values supplied on the command line pass through unchanged to the I/O layer.

### Stage 3: Selective Decoding in [`src/io/CompressedInputStream.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/io/CompressedInputStream.cpp)

The `readBlock` method inside `CompressedInputStream` implements the actual filtering logic. It retrieves the boundaries with safe defaults:

```cpp
const int from = _ctx.getInt("from", 1);
const int to   = _ctx.getInt("to", CompressedInputStream::MAX_BLOCK_ID);

```

During block iteration, the method applies two hard rules:

- **Skip logic**: If the current `blockId` is less than `from`, the block is bypassed entirely.
  ```cpp
  if (blockId < from)
      return T(*_data, blockId, 0, 0, 0, "Skipped", true);
  ```

- **Termination logic**: If `blockId` reaches or exceeds `to`, decoding halts early.
  ```cpp
  else if (blockId >= to)
      return T(*_data, blockId, 0, 0, 0, "Success");
  ```

Only blocks satisfying `from ≤ blockId < to` proceed to the transform and entropy decoding stages.

## Edge Cases and Validation Rules

The Kanzi CLI enforces strict validation to prevent ambiguous range requests:

- **Unspecified `--from`**: Automatically defaults to block `1` (the first block in the archive).
- **Unspecified `--to`**: Automatically defaults to `CompressedInputStream::MAX_BLOCK_ID`, processing all remaining blocks.
- **Invalid numeric values**: Non-integer arguments or values `≤ 0` trigger `Error::ERR_INVALID_PARAM`.
- **Inverted ranges**: If `--to` is less than or equal to `--from`, all blocks are skipped, resulting in empty output.
- **Compression mode usage**: Supplying these flags during compression (`-c`) emits `WARNING_OPT_DECOMP_ONLY` and the options are ignored.

## Practical Usage Examples

| Goal | Command | Blocks Extracted |
|------|---------|------------------|
| Extract single block 3 | `kanzi -d -i data.knz -o block3.bin --from=3 --to=4` | Block 3 only |
| Extract range 5–10 | `kanzi -d -i data.knz -o part.bin --from=5 --to=11` | Blocks 5 through 10 |
| Skip first two blocks | `kanzi -d -i data.knz -o rest.bin --from=3` | Blocks 3 to end |
| Archive info (no output) | `kanzi -y -i data.knz --from=1 --to=1` | Block 1 (metadata scan) |
| Parallel partial extract | `kanzi -d -i data.knz -o out.bin --from=2 --to=6 -j 2` | Blocks 2–5 using 2 threads |

Because `--to` is exclusive, you can calculate the `--from` value for the last *N* blocks by first running `kanzi -y` to determine the total block count, then setting `--from=total-N+1` while omitting `--to`.

## Summary

- Partial decompression requires the `-d` flag; using it with `-c` generates a warning and has no effect.
- Block IDs start at **1**, and `--to` is an **exclusive** upper bound.
- The filtering pipeline spans three files: [`src/app/Kanzi.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/Kanzi.cpp) (parsing), [`src/app/BlockDecompressor.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/BlockDecompressor.cpp) (propagation), and [`src/io/CompressedInputStream.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/io/CompressedInputStream.cpp) (execution).
- Ranges are validated early; invalid inputs return `Error::ERR_INVALID_PARAM` before any I/O occurs.
- The mechanism works transparently with multi-threaded decompression (`-j` flag).

## Frequently Asked Questions

### What is the difference between `--from` and `--to` in Kanzi partial decompression?

**`--from`** specifies the starting block ID (inclusive) to begin decompression, defaulting to `1` if omitted. **`--to`** specifies the block ID where decompression stops (exclusive), meaning the block equal to `--to` is not extracted. For example, `--from=5 --to=8` extracts blocks 5, 6, and 7 only.

### Can I use `--from` and `--to` when compressing files with Kanzi?

No. These options are valid **only in decompression mode** (`-d`). If supplied during compression (`-c`), Kanzi emits `WARNING_OPT_DECOMP_ONLY` and ignores the parameters, as implemented in [`src/app/Kanzi.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/Kanzi.cpp).

### Is the `--to` parameter inclusive or exclusive?

The `--to` parameter is **exclusive**. According to the logic in [`src/io/CompressedInputStream.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/io/CompressedInputStream.cpp), when `blockId >= to`, the decoder returns immediately without processing that block. Therefore, to extract blocks 10 through 20, you must use `--from=10 --to=21`.

### How can I extract only the last N blocks from a Kanzi archive?

First, determine the total number of blocks using info mode: `kanzi -y -i archive.knz`. Then calculate the starting block as `total_blocks - N + 1` and run: `kanzi -d -i archive.knz -o tail.bin --from=<calculated_start>`. Omit `--to` to decompress through the end of the file.