// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie // SPDX-License-Identifier: MIT //! Writes the ProductCode of harrier's MSI, for the winget manifest: //! `product_code PROPERTY.idt OUT`, where the first is the MSI's Property //! table as `zixl-info export` writes it. What it writes is the GUID alone, //! braces and all, and nothing that does not look like one. const std = @import("std"); const Io = std.Io; pub fn main(init: std.process.Init) !void { const arena = init.arena.allocator(); const io = init.io; const args = try init.minimal.args.toSlice(arena); if (args.len != 3) fail("usage: product_code PROPERTY.idt OUT", .{}); const cwd = Io.Dir.cwd(); const table = try cwd.readFileAlloc(io, args[1], arena, .limited(1024 * 1024)); const code = productCode(table) orelse fail("{s}: no ProductCode that looks like one", .{args[1]}); try cwd.writeFile(io, .{ .sub_path = args[2], .data = try std.fmt.allocPrint(arena, "{s}\n", .{code}) }); } /// The ProductCode row's value, if it is a GUID in the form Windows /// Installer writes: braces, upper case. fn productCode(table: []const u8) ?[]const u8 { var lines = std.mem.splitScalar(u8, table, '\n'); while (lines.next()) |raw| { const line = std.mem.trimEnd(u8, raw, "\r"); const tab = std.mem.findScalar(u8, line, '\t') orelse continue; if (!std.mem.eql(u8, line[0..tab], "ProductCode")) continue; const value = line[tab + 1 ..]; return if (isGuid(value)) value else null; } return null; } fn isGuid(s: []const u8) bool { const shape = "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"; if (s.len != shape.len) return false; for (s, shape) |c, want| switch (want) { 'X' => switch (c) { '0'...'9', 'A'...'F' => {}, else => return false, }, else => if (c != want) return false, }; return true; } fn fail(comptime fmt: []const u8, args: anytype) noreturn { std.log.err(fmt, args); std.process.exit(1); } test productCode { const table = "Property\tValue\r\ns72\tl0\r\nProperty\tProperty\r\n" ++ "UpgradeCode\t{E52BBA9C-2A77-4969-9762-41CFD1F050D2}\r\n" ++ "ProductCode\t{435EA6C4-73F3-5440-BE73-EF4B3376479B}\r\n"; try std.testing.expectEqualStrings("{435EA6C4-73F3-5440-BE73-EF4B3376479B}", productCode(table).?); try std.testing.expectEqual(null, productCode("Property\tValue\nProductCode\tnot-a-guid\n")); try std.testing.expectEqual(null, productCode("Property\tValue\nUpgradeCode\t{E52BBA9C-2A77-4969-9762-41CFD1F050D2}\n")); }