457 lines
11 KiB
Markdown
457 lines
11 KiB
Markdown
# std.compress - Compression API Reference (Zig 0.16.0)
|
|
|
|
Compression and decompression algorithms. Zig 0.16 adds Deflate compression, simplifies decompression, and continues migrating compression APIs to `std.Io.Reader` / `std.Io.Writer`.
|
|
|
|
Primary Zig 0.16 release-note source: https://ziglang.org/download/0.16.0/release-notes.html
|
|
|
|
The examples below use Zig 0.16's concrete `std.Io.Reader` / `std.Io.Writer` interfaces rather than removed generic-reader or fixed-buffer-stream patterns.
|
|
|
|
## Table of Contents
|
|
- [Module Structure](#module-structure)
|
|
- [DEFLATE (gzip/zlib)](#deflate-gzipzlib)
|
|
- [Zstandard](#zstandard)
|
|
- [LZMA](#lzma)
|
|
- [LZMA2](#lzma2)
|
|
- [XZ](#xz)
|
|
- [Common Patterns](#common-patterns)
|
|
|
|
## Module Structure
|
|
|
|
```zig
|
|
std.compress.flate // DEFLATE: gzip, zlib, raw deflate
|
|
std.compress.zstd // Zstandard compression
|
|
std.compress.lzma // LZMA compression
|
|
std.compress.lzma2 // LZMA2 compression
|
|
std.compress.xz // XZ format (LZMA2 container)
|
|
```
|
|
|
|
## DEFLATE (gzip/zlib)
|
|
|
|
DEFLATE compression with gzip, zlib, or raw containers. Defined in RFC 1951 (deflate), RFC 1950 (zlib), RFC 1952 (gzip).
|
|
|
|
### Container Types
|
|
|
|
```zig
|
|
const Container = enum {
|
|
raw, // No header/footer, raw deflate stream
|
|
gzip, // gzip header (10+ bytes) + deflate + CRC32 + size footer (8 bytes)
|
|
zlib, // zlib header (2 bytes) + deflate + Adler32 footer (4 bytes)
|
|
};
|
|
```
|
|
|
|
### Decompression
|
|
|
|
```zig
|
|
const flate = std.compress.flate;
|
|
|
|
// Decompress gzip data
|
|
var input: std.Io.Reader = .fixed(compressed_data);
|
|
var output: std.Io.Writer.Allocating = .init(allocator);
|
|
defer output.deinit();
|
|
|
|
var decompress: flate.Decompress = .init(&input, .gzip, &.{});
|
|
_ = try decompress.reader.streamRemaining(&output.writer);
|
|
|
|
const decompressed = output.written();
|
|
```
|
|
|
|
### With History Buffer
|
|
|
|
For streaming decompression with backref support:
|
|
|
|
```zig
|
|
var buffer: [flate.max_window_len]u8 = undefined;
|
|
var decompress: flate.Decompress = .init(&input, .zlib, &buffer);
|
|
```
|
|
|
|
### Decompress Constants
|
|
|
|
```zig
|
|
flate.max_window_len // 65536 - Maximum window size (32768 * 2)
|
|
flate.history_len // 32768 - History buffer length
|
|
```
|
|
|
|
### Compression
|
|
|
|
```zig
|
|
const flate = std.compress.flate;
|
|
|
|
var output: std.Io.Writer.Allocating = .init(allocator);
|
|
defer output.deinit();
|
|
|
|
var buffer: [flate.max_window_len]u8 = undefined;
|
|
var compress: flate.Compress = try .init(
|
|
&output.writer,
|
|
&buffer,
|
|
.gzip,
|
|
.default,
|
|
);
|
|
|
|
try compress.writer.writeAll(data);
|
|
try compress.finish();
|
|
|
|
const compressed = output.written();
|
|
```
|
|
|
|
### Compression Levels
|
|
|
|
```zig
|
|
const Options = struct {
|
|
// Options are parameter sets rather than an enum. Levels 1 through 9 are
|
|
// available; these public constants select common presets:
|
|
level_1: Options,
|
|
level_4, // Fastest
|
|
level_5,
|
|
level_6, // Default
|
|
level_7,
|
|
level_8,
|
|
level_9, // Best compression
|
|
|
|
fastest, // Alias for level_1
|
|
default, // Alias for level_6
|
|
best, // Alias for level_9
|
|
};
|
|
```
|
|
|
|
### Huffman-Only Compression
|
|
|
|
`flate.Compress.Huffman` exposes public initialization and a writer that skips LZ77 match searching. However, in the installed Zig 0.16 source its end-of-stream `finish` method is private. External code therefore cannot complete the container lifecycle through the public API alone. Treat it as an implementation-facing type in this release rather than a standalone archive-writing recipe; use `flate.Compress` when a complete public compression lifecycle is required.
|
|
|
|
## Zstandard
|
|
|
|
Zstandard (zstd) decompression. High compression ratio with fast decompression.
|
|
|
|
### Decompression
|
|
|
|
```zig
|
|
const zstd = std.compress.zstd;
|
|
|
|
var input: std.Io.Reader = .fixed(compressed_data);
|
|
var output: std.Io.Writer.Allocating = .init(allocator);
|
|
defer output.deinit();
|
|
|
|
var decompress: zstd.Decompress = .init(&input, &.{}, .{});
|
|
_ = try decompress.reader.streamRemaining(&output.writer);
|
|
|
|
const decompressed = output.written();
|
|
```
|
|
|
|
### With Custom Window Size
|
|
|
|
```zig
|
|
var buffer: [zstd.default_window_len + zstd.block_size_max]u8 = undefined;
|
|
var decompress: zstd.Decompress = .init(&input, &buffer, .{
|
|
.window_len = zstd.default_window_len,
|
|
.verify_checksum = false, // Not yet implemented
|
|
});
|
|
```
|
|
|
|
### Zstd Constants
|
|
|
|
```zig
|
|
zstd.default_window_len // 8 * 1024 * 1024 (8 MB)
|
|
zstd.block_size_max // 1 << 17 (128 KB)
|
|
```
|
|
|
|
### Options
|
|
|
|
```zig
|
|
pub const Options = struct {
|
|
verify_checksum: bool = false, // Not yet implemented
|
|
window_len: u32 = zstd.default_window_len,
|
|
};
|
|
```
|
|
|
|
## LZMA
|
|
|
|
LZMA decompression with streaming reader interface.
|
|
|
|
### Decompression
|
|
|
|
```zig
|
|
const lzma = std.compress.lzma;
|
|
|
|
var decoder_buffer = try allocator.alloc(u8, 4096);
|
|
errdefer allocator.free(decoder_buffer);
|
|
var decompress: lzma.Decompress = try .initOptions(
|
|
&reader,
|
|
allocator,
|
|
decoder_buffer,
|
|
.{},
|
|
128 * 1024 * 1024,
|
|
);
|
|
defer decompress.deinit();
|
|
|
|
_ = try decompress.reader.streamRemaining(&output.writer);
|
|
```
|
|
|
|
### With Options
|
|
|
|
```zig
|
|
var decompress: lzma.Decompress = try .initOptions(
|
|
&reader,
|
|
allocator,
|
|
decoder_buffer,
|
|
.{ .allow_incomplete = false },
|
|
128 * 1024 * 1024,
|
|
);
|
|
```
|
|
|
|
### Decompress Type
|
|
|
|
```zig
|
|
// Decompress embeds `reader: std.Io.Reader` and owns the caller-supplied
|
|
// buffer after init. `deinit` frees that buffer unless `takeBuffer` first
|
|
// reclaims it. `initParams` and `initOptions` are the construction paths.
|
|
```
|
|
|
|
## LZMA2
|
|
|
|
LZMA2 decompression (improved LZMA with better streaming support).
|
|
|
|
### Decompression
|
|
|
|
```zig
|
|
const lzma2 = std.compress.lzma2;
|
|
|
|
var input: std.Io.Reader = .fixed(compressed_data);
|
|
var output: std.Io.Writer.Allocating = .init(allocator);
|
|
defer output.deinit();
|
|
var decode = try lzma2.Decode.init(allocator);
|
|
defer decode.deinit(allocator);
|
|
_ = try decode.decompress(&input, &output);
|
|
```
|
|
|
|
## XZ
|
|
|
|
XZ format decompression (LZMA2 in a container with checksums).
|
|
|
|
### Decompression
|
|
|
|
```zig
|
|
const xz = std.compress.xz;
|
|
|
|
var decoder_buffer = try allocator.alloc(u8, 4096);
|
|
errdefer allocator.free(decoder_buffer);
|
|
var decompress: xz.Decompress = try .init(&reader, allocator, decoder_buffer);
|
|
defer decompress.deinit();
|
|
|
|
_ = try decompress.reader.streamRemaining(&output.writer);
|
|
```
|
|
|
|
### Check Types
|
|
|
|
XZ parses these integrity-check identifiers, but Zig 0.16 does not implement full XZ block-check verification. Do not treat successful decoding as verification of CRC32, CRC64, or SHA-256 block checks:
|
|
|
|
```zig
|
|
pub const Check = enum(u4) {
|
|
none = 0x00,
|
|
crc32 = 0x01,
|
|
crc64 = 0x04,
|
|
sha256 = 0x0A,
|
|
_,
|
|
};
|
|
```
|
|
|
|
## Common Patterns
|
|
|
|
### Decompress gzip File
|
|
|
|
```zig
|
|
fn decompressGzip(allocator: Allocator, compressed: []const u8) ![]u8 {
|
|
const flate = std.compress.flate;
|
|
|
|
var input: std.Io.Reader = .fixed(compressed);
|
|
var output: std.Io.Writer.Allocating = .init(allocator);
|
|
errdefer output.deinit();
|
|
|
|
var decompress: flate.Decompress = .init(&input, .gzip, &.{});
|
|
_ = try decompress.reader.streamRemaining(&output.writer);
|
|
|
|
return output.toOwnedSlice();
|
|
}
|
|
```
|
|
|
|
### Decompress zlib Data
|
|
|
|
```zig
|
|
fn decompressZlib(allocator: Allocator, compressed: []const u8) ![]u8 {
|
|
const flate = std.compress.flate;
|
|
|
|
var input: std.Io.Reader = .fixed(compressed);
|
|
var output: std.Io.Writer.Allocating = .init(allocator);
|
|
errdefer output.deinit();
|
|
|
|
var decompress: flate.Decompress = .init(&input, .zlib, &.{});
|
|
_ = try decompress.reader.streamRemaining(&output.writer);
|
|
|
|
return output.toOwnedSlice();
|
|
}
|
|
```
|
|
|
|
### Decompress Zstandard
|
|
|
|
```zig
|
|
fn decompressZstd(allocator: Allocator, compressed: []const u8) ![]u8 {
|
|
const zstd = std.compress.zstd;
|
|
|
|
var input: std.Io.Reader = .fixed(compressed);
|
|
var output: std.Io.Writer.Allocating = .init(allocator);
|
|
errdefer output.deinit();
|
|
|
|
var decompress: zstd.Decompress = .init(&input, &.{}, .{});
|
|
_ = try decompress.reader.streamRemaining(&output.writer);
|
|
|
|
return output.toOwnedSlice();
|
|
}
|
|
```
|
|
|
|
### Stream Decompression to File
|
|
|
|
```zig
|
|
fn decompressToFile(
|
|
io: std.Io,
|
|
input_path: []const u8,
|
|
output_path: []const u8,
|
|
container: std.compress.flate.Container,
|
|
) !void {
|
|
const flate = std.compress.flate;
|
|
|
|
const input_file = try std.Io.Dir.cwd().openFile(io, input_path, .{});
|
|
defer input_file.close(io);
|
|
|
|
const output_file = try std.Io.Dir.cwd().createFile(io, output_path, .{});
|
|
defer output_file.close(io);
|
|
|
|
var input_buf: [4096]u8 = undefined;
|
|
var input_reader = input_file.reader(io, &input_buf);
|
|
|
|
var output_buf: [4096]u8 = undefined;
|
|
var output_writer = output_file.writer(io, &output_buf);
|
|
|
|
var decompress: flate.Decompress = .init(&input_reader.interface, container, &.{});
|
|
_ = try decompress.reader.streamRemaining(&output_writer.interface);
|
|
try output_writer.interface.flush();
|
|
}
|
|
```
|
|
|
|
### Detect Compression Format
|
|
|
|
```zig
|
|
fn detectFormat(data: []const u8) ?enum { gzip, zlib, zstd, xz } {
|
|
if (data.len < 2) return null;
|
|
|
|
// gzip: 0x1f 0x8b
|
|
if (data[0] == 0x1f and data[1] == 0x8b) return .gzip;
|
|
|
|
// zlib: CMF byte with CM=8, CINFO<=7
|
|
const cmf = data[0];
|
|
if ((cmf & 0x0f) == 8 and (cmf >> 4) <= 7) {
|
|
// Check FCHECK makes header divisible by 31
|
|
const header: u16 = (@as(u16, data[0]) << 8) | data[1];
|
|
if (header % 31 == 0) return .zlib;
|
|
}
|
|
|
|
// zstd: magic 0xFD2FB528
|
|
if (data.len >= 4) {
|
|
const magic = std.mem.readInt(u32, data[0..4], .little);
|
|
if (magic == 0xFD2FB528) return .zstd;
|
|
}
|
|
|
|
// xz: magic 0xFD377A585A00
|
|
if (data.len >= 6) {
|
|
if (std.mem.eql(u8, data[0..6], &.{ 0xFD, '7', 'z', 'X', 'Z', 0x00 })) return .xz;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
```
|
|
|
|
## Error Types
|
|
|
|
### DEFLATE Errors
|
|
|
|
```zig
|
|
pub const Error = Container.Error || error{
|
|
InvalidCode,
|
|
InvalidMatch,
|
|
WrongStoredBlockNlen,
|
|
InvalidBlockType,
|
|
InvalidDynamicBlockHeader,
|
|
ReadFailed,
|
|
OversubscribedHuffmanTree,
|
|
IncompleteHuffmanTree,
|
|
MissingEndOfBlockCode,
|
|
EndOfStream,
|
|
};
|
|
|
|
pub const Container.Error = error{
|
|
BadGzipHeader,
|
|
BadZlibHeader,
|
|
WrongGzipChecksum,
|
|
WrongGzipSize,
|
|
WrongZlibChecksum,
|
|
};
|
|
```
|
|
|
|
### Zstandard Errors
|
|
|
|
```zig
|
|
pub const Error = error{
|
|
BadMagic,
|
|
BlockOversize,
|
|
ChecksumFailure,
|
|
ContentOversize,
|
|
DictionaryIdFlagUnsupported,
|
|
EndOfStream,
|
|
HuffmanTreeIncomplete,
|
|
InvalidBitStream,
|
|
MalformedAccuracyLog,
|
|
MalformedBlock,
|
|
MalformedCompressedBlock,
|
|
MalformedFrame,
|
|
MalformedFseBits,
|
|
MalformedFseTable,
|
|
MalformedHuffmanTree,
|
|
MalformedLiteralsHeader,
|
|
MalformedLiteralsLength,
|
|
MalformedLiteralsSection,
|
|
MalformedSequence,
|
|
MissingStartBit,
|
|
OutputBufferUndersize,
|
|
InputBufferUndersize,
|
|
ReadFailed,
|
|
RepeatModeFirst,
|
|
ReservedBitSet,
|
|
ReservedBlock,
|
|
SequenceBufferUndersize,
|
|
TreelessLiteralsFirst,
|
|
UnexpectedEndOfLiteralStream,
|
|
WindowOversize,
|
|
WindowSizeUnknown,
|
|
};
|
|
```
|
|
|
|
## Supported Features
|
|
|
|
**DEFLATE (flate)**:
|
|
- Decompression: gzip, zlib, raw deflate
|
|
- Compression: gzip, zlib, raw deflate (levels 1-9)
|
|
- Streaming with history buffer
|
|
|
|
**Zstandard (zstd)**:
|
|
- Decompression only
|
|
- Skippable frames
|
|
- Configurable window size
|
|
- Dictionary support: Not implemented
|
|
|
|
**LZMA/LZMA2**:
|
|
- Decompression only
|
|
- Streaming interface
|
|
- Memory limit configuration
|
|
|
|
**XZ**:
|
|
- Decompression only
|
|
- CRC32/CRC64/SHA256 check IDs are parsed; full block-check verification is incomplete
|
|
- Multiple block support
|