Skip to content

Extracting

This guide covers extracting files from ZIGX archives.

Basic Extraction

zig
const zigx = @import("zigx");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Using the unbundle() alias (same as extract())
    try zigx.unbundle(.{
        .archive_path = "bundle.zigx",
        .output_dir = "extracted",
        .allocator = allocator,
    });

    std.debug.print("Extraction complete!\n", .{});
}

Extract Options

OptionTypeDescription
archive_path[]const u8Path to archive (required)
output_dir[]const u8Output directory (required)
allocatorAllocatorMemory allocator (required)
overwriteboolOverwrite existing files
validateboolVerify checksums (default: true)
progress_callback?ExtractProgressCallbackProgress tracking
progress_context?*anyopaqueCallback context

Progress Tracking

Track extraction progress with detailed events:

zig
fn onExtractProgress(info: zigx.ExtractProgressInfo, ctx: ?*anyopaque) void {
    _ = ctx;
    switch (info.event) {
        .started => std.debug.print("Starting extraction...\n", .{}),
        .reading_archive => std.debug.print("Reading archive header...\n", .{}),
        .decompressing => std.debug.print("Decompressing payload...\n", .{}),
        .extracting_file => {
            if (info.current_file) |file| {
                std.debug.print("\r[{d}/{d}] {d:.1}% - {s}", .{
                    info.files_extracted,
                    info.total_files,
                    info.getPercent(),
                    file,
                });
            }
        },
        .verifying => std.debug.print("\rVerifying checksums...", .{}),
        .completed => std.debug.print("\nExtraction complete!\n", .{}),
    }
}

try zigx.unbundle(.{
    .archive_path = "bundle.zigx",
    .output_dir = "extracted",
    .allocator = allocator,
    .progress_callback = onExtractProgress,
    .progress_context = null,  // Optional context pointer
});

Progress Events

EventDescription
startedExtraction operation started
reading_archiveReading archive header/metadata
decompressingDecompressing payload with zstd
extracting_fileWriting a file to disk
verifyingVerifying file checksums
completedExtraction finished

Progress Info Fields

FieldTypeDescription
eventExtractProgressEventCurrent operation
current_file?[]const u8Current file path
files_extractedusizeFiles completed
total_filesusizeTotal file count
bytes_writtenu64Bytes written
total_bytesu64Total bytes
getPercent()f64Progress 0-100%

Extract with Result

Get detailed information about the extraction:

zig
const result = try zigx.extractWithResult(.{
    .archive_path = "bundle.zigx",
    .output_dir = "extracted",
    .allocator = allocator,
});

std.debug.print(
    \\Extracted:
    \\  Files:       {d}
    \\  Total Size:  {d} bytes
    \\
, .{
    result.file_count,
    result.total_size,
});

Listing Files

List files without extracting:

zig
const files = try zigx.listFiles("bundle.zigx", allocator);
defer {
    for (files) |f| allocator.free(f);
    allocator.free(files);
}

std.debug.print("Files in archive:\n", .{});
for (files) |file| {
    std.debug.print("  - {s}\n", .{file});
}

Getting Archive Info

Read archive metadata before extracting:

zig
var info = try zigx.getArchiveInfo("bundle.zigx", allocator);
defer info.deinit();

std.debug.print(
    \\Archive Info:
    \\  Format Version:      v{d}
    \\  Compression Version: v{d}
    \\  Files:               {d}
    \\  Original Size:       {d} bytes
    \\  Compressed Size:     {d} bytes
    \\
, .{
    info.format_version,
    info.compression_version,
    info.file_count,
    info.original_size,
    info.compressed_size,
});

// Check metadata
var it = info.metadata.entries.iterator();
while (it.next()) |entry| {
    std.debug.print("  {s}: {s}\n", .{
        entry.key_ptr.*,
        entry.value_ptr.*,
    });
}

Validation Before Extraction

zig
// Quick validation
const is_valid = zigx.isValidArchive("bundle.zigx");
if (!is_valid) {
    std.debug.print("Invalid archive!\n", .{});
    return;
}

// Detailed validation
const validation = try zigx.validateDetailed("bundle.zigx", allocator);
if (!validation.is_valid) {
    std.debug.print("Validation failed:\n", .{});
    for (validation.errors) |err| {
        std.debug.print("  - {s}\n", .{err});
    }
    return;
}

// Safe to extract
try zigx.extract(.{
    .archive_path = "bundle.zigx",
    .output_dir = "extracted",
    .allocator = allocator,
});

Complete Example

zig
const std = @import("std");
const zigx = @import("zigx");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const archive_path = "bundle.zigx";
    const output_dir = "extracted";

    // Step 1: Validate archive
    if (!zigx.isValidArchive(archive_path)) {
        std.debug.print("Error: Invalid or corrupted archive\n", .{});
        return;
    }

    // Step 2: Get archive info
    var info = try zigx.getArchiveInfo(archive_path, allocator);
    defer info.deinit();

    std.debug.print(
        \\Extracting: {s}
        \\
        \\Archive Info:
        \\  Format:      v{d}
        \\  Compression: v{d}
        \\  Files:       {d}
        \\  Size:        {d} bytes -> {d} bytes
        \\
    , .{
        archive_path,
        info.format_version,
        info.compression_version,
        info.file_count,
        info.compressed_size,
        info.original_size,
    });

    // Step 3: Extract
    try zigx.extract(.{
        .archive_path = archive_path,
        .output_dir = output_dir,
        .allocator = allocator,
    });

    // Step 4: List extracted files
    const files = try zigx.listFiles(archive_path, allocator);
    defer {
        for (files) |f| allocator.free(f);
        allocator.free(files);
    }

    std.debug.print("\nExtracted to: {s}\n", .{output_dir});
    std.debug.print("\nFiles:\n", .{});
    for (files) |file| {
        std.debug.print("  - {s}\n", .{file});
    }
}

Error Handling

zig
zigx.extract(.{
    .archive_path = "bundle.zigx",
    .output_dir = "extracted",
    .allocator = allocator,
}) catch |err| switch (err) {
    error.FileNotFound => {
        std.debug.print("Error: Archive not found\n", .{});
    },
    error.InvalidFormat => {
        std.debug.print("Error: Invalid archive format\n", .{});
    },
    error.ChecksumMismatch => {
        std.debug.print("Error: Archive corrupted\n", .{});
    },
    error.AccessDenied => {
        std.debug.print("Error: Permission denied\n", .{});
    },
    else => {
        std.debug.print("Error: {any}\n", .{err});
    },
};

Next Steps

Released under the Apache License 2.0.