feature. See also
. The project being documented here (as the example) is the Zig library itself.
cvtres.writeCoff
pub fn writeCoff(
allocator: Allocator,
writer: *std.Io.Writer,
resources: []const Resource,
options: CoffOptions,
diagnostics: ?*Diagnostics,
) !void
File
Code
pub fn writeCoff(
allocator: Allocator,
writer: *std.Io.Writer,
resources: []const Resource,
options: CoffOptions,
diagnostics: ?*Diagnostics,
) !void {
var resource_tree = ResourceTree.init(allocator, options);
defer resource_tree.deinit();
for (resources, 0..) |*resource, i| {
resource_tree.put(resource, i) catch |err| {
switch (err) {
error.DuplicateResource => {
if (diagnostics) |d_ptr| d_ptr.* = .{ .duplicate_resource = i };
},
error.ResourceDataTooLong, error.TotalResourceDataTooLong => {
if (diagnostics) |d_ptr| d_ptr.* = .{ .overflow_resource = i };
},
else => {},
}
return err;
};
}
const lengths = resource_tree.dataLengths();
const byte_size_of_relocation = 10;
const relocations_len: u32 = @intCast(byte_size_of_relocation * resources.len);
const pointer_to_rsrc01_data = @sizeOf(std.coff.Header) + (@sizeOf(std.coff.SectionHeader) * 2);
const pointer_to_relocations = pointer_to_rsrc01_data + lengths.rsrc01;
const pointer_to_rsrc02_data = pointer_to_relocations + relocations_len;
const pointer_to_symbol_table = pointer_to_rsrc02_data + lengths.rsrc02;
const timestamp: i64 = options.timestamp;
const size_of_optional_header = 0;
const machine_type: std.coff.IMAGE.FILE.MACHINE = options.target;
const flags = std.coff.Header.Flags{
.@"32BIT_MACHINE" = true,
};
const number_of_symbols = 5 + @as(u32, @intCast(resources.len)) + @intFromBool(options.define_external_symbol != null);
const coff_header = std.coff.Header{
.machine = machine_type,
.number_of_sections = 2,
.time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))),
.pointer_to_symbol_table = pointer_to_symbol_table,
.number_of_symbols = number_of_symbols,
.size_of_optional_header = size_of_optional_header,
.flags = flags,
};
try writer.writeStruct(coff_header, .little);
const rsrc01_header = std.coff.SectionHeader{
.name = ".rsrc$01".*,
.virtual_size = 0,
.virtual_address = 0,
.size_of_raw_data = lengths.rsrc01,
.pointer_to_raw_data = pointer_to_rsrc01_data,
.pointer_to_relocations = if (relocations_len != 0) pointer_to_relocations else 0,
.pointer_to_linenumbers = 0,
.number_of_relocations = @intCast(resources.len),
.number_of_linenumbers = 0,
.flags = .{
.CNT_INITIALIZED_DATA = true,
.MEM_WRITE = !options.read_only,
.MEM_READ = true,
},
};
try writer.writeStruct(rsrc01_header, .little);
const rsrc02_header = std.coff.SectionHeader{
.name = ".rsrc$02".*,
.virtual_size = 0,
.virtual_address = 0,
.size_of_raw_data = lengths.rsrc02,
.pointer_to_raw_data = pointer_to_rsrc02_data,
.pointer_to_relocations = 0,
.pointer_to_linenumbers = 0,
.number_of_relocations = 0,
.number_of_linenumbers = 0,
.flags = .{
.CNT_INITIALIZED_DATA = true,
.MEM_WRITE = !options.read_only,
.MEM_READ = true,
},
};
try writer.writeStruct(rsrc02_header, .little);
try resource_tree.sort();
var string_table = StringTable{};
defer string_table.deinit(allocator);
const resource_symbols = try resource_tree.writeCoff(
allocator,
writer,
resources,
lengths,
&string_table,
);
defer allocator.free(resource_symbols);
try writeSymbol(writer, .{
.name = "@feat.00".*,
.value = 0x11,
.section_number = .ABSOLUTE,
.type = .{
.base_type = .NULL,
.complex_type = .NULL,
},
.storage_class = .STATIC,
.number_of_aux_symbols = 0,
});
try writeSymbol(writer, .{
.name = ".rsrc$01".*,
.value = 0,
.section_number = @fromBackingInt(@intCast(1)),
.type = .{
.base_type = .NULL,
.complex_type = .NULL,
},
.storage_class = .STATIC,
.number_of_aux_symbols = 1,
});
try writeSectionDefinition(writer, .{
.length = lengths.rsrc01,
.number_of_relocations = @intCast(resources.len),
.number_of_linenumbers = 0,
.checksum = 0,
.number = 0,
.selection = .NONE,
.unused = @splat(0),
});
try writeSymbol(writer, .{
.name = ".rsrc$02".*,
.value = 0,
.section_number = @fromBackingInt(@intCast(2)),
.type = .{
.base_type = .NULL,
.complex_type = .NULL,
},
.storage_class = .STATIC,
.number_of_aux_symbols = 1,
});
try writeSectionDefinition(writer, .{
.length = lengths.rsrc02,
.number_of_relocations = 0,
.number_of_linenumbers = 0,
.checksum = 0,
.number = 0,
.selection = .NONE,
.unused = @splat(0),
});
for (resource_symbols) |resource_symbol| {
try writeSymbol(writer, resource_symbol);
}
if (options.define_external_symbol) |external_symbol_name| {
const name_bytes: [8]u8 = name_bytes: {
if (external_symbol_name.len > 8) {
const string_table_offset: u32 = try string_table.put(allocator, external_symbol_name);
var bytes: [8]u8 = @splat(0);
std.mem.writeInt(u32, bytes[4..8], string_table_offset, .little);
break :name_bytes bytes;
} else {
var symbol_shortname: [8]u8 = @splat(0);
@memcpy(symbol_shortname[0..external_symbol_name.len], external_symbol_name);
break :name_bytes symbol_shortname;
}
};
try writeSymbol(writer, .{
.name = name_bytes,
.value = 0,
.section_number = .ABSOLUTE,
.type = .{
.base_type = .NULL,
.complex_type = .NULL,
},
.storage_class = .EXTERNAL,
.number_of_aux_symbols = 0,
});
}
try writer.writeInt(u32, string_table.totalByteLength(), .little);
try writer.writeAll(string_table.bytes.items);
}