feature. See also
. The project being documented here (as the example) is the Zig library itself.
File
Code
const std = @import("std");
const utils = @import("utils.zig");
const res = @import("res.zig");
const SourceBytes = @import("literals.zig").SourceBytes;
pub const ResourceType = enum {
accelerators,
bitmap,
cursor,
dialog,
dialogex,
dlginclude,
dlginit,
font,
html,
icon,
menu,
menuex,
messagetable,
plugplay,
rcdata,
stringtable,
toolbar,
user_defined,
versioninfo,
vxd,
// Types that are treated as a user-defined type when encountered, but have
// special meaning without the Visual Studio GUI. We match the Win32 RC compiler
// behavior by acting as if these keyword don't exist when compiling the .rc
// (thereby treating them as user-defined).
//textinclude, // A special resource that is interpreted by Visual C++.
//typelib, // A special resource that is used with the /TLBID and /TLBOUT linker options
// Types that can only be specified by numbers, they don't have keywords
cursor_num,
icon_num,
string_num,
anicursor_num,
aniicon_num,
fontdir_num,
manifest_num,
const map = std.StaticStringMapWithEql(
ResourceType,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "ACCELERATORS", .accelerators },
.{ "BITMAP", .bitmap },
.{ "CURSOR", .cursor },
.{ "DIALOG", .dialog },
.{ "DIALOGEX", .dialogex },
.{ "DLGINCLUDE", .dlginclude },
.{ "DLGINIT", .dlginit },
.{ "FONT", .font },
.{ "HTML", .html },
.{ "ICON", .icon },
.{ "MENU", .menu },
.{ "MENUEX", .menuex },
.{ "MESSAGETABLE", .messagetable },
.{ "PLUGPLAY", .plugplay },
.{ "RCDATA", .rcdata },
.{ "STRINGTABLE", .stringtable },
.{ "TOOLBAR", .toolbar },
.{ "VERSIONINFO", .versioninfo },
.{ "VXD", .vxd },
});
pub fn fromString(bytes: SourceBytes) ResourceType {
const maybe_ordinal = res.NameOrOrdinal.maybeOrdinalFromString(bytes);
if (maybe_ordinal) |ordinal| {
if (ordinal.ordinal >= 256) return .user_defined;
return fromRT(@fromBackingInt(@intCast(ordinal.ordinal)));
}
return map.get(bytes.slice) orelse .user_defined;
}
pub fn fromRT(rt: res.RT) ResourceType {
return switch (rt) {
.ACCELERATOR => .accelerators,
.ANICURSOR => .anicursor_num,
.ANIICON => .aniicon_num,
.BITMAP => .bitmap,
.CURSOR => .cursor_num,
.DIALOG => .dialog,
.DLGINCLUDE => .dlginclude,
.DLGINIT => .dlginit,
.FONT => .font,
.FONTDIR => .fontdir_num,
.GROUP_CURSOR => .cursor,
.GROUP_ICON => .icon,
.HTML => .html,
.ICON => .icon_num,
.MANIFEST => .manifest_num,
.MENU => .menu,
.MESSAGETABLE => .messagetable,
.PLUGPLAY => .plugplay,
.RCDATA => .rcdata,
.STRING => .string_num,
.TOOLBAR => .toolbar,
.VERSION => .versioninfo,
.VXD => .vxd,
_ => .user_defined,
};
}
pub fn canUseRawData(resource: ResourceType) bool {
return switch (resource) {
.user_defined,
.html,
.plugplay,
.rcdata,
.vxd,
.manifest_num,
.dlginit,
=> true,
else => false,
};
}
pub fn nameForErrorDisplay(resource: ResourceType) []const u8 {
return switch (resource) {
.accelerators, .bitmap, .cursor, .dialog, .dialogex, .dlginclude, .dlginit, .font,
.html, .icon, .menu, .menuex, .messagetable, .plugplay, .rcdata, .stringtable,
.toolbar, .versioninfo, .vxd => @tagName(resource),
.user_defined => "user-defined",
.cursor_num => std.fmt.comptimePrint("{d} (cursor)", .{@backingInt(res.RT.CURSOR)}),
.icon_num => std.fmt.comptimePrint("{d} (icon)", .{@backingInt(res.RT.ICON)}),
.string_num => std.fmt.comptimePrint("{d} (string)", .{@backingInt(res.RT.STRING)}),
.anicursor_num => std.fmt.comptimePrint("{d} (anicursor)", .{@backingInt(res.RT.ANICURSOR)}),
.aniicon_num => std.fmt.comptimePrint("{d} (aniicon)", .{@backingInt(res.RT.ANIICON)}),
.fontdir_num => std.fmt.comptimePrint("{d} (fontdir)", .{@backingInt(res.RT.FONTDIR)}),
.manifest_num => std.fmt.comptimePrint("{d} (manifest)", .{@backingInt(res.RT.MANIFEST)}),
};
}
};
pub const OptionalStatements = enum {
characteristics,
language,
version,
caption,
class,
exstyle,
font,
menu,
style,
pub const map = std.StaticStringMapWithEql(
OptionalStatements,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "CHARACTERISTICS", .characteristics },
.{ "LANGUAGE", .language },
.{ "VERSION", .version },
});
pub const dialog_map = std.StaticStringMapWithEql(
OptionalStatements,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "CAPTION", .caption },
.{ "CLASS", .class },
.{ "EXSTYLE", .exstyle },
.{ "FONT", .font },
.{ "MENU", .menu },
.{ "STYLE", .style },
});
};
pub const Control = enum {
auto3state,
autocheckbox,
autoradiobutton,
checkbox,
combobox,
control,
ctext,
defpushbutton,
edittext,
hedit,
iedit,
groupbox,
icon,
listbox,
ltext,
pushbox,
pushbutton,
radiobutton,
rtext,
scrollbar,
state3,
userbutton,
pub const map = std.StaticStringMapWithEql(
Control,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "AUTO3STATE", .auto3state },
.{ "AUTOCHECKBOX", .autocheckbox },
.{ "AUTORADIOBUTTON", .autoradiobutton },
.{ "CHECKBOX", .checkbox },
.{ "COMBOBOX", .combobox },
.{ "CONTROL", .control },
.{ "CTEXT", .ctext },
.{ "DEFPUSHBUTTON", .defpushbutton },
.{ "EDITTEXT", .edittext },
.{ "HEDIT", .hedit },
.{ "IEDIT", .iedit },
.{ "GROUPBOX", .groupbox },
.{ "ICON", .icon },
.{ "LISTBOX", .listbox },
.{ "LTEXT", .ltext },
.{ "PUSHBOX", .pushbox },
.{ "PUSHBUTTON", .pushbutton },
.{ "RADIOBUTTON", .radiobutton },
.{ "RTEXT", .rtext },
.{ "SCROLLBAR", .scrollbar },
.{ "STATE3", .state3 },
.{ "USERBUTTON", .userbutton },
});
pub fn hasTextParam(control: Control) bool {
switch (control) {
.scrollbar, .listbox, .iedit, .hedit, .edittext, .combobox => return false,
else => return true,
}
}
};
pub const ControlClass = struct {
pub const map = std.StaticStringMapWithEql(
res.ControlClass,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "BUTTON", .button },
.{ "EDIT", .edit },
.{ "STATIC", .static },
.{ "LISTBOX", .listbox },
.{ "SCROLLBAR", .scrollbar },
.{ "COMBOBOX", .combobox },
});
pub fn fromWideString(str: []const u16) ?res.ControlClass {
const utf16Literal = std.unicode.utf8ToUtf16LeStringLiteral;
return if (ascii.eqlIgnoreCaseW(str, utf16Literal("BUTTON")))
.button
else if (ascii.eqlIgnoreCaseW(str, utf16Literal("EDIT")))
.edit
else if (ascii.eqlIgnoreCaseW(str, utf16Literal("STATIC")))
.static
else if (ascii.eqlIgnoreCaseW(str, utf16Literal("LISTBOX")))
.listbox
else if (ascii.eqlIgnoreCaseW(str, utf16Literal("SCROLLBAR")))
.scrollbar
else if (ascii.eqlIgnoreCaseW(str, utf16Literal("COMBOBOX")))
.combobox
else
null;
}
};
const ascii = struct {
pub fn eqlIgnoreCaseW(a: []const u16, b: []const u16) bool {
if (a.len != b.len) return false;
for (a, b) |a_c, b_c| {
if (a_c < 128) {
if (std.ascii.toLower(@intCast(a_c)) != std.ascii.toLower(@intCast(b_c))) return false;
} else {
if (a_c != b_c) return false;
}
}
return true;
}
};
pub const MenuItem = enum {
menuitem,
popup,
pub const map = std.StaticStringMapWithEql(
MenuItem,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "MENUITEM", .menuitem },
.{ "POPUP", .popup },
});
pub fn isSeparator(bytes: []const u8) bool {
return std.ascii.eqlIgnoreCase(bytes, "SEPARATOR");
}
pub const Option = enum {
checked,
grayed,
help,
inactive,
menubarbreak,
menubreak,
pub const map = std.StaticStringMapWithEql(
Option,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "CHECKED", .checked },
.{ "GRAYED", .grayed },
.{ "HELP", .help },
.{ "INACTIVE", .inactive },
.{ "MENUBARBREAK", .menubarbreak },
.{ "MENUBREAK", .menubreak },
});
};
};
pub const ToolbarButton = enum {
button,
separator,
pub const map = std.StaticStringMapWithEql(
ToolbarButton,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "BUTTON", .button },
.{ "SEPARATOR", .separator },
});
};
pub const VersionInfo = enum {
file_version,
product_version,
file_flags_mask,
file_flags,
file_os,
file_type,
file_subtype,
pub const map = std.StaticStringMapWithEql(
VersionInfo,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "FILEVERSION", .file_version },
.{ "PRODUCTVERSION", .product_version },
.{ "FILEFLAGSMASK", .file_flags_mask },
.{ "FILEFLAGS", .file_flags },
.{ "FILEOS", .file_os },
.{ "FILETYPE", .file_type },
.{ "FILESUBTYPE", .file_subtype },
});
};
pub const VersionBlock = enum {
block,
value,
pub const map = std.StaticStringMapWithEql(
VersionBlock,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "BLOCK", .block },
.{ "VALUE", .value },
});
};
pub const TopLevelKeywords = enum {
language,
version,
characteristics,
stringtable,
pub const map = std.StaticStringMapWithEql(
TopLevelKeywords,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "LANGUAGE", .language },
.{ "VERSION", .version },
.{ "CHARACTERISTICS", .characteristics },
.{ "STRINGTABLE", .stringtable },
});
};
pub const CommonResourceAttributes = enum {
preload,
loadoncall,
fixed,
moveable,
discardable,
pure,
impure,
shared,
nonshared,
pub const map = std.StaticStringMapWithEql(
CommonResourceAttributes,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "PRELOAD", .preload },
.{ "LOADONCALL", .loadoncall },
.{ "FIXED", .fixed },
.{ "MOVEABLE", .moveable },
.{ "DISCARDABLE", .discardable },
.{ "PURE", .pure },
.{ "IMPURE", .impure },
.{ "SHARED", .shared },
.{ "NONSHARED", .nonshared },
});
};
pub const AcceleratorTypeAndOptions = enum {
virtkey,
ascii,
noinvert,
alt,
shift,
control,
pub const map = std.StaticStringMapWithEql(
AcceleratorTypeAndOptions,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
.{ "VIRTKEY", .virtkey },
.{ "ASCII", .ascii },
.{ "NOINVERT", .noinvert },
.{ "ALT", .alt },
.{ "SHIFT", .shift },
.{ "CONTROL", .control },
});
};