Skip to content

Make std.zip more flexible and easier to use #24102

Open
@echoptic

Description

@echoptic

std.zip doesn't make it easy to find an entry by path, also there is no easy way to extract a single entry. I think that std.zip should have a helper function to find and extract an entry by path. I made a helper function in my project that finds an entry and writes the contents to a writer. This is just an example, but i think that a similar function should exist in the stdlib. There is no reason that people should use an external zip library or implement this every time they need to read a zip file because most of the work is already implemented in the stdlib.

fn readZipEntry(it: anytype, path: []const u8, writer: anytype) !void {
    it.cd_record_index = 0;
    it.cd_record_offset = 0;
    const stream = it.stream;

    var filename_buf: [std.fs.max_path_bytes]u8 = undefined;
    while (try it.next()) |entry| {
        const filename = filename_buf[0..entry.filename_len];
        try stream.seekTo(entry.header_zip_offset + @sizeOf(std.zip.CentralDirectoryFileHeader));
        try stream.context.reader().readNoEof(filename);
        if (!mem.eql(u8, filename, path)) continue;

        const local_header = blk: {
            try stream.seekTo(entry.file_offset);
            break :blk try stream.context.reader().readStructEndian(std.zip.LocalFileHeader, .little);
        };
        const local_data_header_offset = @as(u64, local_header.filename_len) + @as(u64, local_header.extra_len);
        const local_data_file_offset = @as(u64, entry.file_offset) + @as(u64, @sizeOf(std.zip.LocalFileHeader)) + local_data_header_offset;
        try stream.seekTo(local_data_file_offset);
        var lr = std.io.limitedReader(stream.context.reader(), entry.compressed_size);
        const crc32 = try std.zip.decompress(
            entry.compression_method,
            entry.uncompressed_size,
            lr.reader(),
            writer,
        );
        _ = crc32;
        return;
    }
    return error.EntryNotFound;
}

    var it = try std.zip.Iterator(@TypeOf(stream)).init(stream);

    var list = std.ArrayList(u8).init(gpa);
    defer list.deinit();
    const writer = list.writer();

    try readZipEntry(&it, "java/lang/Object.class", writer);
    std.debug.print("{}\n", .{list.items.len});
    list.clearRetainingCapacity();

    try readZipEntry(&it, "java/lang/String.class", writer);
    std.debug.print("{}\n", .{list.items.len});
    list.clearRetainingCapacity();

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementSolving this issue will likely involve adding new logic or components to the codebase.standard libraryThis issue involves writing Zig code for the standard library.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions