Decompression Guide
lz4.zig provides safe, high-speed decompression with automatic format detection, checksum validation, and protection against malicious inputs.
Automatic Format Detection
The high-level lz4.decompress and lz4.decompressWithOptions functions automatically inspect the input header:
- If the first 4 bytes match
0x184D2204(FRAME_MAGIC), the input is decoded as an LZ4 Frame. - Otherwise, the input is decoded as a Raw LZ4 Block.
const std = @import("std");
const lz4 = @import("lz4");
pub fn main() !void {
const allocator = std.heap.page_allocator;
// Decompress any valid LZ4 data (frame or raw block)
const decompressed = try lz4.decompress(allocator, compressed_data);
defer allocator.free(decompressed);
std.debug.print("Decompressed size: {d} bytes\n", .{decompressed.len});
}Decompression Security & Resource Limits
Untrusted data from the internet or unauthenticated users can present a "decompression bomb" attack (a tiny payload expanding into gigabytes of memory).
To guard against memory exhaustion, specify maxOutputSize:
const opts: lz4.DecompressionOptions = .{
.maxOutputSize = 10 * 1024 * 1024, // Enforce a 10 MiB limit
.verifyChecksums = true,
};
const safe_decompressed = try lz4.decompressWithOptions(allocator, untrusted_data, opts);
defer allocator.free(safe_decompressed);If the uncompressed content exceeds maxOutputSize, decompression safely terminates with error.OutputTooLarge without overflowing memory.
Zero-Allocation Caller Buffer
To decompress into a pre-allocated slice without any heap allocation:
var out_buf: [4096]u8 = undefined;
const decoded_len = try lz4.decompressInto(compressed_slice, &out_buf);
const result = out_buf[0..decoded_len];Partial Decompression
If you only need the first $N$ bytes of a compressed block (such as an index header or metadata record), use decompressBlockPartial:
var prefix_buf: [128]u8 = undefined;
// Decodes only up to prefix_buf.len bytes from the raw block
const bytes_read = try lz4.decompressBlockPartial(raw_block, &prefix_buf, prefix_buf.len);
const header = prefix_buf[0..bytes_read];This avoids decompressing the remaining megabytes of the block, reducing latency and CPU usage.
Error Handling
All decoders in lz4.zig strictly validate bounds and return structured errors from the canonical error set:
const data = lz4.decompress(allocator, untrusted_slice) catch |err| switch (err) {
error.MalformedInput => {
std.debug.print("Invalid or corrupt LZ4 sequence\n", .{});
return;
},
error.BadChecksum => {
std.debug.print("Data checksum mismatch detected!\n", .{});
return;
},
error.OutputTooLarge => {
std.debug.print("Decompressed size exceeded max safety limits\n", .{});
return;
},
error.OutOfMemory => return err,
else => return err,
};
defer allocator.free(data);