authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-08-27 20:33:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-28 18:30:57-07:00
log46b60dc06945152eee8280b8ff5b1e629ed74553
tree8166732fc4fa0f467ba018bf0f1811f2b7d1fe31
parent9b47dd2028deb45324ca19d909d0cee69f51f1b9

resinator: Complete the update to the new Reader/Writer


16 files changed, 472 insertions(+), 556 deletions(-)

lib/compiler/resinator/ani.zig+13-13
...@@ -16,31 +16,31 @@ const std = @import("std");...@@ -16,31 +16,31 @@ const std = @import("std");
1616
17const AF_ICON: u32 = 1;17const AF_ICON: u32 = 1;
1818
19pub fn isAnimatedIcon(reader: anytype) bool {19pub fn isAnimatedIcon(reader: *std.Io.Reader) bool {
20 const flags = getAniheaderFlags(reader) catch return false;20 const flags = getAniheaderFlags(reader) catch return false;
21 return flags & AF_ICON == AF_ICON;21 return flags & AF_ICON == AF_ICON;
22}22}
2323
24fn getAniheaderFlags(reader: anytype) !u32 {24fn getAniheaderFlags(reader: *std.Io.Reader) !u32 {
25 const riff_header = try reader.readBytesNoEof(4);25 const riff_header = try reader.takeArray(4);
26 if (!std.mem.eql(u8, &riff_header, "RIFF")) return error.InvalidFormat;26 if (!std.mem.eql(u8, riff_header, "RIFF")) return error.InvalidFormat;
2727
28 _ = try reader.readInt(u32, .little); // size of RIFF chunk28 _ = try reader.takeInt(u32, .little); // size of RIFF chunk
2929
30 const form_type = try reader.readBytesNoEof(4);30 const form_type = try reader.takeArray(4);
31 if (!std.mem.eql(u8, &form_type, "ACON")) return error.InvalidFormat;31 if (!std.mem.eql(u8, form_type, "ACON")) return error.InvalidFormat;
3232
33 while (true) {33 while (true) {
34 const chunk_id = try reader.readBytesNoEof(4);34 const chunk_id = try reader.takeArray(4);
35 const chunk_len = try reader.readInt(u32, .little);35 const chunk_len = try reader.takeInt(u32, .little);
36 if (!std.mem.eql(u8, &chunk_id, "anih")) {36 if (!std.mem.eql(u8, chunk_id, "anih")) {
37 // TODO: Move file cursor instead of skipBytes37 // TODO: Move file cursor instead of skipBytes
38 try reader.skipBytes(chunk_len, .{});38 try reader.discardAll(chunk_len);
39 continue;39 continue;
40 }40 }
4141
42 const aniheader = try reader.readStruct(ANIHEADER);42 const aniheader = try reader.takeStruct(ANIHEADER, .little);
43 return std.mem.nativeToLittle(u32, aniheader.flags);43 return aniheader.flags;
44 }44 }
45}45}
4646
lib/compiler/resinator/ast.zig+40-40
...@@ -22,13 +22,13 @@ pub const Tree = struct {...@@ -22,13 +22,13 @@ pub const Tree = struct {
22 return @alignCast(@fieldParentPtr("base", self.node));22 return @alignCast(@fieldParentPtr("base", self.node));
23 }23 }
2424
25 pub fn dump(self: *Tree, writer: anytype) @TypeOf(writer).Error!void {25 pub fn dump(self: *Tree, writer: *std.io.Writer) !void {
26 try self.node.dump(self, writer, 0);26 try self.node.dump(self, writer, 0);
27 }27 }
28};28};
2929
30pub const CodePageLookup = struct {30pub const CodePageLookup = struct {
31 lookup: std.ArrayListUnmanaged(SupportedCodePage) = .empty,31 lookup: std.ArrayList(SupportedCodePage) = .empty,
32 allocator: Allocator,32 allocator: Allocator,
33 default_code_page: SupportedCodePage,33 default_code_page: SupportedCodePage,
3434
...@@ -726,10 +726,10 @@ pub const Node = struct {...@@ -726,10 +726,10 @@ pub const Node = struct {
726 pub fn dump(726 pub fn dump(
727 node: *const Node,727 node: *const Node,
728 tree: *const Tree,728 tree: *const Tree,
729 writer: anytype,729 writer: *std.io.Writer,
730 indent: usize,730 indent: usize,
731 ) @TypeOf(writer).Error!void {731 ) std.io.Writer.Error!void {
732 try writer.writeByteNTimes(' ', indent);732 try writer.splatByteAll(' ', indent);
733 try writer.writeAll(@tagName(node.id));733 try writer.writeAll(@tagName(node.id));
734 switch (node.id) {734 switch (node.id) {
735 .root => {735 .root => {
...@@ -768,11 +768,11 @@ pub const Node = struct {...@@ -768,11 +768,11 @@ pub const Node = struct {
768 .grouped_expression => {768 .grouped_expression => {
769 const grouped: *const Node.GroupedExpression = @alignCast(@fieldParentPtr("base", node));769 const grouped: *const Node.GroupedExpression = @alignCast(@fieldParentPtr("base", node));
770 try writer.writeAll("\n");770 try writer.writeAll("\n");
771 try writer.writeByteNTimes(' ', indent);771 try writer.splatByteAll(' ', indent);
772 try writer.writeAll(grouped.open_token.slice(tree.source));772 try writer.writeAll(grouped.open_token.slice(tree.source));
773 try writer.writeAll("\n");773 try writer.writeAll("\n");
774 try grouped.expression.dump(tree, writer, indent + 1);774 try grouped.expression.dump(tree, writer, indent + 1);
775 try writer.writeByteNTimes(' ', indent);775 try writer.splatByteAll(' ', indent);
776 try writer.writeAll(grouped.close_token.slice(tree.source));776 try writer.writeAll(grouped.close_token.slice(tree.source));
777 try writer.writeAll("\n");777 try writer.writeAll("\n");
778 },778 },
...@@ -790,13 +790,13 @@ pub const Node = struct {...@@ -790,13 +790,13 @@ pub const Node = struct {
790 for (accelerators.optional_statements) |statement| {790 for (accelerators.optional_statements) |statement| {
791 try statement.dump(tree, writer, indent + 1);791 try statement.dump(tree, writer, indent + 1);
792 }792 }
793 try writer.writeByteNTimes(' ', indent);793 try writer.splatByteAll(' ', indent);
794 try writer.writeAll(accelerators.begin_token.slice(tree.source));794 try writer.writeAll(accelerators.begin_token.slice(tree.source));
795 try writer.writeAll("\n");795 try writer.writeAll("\n");
796 for (accelerators.accelerators) |accelerator| {796 for (accelerators.accelerators) |accelerator| {
797 try accelerator.dump(tree, writer, indent + 1);797 try accelerator.dump(tree, writer, indent + 1);
798 }798 }
799 try writer.writeByteNTimes(' ', indent);799 try writer.splatByteAll(' ', indent);
800 try writer.writeAll(accelerators.end_token.slice(tree.source));800 try writer.writeAll(accelerators.end_token.slice(tree.source));
801 try writer.writeAll("\n");801 try writer.writeAll("\n");
802 },802 },
...@@ -815,25 +815,25 @@ pub const Node = struct {...@@ -815,25 +815,25 @@ pub const Node = struct {
815 const dialog: *const Node.Dialog = @alignCast(@fieldParentPtr("base", node));815 const dialog: *const Node.Dialog = @alignCast(@fieldParentPtr("base", node));
816 try writer.print(" {s} {s} [{d} common_resource_attributes]\n", .{ dialog.id.slice(tree.source), dialog.type.slice(tree.source), dialog.common_resource_attributes.len });816 try writer.print(" {s} {s} [{d} common_resource_attributes]\n", .{ dialog.id.slice(tree.source), dialog.type.slice(tree.source), dialog.common_resource_attributes.len });
817 inline for (.{ "x", "y", "width", "height" }) |arg| {817 inline for (.{ "x", "y", "width", "height" }) |arg| {
818 try writer.writeByteNTimes(' ', indent + 1);818 try writer.splatByteAll(' ', indent + 1);
819 try writer.writeAll(arg ++ ":\n");819 try writer.writeAll(arg ++ ":\n");
820 try @field(dialog, arg).dump(tree, writer, indent + 2);820 try @field(dialog, arg).dump(tree, writer, indent + 2);
821 }821 }
822 if (dialog.help_id) |help_id| {822 if (dialog.help_id) |help_id| {
823 try writer.writeByteNTimes(' ', indent + 1);823 try writer.splatByteAll(' ', indent + 1);
824 try writer.writeAll("help_id:\n");824 try writer.writeAll("help_id:\n");
825 try help_id.dump(tree, writer, indent + 2);825 try help_id.dump(tree, writer, indent + 2);
826 }826 }
827 for (dialog.optional_statements) |statement| {827 for (dialog.optional_statements) |statement| {
828 try statement.dump(tree, writer, indent + 1);828 try statement.dump(tree, writer, indent + 1);
829 }829 }
830 try writer.writeByteNTimes(' ', indent);830 try writer.splatByteAll(' ', indent);
831 try writer.writeAll(dialog.begin_token.slice(tree.source));831 try writer.writeAll(dialog.begin_token.slice(tree.source));
832 try writer.writeAll("\n");832 try writer.writeAll("\n");
833 for (dialog.controls) |control| {833 for (dialog.controls) |control| {
834 try control.dump(tree, writer, indent + 1);834 try control.dump(tree, writer, indent + 1);
835 }835 }
836 try writer.writeByteNTimes(' ', indent);836 try writer.splatByteAll(' ', indent);
837 try writer.writeAll(dialog.end_token.slice(tree.source));837 try writer.writeAll(dialog.end_token.slice(tree.source));
838 try writer.writeAll("\n");838 try writer.writeAll("\n");
839 },839 },
...@@ -845,30 +845,30 @@ pub const Node = struct {...@@ -845,30 +845,30 @@ pub const Node = struct {
845 }845 }
846 try writer.writeByte('\n');846 try writer.writeByte('\n');
847 if (control.class) |class| {847 if (control.class) |class| {
848 try writer.writeByteNTimes(' ', indent + 1);848 try writer.splatByteAll(' ', indent + 1);
849 try writer.writeAll("class:\n");849 try writer.writeAll("class:\n");
850 try class.dump(tree, writer, indent + 2);850 try class.dump(tree, writer, indent + 2);
851 }851 }
852 inline for (.{ "id", "x", "y", "width", "height" }) |arg| {852 inline for (.{ "id", "x", "y", "width", "height" }) |arg| {
853 try writer.writeByteNTimes(' ', indent + 1);853 try writer.splatByteAll(' ', indent + 1);
854 try writer.writeAll(arg ++ ":\n");854 try writer.writeAll(arg ++ ":\n");
855 try @field(control, arg).dump(tree, writer, indent + 2);855 try @field(control, arg).dump(tree, writer, indent + 2);
856 }856 }
857 inline for (.{ "style", "exstyle", "help_id" }) |arg| {857 inline for (.{ "style", "exstyle", "help_id" }) |arg| {
858 if (@field(control, arg)) |val_node| {858 if (@field(control, arg)) |val_node| {
859 try writer.writeByteNTimes(' ', indent + 1);859 try writer.splatByteAll(' ', indent + 1);
860 try writer.writeAll(arg ++ ":\n");860 try writer.writeAll(arg ++ ":\n");
861 try val_node.dump(tree, writer, indent + 2);861 try val_node.dump(tree, writer, indent + 2);
862 }862 }
863 }863 }
864 if (control.extra_data_begin != null) {864 if (control.extra_data_begin != null) {
865 try writer.writeByteNTimes(' ', indent);865 try writer.splatByteAll(' ', indent);
866 try writer.writeAll(control.extra_data_begin.?.slice(tree.source));866 try writer.writeAll(control.extra_data_begin.?.slice(tree.source));
867 try writer.writeAll("\n");867 try writer.writeAll("\n");
868 for (control.extra_data) |data_node| {868 for (control.extra_data) |data_node| {
869 try data_node.dump(tree, writer, indent + 1);869 try data_node.dump(tree, writer, indent + 1);
870 }870 }
871 try writer.writeByteNTimes(' ', indent);871 try writer.splatByteAll(' ', indent);
872 try writer.writeAll(control.extra_data_end.?.slice(tree.source));872 try writer.writeAll(control.extra_data_end.?.slice(tree.source));
873 try writer.writeAll("\n");873 try writer.writeAll("\n");
874 }874 }
...@@ -877,17 +877,17 @@ pub const Node = struct {...@@ -877,17 +877,17 @@ pub const Node = struct {
877 const toolbar: *const Node.Toolbar = @alignCast(@fieldParentPtr("base", node));877 const toolbar: *const Node.Toolbar = @alignCast(@fieldParentPtr("base", node));
878 try writer.print(" {s} {s} [{d} common_resource_attributes]\n", .{ toolbar.id.slice(tree.source), toolbar.type.slice(tree.source), toolbar.common_resource_attributes.len });878 try writer.print(" {s} {s} [{d} common_resource_attributes]\n", .{ toolbar.id.slice(tree.source), toolbar.type.slice(tree.source), toolbar.common_resource_attributes.len });
879 inline for (.{ "button_width", "button_height" }) |arg| {879 inline for (.{ "button_width", "button_height" }) |arg| {
880 try writer.writeByteNTimes(' ', indent + 1);880 try writer.splatByteAll(' ', indent + 1);
881 try writer.writeAll(arg ++ ":\n");881 try writer.writeAll(arg ++ ":\n");
882 try @field(toolbar, arg).dump(tree, writer, indent + 2);882 try @field(toolbar, arg).dump(tree, writer, indent + 2);
883 }883 }
884 try writer.writeByteNTimes(' ', indent);884 try writer.splatByteAll(' ', indent);
885 try writer.writeAll(toolbar.begin_token.slice(tree.source));885 try writer.writeAll(toolbar.begin_token.slice(tree.source));
886 try writer.writeAll("\n");886 try writer.writeAll("\n");
887 for (toolbar.buttons) |button_or_sep| {887 for (toolbar.buttons) |button_or_sep| {
888 try button_or_sep.dump(tree, writer, indent + 1);888 try button_or_sep.dump(tree, writer, indent + 1);
889 }889 }
890 try writer.writeByteNTimes(' ', indent);890 try writer.splatByteAll(' ', indent);
891 try writer.writeAll(toolbar.end_token.slice(tree.source));891 try writer.writeAll(toolbar.end_token.slice(tree.source));
892 try writer.writeAll("\n");892 try writer.writeAll("\n");
893 },893 },
...@@ -898,17 +898,17 @@ pub const Node = struct {...@@ -898,17 +898,17 @@ pub const Node = struct {
898 try statement.dump(tree, writer, indent + 1);898 try statement.dump(tree, writer, indent + 1);
899 }899 }
900 if (menu.help_id) |help_id| {900 if (menu.help_id) |help_id| {
901 try writer.writeByteNTimes(' ', indent + 1);901 try writer.splatByteAll(' ', indent + 1);
902 try writer.writeAll("help_id:\n");902 try writer.writeAll("help_id:\n");
903 try help_id.dump(tree, writer, indent + 2);903 try help_id.dump(tree, writer, indent + 2);
904 }904 }
905 try writer.writeByteNTimes(' ', indent);905 try writer.splatByteAll(' ', indent);
906 try writer.writeAll(menu.begin_token.slice(tree.source));906 try writer.writeAll(menu.begin_token.slice(tree.source));
907 try writer.writeAll("\n");907 try writer.writeAll("\n");
908 for (menu.items) |item| {908 for (menu.items) |item| {
909 try item.dump(tree, writer, indent + 1);909 try item.dump(tree, writer, indent + 1);
910 }910 }
911 try writer.writeByteNTimes(' ', indent);911 try writer.splatByteAll(' ', indent);
912 try writer.writeAll(menu.end_token.slice(tree.source));912 try writer.writeAll(menu.end_token.slice(tree.source));
913 try writer.writeAll("\n");913 try writer.writeAll("\n");
914 },914 },
...@@ -926,7 +926,7 @@ pub const Node = struct {...@@ -926,7 +926,7 @@ pub const Node = struct {
926 try writer.print(" {s} {s}\n", .{ menu_item.menuitem.slice(tree.source), menu_item.text.slice(tree.source) });926 try writer.print(" {s} {s}\n", .{ menu_item.menuitem.slice(tree.source), menu_item.text.slice(tree.source) });
927 inline for (.{ "id", "type", "state" }) |arg| {927 inline for (.{ "id", "type", "state" }) |arg| {
928 if (@field(menu_item, arg)) |val_node| {928 if (@field(menu_item, arg)) |val_node| {
929 try writer.writeByteNTimes(' ', indent + 1);929 try writer.splatByteAll(' ', indent + 1);
930 try writer.writeAll(arg ++ ":\n");930 try writer.writeAll(arg ++ ":\n");
931 try val_node.dump(tree, writer, indent + 2);931 try val_node.dump(tree, writer, indent + 2);
932 }932 }
...@@ -935,13 +935,13 @@ pub const Node = struct {...@@ -935,13 +935,13 @@ pub const Node = struct {
935 .popup => {935 .popup => {
936 const popup: *const Node.Popup = @alignCast(@fieldParentPtr("base", node));936 const popup: *const Node.Popup = @alignCast(@fieldParentPtr("base", node));
937 try writer.print(" {s} {s} [{d} options]\n", .{ popup.popup.slice(tree.source), popup.text.slice(tree.source), popup.option_list.len });937 try writer.print(" {s} {s} [{d} options]\n", .{ popup.popup.slice(tree.source), popup.text.slice(tree.source), popup.option_list.len });
938 try writer.writeByteNTimes(' ', indent);938 try writer.splatByteAll(' ', indent);
939 try writer.writeAll(popup.begin_token.slice(tree.source));939 try writer.writeAll(popup.begin_token.slice(tree.source));
940 try writer.writeAll("\n");940 try writer.writeAll("\n");
941 for (popup.items) |item| {941 for (popup.items) |item| {
942 try item.dump(tree, writer, indent + 1);942 try item.dump(tree, writer, indent + 1);
943 }943 }
944 try writer.writeByteNTimes(' ', indent);944 try writer.splatByteAll(' ', indent);
945 try writer.writeAll(popup.end_token.slice(tree.source));945 try writer.writeAll(popup.end_token.slice(tree.source));
946 try writer.writeAll("\n");946 try writer.writeAll("\n");
947 },947 },
...@@ -950,18 +950,18 @@ pub const Node = struct {...@@ -950,18 +950,18 @@ pub const Node = struct {
950 try writer.print(" {s} {s}\n", .{ popup.popup.slice(tree.source), popup.text.slice(tree.source) });950 try writer.print(" {s} {s}\n", .{ popup.popup.slice(tree.source), popup.text.slice(tree.source) });
951 inline for (.{ "id", "type", "state", "help_id" }) |arg| {951 inline for (.{ "id", "type", "state", "help_id" }) |arg| {
952 if (@field(popup, arg)) |val_node| {952 if (@field(popup, arg)) |val_node| {
953 try writer.writeByteNTimes(' ', indent + 1);953 try writer.splatByteAll(' ', indent + 1);
954 try writer.writeAll(arg ++ ":\n");954 try writer.writeAll(arg ++ ":\n");
955 try val_node.dump(tree, writer, indent + 2);955 try val_node.dump(tree, writer, indent + 2);
956 }956 }
957 }957 }
958 try writer.writeByteNTimes(' ', indent);958 try writer.splatByteAll(' ', indent);
959 try writer.writeAll(popup.begin_token.slice(tree.source));959 try writer.writeAll(popup.begin_token.slice(tree.source));
960 try writer.writeAll("\n");960 try writer.writeAll("\n");
961 for (popup.items) |item| {961 for (popup.items) |item| {
962 try item.dump(tree, writer, indent + 1);962 try item.dump(tree, writer, indent + 1);
963 }963 }
964 try writer.writeByteNTimes(' ', indent);964 try writer.splatByteAll(' ', indent);
965 try writer.writeAll(popup.end_token.slice(tree.source));965 try writer.writeAll(popup.end_token.slice(tree.source));
966 try writer.writeAll("\n");966 try writer.writeAll("\n");
967 },967 },
...@@ -971,13 +971,13 @@ pub const Node = struct {...@@ -971,13 +971,13 @@ pub const Node = struct {
971 for (version_info.fixed_info) |fixed_info| {971 for (version_info.fixed_info) |fixed_info| {
972 try fixed_info.dump(tree, writer, indent + 1);972 try fixed_info.dump(tree, writer, indent + 1);
973 }973 }
974 try writer.writeByteNTimes(' ', indent);974 try writer.splatByteAll(' ', indent);
975 try writer.writeAll(version_info.begin_token.slice(tree.source));975 try writer.writeAll(version_info.begin_token.slice(tree.source));
976 try writer.writeAll("\n");976 try writer.writeAll("\n");
977 for (version_info.block_statements) |block| {977 for (version_info.block_statements) |block| {
978 try block.dump(tree, writer, indent + 1);978 try block.dump(tree, writer, indent + 1);
979 }979 }
980 try writer.writeByteNTimes(' ', indent);980 try writer.splatByteAll(' ', indent);
981 try writer.writeAll(version_info.end_token.slice(tree.source));981 try writer.writeAll(version_info.end_token.slice(tree.source));
982 try writer.writeAll("\n");982 try writer.writeAll("\n");
983 },983 },
...@@ -994,13 +994,13 @@ pub const Node = struct {...@@ -994,13 +994,13 @@ pub const Node = struct {
994 for (block.values) |value| {994 for (block.values) |value| {
995 try value.dump(tree, writer, indent + 1);995 try value.dump(tree, writer, indent + 1);
996 }996 }
997 try writer.writeByteNTimes(' ', indent);997 try writer.splatByteAll(' ', indent);
998 try writer.writeAll(block.begin_token.slice(tree.source));998 try writer.writeAll(block.begin_token.slice(tree.source));
999 try writer.writeAll("\n");999 try writer.writeAll("\n");
1000 for (block.children) |child| {1000 for (block.children) |child| {
1001 try child.dump(tree, writer, indent + 1);1001 try child.dump(tree, writer, indent + 1);
1002 }1002 }
1003 try writer.writeByteNTimes(' ', indent);1003 try writer.splatByteAll(' ', indent);
1004 try writer.writeAll(block.end_token.slice(tree.source));1004 try writer.writeAll(block.end_token.slice(tree.source));
1005 try writer.writeAll("\n");1005 try writer.writeAll("\n");
1006 },1006 },
...@@ -1025,13 +1025,13 @@ pub const Node = struct {...@@ -1025,13 +1025,13 @@ pub const Node = struct {
1025 for (string_table.optional_statements) |statement| {1025 for (string_table.optional_statements) |statement| {
1026 try statement.dump(tree, writer, indent + 1);1026 try statement.dump(tree, writer, indent + 1);
1027 }1027 }
1028 try writer.writeByteNTimes(' ', indent);1028 try writer.splatByteAll(' ', indent);
1029 try writer.writeAll(string_table.begin_token.slice(tree.source));1029 try writer.writeAll(string_table.begin_token.slice(tree.source));
1030 try writer.writeAll("\n");1030 try writer.writeAll("\n");
1031 for (string_table.strings) |string| {1031 for (string_table.strings) |string| {
1032 try string.dump(tree, writer, indent + 1);1032 try string.dump(tree, writer, indent + 1);
1033 }1033 }
1034 try writer.writeByteNTimes(' ', indent);1034 try writer.splatByteAll(' ', indent);
1035 try writer.writeAll(string_table.end_token.slice(tree.source));1035 try writer.writeAll(string_table.end_token.slice(tree.source));
1036 try writer.writeAll("\n");1036 try writer.writeAll("\n");
1037 },1037 },
...@@ -1039,7 +1039,7 @@ pub const Node = struct {...@@ -1039,7 +1039,7 @@ pub const Node = struct {
1039 try writer.writeAll("\n");1039 try writer.writeAll("\n");
1040 const string: *const Node.StringTableString = @alignCast(@fieldParentPtr("base", node));1040 const string: *const Node.StringTableString = @alignCast(@fieldParentPtr("base", node));
1041 try string.id.dump(tree, writer, indent + 1);1041 try string.id.dump(tree, writer, indent + 1);
1042 try writer.writeByteNTimes(' ', indent + 1);1042 try writer.splatByteAll(' ', indent + 1);
1043 try writer.print("{s}\n", .{string.string.slice(tree.source)});1043 try writer.print("{s}\n", .{string.string.slice(tree.source)});
1044 },1044 },
1045 .language_statement => {1045 .language_statement => {
...@@ -1051,12 +1051,12 @@ pub const Node = struct {...@@ -1051,12 +1051,12 @@ pub const Node = struct {
1051 .font_statement => {1051 .font_statement => {
1052 const font: *const Node.FontStatement = @alignCast(@fieldParentPtr("base", node));1052 const font: *const Node.FontStatement = @alignCast(@fieldParentPtr("base", node));
1053 try writer.print(" {s} typeface: {s}\n", .{ font.identifier.slice(tree.source), font.typeface.slice(tree.source) });1053 try writer.print(" {s} typeface: {s}\n", .{ font.identifier.slice(tree.source), font.typeface.slice(tree.source) });
1054 try writer.writeByteNTimes(' ', indent + 1);1054 try writer.splatByteAll(' ', indent + 1);
1055 try writer.writeAll("point_size:\n");1055 try writer.writeAll("point_size:\n");
1056 try font.point_size.dump(tree, writer, indent + 2);1056 try font.point_size.dump(tree, writer, indent + 2);
1057 inline for (.{ "weight", "italic", "char_set" }) |arg| {1057 inline for (.{ "weight", "italic", "char_set" }) |arg| {
1058 if (@field(font, arg)) |arg_node| {1058 if (@field(font, arg)) |arg_node| {
1059 try writer.writeByteNTimes(' ', indent + 1);1059 try writer.splatByteAll(' ', indent + 1);
1060 try writer.writeAll(arg ++ ":\n");1060 try writer.writeAll(arg ++ ":\n");
1061 try arg_node.dump(tree, writer, indent + 2);1061 try arg_node.dump(tree, writer, indent + 2);
1062 }1062 }
...@@ -1071,7 +1071,7 @@ pub const Node = struct {...@@ -1071,7 +1071,7 @@ pub const Node = struct {
1071 const invalid: *const Node.Invalid = @alignCast(@fieldParentPtr("base", node));1071 const invalid: *const Node.Invalid = @alignCast(@fieldParentPtr("base", node));
1072 try writer.print(" context.len: {}\n", .{invalid.context.len});1072 try writer.print(" context.len: {}\n", .{invalid.context.len});
1073 for (invalid.context) |context_token| {1073 for (invalid.context) |context_token| {
1074 try writer.writeByteNTimes(' ', indent + 1);1074 try writer.splatByteAll(' ', indent + 1);
1075 try writer.print("{s}:{s}", .{ @tagName(context_token.id), context_token.slice(tree.source) });1075 try writer.print("{s}:{s}", .{ @tagName(context_token.id), context_token.slice(tree.source) });
1076 try writer.writeByte('\n');1076 try writer.writeByte('\n');
1077 }1077 }
lib/compiler/resinator/bmp.zig+25-15
...@@ -27,6 +27,7 @@ pub const windows_format_id = std.mem.readInt(u16, "BM", native_endian);...@@ -27,6 +27,7 @@ pub const windows_format_id = std.mem.readInt(u16, "BM", native_endian);
27pub const file_header_len = 14;27pub const file_header_len = 14;
2828
29pub const ReadError = error{29pub const ReadError = error{
30 ReadFailed,
30 UnexpectedEOF,31 UnexpectedEOF,
31 InvalidFileHeader,32 InvalidFileHeader,
32 ImpossiblePixelDataOffset,33 ImpossiblePixelDataOffset,
...@@ -94,9 +95,12 @@ pub const BitmapInfo = struct {...@@ -94,9 +95,12 @@ pub const BitmapInfo = struct {
94 }95 }
95};96};
9697
97pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {98pub fn read(reader: *std.Io.Reader, max_size: u64) ReadError!BitmapInfo {
98 var bitmap_info: BitmapInfo = undefined;99 var bitmap_info: BitmapInfo = undefined;
99 const file_header = reader.readBytesNoEof(file_header_len) catch return error.UnexpectedEOF;100 const file_header = reader.takeArray(file_header_len) catch |err| switch (err) {
101 error.EndOfStream => return error.UnexpectedEOF,
102 else => |e| return e,
103 };
100104
101 const id = std.mem.readInt(u16, file_header[0..2], native_endian);105 const id = std.mem.readInt(u16, file_header[0..2], native_endian);
102 if (id != windows_format_id) return error.InvalidFileHeader;106 if (id != windows_format_id) return error.InvalidFileHeader;
...@@ -104,14 +108,17 @@ pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {...@@ -104,14 +108,17 @@ pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {
104 bitmap_info.pixel_data_offset = std.mem.readInt(u32, file_header[10..14], .little);108 bitmap_info.pixel_data_offset = std.mem.readInt(u32, file_header[10..14], .little);
105 if (bitmap_info.pixel_data_offset > max_size) return error.ImpossiblePixelDataOffset;109 if (bitmap_info.pixel_data_offset > max_size) return error.ImpossiblePixelDataOffset;
106110
107 bitmap_info.dib_header_size = reader.readInt(u32, .little) catch return error.UnexpectedEOF;111 bitmap_info.dib_header_size = reader.takeInt(u32, .little) catch return error.UnexpectedEOF;
108 if (bitmap_info.pixel_data_offset < file_header_len + bitmap_info.dib_header_size) return error.ImpossiblePixelDataOffset;112 if (bitmap_info.pixel_data_offset < file_header_len + bitmap_info.dib_header_size) return error.ImpossiblePixelDataOffset;
109 const dib_version = BitmapHeader.Version.get(bitmap_info.dib_header_size);113 const dib_version = BitmapHeader.Version.get(bitmap_info.dib_header_size);
110 switch (dib_version) {114 switch (dib_version) {
111 .@"nt3.1", .@"nt4.0", .@"nt5.0" => {115 .@"nt3.1", .@"nt4.0", .@"nt5.0" => {
112 var dib_header_buf: [@sizeOf(BITMAPINFOHEADER)]u8 align(@alignOf(BITMAPINFOHEADER)) = undefined;116 var dib_header_buf: [@sizeOf(BITMAPINFOHEADER)]u8 align(@alignOf(BITMAPINFOHEADER)) = undefined;
113 std.mem.writeInt(u32, dib_header_buf[0..4], bitmap_info.dib_header_size, .little);117 std.mem.writeInt(u32, dib_header_buf[0..4], bitmap_info.dib_header_size, .little);
114 reader.readNoEof(dib_header_buf[4..]) catch return error.UnexpectedEOF;118 reader.readSliceAll(dib_header_buf[4..]) catch |err| switch (err) {
119 error.EndOfStream => return error.UnexpectedEOF,
120 error.ReadFailed => |e| return e,
121 };
115 var dib_header: *BITMAPINFOHEADER = @ptrCast(&dib_header_buf);122 var dib_header: *BITMAPINFOHEADER = @ptrCast(&dib_header_buf);
116 structFieldsLittleToNative(BITMAPINFOHEADER, dib_header);123 structFieldsLittleToNative(BITMAPINFOHEADER, dib_header);
117124
...@@ -126,7 +133,10 @@ pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {...@@ -126,7 +133,10 @@ pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {
126 .@"win2.0" => {133 .@"win2.0" => {
127 var dib_header_buf: [@sizeOf(BITMAPCOREHEADER)]u8 align(@alignOf(BITMAPCOREHEADER)) = undefined;134 var dib_header_buf: [@sizeOf(BITMAPCOREHEADER)]u8 align(@alignOf(BITMAPCOREHEADER)) = undefined;
128 std.mem.writeInt(u32, dib_header_buf[0..4], bitmap_info.dib_header_size, .little);135 std.mem.writeInt(u32, dib_header_buf[0..4], bitmap_info.dib_header_size, .little);
129 reader.readNoEof(dib_header_buf[4..]) catch return error.UnexpectedEOF;136 reader.readSliceAll(dib_header_buf[4..]) catch |err| switch (err) {
137 error.EndOfStream => return error.UnexpectedEOF,
138 error.ReadFailed => |e| return e,
139 };
130 const dib_header: *BITMAPCOREHEADER = @ptrCast(&dib_header_buf);140 const dib_header: *BITMAPCOREHEADER = @ptrCast(&dib_header_buf);
131 structFieldsLittleToNative(BITMAPCOREHEADER, dib_header);141 structFieldsLittleToNative(BITMAPCOREHEADER, dib_header);
132142
...@@ -238,26 +248,26 @@ fn structFieldsLittleToNative(comptime T: type, x: *T) void {...@@ -238,26 +248,26 @@ fn structFieldsLittleToNative(comptime T: type, x: *T) void {
238248
239test "read" {249test "read" {
240 var bmp_data = "BM<\x00\x00\x00\x00\x00\x00\x006\x00\x00\x00(\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x10\x00\x00\x00\x00\x00\x06\x00\x00\x00\x12\x0b\x00\x00\x12\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x7f\x00\x00\x00\x00".*;250 var bmp_data = "BM<\x00\x00\x00\x00\x00\x00\x006\x00\x00\x00(\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x10\x00\x00\x00\x00\x00\x06\x00\x00\x00\x12\x0b\x00\x00\x12\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x7f\x00\x00\x00\x00".*;
241 var fbs = std.io.fixedBufferStream(&bmp_data);251 var fbs: std.Io.Reader = .fixed(&bmp_data);
242252
243 {253 {
244 const bitmap = try read(fbs.reader(), bmp_data.len);254 const bitmap = try read(&fbs, bmp_data.len);
245 try std.testing.expectEqual(@as(u32, BitmapHeader.Version.@"nt3.1".len()), bitmap.dib_header_size);255 try std.testing.expectEqual(@as(u32, BitmapHeader.Version.@"nt3.1".len()), bitmap.dib_header_size);
246 }256 }
247257
248 {258 {
249 fbs.reset();259 fbs.seek = 0;
250 bmp_data[file_header_len] = 11;260 bmp_data[file_header_len] = 11;
251 try std.testing.expectError(error.UnknownBitmapVersion, read(fbs.reader(), bmp_data.len));261 try std.testing.expectError(error.UnknownBitmapVersion, read(&fbs, bmp_data.len));
252262
253 // restore263 // restore
254 bmp_data[file_header_len] = BitmapHeader.Version.@"nt3.1".len();264 bmp_data[file_header_len] = BitmapHeader.Version.@"nt3.1".len();
255 }265 }
256266
257 {267 {
258 fbs.reset();268 fbs.seek = 0;
259 bmp_data[0] = 'b';269 bmp_data[0] = 'b';
260 try std.testing.expectError(error.InvalidFileHeader, read(fbs.reader(), bmp_data.len));270 try std.testing.expectError(error.InvalidFileHeader, read(&fbs, bmp_data.len));
261271
262 // restore272 // restore
263 bmp_data[0] = 'B';273 bmp_data[0] = 'B';
...@@ -265,13 +275,13 @@ test "read" {...@@ -265,13 +275,13 @@ test "read" {
265275
266 {276 {
267 const cutoff_len = file_header_len + BitmapHeader.Version.@"nt3.1".len() - 1;277 const cutoff_len = file_header_len + BitmapHeader.Version.@"nt3.1".len() - 1;
268 var dib_cutoff_fbs = std.io.fixedBufferStream(bmp_data[0..cutoff_len]);278 var dib_cutoff_fbs: std.Io.Reader = .fixed(bmp_data[0..cutoff_len]);
269 try std.testing.expectError(error.UnexpectedEOF, read(dib_cutoff_fbs.reader(), bmp_data.len));279 try std.testing.expectError(error.UnexpectedEOF, read(&dib_cutoff_fbs, bmp_data.len));
270 }280 }
271281
272 {282 {
273 const cutoff_len = file_header_len - 1;283 const cutoff_len = file_header_len - 1;
274 var bmp_cutoff_fbs = std.io.fixedBufferStream(bmp_data[0..cutoff_len]);284 var bmp_cutoff_fbs: std.Io.Reader = .fixed(bmp_data[0..cutoff_len]);
275 try std.testing.expectError(error.UnexpectedEOF, read(bmp_cutoff_fbs.reader(), bmp_data.len));285 try std.testing.expectError(error.UnexpectedEOF, read(&bmp_cutoff_fbs, bmp_data.len));
276 }286 }
277}287}
lib/compiler/resinator/cli.zig+13-13
...@@ -80,20 +80,20 @@ pub const usage_string_after_command_name =...@@ -80,20 +80,20 @@ pub const usage_string_after_command_name =
80 \\80 \\
81;81;
8282
83pub fn writeUsage(writer: anytype, command_name: []const u8) !void {83pub fn writeUsage(writer: *std.Io.Writer, command_name: []const u8) !void {
84 try writer.writeAll("Usage: ");84 try writer.writeAll("Usage: ");
85 try writer.writeAll(command_name);85 try writer.writeAll(command_name);
86 try writer.writeAll(usage_string_after_command_name);86 try writer.writeAll(usage_string_after_command_name);
87}87}
8888
89pub const Diagnostics = struct {89pub const Diagnostics = struct {
90 errors: std.ArrayListUnmanaged(ErrorDetails) = .empty,90 errors: std.ArrayList(ErrorDetails) = .empty,
91 allocator: Allocator,91 allocator: Allocator,
9292
93 pub const ErrorDetails = struct {93 pub const ErrorDetails = struct {
94 arg_index: usize,94 arg_index: usize,
95 arg_span: ArgSpan = .{},95 arg_span: ArgSpan = .{},
96 msg: std.ArrayListUnmanaged(u8) = .empty,96 msg: std.ArrayList(u8) = .empty,
97 type: Type = .err,97 type: Type = .err,
98 print_args: bool = true,98 print_args: bool = true,
9999
...@@ -148,7 +148,7 @@ pub const Options = struct {...@@ -148,7 +148,7 @@ pub const Options = struct {
148 allocator: Allocator,148 allocator: Allocator,
149 input_source: IoSource = .{ .filename = &[_]u8{} },149 input_source: IoSource = .{ .filename = &[_]u8{} },
150 output_source: IoSource = .{ .filename = &[_]u8{} },150 output_source: IoSource = .{ .filename = &[_]u8{} },
151 extra_include_paths: std.ArrayListUnmanaged([]const u8) = .empty,151 extra_include_paths: std.ArrayList([]const u8) = .empty,
152 ignore_include_env_var: bool = false,152 ignore_include_env_var: bool = false,
153 preprocess: Preprocess = .yes,153 preprocess: Preprocess = .yes,
154 default_language_id: ?u16 = null,154 default_language_id: ?u16 = null,
...@@ -295,7 +295,7 @@ pub const Options = struct {...@@ -295,7 +295,7 @@ pub const Options = struct {
295 }295 }
296 }296 }
297297
298 pub fn dumpVerbose(self: *const Options, writer: anytype) !void {298 pub fn dumpVerbose(self: *const Options, writer: *std.Io.Writer) !void {
299 const input_source_name = switch (self.input_source) {299 const input_source_name = switch (self.input_source) {
300 .stdio => "<stdin>",300 .stdio => "<stdin>",
301 .filename => |filename| filename,301 .filename => |filename| filename,
...@@ -1230,19 +1230,19 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1230,19 +1230,19 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1230}1230}
12311231
1232pub fn filepathWithExtension(allocator: Allocator, path: []const u8, ext: []const u8) ![]const u8 {1232pub fn filepathWithExtension(allocator: Allocator, path: []const u8, ext: []const u8) ![]const u8 {
1233 var buf = std.array_list.Managed(u8).init(allocator);1233 var buf: std.ArrayList(u8) = .empty;
1234 errdefer buf.deinit();1234 errdefer buf.deinit(allocator);
1235 if (std.fs.path.dirname(path)) |dirname| {1235 if (std.fs.path.dirname(path)) |dirname| {
1236 var end_pos = dirname.len;1236 var end_pos = dirname.len;
1237 // We want to ensure that we write a path separator at the end, so if the dirname1237 // We want to ensure that we write a path separator at the end, so if the dirname
1238 // doesn't end with a path sep then include the char after the dirname1238 // doesn't end with a path sep then include the char after the dirname
1239 // which must be a path sep.1239 // which must be a path sep.
1240 if (!std.fs.path.isSep(dirname[dirname.len - 1])) end_pos += 1;1240 if (!std.fs.path.isSep(dirname[dirname.len - 1])) end_pos += 1;
1241 try buf.appendSlice(path[0..end_pos]);1241 try buf.appendSlice(allocator, path[0..end_pos]);
1242 }1242 }
1243 try buf.appendSlice(std.fs.path.stem(path));1243 try buf.appendSlice(allocator, std.fs.path.stem(path));
1244 try buf.appendSlice(ext);1244 try buf.appendSlice(allocator, ext);
1245 return try buf.toOwnedSlice();1245 return try buf.toOwnedSlice(allocator);
1246}1246}
12471247
1248pub fn isSupportedInputExtension(ext: []const u8) bool {1248pub fn isSupportedInputExtension(ext: []const u8) bool {
...@@ -1476,7 +1476,7 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti...@@ -1476,7 +1476,7 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti
1476 var options = parse(std.testing.allocator, args, &diagnostics) catch |err| switch (err) {1476 var options = parse(std.testing.allocator, args, &diagnostics) catch |err| switch (err) {
1477 error.ParseError => {1477 error.ParseError => {
1478 try diagnostics.renderToWriter(args, &output.writer, .no_color);1478 try diagnostics.renderToWriter(args, &output.writer, .no_color);
1479 try std.testing.expectEqualStrings(expected_output, output.getWritten());1479 try std.testing.expectEqualStrings(expected_output, output.written());
1480 return null;1480 return null;
1481 },1481 },
1482 else => |e| return e,1482 else => |e| return e,
...@@ -1484,7 +1484,7 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti...@@ -1484,7 +1484,7 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti
1484 errdefer options.deinit();1484 errdefer options.deinit();
14851485
1486 try diagnostics.renderToWriter(args, &output.writer, .no_color);1486 try diagnostics.renderToWriter(args, &output.writer, .no_color);
1487 try std.testing.expectEqualStrings(expected_output, output.getWritten());1487 try std.testing.expectEqualStrings(expected_output, output.written());
1488 return options;1488 return options;
1489}1489}
14901490
lib/compiler/resinator/compile.zig+189-221
...@@ -35,10 +35,7 @@ pub const CompileOptions = struct {...@@ -35,10 +35,7 @@ pub const CompileOptions = struct {
35 diagnostics: *Diagnostics,35 diagnostics: *Diagnostics,
36 source_mappings: ?*SourceMappings = null,36 source_mappings: ?*SourceMappings = null,
37 /// List of paths (absolute or relative to `cwd`) for every file that the resources within the .rc file depend on.37 /// List of paths (absolute or relative to `cwd`) for every file that the resources within the .rc file depend on.
38 /// Items within the list will be allocated using the allocator of the ArrayList and must be38 dependencies: ?*Dependencies = null,
39 /// freed by the caller.
40 /// TODO: Maybe a dedicated struct for this purpose so that it's a bit nicer to work with.
41 dependencies_list: ?*std.array_list.Managed([]const u8) = null,
42 default_code_page: SupportedCodePage = .windows1252,39 default_code_page: SupportedCodePage = .windows1252,
43 /// If true, the first #pragma code_page directive only sets the input code page, but not the output code page.40 /// If true, the first #pragma code_page directive only sets the input code page, but not the output code page.
44 /// This check must be done before comments are removed from the file.41 /// This check must be done before comments are removed from the file.
...@@ -61,6 +58,25 @@ pub const CompileOptions = struct {...@@ -61,6 +58,25 @@ pub const CompileOptions = struct {
61 warn_instead_of_error_on_invalid_code_page: bool = false,58 warn_instead_of_error_on_invalid_code_page: bool = false,
62};59};
6360
61pub const Dependencies = struct {
62 list: std.ArrayList([]const u8),
63 allocator: Allocator,
64
65 pub fn init(allocator: Allocator) Dependencies {
66 return .{
67 .list = .empty,
68 .allocator = allocator,
69 };
70 }
71
72 pub fn deinit(self: *Dependencies) void {
73 for (self.list.items) |item| {
74 self.allocator.free(item);
75 }
76 self.list.deinit(self.allocator);
77 }
78};
79
64pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer, options: CompileOptions) !void {80pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer, options: CompileOptions) !void {
65 var lexer = lex.Lexer.init(source, .{81 var lexer = lex.Lexer.init(source, .{
66 .default_code_page = options.default_code_page,82 .default_code_page = options.default_code_page,
...@@ -74,12 +90,12 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,...@@ -74,12 +90,12 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,
74 var tree = try parser.parse(allocator, options.diagnostics);90 var tree = try parser.parse(allocator, options.diagnostics);
75 defer tree.deinit();91 defer tree.deinit();
7692
77 var search_dirs = std.array_list.Managed(SearchDir).init(allocator);93 var search_dirs: std.ArrayList(SearchDir) = .empty;
78 defer {94 defer {
79 for (search_dirs.items) |*search_dir| {95 for (search_dirs.items) |*search_dir| {
80 search_dir.deinit(allocator);96 search_dir.deinit(allocator);
81 }97 }
82 search_dirs.deinit();98 search_dirs.deinit(allocator);
83 }99 }
84100
85 if (options.source_mappings) |source_mappings| {101 if (options.source_mappings) |source_mappings| {
...@@ -89,7 +105,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,...@@ -89,7 +105,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,
89 if (std.fs.path.dirname(root_path)) |root_dir_path| {105 if (std.fs.path.dirname(root_path)) |root_dir_path| {
90 var root_dir = try options.cwd.openDir(root_dir_path, .{});106 var root_dir = try options.cwd.openDir(root_dir_path, .{});
91 errdefer root_dir.close();107 errdefer root_dir.close();
92 try search_dirs.append(.{ .dir = root_dir, .path = try allocator.dupe(u8, root_dir_path) });108 try search_dirs.append(allocator, .{ .dir = root_dir, .path = try allocator.dupe(u8, root_dir_path) });
93 }109 }
94 }110 }
95 // Re-open the passed in cwd since we want to be able to close it (std.fs.cwd() shouldn't be closed)111 // Re-open the passed in cwd since we want to be able to close it (std.fs.cwd() shouldn't be closed)
...@@ -111,14 +127,14 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,...@@ -111,14 +127,14 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,
111 });127 });
112 return error.CompileError;128 return error.CompileError;
113 };129 };
114 try search_dirs.append(.{ .dir = cwd_dir, .path = null });130 try search_dirs.append(allocator, .{ .dir = cwd_dir, .path = null });
115 for (options.extra_include_paths) |extra_include_path| {131 for (options.extra_include_paths) |extra_include_path| {
116 var dir = openSearchPathDir(options.cwd, extra_include_path) catch {132 var dir = openSearchPathDir(options.cwd, extra_include_path) catch {
117 // TODO: maybe a warning that the search path is skipped?133 // TODO: maybe a warning that the search path is skipped?
118 continue;134 continue;
119 };135 };
120 errdefer dir.close();136 errdefer dir.close();
121 try search_dirs.append(.{ .dir = dir, .path = try allocator.dupe(u8, extra_include_path) });137 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, extra_include_path) });
122 }138 }
123 for (options.system_include_paths) |system_include_path| {139 for (options.system_include_paths) |system_include_path| {
124 var dir = openSearchPathDir(options.cwd, system_include_path) catch {140 var dir = openSearchPathDir(options.cwd, system_include_path) catch {
...@@ -126,7 +142,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,...@@ -126,7 +142,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,
126 continue;142 continue;
127 };143 };
128 errdefer dir.close();144 errdefer dir.close();
129 try search_dirs.append(.{ .dir = dir, .path = try allocator.dupe(u8, system_include_path) });145 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, system_include_path) });
130 }146 }
131 if (!options.ignore_include_env_var) {147 if (!options.ignore_include_env_var) {
132 const INCLUDE = std.process.getEnvVarOwned(allocator, "INCLUDE") catch "";148 const INCLUDE = std.process.getEnvVarOwned(allocator, "INCLUDE") catch "";
...@@ -142,7 +158,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,...@@ -142,7 +158,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,
142 while (it.next()) |search_path| {158 while (it.next()) |search_path| {
143 var dir = openSearchPathDir(options.cwd, search_path) catch continue;159 var dir = openSearchPathDir(options.cwd, search_path) catch continue;
144 errdefer dir.close();160 errdefer dir.close();
145 try search_dirs.append(.{ .dir = dir, .path = try allocator.dupe(u8, search_path) });161 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, search_path) });
146 }162 }
147 }163 }
148164
...@@ -156,7 +172,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,...@@ -156,7 +172,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,
156 .allocator = allocator,172 .allocator = allocator,
157 .cwd = options.cwd,173 .cwd = options.cwd,
158 .diagnostics = options.diagnostics,174 .diagnostics = options.diagnostics,
159 .dependencies_list = options.dependencies_list,175 .dependencies = options.dependencies,
160 .input_code_pages = &tree.input_code_pages,176 .input_code_pages = &tree.input_code_pages,
161 .output_code_pages = &tree.output_code_pages,177 .output_code_pages = &tree.output_code_pages,
162 // This is only safe because we know search_dirs won't be modified past this point178 // This is only safe because we know search_dirs won't be modified past this point
...@@ -178,7 +194,7 @@ pub const Compiler = struct {...@@ -178,7 +194,7 @@ pub const Compiler = struct {
178 cwd: std.fs.Dir,194 cwd: std.fs.Dir,
179 state: State = .{},195 state: State = .{},
180 diagnostics: *Diagnostics,196 diagnostics: *Diagnostics,
181 dependencies_list: ?*std.array_list.Managed([]const u8),197 dependencies: ?*Dependencies,
182 input_code_pages: *const CodePageLookup,198 input_code_pages: *const CodePageLookup,
183 output_code_pages: *const CodePageLookup,199 output_code_pages: *const CodePageLookup,
184 search_dirs: []SearchDir,200 search_dirs: []SearchDir,
...@@ -279,32 +295,32 @@ pub const Compiler = struct {...@@ -279,32 +295,32 @@ pub const Compiler = struct {
279 .literal, .number => {295 .literal, .number => {
280 const slice = literal_node.token.slice(self.source);296 const slice = literal_node.token.slice(self.source);
281 const code_page = self.input_code_pages.getForToken(literal_node.token);297 const code_page = self.input_code_pages.getForToken(literal_node.token);
282 var buf = try std.array_list.Managed(u8).initCapacity(self.allocator, slice.len);298 var buf = try std.ArrayList(u8).initCapacity(self.allocator, slice.len);
283 errdefer buf.deinit();299 errdefer buf.deinit(self.allocator);
284300
285 var index: usize = 0;301 var index: usize = 0;
286 while (code_page.codepointAt(index, slice)) |codepoint| : (index += codepoint.byte_len) {302 while (code_page.codepointAt(index, slice)) |codepoint| : (index += codepoint.byte_len) {
287 const c = codepoint.value;303 const c = codepoint.value;
288 if (c == code_pages.Codepoint.invalid) {304 if (c == code_pages.Codepoint.invalid) {
289 try buf.appendSlice("�");305 try buf.appendSlice(self.allocator, "�");
290 } else {306 } else {
291 // Anything that is not returned as an invalid codepoint must be encodable as UTF-8.307 // Anything that is not returned as an invalid codepoint must be encodable as UTF-8.
292 const utf8_len = std.unicode.utf8CodepointSequenceLength(c) catch unreachable;308 const utf8_len = std.unicode.utf8CodepointSequenceLength(c) catch unreachable;
293 try buf.ensureUnusedCapacity(utf8_len);309 try buf.ensureUnusedCapacity(self.allocator, utf8_len);
294 _ = std.unicode.utf8Encode(c, buf.unusedCapacitySlice()) catch unreachable;310 _ = std.unicode.utf8Encode(c, buf.unusedCapacitySlice()) catch unreachable;
295 buf.items.len += utf8_len;311 buf.items.len += utf8_len;
296 }312 }
297 }313 }
298314
299 return buf.toOwnedSlice();315 return buf.toOwnedSlice(self.allocator);
300 },316 },
301 .quoted_ascii_string, .quoted_wide_string => {317 .quoted_ascii_string, .quoted_wide_string => {
302 const slice = literal_node.token.slice(self.source);318 const slice = literal_node.token.slice(self.source);
303 const column = literal_node.token.calculateColumn(self.source, 8, null);319 const column = literal_node.token.calculateColumn(self.source, 8, null);
304 const bytes = SourceBytes{ .slice = slice, .code_page = self.input_code_pages.getForToken(literal_node.token) };320 const bytes = SourceBytes{ .slice = slice, .code_page = self.input_code_pages.getForToken(literal_node.token) };
305321
306 var buf = std.array_list.Managed(u8).init(self.allocator);322 var buf: std.ArrayList(u8) = .empty;
307 errdefer buf.deinit();323 errdefer buf.deinit(self.allocator);
308324
309 // Filenames are sort-of parsed as if they were wide strings, but the max escape width of325 // Filenames are sort-of parsed as if they were wide strings, but the max escape width of
310 // hex/octal escapes is still determined by the L prefix. Since we want to end up with326 // hex/octal escapes is still determined by the L prefix. Since we want to end up with
...@@ -320,19 +336,19 @@ pub const Compiler = struct {...@@ -320,19 +336,19 @@ pub const Compiler = struct {
320 while (try parser.nextUnchecked()) |parsed| {336 while (try parser.nextUnchecked()) |parsed| {
321 const c = parsed.codepoint;337 const c = parsed.codepoint;
322 if (c == code_pages.Codepoint.invalid) {338 if (c == code_pages.Codepoint.invalid) {
323 try buf.appendSlice("�");339 try buf.appendSlice(self.allocator, "�");
324 } else {340 } else {
325 var codepoint_buf: [4]u8 = undefined;341 var codepoint_buf: [4]u8 = undefined;
326 // If the codepoint cannot be encoded, we fall back to �342 // If the codepoint cannot be encoded, we fall back to �
327 if (std.unicode.utf8Encode(c, &codepoint_buf)) |len| {343 if (std.unicode.utf8Encode(c, &codepoint_buf)) |len| {
328 try buf.appendSlice(codepoint_buf[0..len]);344 try buf.appendSlice(self.allocator, codepoint_buf[0..len]);
329 } else |_| {345 } else |_| {
330 try buf.appendSlice("�");346 try buf.appendSlice(self.allocator, "�");
331 }347 }
332 }348 }
333 }349 }
334350
335 return buf.toOwnedSlice();351 return buf.toOwnedSlice(self.allocator);
336 },352 },
337 else => unreachable, // no other token types should be in a filename literal node353 else => unreachable, // no other token types should be in a filename literal node
338 }354 }
...@@ -386,10 +402,10 @@ pub const Compiler = struct {...@@ -386,10 +402,10 @@ pub const Compiler = struct {
386 const file = try utils.openFileNotDir(std.fs.cwd(), path, .{});402 const file = try utils.openFileNotDir(std.fs.cwd(), path, .{});
387 errdefer file.close();403 errdefer file.close();
388404
389 if (self.dependencies_list) |dependencies_list| {405 if (self.dependencies) |dependencies| {
390 const duped_path = try dependencies_list.allocator.dupe(u8, path);406 const duped_path = try dependencies.allocator.dupe(u8, path);
391 errdefer dependencies_list.allocator.free(duped_path);407 errdefer dependencies.allocator.free(duped_path);
392 try dependencies_list.append(duped_path);408 try dependencies.list.append(dependencies.allocator, duped_path);
393 }409 }
394 }410 }
395411
...@@ -398,12 +414,12 @@ pub const Compiler = struct {...@@ -398,12 +414,12 @@ pub const Compiler = struct {
398 if (utils.openFileNotDir(search_dir.dir, path, .{})) |file| {414 if (utils.openFileNotDir(search_dir.dir, path, .{})) |file| {
399 errdefer file.close();415 errdefer file.close();
400416
401 if (self.dependencies_list) |dependencies_list| {417 if (self.dependencies) |dependencies| {
402 const searched_file_path = try std.fs.path.join(dependencies_list.allocator, &.{418 const searched_file_path = try std.fs.path.join(dependencies.allocator, &.{
403 search_dir.path orelse "", path,419 search_dir.path orelse "", path,
404 });420 });
405 errdefer dependencies_list.allocator.free(searched_file_path);421 errdefer dependencies.allocator.free(searched_file_path);
406 try dependencies_list.append(searched_file_path);422 try dependencies.list.append(dependencies.allocator, searched_file_path);
407 }423 }
408424
409 return file;425 return file;
...@@ -421,8 +437,8 @@ pub const Compiler = struct {...@@ -421,8 +437,8 @@ pub const Compiler = struct {
421 const bytes = self.sourceBytesForToken(token);437 const bytes = self.sourceBytesForToken(token);
422 const output_code_page = self.output_code_pages.getForToken(token);438 const output_code_page = self.output_code_pages.getForToken(token);
423439
424 var buf = try std.array_list.Managed(u8).initCapacity(self.allocator, bytes.slice.len);440 var buf = try std.ArrayList(u8).initCapacity(self.allocator, bytes.slice.len);
425 errdefer buf.deinit();441 errdefer buf.deinit(self.allocator);
426442
427 var iterative_parser = literals.IterativeStringParser.init(bytes, .{443 var iterative_parser = literals.IterativeStringParser.init(bytes, .{
428 .start_column = token.calculateColumn(self.source, 8, null),444 .start_column = token.calculateColumn(self.source, 8, null),
...@@ -444,11 +460,11 @@ pub const Compiler = struct {...@@ -444,11 +460,11 @@ pub const Compiler = struct {
444 switch (iterative_parser.declared_string_type) {460 switch (iterative_parser.declared_string_type) {
445 .wide => {461 .wide => {
446 if (windows1252.bestFitFromCodepoint(c)) |best_fit| {462 if (windows1252.bestFitFromCodepoint(c)) |best_fit| {
447 try buf.append(best_fit);463 try buf.append(self.allocator, best_fit);
448 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid or parsed.escaped_surrogate_pair) {464 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid or parsed.escaped_surrogate_pair) {
449 try buf.append('?');465 try buf.append(self.allocator, '?');
450 } else {466 } else {
451 try buf.appendSlice("??");467 try buf.appendSlice(self.allocator, "??");
452 }468 }
453 },469 },
454 .ascii => {470 .ascii => {
...@@ -456,27 +472,27 @@ pub const Compiler = struct {...@@ -456,27 +472,27 @@ pub const Compiler = struct {
456 const truncated: u8 = @truncate(c);472 const truncated: u8 = @truncate(c);
457 switch (output_code_page) {473 switch (output_code_page) {
458 .utf8 => switch (truncated) {474 .utf8 => switch (truncated) {
459 0...0x7F => try buf.append(truncated),475 0...0x7F => try buf.append(self.allocator, truncated),
460 else => try buf.append('?'),476 else => try buf.append(self.allocator, '?'),
461 },477 },
462 .windows1252 => {478 .windows1252 => {
463 try buf.append(truncated);479 try buf.append(self.allocator, truncated);
464 },480 },
465 }481 }
466 } else {482 } else {
467 if (windows1252.bestFitFromCodepoint(c)) |best_fit| {483 if (windows1252.bestFitFromCodepoint(c)) |best_fit| {
468 try buf.append(best_fit);484 try buf.append(self.allocator, best_fit);
469 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid) {485 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid) {
470 try buf.append('?');486 try buf.append(self.allocator, '?');
471 } else {487 } else {
472 try buf.appendSlice("??");488 try buf.appendSlice(self.allocator, "??");
473 }489 }
474 }490 }
475 },491 },
476 }492 }
477 }493 }
478494
479 return buf.toOwnedSlice();495 return buf.toOwnedSlice(self.allocator);
480 }496 }
481497
482 pub fn writeResourceExternal(self: *Compiler, node: *Node.ResourceExternal, writer: *std.Io.Writer) !void {498 pub fn writeResourceExternal(self: *Compiler, node: *Node.ResourceExternal, writer: *std.Io.Writer) !void {
...@@ -572,7 +588,7 @@ pub const Compiler = struct {...@@ -572,7 +588,7 @@ pub const Compiler = struct {
572 switch (predefined_type) {588 switch (predefined_type) {
573 .GROUP_ICON, .GROUP_CURSOR => {589 .GROUP_ICON, .GROUP_CURSOR => {
574 // Check for animated icon first590 // Check for animated icon first
575 if (ani.isAnimatedIcon(file_reader.interface.adaptToOldInterface())) {591 if (ani.isAnimatedIcon(&file_reader.interface)) {
576 // Animated icons are just put into the resource unmodified,592 // Animated icons are just put into the resource unmodified,
577 // and the resource type changes to ANIICON/ANICURSOR593 // and the resource type changes to ANIICON/ANICURSOR
578594
...@@ -584,7 +600,12 @@ pub const Compiler = struct {...@@ -584,7 +600,12 @@ pub const Compiler = struct {
584 header.type_value.ordinal = @intFromEnum(new_predefined_type);600 header.type_value.ordinal = @intFromEnum(new_predefined_type);
585 header.memory_flags = MemoryFlags.defaults(new_predefined_type);601 header.memory_flags = MemoryFlags.defaults(new_predefined_type);
586 header.applyMemoryFlags(node.common_resource_attributes, self.source);602 header.applyMemoryFlags(node.common_resource_attributes, self.source);
587 header.data_size = @intCast(try file_reader.getSize());603 header.data_size = std.math.cast(u32, try file_reader.getSize()) orelse {
604 return self.addErrorDetailsAndFail(.{
605 .err = .resource_data_size_exceeds_max,
606 .token = node.id,
607 });
608 };
588609
589 try header.write(writer, self.errContext(node.id));610 try header.write(writer, self.errContext(node.id));
590 try file_reader.seekTo(0);611 try file_reader.seekTo(0);
...@@ -595,7 +616,7 @@ pub const Compiler = struct {...@@ -595,7 +616,7 @@ pub const Compiler = struct {
595 // isAnimatedIcon moved the file cursor so reset to the start616 // isAnimatedIcon moved the file cursor so reset to the start
596 try file_reader.seekTo(0);617 try file_reader.seekTo(0);
597618
598 const icon_dir = ico.read(self.allocator, file_reader.interface.adaptToOldInterface(), try file_reader.getSize()) catch |err| switch (err) {619 const icon_dir = ico.read(self.allocator, &file_reader.interface, try file_reader.getSize()) catch |err| switch (err) {
599 error.OutOfMemory => |e| return e,620 error.OutOfMemory => |e| return e,
600 else => |e| {621 else => |e| {
601 return self.iconReadError(622 return self.iconReadError(
...@@ -861,7 +882,7 @@ pub const Compiler = struct {...@@ -861,7 +882,7 @@ pub const Compiler = struct {
861 header.applyMemoryFlags(node.common_resource_attributes, self.source);882 header.applyMemoryFlags(node.common_resource_attributes, self.source);
862 const file_size = try file_reader.getSize();883 const file_size = try file_reader.getSize();
863884
864 const bitmap_info = bmp.read(file_reader.interface.adaptToOldInterface(), file_size) catch |err| {885 const bitmap_info = bmp.read(&file_reader.interface, file_size) catch |err| {
865 const filename_string_index = try self.diagnostics.putString(filename_utf8);886 const filename_string_index = try self.diagnostics.putString(filename_utf8);
866 return self.addErrorDetailsAndFail(.{887 return self.addErrorDetailsAndFail(.{
867 .err = .bmp_read_error,888 .err = .bmp_read_error,
...@@ -969,13 +990,19 @@ pub const Compiler = struct {...@@ -969,13 +990,19 @@ pub const Compiler = struct {
969 header.data_size = @intCast(file_size);990 header.data_size = @intCast(file_size);
970 try header.write(writer, self.errContext(node.id));991 try header.write(writer, self.errContext(node.id));
971992
972 var header_slurping_reader = headerSlurpingReader(148, file_reader.interface.adaptToOldInterface());993 // Slurp the first 148 bytes separately so we can store them in the FontDir
973 var adapter = header_slurping_reader.reader().adaptToNewApi(&.{});994 var font_dir_header_buf: [148]u8 = @splat(0);
974 try writeResourceData(writer, &adapter.new_interface, header.data_size);995 const populated_len: u32 = @intCast(try file_reader.interface.readSliceShort(&font_dir_header_buf));
996
997 // Write only the populated bytes slurped from the header
998 try writer.writeAll(font_dir_header_buf[0..populated_len]);
999 // Then write the rest of the bytes and the padding
1000 try writeResourceDataNoPadding(writer, &file_reader.interface, header.data_size - populated_len);
1001 try writeDataPadding(writer, header.data_size);
9751002
976 try self.state.font_dir.add(self.arena, FontDir.Font{1003 try self.state.font_dir.add(self.arena, FontDir.Font{
977 .id = header.name_value.ordinal,1004 .id = header.name_value.ordinal,
978 .header_bytes = header_slurping_reader.slurped_header,1005 .header_bytes = font_dir_header_buf,
979 }, node.id);1006 }, node.id);
980 return;1007 return;
981 },1008 },
...@@ -1053,7 +1080,7 @@ pub const Compiler = struct {...@@ -1053,7 +1080,7 @@ pub const Compiler = struct {
1053 }1080 }
1054 }1081 }
10551082
1056 pub fn write(self: Data, writer: anytype) !void {1083 pub fn write(self: Data, writer: *std.Io.Writer) !void {
1057 switch (self) {1084 switch (self) {
1058 .number => |number| switch (number.is_long) {1085 .number => |number| switch (number.is_long) {
1059 false => try writer.writeInt(WORD, number.asWord(), .little),1086 false => try writer.writeInt(WORD, number.asWord(), .little),
...@@ -1225,36 +1252,30 @@ pub const Compiler = struct {...@@ -1225,36 +1252,30 @@ pub const Compiler = struct {
1225 }1252 }
1226 }1253 }
12271254
1228 pub fn writeResourceRawData(self: *Compiler, node: *Node.ResourceRawData, writer: anytype) !void {1255 pub fn writeResourceRawData(self: *Compiler, node: *Node.ResourceRawData, writer: *std.Io.Writer) !void {
1229 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);1256 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
1230 defer data_buffer.deinit();1257 defer data_buffer.deinit();
1231 // The header's data length field is a u32 so limit the resource's data size so that
1232 // we know we can always specify the real size.
1233 const data_writer = &data_buffer.writer;
12341258
1235 for (node.raw_data) |expression| {1259 for (node.raw_data) |expression| {
1236 const data = try self.evaluateDataExpression(expression);1260 const data = try self.evaluateDataExpression(expression);
1237 defer data.deinit(self.allocator);1261 defer data.deinit(self.allocator);
1238 data.write(data_writer) catch |err| switch (err) {1262 try data.write(&data_buffer.writer);
1239 error.WriteFailed => {
1240 return self.addErrorDetailsAndFail(.{
1241 .err = .resource_data_size_exceeds_max,
1242 .token = node.id,
1243 });
1244 },
1245 };
1246 }1263 }
12471264
1248 // This intCast can't fail because the limitedWriter above guarantees that1265 // TODO: Limit data_buffer in some way to error when writing more than u32 max bytes
1249 // we will never write more than maxInt(u32) bytes.1266 const data_len: u32 = std.math.cast(u32, data_buffer.written().len) orelse {
1250 const data_len: u32 = @intCast(data_buffer.written().len);1267 return self.addErrorDetailsAndFail(.{
1268 .err = .resource_data_size_exceeds_max,
1269 .token = node.id,
1270 });
1271 };
1251 try self.writeResourceHeader(writer, node.id, node.type, data_len, node.common_resource_attributes, self.state.language);1272 try self.writeResourceHeader(writer, node.id, node.type, data_len, node.common_resource_attributes, self.state.language);
12521273
1253 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());1274 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
1254 try writeResourceData(writer, &data_fbs, data_len);1275 try writeResourceData(writer, &data_fbs, data_len);
1255 }1276 }
12561277
1257 pub fn writeResourceHeader(self: *Compiler, writer: anytype, id_token: Token, type_token: Token, data_size: u32, common_resource_attributes: []Token, language: res.Language) !void {1278 pub fn writeResourceHeader(self: *Compiler, writer: *std.Io.Writer, id_token: Token, type_token: Token, data_size: u32, common_resource_attributes: []Token, language: res.Language) !void {
1258 var header = try self.resourceHeader(id_token, type_token, .{1279 var header = try self.resourceHeader(id_token, type_token, .{
1259 .language = language,1280 .language = language,
1260 .data_size = data_size,1281 .data_size = data_size,
...@@ -1270,7 +1291,7 @@ pub const Compiler = struct {...@@ -1270,7 +1291,7 @@ pub const Compiler = struct {
1270 try data_reader.streamExact(writer, data_size);1291 try data_reader.streamExact(writer, data_size);
1271 }1292 }
12721293
1273 pub fn writeResourceData(writer: anytype, data_reader: *std.Io.Reader, data_size: u32) !void {1294 pub fn writeResourceData(writer: *std.Io.Writer, data_reader: *std.Io.Reader, data_size: u32) !void {
1274 try writeResourceDataNoPadding(writer, data_reader, data_size);1295 try writeResourceDataNoPadding(writer, data_reader, data_size);
1275 try writeDataPadding(writer, data_size);1296 try writeDataPadding(writer, data_size);
1276 }1297 }
...@@ -1303,27 +1324,19 @@ pub const Compiler = struct {...@@ -1303,27 +1324,19 @@ pub const Compiler = struct {
1303 }1324 }
1304 }1325 }
13051326
1306 pub fn writeAccelerators(self: *Compiler, node: *Node.Accelerators, writer: anytype) !void {1327 pub fn writeAccelerators(self: *Compiler, node: *Node.Accelerators, writer: *std.Io.Writer) !void {
1307 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);1328 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
1308 defer data_buffer.deinit();1329 defer data_buffer.deinit();
13091330
1310 // The header's data length field is a u32 so limit the resource's data size so that1331 try self.writeAcceleratorsData(node, &data_buffer.writer);
1311 // we know we can always specify the real size.
1312 const data_writer = &data_buffer.writer;
13131332
1314 self.writeAcceleratorsData(node, data_writer) catch |err| switch (err) {1333 // TODO: Limit data_buffer in some way to error when writing more than u32 max bytes
1315 error.WriteFailed => {1334 const data_size: u32 = std.math.cast(u32, data_buffer.written().len) orelse {
1316 return self.addErrorDetailsAndFail(.{1335 return self.addErrorDetailsAndFail(.{
1317 .err = .resource_data_size_exceeds_max,1336 .err = .resource_data_size_exceeds_max,
1318 .token = node.id,1337 .token = node.id,
1319 });1338 });
1320 },
1321 else => |e| return e,
1322 };1339 };
1323
1324 // This intCast can't fail because the limitedWriter above guarantees that
1325 // we will never write more than maxInt(u32) bytes.
1326 const data_size: u32 = @intCast(data_buffer.written().len);
1327 var header = try self.resourceHeader(node.id, node.type, .{1340 var header = try self.resourceHeader(node.id, node.type, .{
1328 .data_size = data_size,1341 .data_size = data_size,
1329 });1342 });
...@@ -1340,7 +1353,7 @@ pub const Compiler = struct {...@@ -1340,7 +1353,7 @@ pub const Compiler = struct {
13401353
1341 /// Expects `data_writer` to be a LimitedWriter limited to u32, meaning all writes to1354 /// Expects `data_writer` to be a LimitedWriter limited to u32, meaning all writes to
1342 /// the writer within this function could return error.NoSpaceLeft1355 /// the writer within this function could return error.NoSpaceLeft
1343 pub fn writeAcceleratorsData(self: *Compiler, node: *Node.Accelerators, data_writer: anytype) !void {1356 pub fn writeAcceleratorsData(self: *Compiler, node: *Node.Accelerators, data_writer: *std.Io.Writer) !void {
1344 for (node.accelerators, 0..) |accel_node, i| {1357 for (node.accelerators, 0..) |accel_node, i| {
1345 const accelerator: *Node.Accelerator = @alignCast(@fieldParentPtr("base", accel_node));1358 const accelerator: *Node.Accelerator = @alignCast(@fieldParentPtr("base", accel_node));
1346 var modifiers = res.AcceleratorModifiers{};1359 var modifiers = res.AcceleratorModifiers{};
...@@ -1401,12 +1414,9 @@ pub const Compiler = struct {...@@ -1401,12 +1414,9 @@ pub const Compiler = struct {
1401 caption: ?Token = null,1414 caption: ?Token = null,
1402 };1415 };
14031416
1404 pub fn writeDialog(self: *Compiler, node: *Node.Dialog, writer: anytype) !void {1417 pub fn writeDialog(self: *Compiler, node: *Node.Dialog, writer: *std.Io.Writer) !void {
1405 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);1418 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
1406 defer data_buffer.deinit();1419 defer data_buffer.deinit();
1407 // The header's data length field is a u32 so limit the resource's data size so that
1408 // we know we can always specify the real size.
1409 const data_writer = &data_buffer.writer;
14101420
1411 const resource = ResourceType.fromString(.{1421 const resource = ResourceType.fromString(.{
1412 .slice = node.type.slice(self.source),1422 .slice = node.type.slice(self.source),
...@@ -1667,21 +1677,18 @@ pub const Compiler = struct {...@@ -1667,21 +1677,18 @@ pub const Compiler = struct {
1667 optional_statement_values.style |= res.WS.CAPTION;1677 optional_statement_values.style |= res.WS.CAPTION;
1668 }1678 }
16691679
1670 self.writeDialogHeaderAndStrings(1680 // NOTE: Dialog header and menu/class/title strings can never exceed u32 bytes
1681 // on their own.
1682 try self.writeDialogHeaderAndStrings(
1671 node,1683 node,
1672 data_writer,1684 &data_buffer.writer,
1673 resource,1685 resource,
1674 &optional_statement_values,1686 &optional_statement_values,
1675 x,1687 x,
1676 y,1688 y,
1677 width,1689 width,
1678 height,1690 height,
1679 ) catch |err| switch (err) {1691 );
1680 // Dialog header and menu/class/title strings can never exceed u32 bytes
1681 // on their own, so this error is unreachable.
1682 error.WriteFailed => unreachable,
1683 else => |e| return e,
1684 };
16851692
1686 var controls_by_id = std.AutoHashMap(u32, *const Node.ControlStatement).init(self.allocator);1693 var controls_by_id = std.AutoHashMap(u32, *const Node.ControlStatement).init(self.allocator);
1687 // Number of controls are guaranteed by the parser to be within maxInt(u16).1694 // Number of controls are guaranteed by the parser to be within maxInt(u16).
...@@ -1691,27 +1698,26 @@ pub const Compiler = struct {...@@ -1691,27 +1698,26 @@ pub const Compiler = struct {
1691 for (node.controls) |control_node| {1698 for (node.controls) |control_node| {
1692 const control: *Node.ControlStatement = @alignCast(@fieldParentPtr("base", control_node));1699 const control: *Node.ControlStatement = @alignCast(@fieldParentPtr("base", control_node));
16931700
1694 self.writeDialogControl(1701 try self.writeDialogControl(
1695 control,1702 control,
1696 data_writer,1703 &data_buffer.writer,
1697 resource,1704 resource,
1698 // We know the data_buffer len is limited to u32 max.1705 // We know the data_buffer len is limited to u32 max.
1699 @intCast(data_buffer.written().len),1706 @intCast(data_buffer.written().len),
1700 &controls_by_id,1707 &controls_by_id,
1701 ) catch |err| switch (err) {1708 );
1702 error.WriteFailed => {1709
1703 try self.addErrorDetails(.{1710 if (data_buffer.written().len > std.math.maxInt(u32)) {
1704 .err = .resource_data_size_exceeds_max,1711 try self.addErrorDetails(.{
1705 .token = node.id,1712 .err = .resource_data_size_exceeds_max,
1706 });1713 .token = node.id,
1707 return self.addErrorDetailsAndFail(.{1714 });
1708 .err = .resource_data_size_exceeds_max,1715 return self.addErrorDetailsAndFail(.{
1709 .type = .note,1716 .err = .resource_data_size_exceeds_max,
1710 .token = control.type,1717 .type = .note,
1711 });1718 .token = control.type,
1712 },1719 });
1713 else => |e| return e,1720 }
1714 };
1715 }1721 }
17161722
1717 // We know the data_buffer len is limited to u32 max.1723 // We know the data_buffer len is limited to u32 max.
...@@ -1733,7 +1739,7 @@ pub const Compiler = struct {...@@ -1733,7 +1739,7 @@ pub const Compiler = struct {
1733 fn writeDialogHeaderAndStrings(1739 fn writeDialogHeaderAndStrings(
1734 self: *Compiler,1740 self: *Compiler,
1735 node: *Node.Dialog,1741 node: *Node.Dialog,
1736 data_writer: anytype,1742 data_writer: *std.Io.Writer,
1737 resource: ResourceType,1743 resource: ResourceType,
1738 optional_statement_values: *const DialogOptionalStatementValues,1744 optional_statement_values: *const DialogOptionalStatementValues,
1739 x: Number,1745 x: Number,
...@@ -1793,7 +1799,7 @@ pub const Compiler = struct {...@@ -1793,7 +1799,7 @@ pub const Compiler = struct {
1793 fn writeDialogControl(1799 fn writeDialogControl(
1794 self: *Compiler,1800 self: *Compiler,
1795 control: *Node.ControlStatement,1801 control: *Node.ControlStatement,
1796 data_writer: anytype,1802 data_writer: *std.Io.Writer,
1797 resource: ResourceType,1803 resource: ResourceType,
1798 bytes_written_so_far: u32,1804 bytes_written_so_far: u32,
1799 controls_by_id: *std.AutoHashMap(u32, *const Node.ControlStatement),1805 controls_by_id: *std.AutoHashMap(u32, *const Node.ControlStatement),
...@@ -1969,28 +1975,26 @@ pub const Compiler = struct {...@@ -1969,28 +1975,26 @@ pub const Compiler = struct {
1969 try NameOrOrdinal.writeEmpty(data_writer);1975 try NameOrOrdinal.writeEmpty(data_writer);
1970 }1976 }
19711977
1978 // The extra data byte length must be able to fit within a u16.
1972 var extra_data_buf: std.Io.Writer.Allocating = .init(self.allocator);1979 var extra_data_buf: std.Io.Writer.Allocating = .init(self.allocator);
1973 defer extra_data_buf.deinit();1980 defer extra_data_buf.deinit();
1974 // The extra data byte length must be able to fit within a u16.
1975 const extra_data_writer = &extra_data_buf.writer;
1976 for (control.extra_data) |data_expression| {1981 for (control.extra_data) |data_expression| {
1977 const data = try self.evaluateDataExpression(data_expression);1982 const data = try self.evaluateDataExpression(data_expression);
1978 defer data.deinit(self.allocator);1983 defer data.deinit(self.allocator);
1979 data.write(extra_data_writer) catch |err| switch (err) {1984 try data.write(&extra_data_buf.writer);
1980 error.WriteFailed => {1985
1981 try self.addErrorDetails(.{1986 if (extra_data_buf.written().len > std.math.maxInt(u16)) {
1982 .err = .control_extra_data_size_exceeds_max,1987 try self.addErrorDetails(.{
1983 .token = control.type,1988 .err = .control_extra_data_size_exceeds_max,
1984 });1989 .token = control.type,
1985 return self.addErrorDetailsAndFail(.{1990 });
1986 .err = .control_extra_data_size_exceeds_max,1991 return self.addErrorDetailsAndFail(.{
1987 .type = .note,1992 .err = .control_extra_data_size_exceeds_max,
1988 .token = data_expression.getFirstToken(),1993 .type = .note,
1989 .token_span_end = data_expression.getLastToken(),1994 .token = data_expression.getFirstToken(),
1990 });1995 .token_span_end = data_expression.getLastToken(),
1991 },1996 });
1992 else => |e| return e,1997 }
1993 };
1994 }1998 }
1995 // We know the extra_data_buf size fits within a u16.1999 // We know the extra_data_buf size fits within a u16.
1996 const extra_data_size: u16 = @intCast(extra_data_buf.written().len);2000 const extra_data_size: u16 = @intCast(extra_data_buf.written().len);
...@@ -1998,7 +2002,7 @@ pub const Compiler = struct {...@@ -1998,7 +2002,7 @@ pub const Compiler = struct {
1998 try data_writer.writeAll(extra_data_buf.written());2002 try data_writer.writeAll(extra_data_buf.written());
1999 }2003 }
20002004
2001 pub fn writeToolbar(self: *Compiler, node: *Node.Toolbar, writer: anytype) !void {2005 pub fn writeToolbar(self: *Compiler, node: *Node.Toolbar, writer: *std.Io.Writer) !void {
2002 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);2006 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
2003 defer data_buffer.deinit();2007 defer data_buffer.deinit();
2004 const data_writer = &data_buffer.writer;2008 const data_writer = &data_buffer.writer;
...@@ -2051,7 +2055,7 @@ pub const Compiler = struct {...@@ -2051,7 +2055,7 @@ pub const Compiler = struct {
2051 node: *Node.FontStatement,2055 node: *Node.FontStatement,
2052 };2056 };
20532057
2054 pub fn writeDialogFont(self: *Compiler, resource: ResourceType, values: FontStatementValues, writer: anytype) !void {2058 pub fn writeDialogFont(self: *Compiler, resource: ResourceType, values: FontStatementValues, writer: *std.Io.Writer) !void {
2055 const node = values.node;2059 const node = values.node;
2056 const point_size = evaluateNumberExpression(node.point_size, self.source, self.input_code_pages);2060 const point_size = evaluateNumberExpression(node.point_size, self.source, self.input_code_pages);
2057 try writer.writeInt(u16, point_size.asWord(), .little);2061 try writer.writeInt(u16, point_size.asWord(), .little);
...@@ -2076,12 +2080,9 @@ pub const Compiler = struct {...@@ -2076,12 +2080,9 @@ pub const Compiler = struct {
2076 try writer.writeAll(std.mem.sliceAsBytes(typeface[0 .. typeface.len + 1]));2080 try writer.writeAll(std.mem.sliceAsBytes(typeface[0 .. typeface.len + 1]));
2077 }2081 }
20782082
2079 pub fn writeMenu(self: *Compiler, node: *Node.Menu, writer: anytype) !void {2083 pub fn writeMenu(self: *Compiler, node: *Node.Menu, writer: *std.Io.Writer) !void {
2080 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);2084 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
2081 defer data_buffer.deinit();2085 defer data_buffer.deinit();
2082 // The header's data length field is a u32 so limit the resource's data size so that
2083 // we know we can always specify the real size.
2084 const data_writer = &data_buffer.writer;
20852086
2086 const type_bytes = SourceBytes{2087 const type_bytes = SourceBytes{
2087 .slice = node.type.slice(self.source),2088 .slice = node.type.slice(self.source),
...@@ -2090,19 +2091,15 @@ pub const Compiler = struct {...@@ -2090,19 +2091,15 @@ pub const Compiler = struct {
2090 const resource = ResourceType.fromString(type_bytes);2091 const resource = ResourceType.fromString(type_bytes);
2091 std.debug.assert(resource == .menu or resource == .menuex);2092 std.debug.assert(resource == .menu or resource == .menuex);
20922093
2093 self.writeMenuData(node, data_writer, resource) catch |err| switch (err) {2094 try self.writeMenuData(node, &data_buffer.writer, resource);
2094 error.WriteFailed => {
2095 return self.addErrorDetailsAndFail(.{
2096 .err = .resource_data_size_exceeds_max,
2097 .token = node.id,
2098 });
2099 },
2100 else => |e| return e,
2101 };
21022095
2103 // This intCast can't fail because the limitedWriter above guarantees that2096 // TODO: Limit data_buffer in some way to error when writing more than u32 max bytes
2104 // we will never write more than maxInt(u32) bytes.2097 const data_size: u32 = std.math.cast(u32, data_buffer.written().len) orelse {
2105 const data_size: u32 = @intCast(data_buffer.written().len);2098 return self.addErrorDetailsAndFail(.{
2099 .err = .resource_data_size_exceeds_max,
2100 .token = node.id,
2101 });
2102 };
2106 var header = try self.resourceHeader(node.id, node.type, .{2103 var header = try self.resourceHeader(node.id, node.type, .{
2107 .data_size = data_size,2104 .data_size = data_size,
2108 });2105 });
...@@ -2256,11 +2253,10 @@ pub const Compiler = struct {...@@ -2256,11 +2253,10 @@ pub const Compiler = struct {
2256 }2253 }
2257 }2254 }
22582255
2259 pub fn writeVersionInfo(self: *Compiler, node: *Node.VersionInfo, writer: anytype) !void {2256 pub fn writeVersionInfo(self: *Compiler, node: *Node.VersionInfo, writer: *std.Io.Writer) !void {
2257 // NOTE: The node's length field (which is inclusive of the length of all of its children) is a u16
2260 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);2258 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
2261 defer data_buffer.deinit();2259 defer data_buffer.deinit();
2262 // The node's length field (which is inclusive of the length of all of its children) is a u16
2263 // so limit the node's data size so that we know we can always specify the real size.
2264 const data_writer = &data_buffer.writer;2260 const data_writer = &data_buffer.writer;
22652261
2266 try data_writer.writeInt(u16, 0, .little); // placeholder size2262 try data_writer.writeInt(u16, 0, .little); // placeholder size
...@@ -2345,25 +2341,29 @@ pub const Compiler = struct {...@@ -2345,25 +2341,29 @@ pub const Compiler = struct {
2345 try fixed_file_info.write(data_writer);2341 try fixed_file_info.write(data_writer);
23462342
2347 for (node.block_statements) |statement| {2343 for (node.block_statements) |statement| {
2348 self.writeVersionNode(statement, data_writer, &data_buffer) catch |err| switch (err) {2344 var overflow = false;
2349 error.WriteFailed => {2345 self.writeVersionNode(statement, data_writer) catch |err| switch (err) {
2350 try self.addErrorDetails(.{2346 error.NoSpaceLeft => {
2351 .err = .version_node_size_exceeds_max,2347 overflow = true;
2352 .token = node.id,
2353 });
2354 return self.addErrorDetailsAndFail(.{
2355 .err = .version_node_size_exceeds_max,
2356 .type = .note,
2357 .token = statement.getFirstToken(),
2358 .token_span_end = statement.getLastToken(),
2359 });
2360 },2348 },
2361 else => |e| return e,2349 else => |e| return e,
2362 };2350 };
2351 if (overflow or data_buffer.written().len > std.math.maxInt(u16)) {
2352 try self.addErrorDetails(.{
2353 .err = .version_node_size_exceeds_max,
2354 .token = node.id,
2355 });
2356 return self.addErrorDetailsAndFail(.{
2357 .err = .version_node_size_exceeds_max,
2358 .type = .note,
2359 .token = statement.getFirstToken(),
2360 .token_span_end = statement.getLastToken(),
2361 });
2362 }
2363 }2363 }
23642364
2365 // We know that data_buffer.items.len is within the limits of a u16, since we2365 // We know that data_buffer len is within the limits of a u16, since we check in the block
2366 // limited the writer to maxInt(u16)2366 // statements loop above which is the only place it can overflow.
2367 const data_size: u16 = @intCast(data_buffer.written().len);2367 const data_size: u16 = @intCast(data_buffer.written().len);
2368 // And now that we know the full size of this node (including its children), set its size2368 // And now that we know the full size of this node (including its children), set its size
2369 std.mem.writeInt(u16, data_buffer.written()[0..2], data_size, .little);2369 std.mem.writeInt(u16, data_buffer.written()[0..2], data_size, .little);
...@@ -2381,18 +2381,17 @@ pub const Compiler = struct {...@@ -2381,18 +2381,17 @@ pub const Compiler = struct {
2381 try writeResourceData(writer, &data_fbs, data_size);2381 try writeResourceData(writer, &data_fbs, data_size);
2382 }2382 }
23832383
2384 /// Expects writer to be a LimitedWriter limited to u16, meaning all writes to2384 /// Assumes that writer is Writer.Allocating (specifically, that buffered() gets the entire data)
2385 /// the writer within this function could return error.NoSpaceLeft, and that buf.items.len2385 /// TODO: This function could be nicer if writer was guaranteed to fail if it wrote more than u16 max bytes
2386 /// will never be able to exceed maxInt(u16).2386 pub fn writeVersionNode(self: *Compiler, node: *Node, writer: *std.Io.Writer) !void {
2387 pub fn writeVersionNode(self: *Compiler, node: *Node, writer: *std.Io.Writer, buf: *std.Io.Writer.Allocating) !void {
2388 // We can assume that buf.items.len will never be able to exceed the limits of a u162387 // We can assume that buf.items.len will never be able to exceed the limits of a u16
2389 try writeDataPadding(writer, @as(u16, @intCast(buf.written().len)));2388 try writeDataPadding(writer, std.math.cast(u16, writer.buffered().len) orelse return error.NoSpaceLeft);
23902389
2391 const node_and_children_size_offset = buf.written().len;2390 const node_and_children_size_offset = writer.buffered().len;
2392 try writer.writeInt(u16, 0, .little); // placeholder for size2391 try writer.writeInt(u16, 0, .little); // placeholder for size
2393 const data_size_offset = buf.written().len;2392 const data_size_offset = writer.buffered().len;
2394 try writer.writeInt(u16, 0, .little); // placeholder for data size2393 try writer.writeInt(u16, 0, .little); // placeholder for data size
2395 const data_type_offset = buf.written().len;2394 const data_type_offset = writer.buffered().len;
2396 // Data type is string unless the node contains values that are numbers.2395 // Data type is string unless the node contains values that are numbers.
2397 try writer.writeInt(u16, res.VersionNode.type_string, .little);2396 try writer.writeInt(u16, res.VersionNode.type_string, .little);
23982397
...@@ -2422,7 +2421,7 @@ pub const Compiler = struct {...@@ -2422,7 +2421,7 @@ pub const Compiler = struct {
2422 // during parsing, so we can just do the correct thing here.2421 // during parsing, so we can just do the correct thing here.
2423 var values_size: usize = 0;2422 var values_size: usize = 0;
24242423
2425 try writeDataPadding(writer, @intCast(buf.written().len));2424 try writeDataPadding(writer, std.math.cast(u16, writer.buffered().len) orelse return error.NoSpaceLeft);
24262425
2427 for (block_or_value.values, 0..) |value_value_node_uncasted, i| {2426 for (block_or_value.values, 0..) |value_value_node_uncasted, i| {
2428 const value_value_node = value_value_node_uncasted.cast(.block_value_value).?;2427 const value_value_node = value_value_node_uncasted.cast(.block_value_value).?;
...@@ -2461,26 +2460,26 @@ pub const Compiler = struct {...@@ -2461,26 +2460,26 @@ pub const Compiler = struct {
2461 }2460 }
2462 }2461 }
2463 }2462 }
2464 var data_size_slice = buf.written()[data_size_offset..];2463 var data_size_slice = writer.buffered()[data_size_offset..];
2465 std.mem.writeInt(u16, data_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(values_size)), .little);2464 std.mem.writeInt(u16, data_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(values_size)), .little);
24662465
2467 if (has_number_value) {2466 if (has_number_value) {
2468 const data_type_slice = buf.written()[data_type_offset..];2467 const data_type_slice = writer.buffered()[data_type_offset..];
2469 std.mem.writeInt(u16, data_type_slice[0..@sizeOf(u16)], res.VersionNode.type_binary, .little);2468 std.mem.writeInt(u16, data_type_slice[0..@sizeOf(u16)], res.VersionNode.type_binary, .little);
2470 }2469 }
24712470
2472 if (node_type == .block) {2471 if (node_type == .block) {
2473 const block = block_or_value;2472 const block = block_or_value;
2474 for (block.children) |child| {2473 for (block.children) |child| {
2475 try self.writeVersionNode(child, writer, buf);2474 try self.writeVersionNode(child, writer);
2476 }2475 }
2477 }2476 }
2478 },2477 },
2479 else => unreachable,2478 else => unreachable,
2480 }2479 }
24812480
2482 const node_and_children_size = buf.written().len - node_and_children_size_offset;2481 const node_and_children_size = writer.buffered().len - node_and_children_size_offset;
2483 const node_and_children_size_slice = buf.written()[node_and_children_size_offset..];2482 const node_and_children_size_slice = writer.buffered()[node_and_children_size_offset..];
2484 std.mem.writeInt(u16, node_and_children_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(node_and_children_size)), .little);2483 std.mem.writeInt(u16, node_and_children_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(node_and_children_size)), .little);
2485 }2484 }
24862485
...@@ -2673,11 +2672,11 @@ pub const Compiler = struct {...@@ -2673,11 +2672,11 @@ pub const Compiler = struct {
2673 return .{ .bytes = header_size, .padding_after_name = padding_after_name };2672 return .{ .bytes = header_size, .padding_after_name = padding_after_name };
2674 }2673 }
26752674
2676 pub fn writeAssertNoOverflow(self: ResourceHeader, writer: anytype) !void {2675 pub fn writeAssertNoOverflow(self: ResourceHeader, writer: *std.Io.Writer) !void {
2677 return self.writeSizeInfo(writer, self.calcSize() catch unreachable);2676 return self.writeSizeInfo(writer, self.calcSize() catch unreachable);
2678 }2677 }
26792678
2680 pub fn write(self: ResourceHeader, writer: anytype, err_ctx: errors.DiagnosticsContext) !void {2679 pub fn write(self: ResourceHeader, writer: *std.Io.Writer, err_ctx: errors.DiagnosticsContext) !void {
2681 const size_info = self.calcSize() catch {2680 const size_info = self.calcSize() catch {
2682 try err_ctx.diagnostics.append(.{2681 try err_ctx.diagnostics.append(.{
2683 .err = .resource_data_size_exceeds_max,2682 .err = .resource_data_size_exceeds_max,
...@@ -2815,7 +2814,7 @@ pub const Compiler = struct {...@@ -2815,7 +2814,7 @@ pub const Compiler = struct {
2815 return null;2814 return null;
2816 }2815 }
28172816
2818 pub fn writeEmptyResource(writer: anytype) !void {2817 pub fn writeEmptyResource(writer: *std.Io.Writer) !void {
2819 const header = ResourceHeader{2818 const header = ResourceHeader{
2820 .name_value = .{ .ordinal = 0 },2819 .name_value = .{ .ordinal = 0 },
2821 .type_value = .{ .ordinal = 0 },2820 .type_value = .{ .ordinal = 0 },
...@@ -2932,39 +2931,8 @@ pub const SearchDir = struct {...@@ -2932,39 +2931,8 @@ pub const SearchDir = struct {
2932 }2931 }
2933};2932};
29342933
2935/// Slurps the first `size` bytes read into `slurped_header`
2936pub fn HeaderSlurpingReader(comptime size: usize, comptime ReaderType: anytype) type {
2937 return struct {
2938 child_reader: ReaderType,
2939 bytes_read: usize = 0,
2940 slurped_header: [size]u8 = [_]u8{0x00} ** size,
2941
2942 pub const Error = ReaderType.Error;
2943 pub const Reader = std.io.GenericReader(*@This(), Error, read);
2944
2945 pub fn read(self: *@This(), buf: []u8) Error!usize {
2946 const amt = try self.child_reader.read(buf);
2947 if (self.bytes_read < size) {
2948 const bytes_to_add = @min(amt, size - self.bytes_read);
2949 const end_index = self.bytes_read + bytes_to_add;
2950 @memcpy(self.slurped_header[self.bytes_read..end_index], buf[0..bytes_to_add]);
2951 }
2952 self.bytes_read +|= amt;
2953 return amt;
2954 }
2955
2956 pub fn reader(self: *@This()) Reader {
2957 return .{ .context = self };
2958 }
2959 };
2960}
2961
2962pub fn headerSlurpingReader(comptime size: usize, reader: anytype) HeaderSlurpingReader(size, @TypeOf(reader)) {
2963 return .{ .child_reader = reader };
2964}
2965
2966pub const FontDir = struct {2934pub const FontDir = struct {
2967 fonts: std.ArrayListUnmanaged(Font) = .empty,2935 fonts: std.ArrayList(Font) = .empty,
2968 /// To keep track of which ids are set and where they were set from2936 /// To keep track of which ids are set and where they were set from
2969 ids: std.AutoHashMapUnmanaged(u16, Token) = .empty,2937 ids: std.AutoHashMapUnmanaged(u16, Token) = .empty,
29702938
...@@ -2982,7 +2950,7 @@ pub const FontDir = struct {...@@ -2982,7 +2950,7 @@ pub const FontDir = struct {
2982 try self.fonts.append(allocator, font);2950 try self.fonts.append(allocator, font);
2983 }2951 }
29842952
2985 pub fn writeResData(self: *FontDir, compiler: *Compiler, writer: anytype) !void {2953 pub fn writeResData(self: *FontDir, compiler: *Compiler, writer: *std.Io.Writer) !void {
2986 if (self.fonts.items.len == 0) return;2954 if (self.fonts.items.len == 0) return;
29872955
2988 // We know the number of fonts is limited to maxInt(u16) because fonts2956 // We know the number of fonts is limited to maxInt(u16) because fonts
...@@ -3106,7 +3074,7 @@ pub const StringTable = struct {...@@ -3106,7 +3074,7 @@ pub const StringTable = struct {
3106 blocks: std.AutoArrayHashMapUnmanaged(u16, Block) = .empty,3074 blocks: std.AutoArrayHashMapUnmanaged(u16, Block) = .empty,
31073075
3108 pub const Block = struct {3076 pub const Block = struct {
3109 strings: std.ArrayListUnmanaged(Token) = .empty,3077 strings: std.ArrayList(Token) = .empty,
3110 set_indexes: std.bit_set.IntegerBitSet(16) = .{ .mask = 0 },3078 set_indexes: std.bit_set.IntegerBitSet(16) = .{ .mask = 0 },
3111 memory_flags: MemoryFlags = MemoryFlags.defaults(res.RT.STRING),3079 memory_flags: MemoryFlags = MemoryFlags.defaults(res.RT.STRING),
3112 characteristics: u32,3080 characteristics: u32,
...@@ -3187,7 +3155,7 @@ pub const StringTable = struct {...@@ -3187,7 +3155,7 @@ pub const StringTable = struct {
3187 try std.testing.expectEqualStrings("a", trimToDoubleNUL(u8, "a\x00\x00b"));3155 try std.testing.expectEqualStrings("a", trimToDoubleNUL(u8, "a\x00\x00b"));
3188 }3156 }
31893157
3190 pub fn writeResData(self: *Block, compiler: *Compiler, language: res.Language, block_id: u16, writer: anytype) !void {3158 pub fn writeResData(self: *Block, compiler: *Compiler, language: res.Language, block_id: u16, writer: *std.Io.Writer) !void {
3191 var data_buffer: std.Io.Writer.Allocating = .init(compiler.allocator);3159 var data_buffer: std.Io.Writer.Allocating = .init(compiler.allocator);
3192 defer data_buffer.deinit();3160 defer data_buffer.deinit();
3193 const data_writer = &data_buffer.writer;3161 const data_writer = &data_buffer.writer;
lib/compiler/resinator/cvtres.zig+12-12
...@@ -43,7 +43,7 @@ pub const Resource = struct {...@@ -43,7 +43,7 @@ pub const Resource = struct {
43};43};
4444
45pub const ParsedResources = struct {45pub const ParsedResources = struct {
46 list: std.ArrayListUnmanaged(Resource) = .empty,46 list: std.ArrayList(Resource) = .empty,
47 allocator: Allocator,47 allocator: Allocator,
4848
49 pub fn init(allocator: Allocator) ParsedResources {49 pub fn init(allocator: Allocator) ParsedResources {
...@@ -157,7 +157,7 @@ pub fn parseNameOrOrdinal(allocator: Allocator, reader: *std.Io.Reader) !NameOrO...@@ -157,7 +157,7 @@ pub fn parseNameOrOrdinal(allocator: Allocator, reader: *std.Io.Reader) !NameOrO
157 const ordinal_value = try reader.takeInt(u16, .little);157 const ordinal_value = try reader.takeInt(u16, .little);
158 return .{ .ordinal = ordinal_value };158 return .{ .ordinal = ordinal_value };
159 }159 }
160 var name_buf = try std.ArrayListUnmanaged(u16).initCapacity(allocator, 16);160 var name_buf = try std.ArrayList(u16).initCapacity(allocator, 16);
161 errdefer name_buf.deinit(allocator);161 errdefer name_buf.deinit(allocator);
162 var code_unit = first_code_unit;162 var code_unit = first_code_unit;
163 while (code_unit != 0) {163 while (code_unit != 0) {
...@@ -373,7 +373,7 @@ pub fn writeCoff(allocator: Allocator, writer: *std.Io.Writer, resources: []cons...@@ -373,7 +373,7 @@ pub fn writeCoff(allocator: Allocator, writer: *std.Io.Writer, resources: []cons
373 try writer.writeAll(string_table.bytes.items);373 try writer.writeAll(string_table.bytes.items);
374}374}
375375
376fn writeSymbol(writer: anytype, symbol: std.coff.Symbol) !void {376fn writeSymbol(writer: *std.Io.Writer, symbol: std.coff.Symbol) !void {
377 try writer.writeAll(&symbol.name);377 try writer.writeAll(&symbol.name);
378 try writer.writeInt(u32, symbol.value, .little);378 try writer.writeInt(u32, symbol.value, .little);
379 try writer.writeInt(u16, @intFromEnum(symbol.section_number), .little);379 try writer.writeInt(u16, @intFromEnum(symbol.section_number), .little);
...@@ -383,7 +383,7 @@ fn writeSymbol(writer: anytype, symbol: std.coff.Symbol) !void {...@@ -383,7 +383,7 @@ fn writeSymbol(writer: anytype, symbol: std.coff.Symbol) !void {
383 try writer.writeInt(u8, symbol.number_of_aux_symbols, .little);383 try writer.writeInt(u8, symbol.number_of_aux_symbols, .little);
384}384}
385385
386fn writeSectionDefinition(writer: anytype, def: std.coff.SectionDefinition) !void {386fn writeSectionDefinition(writer: *std.Io.Writer, def: std.coff.SectionDefinition) !void {
387 try writer.writeInt(u32, def.length, .little);387 try writer.writeInt(u32, def.length, .little);
388 try writer.writeInt(u16, def.number_of_relocations, .little);388 try writer.writeInt(u16, def.number_of_relocations, .little);
389 try writer.writeInt(u16, def.number_of_linenumbers, .little);389 try writer.writeInt(u16, def.number_of_linenumbers, .little);
...@@ -417,7 +417,7 @@ pub const ResourceDirectoryEntry = extern struct {...@@ -417,7 +417,7 @@ pub const ResourceDirectoryEntry = extern struct {
417 to_subdirectory: bool,417 to_subdirectory: bool,
418 },418 },
419419
420 pub fn writeCoff(self: ResourceDirectoryEntry, writer: anytype) !void {420 pub fn writeCoff(self: ResourceDirectoryEntry, writer: *std.Io.Writer) !void {
421 try writer.writeInt(u32, @bitCast(self.entry), .little);421 try writer.writeInt(u32, @bitCast(self.entry), .little);
422 try writer.writeInt(u32, @bitCast(self.offset), .little);422 try writer.writeInt(u32, @bitCast(self.offset), .little);
423 }423 }
...@@ -435,7 +435,7 @@ const ResourceTree = struct {...@@ -435,7 +435,7 @@ const ResourceTree = struct {
435 type_to_name_map: std.ArrayHashMapUnmanaged(NameOrOrdinal, NameToLanguageMap, NameOrOrdinalHashContext, true),435 type_to_name_map: std.ArrayHashMapUnmanaged(NameOrOrdinal, NameToLanguageMap, NameOrOrdinalHashContext, true),
436 rsrc_string_table: std.ArrayHashMapUnmanaged(NameOrOrdinal, void, NameOrOrdinalHashContext, true),436 rsrc_string_table: std.ArrayHashMapUnmanaged(NameOrOrdinal, void, NameOrOrdinalHashContext, true),
437 deduplicated_data: std.StringArrayHashMapUnmanaged(u32),437 deduplicated_data: std.StringArrayHashMapUnmanaged(u32),
438 data_offsets: std.ArrayListUnmanaged(u32),438 data_offsets: std.ArrayList(u32),
439 rsrc02_len: u32,439 rsrc02_len: u32,
440 coff_options: CoffOptions,440 coff_options: CoffOptions,
441 allocator: Allocator,441 allocator: Allocator,
...@@ -675,13 +675,13 @@ const ResourceTree = struct {...@@ -675,13 +675,13 @@ const ResourceTree = struct {
675 return &.{};675 return &.{};
676 }676 }
677677
678 var level2_list: std.ArrayListUnmanaged(*const NameToLanguageMap) = .empty;678 var level2_list: std.ArrayList(*const NameToLanguageMap) = .empty;
679 defer level2_list.deinit(allocator);679 defer level2_list.deinit(allocator);
680680
681 var level3_list: std.ArrayListUnmanaged(*const LanguageToResourceMap) = .empty;681 var level3_list: std.ArrayList(*const LanguageToResourceMap) = .empty;
682 defer level3_list.deinit(allocator);682 defer level3_list.deinit(allocator);
683683
684 var resources_list: std.ArrayListUnmanaged(*const RelocatableResource) = .empty;684 var resources_list: std.ArrayList(*const RelocatableResource) = .empty;
685 defer resources_list.deinit(allocator);685 defer resources_list.deinit(allocator);
686686
687 var relocations = Relocations.init(allocator);687 var relocations = Relocations.init(allocator);
...@@ -896,7 +896,7 @@ const ResourceTree = struct {...@@ -896,7 +896,7 @@ const ResourceTree = struct {
896 return symbols;896 return symbols;
897 }897 }
898898
899 fn writeRelocation(writer: anytype, relocation: std.coff.Relocation) !void {899 fn writeRelocation(writer: *std.Io.Writer, relocation: std.coff.Relocation) !void {
900 try writer.writeInt(u32, relocation.virtual_address, .little);900 try writer.writeInt(u32, relocation.virtual_address, .little);
901 try writer.writeInt(u32, relocation.symbol_table_index, .little);901 try writer.writeInt(u32, relocation.symbol_table_index, .little);
902 try writer.writeInt(u16, relocation.type, .little);902 try writer.writeInt(u16, relocation.type, .little);
...@@ -928,7 +928,7 @@ const Relocation = struct {...@@ -928,7 +928,7 @@ const Relocation = struct {
928928
929const Relocations = struct {929const Relocations = struct {
930 allocator: Allocator,930 allocator: Allocator,
931 list: std.ArrayListUnmanaged(Relocation) = .empty,931 list: std.ArrayList(Relocation) = .empty,
932 cur_symbol_index: u32 = 5,932 cur_symbol_index: u32 = 5,
933933
934 pub fn init(allocator: Allocator) Relocations {934 pub fn init(allocator: Allocator) Relocations {
...@@ -952,7 +952,7 @@ const Relocations = struct {...@@ -952,7 +952,7 @@ const Relocations = struct {
952/// Does not do deduplication (only because there's no chance of duplicate strings in this952/// Does not do deduplication (only because there's no chance of duplicate strings in this
953/// instance).953/// instance).
954const StringTable = struct {954const StringTable = struct {
955 bytes: std.ArrayListUnmanaged(u8) = .empty,955 bytes: std.ArrayList(u8) = .empty,
956956
957 pub fn deinit(self: *StringTable, allocator: Allocator) void {957 pub fn deinit(self: *StringTable, allocator: Allocator) void {
958 self.bytes.deinit(allocator);958 self.bytes.deinit(allocator);
lib/compiler/resinator/errors.zig+25-26
...@@ -15,10 +15,10 @@ const builtin = @import("builtin");...@@ -15,10 +15,10 @@ const builtin = @import("builtin");
15const native_endian = builtin.cpu.arch.endian();15const native_endian = builtin.cpu.arch.endian();
1616
17pub const Diagnostics = struct {17pub const Diagnostics = struct {
18 errors: std.ArrayListUnmanaged(ErrorDetails) = .empty,18 errors: std.ArrayList(ErrorDetails) = .empty,
19 /// Append-only, cannot handle removing strings.19 /// Append-only, cannot handle removing strings.
20 /// Expects to own all strings within the list.20 /// Expects to own all strings within the list.
21 strings: std.ArrayListUnmanaged([]const u8) = .empty,21 strings: std.ArrayList([]const u8) = .empty,
22 allocator: std.mem.Allocator,22 allocator: std.mem.Allocator,
2323
24 pub fn init(allocator: std.mem.Allocator) Diagnostics {24 pub fn init(allocator: std.mem.Allocator) Diagnostics {
...@@ -256,7 +256,7 @@ pub const ErrorDetails = struct {...@@ -256,7 +256,7 @@ pub const ErrorDetails = struct {
256 .{ "literal", "unquoted literal" },256 .{ "literal", "unquoted literal" },
257 });257 });
258258
259 pub fn writeCommaSeparated(self: ExpectedTypes, writer: anytype) !void {259 pub fn writeCommaSeparated(self: ExpectedTypes, writer: *std.Io.Writer) !void {
260 const struct_info = @typeInfo(ExpectedTypes).@"struct";260 const struct_info = @typeInfo(ExpectedTypes).@"struct";
261 const num_real_fields = struct_info.fields.len - 1;261 const num_real_fields = struct_info.fields.len - 1;
262 const num_padding_bits = @bitSizeOf(ExpectedTypes) - num_real_fields;262 const num_padding_bits = @bitSizeOf(ExpectedTypes) - num_real_fields;
...@@ -441,7 +441,7 @@ pub const ErrorDetails = struct {...@@ -441,7 +441,7 @@ pub const ErrorDetails = struct {
441 } };441 } };
442 }442 }
443443
444 pub fn render(self: ErrorDetails, writer: anytype, source: []const u8, strings: []const []const u8) !void {444 pub fn render(self: ErrorDetails, writer: *std.Io.Writer, source: []const u8, strings: []const []const u8) !void {
445 switch (self.err) {445 switch (self.err) {
446 .unfinished_string_literal => {446 .unfinished_string_literal => {
447 return writer.print("unfinished string literal at '{f}', expected closing '\"'", .{self.fmtToken(source)});447 return writer.print("unfinished string literal at '{f}', expected closing '\"'", .{self.fmtToken(source)});
...@@ -987,12 +987,14 @@ pub fn renderErrorMessage(writer: *std.io.Writer, tty_config: std.io.tty.Config,...@@ -987,12 +987,14 @@ pub fn renderErrorMessage(writer: *std.io.Writer, tty_config: std.io.tty.Config,
987 if (corresponding_span != null and corresponding_file != null) {987 if (corresponding_span != null and corresponding_file != null) {
988 var worth_printing_lines: bool = true;988 var worth_printing_lines: bool = true;
989 var initial_lines_err: ?anyerror = null;989 var initial_lines_err: ?anyerror = null;
990 var file_reader_buf: [max_source_line_bytes * 2]u8 = undefined;
990 var corresponding_lines: ?CorrespondingLines = CorrespondingLines.init(991 var corresponding_lines: ?CorrespondingLines = CorrespondingLines.init(
991 cwd,992 cwd,
992 err_details,993 err_details,
993 source_line_for_display.line,994 source_line_for_display.line,
994 corresponding_span.?,995 corresponding_span.?,
995 corresponding_file.?,996 corresponding_file.?,
997 &file_reader_buf,
996 ) catch |err| switch (err) {998 ) catch |err| switch (err) {
997 error.NotWorthPrintingLines => blk: {999 error.NotWorthPrintingLines => blk: {
998 worth_printing_lines = false;1000 worth_printing_lines = false;
...@@ -1078,10 +1080,17 @@ const CorrespondingLines = struct {...@@ -1078,10 +1080,17 @@ const CorrespondingLines = struct {
1078 at_eof: bool = false,1080 at_eof: bool = false,
1079 span: SourceMappings.CorrespondingSpan,1081 span: SourceMappings.CorrespondingSpan,
1080 file: std.fs.File,1082 file: std.fs.File,
1081 buffered_reader: std.fs.File.Reader,1083 file_reader: std.fs.File.Reader,
1082 code_page: SupportedCodePage,1084 code_page: SupportedCodePage,
10831085
1084 pub fn init(cwd: std.fs.Dir, err_details: ErrorDetails, line_for_comparison: []const u8, corresponding_span: SourceMappings.CorrespondingSpan, corresponding_file: []const u8) !CorrespondingLines {1086 pub fn init(
1087 cwd: std.fs.Dir,
1088 err_details: ErrorDetails,
1089 line_for_comparison: []const u8,
1090 corresponding_span: SourceMappings.CorrespondingSpan,
1091 corresponding_file: []const u8,
1092 file_reader_buf: []u8,
1093 ) !CorrespondingLines {
1085 // We don't do line comparison for this error, so don't print the note if the line1094 // We don't do line comparison for this error, so don't print the note if the line
1086 // number is different1095 // number is different
1087 if (err_details.err == .string_literal_too_long and err_details.token.line_number != corresponding_span.start_line) {1096 if (err_details.err == .string_literal_too_long and err_details.token.line_number != corresponding_span.start_line) {
...@@ -1096,17 +1105,14 @@ const CorrespondingLines = struct {...@@ -1096,17 +1105,14 @@ const CorrespondingLines = struct {
1096 var corresponding_lines = CorrespondingLines{1105 var corresponding_lines = CorrespondingLines{
1097 .span = corresponding_span,1106 .span = corresponding_span,
1098 .file = try utils.openFileNotDir(cwd, corresponding_file, .{}),1107 .file = try utils.openFileNotDir(cwd, corresponding_file, .{}),
1099 .buffered_reader = undefined,
1100 .code_page = err_details.code_page,1108 .code_page = err_details.code_page,
1109 .file_reader = undefined,
1101 };1110 };
1102 corresponding_lines.buffered_reader = corresponding_lines.file.reader(&.{});1111 corresponding_lines.file_reader = corresponding_lines.file.reader(file_reader_buf);
1103 errdefer corresponding_lines.deinit();1112 errdefer corresponding_lines.deinit();
11041113
1105 var writer: std.Io.Writer = .fixed(&corresponding_lines.line_buf);
1106
1107 try corresponding_lines.writeLineFromStreamVerbatim(1114 try corresponding_lines.writeLineFromStreamVerbatim(
1108 &writer,1115 &corresponding_lines.file_reader.interface,
1109 corresponding_lines.buffered_reader.interface.adaptToOldInterface(),
1110 corresponding_span.start_line,1116 corresponding_span.start_line,
1111 );1117 );
11121118
...@@ -1144,11 +1150,8 @@ const CorrespondingLines = struct {...@@ -1144,11 +1150,8 @@ const CorrespondingLines = struct {
1144 self.line_len = 0;1150 self.line_len = 0;
1145 self.visual_line_len = 0;1151 self.visual_line_len = 0;
11461152
1147 var writer: std.Io.Writer = .fixed(&self.line_buf);
1148
1149 try self.writeLineFromStreamVerbatim(1153 try self.writeLineFromStreamVerbatim(
1150 &writer,1154 &self.file_reader.interface,
1151 self.buffered_reader.interface.adaptToOldInterface(),
1152 self.line_num,1155 self.line_num,
1153 );1156 );
11541157
...@@ -1162,7 +1165,7 @@ const CorrespondingLines = struct {...@@ -1162,7 +1165,7 @@ const CorrespondingLines = struct {
1162 return visual_line;1165 return visual_line;
1163 }1166 }
11641167
1165 fn writeLineFromStreamVerbatim(self: *CorrespondingLines, writer: *std.Io.Writer, input: anytype, line_num: usize) !void {1168 fn writeLineFromStreamVerbatim(self: *CorrespondingLines, input: *std.Io.Reader, line_num: usize) !void {
1166 while (try readByteOrEof(input)) |byte| {1169 while (try readByteOrEof(input)) |byte| {
1167 switch (byte) {1170 switch (byte) {
1168 '\n', '\r' => {1171 '\n', '\r' => {
...@@ -1182,13 +1185,9 @@ const CorrespondingLines = struct {...@@ -1182,13 +1185,9 @@ const CorrespondingLines = struct {
1182 }1185 }
1183 },1186 },
1184 else => {1187 else => {
1185 if (self.line_num == line_num) {1188 if (self.line_num == line_num and self.line_len < self.line_buf.len) {
1186 if (writer.writeByte(byte)) {1189 self.line_buf[self.line_len] = byte;
1187 self.line_len += 1;1190 self.line_len += 1;
1188 } else |err| switch (err) {
1189 error.WriteFailed => {},
1190 else => |e| return e,
1191 }
1192 }1191 }
1193 },1192 },
1194 }1193 }
...@@ -1199,8 +1198,8 @@ const CorrespondingLines = struct {...@@ -1199,8 +1198,8 @@ const CorrespondingLines = struct {
1199 self.line_num += 1;1198 self.line_num += 1;
1200 }1199 }
12011200
1202 fn readByteOrEof(reader: anytype) !?u8 {1201 fn readByteOrEof(reader: *std.Io.Reader) !?u8 {
1203 return reader.readByte() catch |err| switch (err) {1202 return reader.takeByte() catch |err| switch (err) {
1204 error.EndOfStream => return null,1203 error.EndOfStream => return null,
1205 else => |e| return e,1204 else => |e| return e,
1206 };1205 };
lib/compiler/resinator/ico.zig+43-57
...@@ -8,80 +8,66 @@ const std = @import("std");...@@ -8,80 +8,66 @@ const std = @import("std");
8const builtin = @import("builtin");8const builtin = @import("builtin");
9const native_endian = builtin.cpu.arch.endian();9const native_endian = builtin.cpu.arch.endian();
1010
11pub const ReadError = std.mem.Allocator.Error || error{ InvalidHeader, InvalidImageType, ImpossibleDataSize, UnexpectedEOF, ReadError };11pub const ReadError = std.mem.Allocator.Error || error{ InvalidHeader, InvalidImageType, ImpossibleDataSize, UnexpectedEOF, ReadFailed };
1212
13pub fn read(allocator: std.mem.Allocator, reader: anytype, max_size: u64) ReadError!IconDir {13pub fn read(allocator: std.mem.Allocator, reader: *std.Io.Reader, max_size: u64) ReadError!IconDir {
14 // Some Reader implementations have an empty ReadError error set which would14 return readInner(allocator, reader, max_size) catch |err| switch (err) {
15 // cause 'unreachable else' if we tried to use an else in the switch, so we15 error.OutOfMemory,
16 // need to detect this case and not try to translate to ReadError16 error.InvalidHeader,
17 const anyerror_reader_errorset = @TypeOf(reader).Error == anyerror;17 error.InvalidImageType,
18 const empty_reader_errorset = @typeInfo(@TypeOf(reader).Error).error_set == null or @typeInfo(@TypeOf(reader).Error).error_set.?.len == 0;18 error.ImpossibleDataSize,
19 if (empty_reader_errorset and !anyerror_reader_errorset) {19 error.ReadFailed,
20 return readAnyError(allocator, reader, max_size) catch |err| switch (err) {20 => |e| return e,
21 error.EndOfStream => error.UnexpectedEOF,21 error.EndOfStream => error.UnexpectedEOF,
22 else => |e| return e,22 };
23 };
24 } else {
25 return readAnyError(allocator, reader, max_size) catch |err| switch (err) {
26 error.OutOfMemory,
27 error.InvalidHeader,
28 error.InvalidImageType,
29 error.ImpossibleDataSize,
30 => |e| return e,
31 error.EndOfStream => error.UnexpectedEOF,
32 // The remaining errors are dependent on the `reader`, so
33 // we just translate them all to generic ReadError
34 else => error.ReadError,
35 };
36 }
37}23}
3824
39// TODO: This seems like a somewhat strange pattern, could be a better way25// TODO: This seems like a somewhat strange pattern, could be a better way
40// to do this. Maybe it makes more sense to handle the translation26// to do this. Maybe it makes more sense to handle the translation
41// at the call site instead of having a helper function here.27// at the call site instead of having a helper function here.
42pub fn readAnyError(allocator: std.mem.Allocator, reader: anytype, max_size: u64) !IconDir {28fn readInner(allocator: std.mem.Allocator, reader: *std.Io.Reader, max_size: u64) !IconDir {
43 const reserved = try reader.readInt(u16, .little);29 const reserved = try reader.takeInt(u16, .little);
44 if (reserved != 0) {30 if (reserved != 0) {
45 return error.InvalidHeader;31 return error.InvalidHeader;
46 }32 }
4733
48 const image_type = reader.readEnum(ImageType, .little) catch |err| switch (err) {34 const image_type = reader.takeEnum(ImageType, .little) catch |err| switch (err) {
49 error.InvalidValue => return error.InvalidImageType,35 error.InvalidEnumTag => return error.InvalidImageType,
50 else => |e| return e,36 else => |e| return e,
51 };37 };
5238
53 const num_images = try reader.readInt(u16, .little);39 const num_images = try reader.takeInt(u16, .little);
5440
55 // To avoid over-allocation in the case of a file that says it has way more41 // To avoid over-allocation in the case of a file that says it has way more
56 // entries than it actually does, we use an ArrayList with a conservatively42 // entries than it actually does, we use an ArrayList with a conservatively
57 // limited initial capacity instead of allocating the entire slice at once.43 // limited initial capacity instead of allocating the entire slice at once.
58 const initial_capacity = @min(num_images, 8);44 const initial_capacity = @min(num_images, 8);
59 var entries = try std.array_list.Managed(Entry).initCapacity(allocator, initial_capacity);45 var entries = try std.ArrayList(Entry).initCapacity(allocator, initial_capacity);
60 errdefer entries.deinit();46 errdefer entries.deinit(allocator);
6147
62 var i: usize = 0;48 var i: usize = 0;
63 while (i < num_images) : (i += 1) {49 while (i < num_images) : (i += 1) {
64 var entry: Entry = undefined;50 var entry: Entry = undefined;
65 entry.width = try reader.readByte();51 entry.width = try reader.takeByte();
66 entry.height = try reader.readByte();52 entry.height = try reader.takeByte();
67 entry.num_colors = try reader.readByte();53 entry.num_colors = try reader.takeByte();
68 entry.reserved = try reader.readByte();54 entry.reserved = try reader.takeByte();
69 switch (image_type) {55 switch (image_type) {
70 .icon => {56 .icon => {
71 entry.type_specific_data = .{ .icon = .{57 entry.type_specific_data = .{ .icon = .{
72 .color_planes = try reader.readInt(u16, .little),58 .color_planes = try reader.takeInt(u16, .little),
73 .bits_per_pixel = try reader.readInt(u16, .little),59 .bits_per_pixel = try reader.takeInt(u16, .little),
74 } };60 } };
75 },61 },
76 .cursor => {62 .cursor => {
77 entry.type_specific_data = .{ .cursor = .{63 entry.type_specific_data = .{ .cursor = .{
78 .hotspot_x = try reader.readInt(u16, .little),64 .hotspot_x = try reader.takeInt(u16, .little),
79 .hotspot_y = try reader.readInt(u16, .little),65 .hotspot_y = try reader.takeInt(u16, .little),
80 } };66 } };
81 },67 },
82 }68 }
83 entry.data_size_in_bytes = try reader.readInt(u32, .little);69 entry.data_size_in_bytes = try reader.takeInt(u32, .little);
84 entry.data_offset_from_start_of_file = try reader.readInt(u32, .little);70 entry.data_offset_from_start_of_file = try reader.takeInt(u32, .little);
85 // Validate that the offset/data size is feasible71 // Validate that the offset/data size is feasible
86 if (@as(u64, entry.data_offset_from_start_of_file) + entry.data_size_in_bytes > max_size) {72 if (@as(u64, entry.data_offset_from_start_of_file) + entry.data_size_in_bytes > max_size) {
87 return error.ImpossibleDataSize;73 return error.ImpossibleDataSize;
...@@ -101,12 +87,12 @@ pub fn readAnyError(allocator: std.mem.Allocator, reader: anytype, max_size: u64...@@ -101,12 +87,12 @@ pub fn readAnyError(allocator: std.mem.Allocator, reader: anytype, max_size: u64
101 if (entry.data_size_in_bytes < 16) {87 if (entry.data_size_in_bytes < 16) {
102 return error.ImpossibleDataSize;88 return error.ImpossibleDataSize;
103 }89 }
104 try entries.append(entry);90 try entries.append(allocator, entry);
105 }91 }
10692
107 return .{93 return .{
108 .image_type = image_type,94 .image_type = image_type,
109 .entries = try entries.toOwnedSlice(),95 .entries = try entries.toOwnedSlice(allocator),
110 .allocator = allocator,96 .allocator = allocator,
111 };97 };
112}98}
...@@ -135,7 +121,7 @@ pub const IconDir = struct {...@@ -135,7 +121,7 @@ pub const IconDir = struct {
135 return @intCast(IconDir.res_header_byte_len + self.entries.len * Entry.res_byte_len);121 return @intCast(IconDir.res_header_byte_len + self.entries.len * Entry.res_byte_len);
136 }122 }
137123
138 pub fn writeResData(self: IconDir, writer: anytype, first_image_id: u16) !void {124 pub fn writeResData(self: IconDir, writer: *std.Io.Writer, first_image_id: u16) !void {
139 try writer.writeInt(u16, 0, .little);125 try writer.writeInt(u16, 0, .little);
140 try writer.writeInt(u16, @intFromEnum(self.image_type), .little);126 try writer.writeInt(u16, @intFromEnum(self.image_type), .little);
141 // We know that entries.len must fit into a u16127 // We know that entries.len must fit into a u16
...@@ -173,7 +159,7 @@ pub const Entry = struct {...@@ -173,7 +159,7 @@ pub const Entry = struct {
173159
174 pub const res_byte_len = 14;160 pub const res_byte_len = 14;
175161
176 pub fn writeResData(self: Entry, writer: anytype, id: u16) !void {162 pub fn writeResData(self: Entry, writer: *std.Io.Writer, id: u16) !void {
177 switch (self.type_specific_data) {163 switch (self.type_specific_data) {
178 .icon => |icon_data| {164 .icon => |icon_data| {
179 try writer.writeInt(u8, @as(u8, @truncate(self.width)), .little);165 try writer.writeInt(u8, @as(u8, @truncate(self.width)), .little);
...@@ -198,8 +184,8 @@ pub const Entry = struct {...@@ -198,8 +184,8 @@ pub const Entry = struct {
198184
199test "icon" {185test "icon" {
200 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;186 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;
201 var fbs = std.io.fixedBufferStream(data);187 var fbs: std.Io.Reader = .fixed(data);
202 const icon = try read(std.testing.allocator, fbs.reader(), data.len);188 const icon = try read(std.testing.allocator, &fbs, data.len);
203 defer icon.deinit();189 defer icon.deinit();
204190
205 try std.testing.expectEqual(ImageType.icon, icon.image_type);191 try std.testing.expectEqual(ImageType.icon, icon.image_type);
...@@ -211,26 +197,26 @@ test "icon too many images" {...@@ -211,26 +197,26 @@ test "icon too many images" {
211 // it's not possible to hit EOF when looking for more RESDIR structures, since they are197 // it's not possible to hit EOF when looking for more RESDIR structures, since they are
212 // themselves 16 bytes long, so we'll always hit ImpossibleDataSize instead.198 // themselves 16 bytes long, so we'll always hit ImpossibleDataSize instead.
213 const data = "\x00\x00\x01\x00\x02\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;199 const data = "\x00\x00\x01\x00\x02\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;
214 var fbs = std.io.fixedBufferStream(data);200 var fbs: std.Io.Reader = .fixed(data);
215 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));201 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
216}202}
217203
218test "icon data size past EOF" {204test "icon data size past EOF" {
219 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x01\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;205 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x01\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;
220 var fbs = std.io.fixedBufferStream(data);206 var fbs: std.Io.Reader = .fixed(data);
221 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));207 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
222}208}
223209
224test "icon data offset past EOF" {210test "icon data offset past EOF" {
225 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x17\x00\x00\x00" ++ [_]u8{0} ** 16;211 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x17\x00\x00\x00" ++ [_]u8{0} ** 16;
226 var fbs = std.io.fixedBufferStream(data);212 var fbs: std.Io.Reader = .fixed(data);
227 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));213 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
228}214}
229215
230test "icon data size too small" {216test "icon data size too small" {
231 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x0F\x00\x00\x00\x16\x00\x00\x00";217 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x0F\x00\x00\x00\x16\x00\x00\x00";
232 var fbs = std.io.fixedBufferStream(data);218 var fbs: std.Io.Reader = .fixed(data);
233 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));219 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
234}220}
235221
236pub const ImageFormat = enum(u2) {222pub const ImageFormat = enum(u2) {
lib/compiler/resinator/lang.zig+6-5
...@@ -119,6 +119,7 @@ test tagToId {...@@ -119,6 +119,7 @@ test tagToId {
119}119}
120120
121test "exhaustive tagToId" {121test "exhaustive tagToId" {
122 @setEvalBranchQuota(2000);
122 inline for (@typeInfo(LanguageId).@"enum".fields) |field| {123 inline for (@typeInfo(LanguageId).@"enum".fields) |field| {
123 const id = tagToId(field.name) catch |err| {124 const id = tagToId(field.name) catch |err| {
124 std.debug.print("tag: {s}\n", .{field.name});125 std.debug.print("tag: {s}\n", .{field.name});
...@@ -131,8 +132,8 @@ test "exhaustive tagToId" {...@@ -131,8 +132,8 @@ test "exhaustive tagToId" {
131 }132 }
132 var buf: [32]u8 = undefined;133 var buf: [32]u8 = undefined;
133 inline for (valid_alternate_sorts) |parsed_sort| {134 inline for (valid_alternate_sorts) |parsed_sort| {
134 var fbs = std.io.fixedBufferStream(&buf);135 var fbs: std.Io.Writer = .fixed(&buf);
135 const writer = fbs.writer();136 const writer = &fbs;
136 writer.writeAll(parsed_sort.language_code) catch unreachable;137 writer.writeAll(parsed_sort.language_code) catch unreachable;
137 writer.writeAll("-") catch unreachable;138 writer.writeAll("-") catch unreachable;
138 writer.writeAll(parsed_sort.country_code.?) catch unreachable;139 writer.writeAll(parsed_sort.country_code.?) catch unreachable;
...@@ -146,12 +147,12 @@ test "exhaustive tagToId" {...@@ -146,12 +147,12 @@ test "exhaustive tagToId" {
146 break :field name_buf;147 break :field name_buf;
147 };148 };
148 const expected = @field(LanguageId, &expected_field_name);149 const expected = @field(LanguageId, &expected_field_name);
149 const id = tagToId(fbs.getWritten()) catch |err| {150 const id = tagToId(fbs.buffered()) catch |err| {
150 std.debug.print("tag: {s}\n", .{fbs.getWritten()});151 std.debug.print("tag: {s}\n", .{fbs.buffered()});
151 return err;152 return err;
152 };153 };
153 try std.testing.expectEqual(expected, id orelse {154 try std.testing.expectEqual(expected, id orelse {
154 std.debug.print("tag: {s}, expected: {}, got null\n", .{ fbs.getWritten(), expected });155 std.debug.print("tag: {s}, expected: {}, got null\n", .{ fbs.buffered(), expected });
155 return error.TestExpectedEqual;156 return error.TestExpectedEqual;
156 });157 });
157 }158 }
lib/compiler/resinator/literals.zig+22-22
...@@ -469,8 +469,8 @@ pub fn parseQuotedString(...@@ -469,8 +469,8 @@ pub fn parseQuotedString(
469 const T = if (literal_type == .ascii) u8 else u16;469 const T = if (literal_type == .ascii) u8 else u16;
470 std.debug.assert(bytes.slice.len >= 2); // must at least have 2 double quote chars470 std.debug.assert(bytes.slice.len >= 2); // must at least have 2 double quote chars
471471
472 var buf = try std.array_list.Managed(T).initCapacity(allocator, bytes.slice.len);472 var buf = try std.ArrayList(T).initCapacity(allocator, bytes.slice.len);
473 errdefer buf.deinit();473 errdefer buf.deinit(allocator);
474474
475 var iterative_parser = IterativeStringParser.init(bytes, options);475 var iterative_parser = IterativeStringParser.init(bytes, options);
476476
...@@ -480,13 +480,13 @@ pub fn parseQuotedString(...@@ -480,13 +480,13 @@ pub fn parseQuotedString(
480 .ascii => switch (options.output_code_page) {480 .ascii => switch (options.output_code_page) {
481 .windows1252 => {481 .windows1252 => {
482 if (parsed.from_escaped_integer) {482 if (parsed.from_escaped_integer) {
483 try buf.append(@truncate(c));483 try buf.append(allocator, @truncate(c));
484 } else if (windows1252.bestFitFromCodepoint(c)) |best_fit| {484 } else if (windows1252.bestFitFromCodepoint(c)) |best_fit| {
485 try buf.append(best_fit);485 try buf.append(allocator, best_fit);
486 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid) {486 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid) {
487 try buf.append('?');487 try buf.append(allocator, '?');
488 } else {488 } else {
489 try buf.appendSlice("??");489 try buf.appendSlice(allocator, "??");
490 }490 }
491 },491 },
492 .utf8 => {492 .utf8 => {
...@@ -500,35 +500,35 @@ pub fn parseQuotedString(...@@ -500,35 +500,35 @@ pub fn parseQuotedString(
500 }500 }
501 var utf8_buf: [4]u8 = undefined;501 var utf8_buf: [4]u8 = undefined;
502 const utf8_len = std.unicode.utf8Encode(codepoint_to_encode, &utf8_buf) catch unreachable;502 const utf8_len = std.unicode.utf8Encode(codepoint_to_encode, &utf8_buf) catch unreachable;
503 try buf.appendSlice(utf8_buf[0..utf8_len]);503 try buf.appendSlice(allocator, utf8_buf[0..utf8_len]);
504 },504 },
505 },505 },
506 .wide => {506 .wide => {
507 // Parsing any string type as a wide string is handled separately, see parseQuotedStringAsWideString507 // Parsing any string type as a wide string is handled separately, see parseQuotedStringAsWideString
508 std.debug.assert(iterative_parser.declared_string_type == .wide);508 std.debug.assert(iterative_parser.declared_string_type == .wide);
509 if (parsed.from_escaped_integer) {509 if (parsed.from_escaped_integer) {
510 try buf.append(std.mem.nativeToLittle(u16, @truncate(c)));510 try buf.append(allocator, std.mem.nativeToLittle(u16, @truncate(c)));
511 } else if (c == code_pages.Codepoint.invalid) {511 } else if (c == code_pages.Codepoint.invalid) {
512 try buf.append(std.mem.nativeToLittle(u16, '�'));512 try buf.append(allocator, std.mem.nativeToLittle(u16, '�'));
513 } else if (c < 0x10000) {513 } else if (c < 0x10000) {
514 const short: u16 = @intCast(c);514 const short: u16 = @intCast(c);
515 try buf.append(std.mem.nativeToLittle(u16, short));515 try buf.append(allocator, std.mem.nativeToLittle(u16, short));
516 } else {516 } else {
517 if (!parsed.escaped_surrogate_pair) {517 if (!parsed.escaped_surrogate_pair) {
518 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;518 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;
519 try buf.append(std.mem.nativeToLittle(u16, high));519 try buf.append(allocator, std.mem.nativeToLittle(u16, high));
520 }520 }
521 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;521 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;
522 try buf.append(std.mem.nativeToLittle(u16, low));522 try buf.append(allocator, std.mem.nativeToLittle(u16, low));
523 }523 }
524 },524 },
525 }525 }
526 }526 }
527527
528 if (literal_type == .wide) {528 if (literal_type == .wide) {
529 return buf.toOwnedSliceSentinel(0);529 return buf.toOwnedSliceSentinel(allocator, 0);
530 } else {530 } else {
531 return buf.toOwnedSlice();531 return buf.toOwnedSlice(allocator);
532 }532 }
533}533}
534534
...@@ -564,8 +564,8 @@ pub fn parseQuotedStringAsWideString(allocator: std.mem.Allocator, bytes: Source...@@ -564,8 +564,8 @@ pub fn parseQuotedStringAsWideString(allocator: std.mem.Allocator, bytes: Source
564 // Note: We're only handling the case of parsing an ASCII string into a wide string from here on out.564 // Note: We're only handling the case of parsing an ASCII string into a wide string from here on out.
565 // TODO: The logic below is similar to that in AcceleratorKeyCodepointTranslator, might be worth merging the two565 // TODO: The logic below is similar to that in AcceleratorKeyCodepointTranslator, might be worth merging the two
566566
567 var buf = try std.array_list.Managed(u16).initCapacity(allocator, bytes.slice.len);567 var buf = try std.ArrayList(u16).initCapacity(allocator, bytes.slice.len);
568 errdefer buf.deinit();568 errdefer buf.deinit(allocator);
569569
570 var iterative_parser = IterativeStringParser.init(bytes, options);570 var iterative_parser = IterativeStringParser.init(bytes, options);
571571
...@@ -578,23 +578,23 @@ pub fn parseQuotedStringAsWideString(allocator: std.mem.Allocator, bytes: Source...@@ -578,23 +578,23 @@ pub fn parseQuotedStringAsWideString(allocator: std.mem.Allocator, bytes: Source
578 .windows1252 => windows1252.toCodepoint(byte_to_interpret),578 .windows1252 => windows1252.toCodepoint(byte_to_interpret),
579 .utf8 => if (byte_to_interpret > 0x7F) '�' else byte_to_interpret,579 .utf8 => if (byte_to_interpret > 0x7F) '�' else byte_to_interpret,
580 };580 };
581 try buf.append(std.mem.nativeToLittle(u16, code_unit_to_encode));581 try buf.append(allocator, std.mem.nativeToLittle(u16, code_unit_to_encode));
582 } else if (c == code_pages.Codepoint.invalid) {582 } else if (c == code_pages.Codepoint.invalid) {
583 try buf.append(std.mem.nativeToLittle(u16, '�'));583 try buf.append(allocator, std.mem.nativeToLittle(u16, '�'));
584 } else if (c < 0x10000) {584 } else if (c < 0x10000) {
585 const short: u16 = @intCast(c);585 const short: u16 = @intCast(c);
586 try buf.append(std.mem.nativeToLittle(u16, short));586 try buf.append(allocator, std.mem.nativeToLittle(u16, short));
587 } else {587 } else {
588 if (!parsed.escaped_surrogate_pair) {588 if (!parsed.escaped_surrogate_pair) {
589 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;589 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;
590 try buf.append(std.mem.nativeToLittle(u16, high));590 try buf.append(allocator, std.mem.nativeToLittle(u16, high));
591 }591 }
592 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;592 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;
593 try buf.append(std.mem.nativeToLittle(u16, low));593 try buf.append(allocator, std.mem.nativeToLittle(u16, low));
594 }594 }
595 }595 }
596596
597 return buf.toOwnedSliceSentinel(0);597 return buf.toOwnedSliceSentinel(allocator, 0);
598}598}
599599
600test "parse quoted ascii string" {600test "parse quoted ascii string" {
lib/compiler/resinator/main.zig+23-27
...@@ -3,6 +3,7 @@ const builtin = @import("builtin");...@@ -3,6 +3,7 @@ const builtin = @import("builtin");
3const removeComments = @import("comments.zig").removeComments;3const removeComments = @import("comments.zig").removeComments;
4const parseAndRemoveLineCommands = @import("source_mapping.zig").parseAndRemoveLineCommands;4const parseAndRemoveLineCommands = @import("source_mapping.zig").parseAndRemoveLineCommands;
5const compile = @import("compile.zig").compile;5const compile = @import("compile.zig").compile;
6const Dependencies = @import("compile.zig").Dependencies;
6const Diagnostics = @import("errors.zig").Diagnostics;7const Diagnostics = @import("errors.zig").Diagnostics;
7const cli = @import("cli.zig");8const cli = @import("cli.zig");
8const preprocess = @import("preprocess.zig");9const preprocess = @import("preprocess.zig");
...@@ -13,8 +14,6 @@ const hasDisjointCodePage = @import("disjoint_code_page.zig").hasDisjointCodePag...@@ -13,8 +14,6 @@ const hasDisjointCodePage = @import("disjoint_code_page.zig").hasDisjointCodePag
13const fmtResourceType = @import("res.zig").NameOrOrdinal.fmtResourceType;14const fmtResourceType = @import("res.zig").NameOrOrdinal.fmtResourceType;
14const aro = @import("aro");15const aro = @import("aro");
1516
16var stdout_buffer: [1024]u8 = undefined;
17
18pub fn main() !void {17pub fn main() !void {
19 var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;18 var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
20 defer std.debug.assert(gpa.deinit() == .ok);19 defer std.debug.assert(gpa.deinit() == .ok);
...@@ -43,11 +42,13 @@ pub fn main() !void {...@@ -43,11 +42,13 @@ pub fn main() !void {
43 cli_args = args[3..];42 cli_args = args[3..];
44 }43 }
4544
45 var stdout_buffer: [1024]u8 = undefined;
46 var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);46 var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
47 const stdout = &stdout_writer.interface;
47 var error_handler: ErrorHandler = switch (zig_integration) {48 var error_handler: ErrorHandler = switch (zig_integration) {
48 true => .{49 true => .{
49 .server = .{50 .server = .{
50 .out = &stdout_writer.interface,51 .out = stdout,
51 .in = undefined, // won't be receiving messages52 .in = undefined, // won't be receiving messages
52 },53 },
53 },54 },
...@@ -83,8 +84,8 @@ pub fn main() !void {...@@ -83,8 +84,8 @@ pub fn main() !void {
83 defer options.deinit();84 defer options.deinit();
8485
85 if (options.print_help_and_exit) {86 if (options.print_help_and_exit) {
86 try cli.writeUsage(&stdout_writer.interface, "zig rc");87 try cli.writeUsage(stdout, "zig rc");
87 try stdout_writer.interface.flush();88 try stdout.flush();
88 return;89 return;
89 }90 }
9091
...@@ -92,19 +93,14 @@ pub fn main() !void {...@@ -92,19 +93,14 @@ pub fn main() !void {
92 options.verbose = false;93 options.verbose = false;
9394
94 if (options.verbose) {95 if (options.verbose) {
95 try options.dumpVerbose(&stdout_writer.interface);96 try options.dumpVerbose(stdout);
96 try stdout_writer.interface.writeByte('\n');97 try stdout.writeByte('\n');
97 try stdout_writer.interface.flush();98 try stdout.flush();
98 }99 }
99100
100 var dependencies_list = std.array_list.Managed([]const u8).init(allocator);101 var dependencies = Dependencies.init(allocator);
101 defer {102 defer dependencies.deinit();
102 for (dependencies_list.items) |item| {103 const maybe_dependencies: ?*Dependencies = if (options.depfile_path != null) &dependencies else null;
103 allocator.free(item);
104 }
105 dependencies_list.deinit();
106 }
107 const maybe_dependencies_list: ?*std.array_list.Managed([]const u8) = if (options.depfile_path != null) &dependencies_list else null;
108104
109 var include_paths = LazyIncludePaths{105 var include_paths = LazyIncludePaths{
110 .arena = arena,106 .arena = arena,
...@@ -127,27 +123,27 @@ pub fn main() !void {...@@ -127,27 +123,27 @@ pub fn main() !void {
127 var comp = aro.Compilation.init(aro_arena, std.fs.cwd());123 var comp = aro.Compilation.init(aro_arena, std.fs.cwd());
128 defer comp.deinit();124 defer comp.deinit();
129125
130 var argv = std.array_list.Managed([]const u8).init(comp.gpa);126 var argv: std.ArrayList([]const u8) = .empty;
131 defer argv.deinit();127 defer argv.deinit(aro_arena);
132128
133 try argv.append("arocc"); // dummy command name129 try argv.append(aro_arena, "arocc"); // dummy command name
134 const resolved_include_paths = try include_paths.get(&error_handler);130 const resolved_include_paths = try include_paths.get(&error_handler);
135 try preprocess.appendAroArgs(aro_arena, &argv, options, resolved_include_paths);131 try preprocess.appendAroArgs(aro_arena, &argv, options, resolved_include_paths);
136 try argv.append(switch (options.input_source) {132 try argv.append(aro_arena, switch (options.input_source) {
137 .stdio => "-",133 .stdio => "-",
138 .filename => |filename| filename,134 .filename => |filename| filename,
139 });135 });
140136
141 if (options.verbose) {137 if (options.verbose) {
142 try stdout_writer.interface.writeAll("Preprocessor: arocc (built-in)\n");138 try stdout.writeAll("Preprocessor: arocc (built-in)\n");
143 for (argv.items[0 .. argv.items.len - 1]) |arg| {139 for (argv.items[0 .. argv.items.len - 1]) |arg| {
144 try stdout_writer.interface.print("{s} ", .{arg});140 try stdout.print("{s} ", .{arg});
145 }141 }
146 try stdout_writer.interface.print("{s}\n\n", .{argv.items[argv.items.len - 1]});142 try stdout.print("{s}\n\n", .{argv.items[argv.items.len - 1]});
147 try stdout_writer.interface.flush();143 try stdout.flush();
148 }144 }
149145
150 preprocess.preprocess(&comp, &preprocessed_buf.writer, argv.items, maybe_dependencies_list) catch |err| switch (err) {146 preprocess.preprocess(&comp, &preprocessed_buf.writer, argv.items, maybe_dependencies) catch |err| switch (err) {
151 error.GeneratedSourceError => {147 error.GeneratedSourceError => {
152 try error_handler.emitAroDiagnostics(allocator, "failed during preprocessor setup (this is always a bug):", &comp);148 try error_handler.emitAroDiagnostics(allocator, "failed during preprocessor setup (this is always a bug):", &comp);
153 std.process.exit(1);149 std.process.exit(1);
...@@ -258,7 +254,7 @@ pub fn main() !void {...@@ -258,7 +254,7 @@ pub fn main() !void {
258 .cwd = std.fs.cwd(),254 .cwd = std.fs.cwd(),
259 .diagnostics = &diagnostics,255 .diagnostics = &diagnostics,
260 .source_mappings = &mapping_results.mappings,256 .source_mappings = &mapping_results.mappings,
261 .dependencies_list = maybe_dependencies_list,257 .dependencies = maybe_dependencies,
262 .ignore_include_env_var = options.ignore_include_env_var,258 .ignore_include_env_var = options.ignore_include_env_var,
263 .extra_include_paths = options.extra_include_paths.items,259 .extra_include_paths = options.extra_include_paths.items,
264 .system_include_paths = try include_paths.get(&error_handler),260 .system_include_paths = try include_paths.get(&error_handler),
...@@ -305,7 +301,7 @@ pub fn main() !void {...@@ -305,7 +301,7 @@ pub fn main() !void {
305 };301 };
306302
307 try write_stream.beginArray();303 try write_stream.beginArray();
308 for (dependencies_list.items) |dep_path| {304 for (dependencies.list.items) |dep_path| {
309 try write_stream.write(dep_path);305 try write_stream.write(dep_path);
310 }306 }
311 try write_stream.endArray();307 try write_stream.endArray();
lib/compiler/resinator/parse.zig+26-26
...@@ -82,8 +82,8 @@ pub const Parser = struct {...@@ -82,8 +82,8 @@ pub const Parser = struct {
82 }82 }
8383
84 fn parseRoot(self: *Self) Error!*Node {84 fn parseRoot(self: *Self) Error!*Node {
85 var statements = std.array_list.Managed(*Node).init(self.state.allocator);85 var statements: std.ArrayList(*Node) = .empty;
86 defer statements.deinit();86 defer statements.deinit(self.state.allocator);
8787
88 try self.parseStatements(&statements);88 try self.parseStatements(&statements);
89 try self.check(.eof);89 try self.check(.eof);
...@@ -95,7 +95,7 @@ pub const Parser = struct {...@@ -95,7 +95,7 @@ pub const Parser = struct {
95 return &node.base;95 return &node.base;
96 }96 }
9797
98 fn parseStatements(self: *Self, statements: *std.array_list.Managed(*Node)) Error!void {98 fn parseStatements(self: *Self, statements: *std.ArrayList(*Node)) Error!void {
99 while (true) {99 while (true) {
100 try self.nextToken(.whitespace_delimiter_only);100 try self.nextToken(.whitespace_delimiter_only);
101 if (self.state.token.id == .eof) break;101 if (self.state.token.id == .eof) break;
...@@ -105,7 +105,7 @@ pub const Parser = struct {...@@ -105,7 +105,7 @@ pub const Parser = struct {
105 // (usually it will end up with bogus things like 'file105 // (usually it will end up with bogus things like 'file
106 // not found: {')106 // not found: {')
107 const statement = try self.parseStatement();107 const statement = try self.parseStatement();
108 try statements.append(statement);108 try statements.append(self.state.allocator, statement);
109 }109 }
110 }110 }
111111
...@@ -115,7 +115,7 @@ pub const Parser = struct {...@@ -115,7 +115,7 @@ pub const Parser = struct {
115 /// current token is unchanged.115 /// current token is unchanged.
116 /// The returned slice is allocated by the parser's arena116 /// The returned slice is allocated by the parser's arena
117 fn parseCommonResourceAttributes(self: *Self) ![]Token {117 fn parseCommonResourceAttributes(self: *Self) ![]Token {
118 var common_resource_attributes: std.ArrayListUnmanaged(Token) = .empty;118 var common_resource_attributes: std.ArrayList(Token) = .empty;
119 while (true) {119 while (true) {
120 const maybe_common_resource_attribute = try self.lookaheadToken(.normal);120 const maybe_common_resource_attribute = try self.lookaheadToken(.normal);
121 if (maybe_common_resource_attribute.id == .literal and rc.CommonResourceAttributes.map.has(maybe_common_resource_attribute.slice(self.lexer.buffer))) {121 if (maybe_common_resource_attribute.id == .literal and rc.CommonResourceAttributes.map.has(maybe_common_resource_attribute.slice(self.lexer.buffer))) {
...@@ -135,7 +135,7 @@ pub const Parser = struct {...@@ -135,7 +135,7 @@ pub const Parser = struct {
135 /// current token is unchanged.135 /// current token is unchanged.
136 /// The returned slice is allocated by the parser's arena136 /// The returned slice is allocated by the parser's arena
137 fn parseOptionalStatements(self: *Self, resource: ResourceType) ![]*Node {137 fn parseOptionalStatements(self: *Self, resource: ResourceType) ![]*Node {
138 var optional_statements: std.ArrayListUnmanaged(*Node) = .empty;138 var optional_statements: std.ArrayList(*Node) = .empty;
139139
140 const num_statement_types = @typeInfo(rc.OptionalStatements).@"enum".fields.len;140 const num_statement_types = @typeInfo(rc.OptionalStatements).@"enum".fields.len;
141 var statement_type_has_duplicates = [_]bool{false} ** num_statement_types;141 var statement_type_has_duplicates = [_]bool{false} ** num_statement_types;
...@@ -355,8 +355,8 @@ pub const Parser = struct {...@@ -355,8 +355,8 @@ pub const Parser = struct {
355 const begin_token = self.state.token;355 const begin_token = self.state.token;
356 try self.check(.begin);356 try self.check(.begin);
357357
358 var strings = std.array_list.Managed(*Node).init(self.state.allocator);358 var strings: std.ArrayList(*Node) = .empty;
359 defer strings.deinit();359 defer strings.deinit(self.state.allocator);
360 while (true) {360 while (true) {
361 const maybe_end_token = try self.lookaheadToken(.normal);361 const maybe_end_token = try self.lookaheadToken(.normal);
362 switch (maybe_end_token.id) {362 switch (maybe_end_token.id) {
...@@ -392,7 +392,7 @@ pub const Parser = struct {...@@ -392,7 +392,7 @@ pub const Parser = struct {
392 .maybe_comma = comma_token,392 .maybe_comma = comma_token,
393 .string = self.state.token,393 .string = self.state.token,
394 };394 };
395 try strings.append(&string_node.base);395 try strings.append(self.state.allocator, &string_node.base);
396 }396 }
397397
398 if (strings.items.len == 0) {398 if (strings.items.len == 0) {
...@@ -501,7 +501,7 @@ pub const Parser = struct {...@@ -501,7 +501,7 @@ pub const Parser = struct {
501 const begin_token = self.state.token;501 const begin_token = self.state.token;
502 try self.check(.begin);502 try self.check(.begin);
503503
504 var accelerators: std.ArrayListUnmanaged(*Node) = .empty;504 var accelerators: std.ArrayList(*Node) = .empty;
505505
506 while (true) {506 while (true) {
507 const lookahead = try self.lookaheadToken(.normal);507 const lookahead = try self.lookaheadToken(.normal);
...@@ -519,7 +519,7 @@ pub const Parser = struct {...@@ -519,7 +519,7 @@ pub const Parser = struct {
519519
520 const idvalue = try self.parseExpression(.{ .allowed_types = .{ .number = true } });520 const idvalue = try self.parseExpression(.{ .allowed_types = .{ .number = true } });
521521
522 var type_and_options: std.ArrayListUnmanaged(Token) = .empty;522 var type_and_options: std.ArrayList(Token) = .empty;
523 while (true) {523 while (true) {
524 if (!(try self.parseOptionalToken(.comma))) break;524 if (!(try self.parseOptionalToken(.comma))) break;
525525
...@@ -584,7 +584,7 @@ pub const Parser = struct {...@@ -584,7 +584,7 @@ pub const Parser = struct {
584 const begin_token = self.state.token;584 const begin_token = self.state.token;
585 try self.check(.begin);585 try self.check(.begin);
586586
587 var controls: std.ArrayListUnmanaged(*Node) = .empty;587 var controls: std.ArrayList(*Node) = .empty;
588 defer controls.deinit(self.state.allocator);588 defer controls.deinit(self.state.allocator);
589 while (try self.parseControlStatement(resource)) |control_node| {589 while (try self.parseControlStatement(resource)) |control_node| {
590 // The number of controls must fit in a u16 in order for it to590 // The number of controls must fit in a u16 in order for it to
...@@ -643,7 +643,7 @@ pub const Parser = struct {...@@ -643,7 +643,7 @@ pub const Parser = struct {
643 const begin_token = self.state.token;643 const begin_token = self.state.token;
644 try self.check(.begin);644 try self.check(.begin);
645645
646 var buttons: std.ArrayListUnmanaged(*Node) = .empty;646 var buttons: std.ArrayList(*Node) = .empty;
647 defer buttons.deinit(self.state.allocator);647 defer buttons.deinit(self.state.allocator);
648 while (try self.parseToolbarButtonStatement()) |button_node| {648 while (try self.parseToolbarButtonStatement()) |button_node| {
649 // The number of buttons must fit in a u16 in order for it to649 // The number of buttons must fit in a u16 in order for it to
...@@ -701,7 +701,7 @@ pub const Parser = struct {...@@ -701,7 +701,7 @@ pub const Parser = struct {
701 const begin_token = self.state.token;701 const begin_token = self.state.token;
702 try self.check(.begin);702 try self.check(.begin);
703703
704 var items: std.ArrayListUnmanaged(*Node) = .empty;704 var items: std.ArrayList(*Node) = .empty;
705 defer items.deinit(self.state.allocator);705 defer items.deinit(self.state.allocator);
706 while (try self.parseMenuItemStatement(resource, id_token, 1)) |item_node| {706 while (try self.parseMenuItemStatement(resource, id_token, 1)) |item_node| {
707 try items.append(self.state.allocator, item_node);707 try items.append(self.state.allocator, item_node);
...@@ -735,7 +735,7 @@ pub const Parser = struct {...@@ -735,7 +735,7 @@ pub const Parser = struct {
735 // common resource attributes must all be contiguous and come before optional-statements735 // common resource attributes must all be contiguous and come before optional-statements
736 const common_resource_attributes = try self.parseCommonResourceAttributes();736 const common_resource_attributes = try self.parseCommonResourceAttributes();
737737
738 var fixed_info: std.ArrayListUnmanaged(*Node) = .empty;738 var fixed_info: std.ArrayList(*Node) = .empty;
739 while (try self.parseVersionStatement()) |version_statement| {739 while (try self.parseVersionStatement()) |version_statement| {
740 try fixed_info.append(self.state.arena, version_statement);740 try fixed_info.append(self.state.arena, version_statement);
741 }741 }
...@@ -744,7 +744,7 @@ pub const Parser = struct {...@@ -744,7 +744,7 @@ pub const Parser = struct {
744 const begin_token = self.state.token;744 const begin_token = self.state.token;
745 try self.check(.begin);745 try self.check(.begin);
746746
747 var block_statements: std.ArrayListUnmanaged(*Node) = .empty;747 var block_statements: std.ArrayList(*Node) = .empty;
748 while (try self.parseVersionBlockOrValue(id_token, 1)) |block_node| {748 while (try self.parseVersionBlockOrValue(id_token, 1)) |block_node| {
749 try block_statements.append(self.state.arena, block_node);749 try block_statements.append(self.state.arena, block_node);
750 }750 }
...@@ -852,8 +852,8 @@ pub const Parser = struct {...@@ -852,8 +852,8 @@ pub const Parser = struct {
852 /// Expects the current token to be a begin token.852 /// Expects the current token to be a begin token.
853 /// After return, the current token will be the end token.853 /// After return, the current token will be the end token.
854 fn parseRawDataBlock(self: *Self) Error![]*Node {854 fn parseRawDataBlock(self: *Self) Error![]*Node {
855 var raw_data = std.array_list.Managed(*Node).init(self.state.allocator);855 var raw_data: std.ArrayList(*Node) = .empty;
856 defer raw_data.deinit();856 defer raw_data.deinit(self.state.allocator);
857 while (true) {857 while (true) {
858 const maybe_end_token = try self.lookaheadToken(.normal);858 const maybe_end_token = try self.lookaheadToken(.normal);
859 switch (maybe_end_token.id) {859 switch (maybe_end_token.id) {
...@@ -888,7 +888,7 @@ pub const Parser = struct {...@@ -888,7 +888,7 @@ pub const Parser = struct {
888 else => {},888 else => {},
889 }889 }
890 const expression = try self.parseExpression(.{ .allowed_types = .{ .number = true, .string = true } });890 const expression = try self.parseExpression(.{ .allowed_types = .{ .number = true, .string = true } });
891 try raw_data.append(expression);891 try raw_data.append(self.state.allocator, expression);
892892
893 if (expression.isNumberExpression()) {893 if (expression.isNumberExpression()) {
894 const maybe_close_paren = try self.lookaheadToken(.normal);894 const maybe_close_paren = try self.lookaheadToken(.normal);
...@@ -1125,7 +1125,7 @@ pub const Parser = struct {...@@ -1125,7 +1125,7 @@ pub const Parser = struct {
11251125
1126 _ = try self.parseOptionalToken(.comma);1126 _ = try self.parseOptionalToken(.comma);
11271127
1128 var options: std.ArrayListUnmanaged(Token) = .empty;1128 var options: std.ArrayList(Token) = .empty;
1129 while (true) {1129 while (true) {
1130 const option_token = try self.lookaheadToken(.normal);1130 const option_token = try self.lookaheadToken(.normal);
1131 if (!rc.MenuItem.Option.map.has(option_token.slice(self.lexer.buffer))) {1131 if (!rc.MenuItem.Option.map.has(option_token.slice(self.lexer.buffer))) {
...@@ -1160,7 +1160,7 @@ pub const Parser = struct {...@@ -1160,7 +1160,7 @@ pub const Parser = struct {
1160 }1160 }
1161 try self.skipAnyCommas();1161 try self.skipAnyCommas();
11621162
1163 var options: std.ArrayListUnmanaged(Token) = .empty;1163 var options: std.ArrayList(Token) = .empty;
1164 while (true) {1164 while (true) {
1165 const option_token = try self.lookaheadToken(.normal);1165 const option_token = try self.lookaheadToken(.normal);
1166 if (!rc.MenuItem.Option.map.has(option_token.slice(self.lexer.buffer))) {1166 if (!rc.MenuItem.Option.map.has(option_token.slice(self.lexer.buffer))) {
...@@ -1175,7 +1175,7 @@ pub const Parser = struct {...@@ -1175,7 +1175,7 @@ pub const Parser = struct {
1175 const begin_token = self.state.token;1175 const begin_token = self.state.token;
1176 try self.check(.begin);1176 try self.check(.begin);
11771177
1178 var items: std.ArrayListUnmanaged(*Node) = .empty;1178 var items: std.ArrayList(*Node) = .empty;
1179 while (try self.parseMenuItemStatement(resource, top_level_menu_id_token, nesting_level + 1)) |item_node| {1179 while (try self.parseMenuItemStatement(resource, top_level_menu_id_token, nesting_level + 1)) |item_node| {
1180 try items.append(self.state.arena, item_node);1180 try items.append(self.state.arena, item_node);
1181 }1181 }
...@@ -1245,7 +1245,7 @@ pub const Parser = struct {...@@ -1245,7 +1245,7 @@ pub const Parser = struct {
1245 const begin_token = self.state.token;1245 const begin_token = self.state.token;
1246 try self.check(.begin);1246 try self.check(.begin);
12471247
1248 var items: std.ArrayListUnmanaged(*Node) = .empty;1248 var items: std.ArrayList(*Node) = .empty;
1249 while (try self.parseMenuItemStatement(resource, top_level_menu_id_token, nesting_level + 1)) |item_node| {1249 while (try self.parseMenuItemStatement(resource, top_level_menu_id_token, nesting_level + 1)) |item_node| {
1250 try items.append(self.state.arena, item_node);1250 try items.append(self.state.arena, item_node);
1251 }1251 }
...@@ -1322,7 +1322,7 @@ pub const Parser = struct {...@@ -1322,7 +1322,7 @@ pub const Parser = struct {
1322 switch (statement_type) {1322 switch (statement_type) {
1323 .file_version, .product_version => {1323 .file_version, .product_version => {
1324 var parts_buffer: [4]*Node = undefined;1324 var parts_buffer: [4]*Node = undefined;
1325 var parts = std.ArrayListUnmanaged(*Node).initBuffer(&parts_buffer);1325 var parts = std.ArrayList(*Node).initBuffer(&parts_buffer);
13261326
1327 while (true) {1327 while (true) {
1328 const value = try self.parseExpression(.{ .allowed_types = .{ .number = true } });1328 const value = try self.parseExpression(.{ .allowed_types = .{ .number = true } });
...@@ -1402,7 +1402,7 @@ pub const Parser = struct {...@@ -1402,7 +1402,7 @@ pub const Parser = struct {
1402 const begin_token = self.state.token;1402 const begin_token = self.state.token;
1403 try self.check(.begin);1403 try self.check(.begin);
14041404
1405 var children: std.ArrayListUnmanaged(*Node) = .empty;1405 var children: std.ArrayList(*Node) = .empty;
1406 while (try self.parseVersionBlockOrValue(top_level_version_id_token, nesting_level + 1)) |value_node| {1406 while (try self.parseVersionBlockOrValue(top_level_version_id_token, nesting_level + 1)) |value_node| {
1407 try children.append(self.state.arena, value_node);1407 try children.append(self.state.arena, value_node);
1408 }1408 }
...@@ -1435,7 +1435,7 @@ pub const Parser = struct {...@@ -1435,7 +1435,7 @@ pub const Parser = struct {
1435 }1435 }
14361436
1437 fn parseBlockValuesList(self: *Self, had_comma_before_first_value: bool) Error![]*Node {1437 fn parseBlockValuesList(self: *Self, had_comma_before_first_value: bool) Error![]*Node {
1438 var values: std.ArrayListUnmanaged(*Node) = .empty;1438 var values: std.ArrayList(*Node) = .empty;
1439 var seen_number: bool = false;1439 var seen_number: bool = false;
1440 var first_string_value: ?*Node = null;1440 var first_string_value: ?*Node = null;
1441 while (true) {1441 while (true) {
lib/compiler/resinator/preprocess.zig+19-18
...@@ -2,16 +2,17 @@ const std = @import("std");...@@ -2,16 +2,17 @@ const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const cli = @import("cli.zig");4const cli = @import("cli.zig");
5const Dependencies = @import("compile.zig").Dependencies;
5const aro = @import("aro");6const aro = @import("aro");
67
7const PreprocessError = error{ ArgError, GeneratedSourceError, PreprocessError, StreamTooLong, OutOfMemory };8const PreprocessError = error{ ArgError, GeneratedSourceError, PreprocessError, StreamTooLong, OutOfMemory };
89
9pub fn preprocess(10pub fn preprocess(
10 comp: *aro.Compilation,11 comp: *aro.Compilation,
11 writer: anytype,12 writer: *std.Io.Writer,
12 /// Expects argv[0] to be the command name13 /// Expects argv[0] to be the command name
13 argv: []const []const u8,14 argv: []const []const u8,
14 maybe_dependencies_list: ?*std.array_list.Managed([]const u8),15 maybe_dependencies: ?*Dependencies,
15) PreprocessError!void {16) PreprocessError!void {
16 try comp.addDefaultPragmaHandlers();17 try comp.addDefaultPragmaHandlers();
1718
...@@ -66,13 +67,13 @@ pub fn preprocess(...@@ -66,13 +67,13 @@ pub fn preprocess(
66 error.WriteFailed => return error.OutOfMemory,67 error.WriteFailed => return error.OutOfMemory,
67 };68 };
6869
69 if (maybe_dependencies_list) |dependencies_list| {70 if (maybe_dependencies) |dependencies| {
70 for (comp.sources.values()) |comp_source| {71 for (comp.sources.values()) |comp_source| {
71 if (comp_source.id == builtin_macros.id or comp_source.id == user_macros.id) continue;72 if (comp_source.id == builtin_macros.id or comp_source.id == user_macros.id) continue;
72 if (comp_source.id == .unused or comp_source.id == .generated) continue;73 if (comp_source.id == .unused or comp_source.id == .generated) continue;
73 const duped_path = try dependencies_list.allocator.dupe(u8, comp_source.path);74 const duped_path = try dependencies.allocator.dupe(u8, comp_source.path);
74 errdefer dependencies_list.allocator.free(duped_path);75 errdefer dependencies.allocator.free(duped_path);
75 try dependencies_list.append(duped_path);76 try dependencies.list.append(dependencies.allocator, duped_path);
76 }77 }
77 }78 }
78}79}
...@@ -92,8 +93,8 @@ fn hasAnyErrors(comp: *aro.Compilation) bool {...@@ -92,8 +93,8 @@ fn hasAnyErrors(comp: *aro.Compilation) bool {
9293
93/// `arena` is used for temporary -D argument strings and the INCLUDE environment variable.94/// `arena` is used for temporary -D argument strings and the INCLUDE environment variable.
94/// The arena should be kept alive at least as long as `argv`.95/// The arena should be kept alive at least as long as `argv`.
95pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8), options: cli.Options, system_include_paths: []const []const u8) !void {96pub fn appendAroArgs(arena: Allocator, argv: *std.ArrayList([]const u8), options: cli.Options, system_include_paths: []const []const u8) !void {
96 try argv.appendSlice(&.{97 try argv.appendSlice(arena, &.{
97 "-E",98 "-E",
98 "--comments",99 "--comments",
99 "-fuse-line-directives",100 "-fuse-line-directives",
...@@ -104,13 +105,13 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)...@@ -104,13 +105,13 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)
104 "-D_WIN32", // undocumented, but defined by default105 "-D_WIN32", // undocumented, but defined by default
105 });106 });
106 for (options.extra_include_paths.items) |extra_include_path| {107 for (options.extra_include_paths.items) |extra_include_path| {
107 try argv.append("-I");108 try argv.append(arena, "-I");
108 try argv.append(extra_include_path);109 try argv.append(arena, extra_include_path);
109 }110 }
110111
111 for (system_include_paths) |include_path| {112 for (system_include_paths) |include_path| {
112 try argv.append("-isystem");113 try argv.append(arena, "-isystem");
113 try argv.append(include_path);114 try argv.append(arena, include_path);
114 }115 }
115116
116 if (!options.ignore_include_env_var) {117 if (!options.ignore_include_env_var) {
...@@ -124,8 +125,8 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)...@@ -124,8 +125,8 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)
124 };125 };
125 var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);126 var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);
126 while (it.next()) |include_path| {127 while (it.next()) |include_path| {
127 try argv.append("-isystem");128 try argv.append(arena, "-isystem");
128 try argv.append(include_path);129 try argv.append(arena, include_path);
129 }130 }
130 }131 }
131132
...@@ -133,13 +134,13 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)...@@ -133,13 +134,13 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)
133 while (symbol_it.next()) |entry| {134 while (symbol_it.next()) |entry| {
134 switch (entry.value_ptr.*) {135 switch (entry.value_ptr.*) {
135 .define => |value| {136 .define => |value| {
136 try argv.append("-D");137 try argv.append(arena, "-D");
137 const define_arg = try std.fmt.allocPrint(arena, "{s}={s}", .{ entry.key_ptr.*, value });138 const define_arg = try std.fmt.allocPrint(arena, "{s}={s}", .{ entry.key_ptr.*, value });
138 try argv.append(define_arg);139 try argv.append(arena, define_arg);
139 },140 },
140 .undefine => {141 .undefine => {
141 try argv.append("-U");142 try argv.append(arena, "-U");
142 try argv.append(entry.key_ptr.*);143 try argv.append(arena, entry.key_ptr.*);
143 },144 },
144 }145 }
145 }146 }
lib/compiler/resinator/res.zig+11-11
...@@ -258,7 +258,7 @@ pub const NameOrOrdinal = union(enum) {...@@ -258,7 +258,7 @@ pub const NameOrOrdinal = union(enum) {
258 }258 }
259 }259 }
260260
261 pub fn write(self: NameOrOrdinal, writer: anytype) !void {261 pub fn write(self: NameOrOrdinal, writer: *std.Io.Writer) !void {
262 switch (self) {262 switch (self) {
263 .name => |name| {263 .name => |name| {
264 try writer.writeAll(std.mem.sliceAsBytes(name[0 .. name.len + 1]));264 try writer.writeAll(std.mem.sliceAsBytes(name[0 .. name.len + 1]));
...@@ -270,7 +270,7 @@ pub const NameOrOrdinal = union(enum) {...@@ -270,7 +270,7 @@ pub const NameOrOrdinal = union(enum) {
270 }270 }
271 }271 }
272272
273 pub fn writeEmpty(writer: anytype) !void {273 pub fn writeEmpty(writer: *std.Io.Writer) !void {
274 try writer.writeInt(u16, 0, .little);274 try writer.writeInt(u16, 0, .little);
275 }275 }
276276
...@@ -283,8 +283,8 @@ pub const NameOrOrdinal = union(enum) {...@@ -283,8 +283,8 @@ pub const NameOrOrdinal = union(enum) {
283283
284 pub fn nameFromString(allocator: Allocator, bytes: SourceBytes) !NameOrOrdinal {284 pub fn nameFromString(allocator: Allocator, bytes: SourceBytes) !NameOrOrdinal {
285 // Names have a limit of 256 UTF-16 code units + null terminator285 // Names have a limit of 256 UTF-16 code units + null terminator
286 var buf = try std.array_list.Managed(u16).initCapacity(allocator, @min(257, bytes.slice.len));286 var buf = try std.ArrayList(u16).initCapacity(allocator, @min(257, bytes.slice.len));
287 errdefer buf.deinit();287 errdefer buf.deinit(allocator);
288288
289 var i: usize = 0;289 var i: usize = 0;
290 while (bytes.code_page.codepointAt(i, bytes.slice)) |codepoint| : (i += codepoint.byte_len) {290 while (bytes.code_page.codepointAt(i, bytes.slice)) |codepoint| : (i += codepoint.byte_len) {
...@@ -292,27 +292,27 @@ pub const NameOrOrdinal = union(enum) {...@@ -292,27 +292,27 @@ pub const NameOrOrdinal = union(enum) {
292292
293 const c = codepoint.value;293 const c = codepoint.value;
294 if (c == Codepoint.invalid) {294 if (c == Codepoint.invalid) {
295 try buf.append(std.mem.nativeToLittle(u16, '�'));295 try buf.append(allocator, std.mem.nativeToLittle(u16, '�'));
296 } else if (c < 0x7F) {296 } else if (c < 0x7F) {
297 // ASCII chars in names are always converted to uppercase297 // ASCII chars in names are always converted to uppercase
298 try buf.append(std.mem.nativeToLittle(u16, std.ascii.toUpper(@intCast(c))));298 try buf.append(allocator, std.mem.nativeToLittle(u16, std.ascii.toUpper(@intCast(c))));
299 } else if (c < 0x10000) {299 } else if (c < 0x10000) {
300 const short: u16 = @intCast(c);300 const short: u16 = @intCast(c);
301 try buf.append(std.mem.nativeToLittle(u16, short));301 try buf.append(allocator, std.mem.nativeToLittle(u16, short));
302 } else {302 } else {
303 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;303 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;
304 try buf.append(std.mem.nativeToLittle(u16, high));304 try buf.append(allocator, std.mem.nativeToLittle(u16, high));
305305
306 // Note: This can cut-off in the middle of a UTF-16 surrogate pair,306 // Note: This can cut-off in the middle of a UTF-16 surrogate pair,
307 // i.e. it can make the string end with an unpaired high surrogate307 // i.e. it can make the string end with an unpaired high surrogate
308 if (buf.items.len == 256) break;308 if (buf.items.len == 256) break;
309309
310 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;310 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;
311 try buf.append(std.mem.nativeToLittle(u16, low));311 try buf.append(allocator, std.mem.nativeToLittle(u16, low));
312 }312 }
313 }313 }
314314
315 return NameOrOrdinal{ .name = try buf.toOwnedSliceSentinel(0) };315 return NameOrOrdinal{ .name = try buf.toOwnedSliceSentinel(allocator, 0) };
316 }316 }
317317
318 /// Returns `null` if the bytes do not form a valid number.318 /// Returns `null` if the bytes do not form a valid number.
...@@ -1079,7 +1079,7 @@ pub const FixedFileInfo = struct {...@@ -1079,7 +1079,7 @@ pub const FixedFileInfo = struct {
1079 }1079 }
1080 };1080 };
10811081
1082 pub fn write(self: FixedFileInfo, writer: anytype) !void {1082 pub fn write(self: FixedFileInfo, writer: *std.Io.Writer) !void {
1083 try writer.writeInt(u32, signature, .little);1083 try writer.writeInt(u32, signature, .little);
1084 try writer.writeInt(u32, version, .little);1084 try writer.writeInt(u32, version, .little);
1085 try writer.writeInt(u32, self.file_version.mostSignificantCombinedParts(), .little);1085 try writer.writeInt(u32, self.file_version.mostSignificantCombinedParts(), .little);
lib/compiler/resinator/source_mapping.zig+5-5
...@@ -10,7 +10,7 @@ pub const ParseLineCommandsResult = struct {...@@ -10,7 +10,7 @@ pub const ParseLineCommandsResult = struct {
1010
11const CurrentMapping = struct {11const CurrentMapping = struct {
12 line_num: usize = 1,12 line_num: usize = 1,
13 filename: std.ArrayListUnmanaged(u8) = .empty,13 filename: std.ArrayList(u8) = .empty,
14 pending: bool = true,14 pending: bool = true,
15 ignore_contents: bool = false,15 ignore_contents: bool = false,
16};16};
...@@ -574,8 +574,8 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva...@@ -574,8 +574,8 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva
574 escape_u,574 escape_u,
575 };575 };
576576
577 var filename = try std.array_list.Managed(u8).initCapacity(allocator, str.len);577 var filename = try std.ArrayList(u8).initCapacity(allocator, str.len);
578 errdefer filename.deinit();578 errdefer filename.deinit(allocator);
579 var state: State = .string;579 var state: State = .string;
580 var index: usize = 0;580 var index: usize = 0;
581 var escape_len: usize = undefined;581 var escape_len: usize = undefined;
...@@ -693,7 +693,7 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva...@@ -693,7 +693,7 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva
693 }693 }
694 }694 }
695695
696 return filename.toOwnedSlice();696 return filename.toOwnedSlice(allocator);
697}697}
698698
699fn testParseFilename(expected: []const u8, input: []const u8) !void {699fn testParseFilename(expected: []const u8, input: []const u8) !void {
...@@ -927,7 +927,7 @@ test "SourceMappings collapse" {...@@ -927,7 +927,7 @@ test "SourceMappings collapse" {
927927
928/// Same thing as StringTable in Zig's src/Wasm.zig928/// Same thing as StringTable in Zig's src/Wasm.zig
929pub const StringTable = struct {929pub const StringTable = struct {
930 data: std.ArrayListUnmanaged(u8) = .empty,930 data: std.ArrayList(u8) = .empty,
931 map: std.HashMapUnmanaged(u32, void, std.hash_map.StringIndexContext, std.hash_map.default_max_load_percentage) = .empty,931 map: std.HashMapUnmanaged(u32, void, std.hash_map.StringIndexContext, std.hash_map.default_max_load_percentage) = .empty,
932932
933 pub fn deinit(self: *StringTable, allocator: Allocator) void {933 pub fn deinit(self: *StringTable, allocator: Allocator) void {
lib/compiler/resinator/windows1252.zig-45
...@@ -1,36 +1,5 @@...@@ -1,36 +1,5 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn windows1252ToUtf8Stream(writer: anytype, reader: anytype) !usize {
4 var bytes_written: usize = 0;
5 var utf8_buf: [3]u8 = undefined;
6 while (true) {
7 const c = reader.readByte() catch |err| switch (err) {
8 error.EndOfStream => return bytes_written,
9 else => |e| return e,
10 };
11 const codepoint = toCodepoint(c);
12 if (codepoint <= 0x7F) {
13 try writer.writeByte(c);
14 bytes_written += 1;
15 } else {
16 const utf8_len = std.unicode.utf8Encode(codepoint, &utf8_buf) catch unreachable;
17 try writer.writeAll(utf8_buf[0..utf8_len]);
18 bytes_written += utf8_len;
19 }
20 }
21}
22
23/// Returns the number of code units written to the writer
24pub fn windows1252ToUtf16AllocZ(allocator: std.mem.Allocator, win1252_str: []const u8) ![:0]u16 {
25 // Guaranteed to need exactly the same number of code units as Windows-1252 bytes
26 var utf16_slice = try allocator.allocSentinel(u16, win1252_str.len, 0);
27 errdefer allocator.free(utf16_slice);
28 for (win1252_str, 0..) |c, i| {
29 utf16_slice[i] = toCodepoint(c);
30 }
31 return utf16_slice;
32}
33
34/// https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/bestfit1252.txt3/// https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/bestfit1252.txt
35pub fn toCodepoint(c: u8) u16 {4pub fn toCodepoint(c: u8) u16 {
36 return switch (c) {5 return switch (c) {
...@@ -572,17 +541,3 @@ pub fn bestFitFromCodepoint(codepoint: u21) ?u8 {...@@ -572,17 +541,3 @@ pub fn bestFitFromCodepoint(codepoint: u21) ?u8 {
572 else => null,541 else => null,
573 };542 };
574}543}
575
576test "windows-1252 to utf8" {
577 var buf = std.array_list.Managed(u8).init(std.testing.allocator);
578 defer buf.deinit();
579
580 const input_windows1252 = "\x81pqrstuvwxyz{|}~\x80\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8e\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9e\x9f\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
581 const expected_utf8 = "\xc2\x81pqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ";
582
583 var fbs = std.io.fixedBufferStream(input_windows1252);
584 const bytes_written = try windows1252ToUtf8Stream(buf.writer(), fbs.reader());
585
586 try std.testing.expectEqualStrings(expected_utf8, buf.items);
587 try std.testing.expectEqual(expected_utf8.len, bytes_written);
588}