feature. See also
. The project being documented here (as the example) is the Zig library itself.
res.NameOrOrdinal
pub const NameOrOrdinal = union(enum)
File
Code
pub const NameOrOrdinal = union(enum) {
name: [:0]const u16,
ordinal: u16,
pub fn deinit(self: NameOrOrdinal, allocator: Allocator) void {
switch (self) {
.name => |name| {
allocator.free(name);
},
.ordinal => {},
}
}
pub fn byteLen(self: NameOrOrdinal) usize {
switch (self) {
.name => |name| {
return (name.len + 1) * @sizeOf(u16);
},
.ordinal => return 4,
}
}
pub fn write(self: NameOrOrdinal, writer: *std.Io.Writer) !void {
switch (self) {
.name => |name| {
try writer.writeAll(std.mem.sliceAsBytes(name[0 .. name.len + 1]));
},
.ordinal => |ordinal| {
try writer.writeInt(u16, 0xffff, .little);
try writer.writeInt(u16, ordinal, .little);
},
}
}
pub fn writeEmpty(writer: *std.Io.Writer) !void {
try writer.writeInt(u16, 0, .little);
}
pub fn fromString(allocator: Allocator, bytes: SourceBytes) !NameOrOrdinal {
if (maybeOrdinalFromString(bytes)) |ordinal| {
return ordinal;
}
return nameFromString(allocator, bytes);
}
pub fn nameFromString(allocator: Allocator, bytes: SourceBytes) !NameOrOrdinal {
var buf = try std.ArrayList(u16).initCapacity(allocator, @min(257, bytes.slice.len));
errdefer buf.deinit(allocator);
var i: usize = 0;
while (bytes.code_page.codepointAt(i, bytes.slice)) |codepoint| : (i += codepoint.byte_len) {
if (buf.items.len == 256) break;
const c = codepoint.value;
if (c == Codepoint.invalid) {
try buf.append(allocator, std.mem.nativeToLittle(u16, '�'));
} else if (c < 0x7F) {
try buf.append(allocator, std.mem.nativeToLittle(u16, std.ascii.toUpper(@intCast(c))));
} else if (c < 0x10000) {
const short: u16 = @intCast(c);
try buf.append(allocator, std.mem.nativeToLittle(u16, short));
} else {
const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;
try buf.append(allocator, std.mem.nativeToLittle(u16, high));
// i.e. it can make the string end with an unpaired high surrogate
if (buf.items.len == 256) break;
const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;
try buf.append(allocator, std.mem.nativeToLittle(u16, low));
}
}
return NameOrOrdinal{ .name = try buf.toOwnedSliceSentinel(allocator, 0) };
}
pub fn maybeOrdinalFromString(bytes: SourceBytes) ?NameOrOrdinal {
var buf = bytes.slice;
var radix: u8 = 10;
if (buf.len > 2 and buf[0] == '0') {
switch (buf[1]) {
'0'...'9' => {},
'x', 'X' => {
radix = 16;
buf = buf[2..];
// i.e. 0x12345 is treated as if it were 0x1234
buf.len = @min(buf.len, 4);
},
else => return null,
}
}
var i: usize = 0;
var result: u16 = 0;
while (bytes.code_page.codepointAt(i, buf)) |codepoint| : (i += codepoint.byte_len) {
const c = codepoint.value;
const digit: u8 = switch (c) {
0x00...0x7F => std.fmt.charToDigit(@intCast(c), radix) catch switch (radix) {
10 => return null,
// the number (note: if there are no valid hex digits then the result
// will be zero which is not treated as a valid number)
16 => break,
else => unreachable,
},
else => if (radix == 10) return null else break,
};
if (result != 0) {
result *%= radix;
}
result +%= digit;
}
if (result == 0) return null;
return NameOrOrdinal{ .ordinal = result };
}
pub fn maybeNonAsciiOrdinalFromString(bytes: SourceBytes) ?NameOrOrdinal {
const buf = bytes.slice;
const radix = 10;
if (buf.len > 2 and buf[0] == '0') {
switch (buf[1]) {
'x', 'X' => return null,
else => {},
}
}
var i: usize = 0;
var result: u16 = 0;
while (bytes.code_page.codepointAt(i, buf)) |codepoint| : (i += codepoint.byte_len) {
const c = codepoint.value;
const digit: u16 = digit: {
const is_digit = (c >= '0' and c <= '9') or isNonAsciiDigit(c);
if (!is_digit) return null;
break :digit @intCast(c - '0');
};
if (result != 0) {
result *%= radix;
}
result +%= digit;
}
if (result == 0) return null;
return NameOrOrdinal{ .ordinal = result };
}
pub fn predefinedResourceType(self: NameOrOrdinal) ?RT {
switch (self) {
.ordinal => |ordinal| {
if (ordinal >= 256) return null;
switch (@as(RT, @fromBackingInt(@intCast(ordinal)))) {
.ACCELERATOR,
.ANICURSOR,
.ANIICON,
.BITMAP,
.CURSOR,
.DIALOG,
.DLGINCLUDE,
.DLGINIT,
.FONT,
.FONTDIR,
.GROUP_CURSOR,
.GROUP_ICON,
.HTML,
.ICON,
.MANIFEST,
.MENU,
.MESSAGETABLE,
.PLUGPLAY,
.RCDATA,
.STRING,
.TOOLBAR,
.VERSION,
.VXD,
=> |rt| return rt,
_ => return null,
}
},
.name => return null,
}
}
pub fn format(self: NameOrOrdinal, w: *std.Io.Writer) !void {
switch (self) {
.name => |name| {
try w.print("{f}", .{std.unicode.fmtUtf16Le(name)});
},
.ordinal => |ordinal| {
try w.print("{d}", .{ordinal});
},
}
}
fn formatResourceType(self: NameOrOrdinal, w: *std.Io.Writer) std.Io.Writer.Error!void {
switch (self) {
.name => |name| {
try w.print("{f}", .{std.unicode.fmtUtf16Le(name)});
},
.ordinal => |ordinal| {
if (std.enums.tagName(RT, @fromBackingInt(@intCast(ordinal)))) |predefined_type_name| {
try w.print("{s}", .{predefined_type_name});
} else {
try w.print("{d}", .{ordinal});
}
},
}
}
pub fn fmtResourceType(type_value: NameOrOrdinal) std.fmt.Alt(NameOrOrdinal, formatResourceType) {
return .{ .data = type_value };
}
}