Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

readInner

ico.readInner
fn readInner(allocator: std.mem.Allocator, reader: *std.Io.Reader, max_size: u64) !IconDir

File

Code

fn readInner(allocator: std.mem.Allocator, reader: *std.Io.Reader, max_size: u64) !IconDir {
    const reserved = try reader.takeInt(u16, .little);
    if (reserved != 0) {
        return error.InvalidHeader;
    }

    const image_type = reader.takeEnum(ImageType, .little) catch |err| switch (err) {
        error.InvalidEnumTag => return error.InvalidImageType,
        else => |e| return e,
    };

    const num_images = try reader.takeInt(u16, .little);

    // To avoid over-allocation in the case of a file that says it has way more
    // entries than it actually does, we use an ArrayList with a conservatively
    // limited initial capacity instead of allocating the entire slice at once.
    const initial_capacity = @min(num_images, 8);
    var entries = try std.ArrayList(Entry).initCapacity(allocator, initial_capacity);
    errdefer entries.deinit(allocator);

    var i: usize = 0;
    while (i < num_images) : (i += 1) {
        var entry: Entry = undefined;
        entry.width = try reader.takeByte();
        entry.height = try reader.takeByte();
        entry.num_colors = try reader.takeByte();
        entry.reserved = try reader.takeByte();
        switch (image_type) {
            .icon => {
                entry.type_specific_data = .{ .icon = .{
                    .color_planes = try reader.takeInt(u16, .little),
                    .bits_per_pixel = try reader.takeInt(u16, .little),
                } };
            },
            .cursor => {
                entry.type_specific_data = .{ .cursor = .{
                    .hotspot_x = try reader.takeInt(u16, .little),
                    .hotspot_y = try reader.takeInt(u16, .little),
                } };
            },
        }
        entry.data_size_in_bytes = try reader.takeInt(u32, .little);
        entry.data_offset_from_start_of_file = try reader.takeInt(u32, .little);
        // Validate that the offset/data size is feasible
        if (@as(u64, entry.data_offset_from_start_of_file) + entry.data_size_in_bytes > max_size) {
            return error.ImpossibleDataSize;
        }
        // and that the data size is large enough for at least the header of an image
        // Note: This avoids needing to deal with a miscompilation from the Win32 RC
        //       compiler when the data size of an image is specified as zero but there
        //       is data to-be-read at the offset. The Win32 RC compiler will output
        //       an ICON/CURSOR resource with a bogus size in its header but with no actual
        //       data bytes in it, leading to an invalid .res. Similarly, if, for example,
        //       there is valid PNG data at the image's offset, but the size is specified
        //       as fewer bytes than the PNG header, then the Win32 RC compiler will still
        //       treat it as a PNG (e.g. unconditionally set num_planes to 1) but the data
        //       of the resource will only be 1 byte so treating it as a PNG doesn't make
        //       sense (especially not when you have to read past the data size to determine
        //       that it's a PNG).
        if (entry.data_size_in_bytes < 16) {
            return error.ImpossibleDataSize;
        }
        try entries.append(allocator, entry);
    }

    return .{
        .image_type = image_type,
        .entries = try entries.toOwnedSlice(allocator),
        .allocator = allocator,
    };
}