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.

FontDir

compile.FontDir
pub const FontDir = struct

File

lib/compiler/resinator/compile.zig:2943

Code

pub const FontDir = struct {
    fonts: std.ArrayList(Font) = .empty,
    /// To keep track of which ids are set and where they were set from
    ids: std.AutoHashMapUnmanaged(u16, Token) = .empty,

    pub const Font = struct {
        id: u16,
        header_bytes: [148]u8,
    };

    pub fn deinit(self: *FontDir, allocator: Allocator) void {
        self.fonts.deinit(allocator);
    }

    pub fn add(self: *FontDir, allocator: Allocator, font: Font, id_token: Token) !void {
        try self.ids.putNoClobber(allocator, font.id, id_token);
        try self.fonts.append(allocator, font);
    }

    pub fn writeResData(self: *FontDir, compiler: *Compiler, writer: *std.Io.Writer) !void {
        if (self.fonts.items.len == 0) return;

        // We know the number of fonts is limited to maxInt(u16) because fonts
        // must have a valid and unique u16 ordinal ID (trying to specify a FONT
        // with e.g. id 65537 will wrap around to 1 and be ignored if there's already
        // a font with that ID in the file).
        const num_fonts: u16 = @intCast(self.fonts.items.len);

        // u16 count + [(u16 id + 150 bytes) for each font]
        // Note: This works out to a maximum data_size of 9,961,322.
        const data_size: u32 = 2 + (2 + 150) * num_fonts;

        var header = Compiler.ResourceHeader{
            .name_value = try NameOrOrdinal.nameFromString(compiler.allocator, .{ .slice = "FONTDIR", .code_page = .windows1252 }),
            .type_value = NameOrOrdinal{ .ordinal = @backingInt(res.RT.FONTDIR) },
            .memory_flags = res.MemoryFlags.defaults(res.RT.FONTDIR),
            .language = compiler.state.language,
            .version = compiler.state.version,
            .characteristics = compiler.state.characteristics,
            .data_size = data_size,
        };
        defer header.deinit(compiler.allocator);

        try header.writeAssertNoOverflow(writer);
        try writer.writeInt(u16, num_fonts, .little);
        for (self.fonts.items) |font| {
            // The format of the FONTDIR is a strange beast.
            // Technically, each FONT is seemingly meant to be written as a
            // FONTDIRENTRY with two trailing NUL-terminated strings corresponding to
            // the 'device name' and 'face name' of the .FNT file, but:
            //
            // 1. When dealing with .FNT files, the Win32 implementation
            //    gets the device name and face name from the wrong locations,
            //    so it's basically never going to write the real device/face name
            //    strings.
            // 2. When dealing with files 76-140 bytes long, the Win32 implementation
            //    can just crash (if there are no NUL bytes in the file).
            // 3. The 32-bit Win32 rc.exe uses a 148 byte size for the portion of
            //    the FONTDIRENTRY before the NUL-terminated strings, which
            //    does not match the documented FONTDIRENTRY size that (presumably)
            //    this format is meant to be using, so anything iterating the
            //    FONTDIR according to the available documentation will get bogus results.
            // 4. The FONT resource can be used for non-.FNT types like TTF and OTF,
            //    in which case emulating the Win32 behavior of unconditionally
            //    interpreting the bytes as a .FNT and trying to grab device/face names
            //    from random bytes in the TTF/OTF file can lead to weird behavior
            //    and errors in the Win32 implementation (for example, the device/face
            //    name fields are offsets into the file where the NUL-terminated
            //    string is located, but the Win32 implementation actually treats
            //    them as signed so if they are negative then the Win32 implementation
            //    will error; this happening for TTF fonts would just be a bug
            //    since the TTF could otherwise be valid)
            // 5. The FONTDIR resource doesn't actually seem to be used at all by
            //    anything that I've found, and instead in Windows 3.0 and newer
            //    it seems like the FONT resources are always just iterated/accessed
            //    directly without ever looking at the FONTDIR.
            //
            // All of these combined means that we:
            // - Do not need or want to emulate Win32 behavior here
            // - For maximum simplicity and compatibility, we just write the first
            //   148 bytes of the file without any interpretation (padded with
            //   zeroes to get up to 148 bytes if necessary), and then
            //   unconditionally write two NUL bytes, meaning that we always
            //   write 'device name' and 'face name' as if they were 0-length
            //   strings.
            //
            // This gives us byte-for-byte .RES compatibility in the common case while
            // allowing us to avoid any erroneous errors caused by trying to read
            // the face/device name from a bogus location. Note that the Win32
            // implementation never actually writes the real device/face name here
            // anyway (except in the bizarre case that a .FNT file has the proper
            // device/face name offsets within a reserved section of the .FNT file)
            // so there's no feasible way that anything can actually think that the
            // device name/face name in the FONTDIR is reliable.

            // First, the ID is written, though
            try writer.writeInt(u16, font.id, .little);
            try writer.writeAll(&font.header_bytes);
            try writer.splatByteAll(0, 2);
        }
        try Compiler.writeDataPadding(writer, data_size);
    }
}