feature. See also
. The project being documented here (as the example) is the Zig library itself.
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);
// 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);
if (@as(u64, entry.data_offset_from_start_of_file) + entry.data_size_in_bytes > max_size) {
return error.ImpossibleDataSize;
}
// 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,
};
}