diff --git a/src/svg/icons.zig b/src/svg/icons.zig new file mode 100644 index 0000000..6a9b5d1 --- /dev/null +++ b/src/svg/icons.zig @@ -0,0 +1,111 @@ +const std = @import("std"); + +pub const IconSet = enum { + bootstrap, + dripicons, + hero_outline, + hero_solid, + material, +}; + +pub const embedded_data = std.EnumMap(IconSet, []const u8).init(.{ + .bootstrap = @embedFile("bootstrap.svgs.bin"), + .dripicons = @embedFile("dripicons.svgs.bin"), + .hero_outline = @embedFile("hero_outline.svgs.bin"), + .hero_solid = @embedFile("hero_solid.svgs.bin"), + .material = @embedFile("material.svgs.bin"), +}); + +pub const SvgIcon = struct { + icon_map: std.StringHashMapUnmanaged([]const u8) = .{}, + + pub fn init(allocator: std.mem.Allocator) !SvgIcon { + var self = SvgIcon{}; + + // const sets = [_]IconSet{ .bootstrap, .dripicons, .hero_outline, .hero_solid, .material }; + // + // inline for (sets) |set| { + // const data = embedded_data.get(set).?; + // + // try self.loadSet(allocator, set, data); + // } + // + + inline for (std.meta.fields(IconSet)) |field| { + const set = @field(IconSet, field.name); + const data = embedded_data.get(set); + + try self.loadSet(allocator, set, data.?); + } + + return self; + } + + pub fn deinit(self: *SvgIcon, allocator: std.mem.Allocator) void { + var it = self.icon_map.iterator(); + while (it.next()) |entry| { + allocator.free(entry.key_ptr.*); + allocator.free(entry.value_ptr.*); + } + self.icon_map.deinit(allocator); + self.* = .{}; + } + + pub fn get(self: *const SvgIcon, key: []const u8) ?[]const u8 { + return self.icon_map.get(key); + } + + pub fn count(self: *const SvgIcon) usize { + return self.icon_map.count(); + } + + fn loadSet( + self: *SvgIcon, + allocator: std.mem.Allocator, + set: IconSet, + data: []const u8, + ) !void { + if (data.len < 12) return error.InvalidEmbeddedData; + + var pos: usize = 0; + + const magic = std.mem.readInt(u32, data[pos..][0..4], .little); + pos += 4; + if (magic != 0x53564749) return error.InvalidMagic; + + const version = std.mem.readInt(u32, data[pos..][0..4], .little); + pos += 4; + if (version != 1) return error.UnsupportedVersion; + + const num_entries = std.mem.readInt(u32, data[pos..][0..4], .little); + pos += 4; + + const prefix = @tagName(set); + + var i: u32 = 0; + while (i < num_entries) : (i += 1) { + const name_len = std.mem.readInt(u32, data[pos..][0..4], .little); + pos += 4; + + if (pos + name_len > data.len) return error.CorruptedNameLength; + const name_slice = data[pos .. pos + name_len]; + pos += name_len; + + const svg_len = std.mem.readInt(u32, data[pos..][0..4], .little); + pos += 4; + + if (pos + svg_len > data.len) return error.CorruptedSvgLength; + const svg_slice = data[pos .. pos + svg_len]; + pos += svg_len; + + // Monta a chave com prefixo do set + const key = try std.fmt.allocPrint(allocator, "{s}:{s}", .{ prefix, name_slice }); + + // Duplica o conteúdo SVG (o map assume ownership) + const value = try allocator.dupe(u8, svg_slice); + + // Insere no mapa unmanaged + try self.icon_map.put(allocator, key, value); + } + } +};