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");
1616
1717const AF_ICON: u32 = 1;
1818
19pub fn isAnimatedIcon(reader: anytype) bool {
19pub fn isAnimatedIcon(reader: *std.Io.Reader) bool {
2020 const flags = getAniheaderFlags(reader) catch return false;
2121 return flags & AF_ICON == AF_ICON;
2222}
2323
24fn getAniheaderFlags(reader: anytype) !u32 {
25 const riff_header = try reader.readBytesNoEof(4);
26 if (!std.mem.eql(u8, &riff_header, "RIFF")) return error.InvalidFormat;
24fn getAniheaderFlags(reader: *std.Io.Reader) !u32 {
25 const riff_header = try reader.takeArray(4);
26 if (!std.mem.eql(u8, riff_header, "RIFF")) return error.InvalidFormat;
2727
28 _ = try reader.readInt(u32, .little); // size of RIFF chunk
28 _ = try reader.takeInt(u32, .little); // size of RIFF chunk
2929
30 const form_type = try reader.readBytesNoEof(4);
31 if (!std.mem.eql(u8, &form_type, "ACON")) return error.InvalidFormat;
30 const form_type = try reader.takeArray(4);
31 if (!std.mem.eql(u8, form_type, "ACON")) return error.InvalidFormat;
3232
3333 while (true) {
34 const chunk_id = try reader.readBytesNoEof(4);
35 const chunk_len = try reader.readInt(u32, .little);
36 if (!std.mem.eql(u8, &chunk_id, "anih")) {
34 const chunk_id = try reader.takeArray(4);
35 const chunk_len = try reader.takeInt(u32, .little);
36 if (!std.mem.eql(u8, chunk_id, "anih")) {
3737 // TODO: Move file cursor instead of skipBytes
38 try reader.skipBytes(chunk_len, .{});
38 try reader.discardAll(chunk_len);
3939 continue;
4040 }
4141
42 const aniheader = try reader.readStruct(ANIHEADER);
43 return std.mem.nativeToLittle(u32, aniheader.flags);
42 const aniheader = try reader.takeStruct(ANIHEADER, .little);
43 return aniheader.flags;
4444 }
4545}
4646
lib/compiler/resinator/ast.zig+40-40
......@@ -22,13 +22,13 @@ pub const Tree = struct {
2222 return @alignCast(@fieldParentPtr("base", self.node));
2323 }
2424
25 pub fn dump(self: *Tree, writer: anytype) @TypeOf(writer).Error!void {
25 pub fn dump(self: *Tree, writer: *std.io.Writer) !void {
2626 try self.node.dump(self, writer, 0);
2727 }
2828};
2929
3030pub const CodePageLookup = struct {
31 lookup: std.ArrayListUnmanaged(SupportedCodePage) = .empty,
31 lookup: std.ArrayList(SupportedCodePage) = .empty,
3232 allocator: Allocator,
3333 default_code_page: SupportedCodePage,
3434
......@@ -726,10 +726,10 @@ pub const Node = struct {
726726 pub fn dump(
727727 node: *const Node,
728728 tree: *const Tree,
729 writer: anytype,
729 writer: *std.io.Writer,
730730 indent: usize,
731 ) @TypeOf(writer).Error!void {
732 try writer.writeByteNTimes(' ', indent);
731 ) std.io.Writer.Error!void {
732 try writer.splatByteAll(' ', indent);
733733 try writer.writeAll(@tagName(node.id));
734734 switch (node.id) {
735735 .root => {
......@@ -768,11 +768,11 @@ pub const Node = struct {
768768 .grouped_expression => {
769769 const grouped: *const Node.GroupedExpression = @alignCast(@fieldParentPtr("base", node));
770770 try writer.writeAll("\n");
771 try writer.writeByteNTimes(' ', indent);
771 try writer.splatByteAll(' ', indent);
772772 try writer.writeAll(grouped.open_token.slice(tree.source));
773773 try writer.writeAll("\n");
774774 try grouped.expression.dump(tree, writer, indent + 1);
775 try writer.writeByteNTimes(' ', indent);
775 try writer.splatByteAll(' ', indent);
776776 try writer.writeAll(grouped.close_token.slice(tree.source));
777777 try writer.writeAll("\n");
778778 },
......@@ -790,13 +790,13 @@ pub const Node = struct {
790790 for (accelerators.optional_statements) |statement| {
791791 try statement.dump(tree, writer, indent + 1);
792792 }
793 try writer.writeByteNTimes(' ', indent);
793 try writer.splatByteAll(' ', indent);
794794 try writer.writeAll(accelerators.begin_token.slice(tree.source));
795795 try writer.writeAll("\n");
796796 for (accelerators.accelerators) |accelerator| {
797797 try accelerator.dump(tree, writer, indent + 1);
798798 }
799 try writer.writeByteNTimes(' ', indent);
799 try writer.splatByteAll(' ', indent);
800800 try writer.writeAll(accelerators.end_token.slice(tree.source));
801801 try writer.writeAll("\n");
802802 },
......@@ -815,25 +815,25 @@ pub const Node = struct {
815815 const dialog: *const Node.Dialog = @alignCast(@fieldParentPtr("base", node));
816816 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 });
817817 inline for (.{ "x", "y", "width", "height" }) |arg| {
818 try writer.writeByteNTimes(' ', indent + 1);
818 try writer.splatByteAll(' ', indent + 1);
819819 try writer.writeAll(arg ++ ":\n");
820820 try @field(dialog, arg).dump(tree, writer, indent + 2);
821821 }
822822 if (dialog.help_id) |help_id| {
823 try writer.writeByteNTimes(' ', indent + 1);
823 try writer.splatByteAll(' ', indent + 1);
824824 try writer.writeAll("help_id:\n");
825825 try help_id.dump(tree, writer, indent + 2);
826826 }
827827 for (dialog.optional_statements) |statement| {
828828 try statement.dump(tree, writer, indent + 1);
829829 }
830 try writer.writeByteNTimes(' ', indent);
830 try writer.splatByteAll(' ', indent);
831831 try writer.writeAll(dialog.begin_token.slice(tree.source));
832832 try writer.writeAll("\n");
833833 for (dialog.controls) |control| {
834834 try control.dump(tree, writer, indent + 1);
835835 }
836 try writer.writeByteNTimes(' ', indent);
836 try writer.splatByteAll(' ', indent);
837837 try writer.writeAll(dialog.end_token.slice(tree.source));
838838 try writer.writeAll("\n");
839839 },
......@@ -845,30 +845,30 @@ pub const Node = struct {
845845 }
846846 try writer.writeByte('\n');
847847 if (control.class) |class| {
848 try writer.writeByteNTimes(' ', indent + 1);
848 try writer.splatByteAll(' ', indent + 1);
849849 try writer.writeAll("class:\n");
850850 try class.dump(tree, writer, indent + 2);
851851 }
852852 inline for (.{ "id", "x", "y", "width", "height" }) |arg| {
853 try writer.writeByteNTimes(' ', indent + 1);
853 try writer.splatByteAll(' ', indent + 1);
854854 try writer.writeAll(arg ++ ":\n");
855855 try @field(control, arg).dump(tree, writer, indent + 2);
856856 }
857857 inline for (.{ "style", "exstyle", "help_id" }) |arg| {
858858 if (@field(control, arg)) |val_node| {
859 try writer.writeByteNTimes(' ', indent + 1);
859 try writer.splatByteAll(' ', indent + 1);
860860 try writer.writeAll(arg ++ ":\n");
861861 try val_node.dump(tree, writer, indent + 2);
862862 }
863863 }
864864 if (control.extra_data_begin != null) {
865 try writer.writeByteNTimes(' ', indent);
865 try writer.splatByteAll(' ', indent);
866866 try writer.writeAll(control.extra_data_begin.?.slice(tree.source));
867867 try writer.writeAll("\n");
868868 for (control.extra_data) |data_node| {
869869 try data_node.dump(tree, writer, indent + 1);
870870 }
871 try writer.writeByteNTimes(' ', indent);
871 try writer.splatByteAll(' ', indent);
872872 try writer.writeAll(control.extra_data_end.?.slice(tree.source));
873873 try writer.writeAll("\n");
874874 }
......@@ -877,17 +877,17 @@ pub const Node = struct {
877877 const toolbar: *const Node.Toolbar = @alignCast(@fieldParentPtr("base", node));
878878 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 });
879879 inline for (.{ "button_width", "button_height" }) |arg| {
880 try writer.writeByteNTimes(' ', indent + 1);
880 try writer.splatByteAll(' ', indent + 1);
881881 try writer.writeAll(arg ++ ":\n");
882882 try @field(toolbar, arg).dump(tree, writer, indent + 2);
883883 }
884 try writer.writeByteNTimes(' ', indent);
884 try writer.splatByteAll(' ', indent);
885885 try writer.writeAll(toolbar.begin_token.slice(tree.source));
886886 try writer.writeAll("\n");
887887 for (toolbar.buttons) |button_or_sep| {
888888 try button_or_sep.dump(tree, writer, indent + 1);
889889 }
890 try writer.writeByteNTimes(' ', indent);
890 try writer.splatByteAll(' ', indent);
891891 try writer.writeAll(toolbar.end_token.slice(tree.source));
892892 try writer.writeAll("\n");
893893 },
......@@ -898,17 +898,17 @@ pub const Node = struct {
898898 try statement.dump(tree, writer, indent + 1);
899899 }
900900 if (menu.help_id) |help_id| {
901 try writer.writeByteNTimes(' ', indent + 1);
901 try writer.splatByteAll(' ', indent + 1);
902902 try writer.writeAll("help_id:\n");
903903 try help_id.dump(tree, writer, indent + 2);
904904 }
905 try writer.writeByteNTimes(' ', indent);
905 try writer.splatByteAll(' ', indent);
906906 try writer.writeAll(menu.begin_token.slice(tree.source));
907907 try writer.writeAll("\n");
908908 for (menu.items) |item| {
909909 try item.dump(tree, writer, indent + 1);
910910 }
911 try writer.writeByteNTimes(' ', indent);
911 try writer.splatByteAll(' ', indent);
912912 try writer.writeAll(menu.end_token.slice(tree.source));
913913 try writer.writeAll("\n");
914914 },
......@@ -926,7 +926,7 @@ pub const Node = struct {
926926 try writer.print(" {s} {s}\n", .{ menu_item.menuitem.slice(tree.source), menu_item.text.slice(tree.source) });
927927 inline for (.{ "id", "type", "state" }) |arg| {
928928 if (@field(menu_item, arg)) |val_node| {
929 try writer.writeByteNTimes(' ', indent + 1);
929 try writer.splatByteAll(' ', indent + 1);
930930 try writer.writeAll(arg ++ ":\n");
931931 try val_node.dump(tree, writer, indent + 2);
932932 }
......@@ -935,13 +935,13 @@ pub const Node = struct {
935935 .popup => {
936936 const popup: *const Node.Popup = @alignCast(@fieldParentPtr("base", node));
937937 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);
939939 try writer.writeAll(popup.begin_token.slice(tree.source));
940940 try writer.writeAll("\n");
941941 for (popup.items) |item| {
942942 try item.dump(tree, writer, indent + 1);
943943 }
944 try writer.writeByteNTimes(' ', indent);
944 try writer.splatByteAll(' ', indent);
945945 try writer.writeAll(popup.end_token.slice(tree.source));
946946 try writer.writeAll("\n");
947947 },
......@@ -950,18 +950,18 @@ pub const Node = struct {
950950 try writer.print(" {s} {s}\n", .{ popup.popup.slice(tree.source), popup.text.slice(tree.source) });
951951 inline for (.{ "id", "type", "state", "help_id" }) |arg| {
952952 if (@field(popup, arg)) |val_node| {
953 try writer.writeByteNTimes(' ', indent + 1);
953 try writer.splatByteAll(' ', indent + 1);
954954 try writer.writeAll(arg ++ ":\n");
955955 try val_node.dump(tree, writer, indent + 2);
956956 }
957957 }
958 try writer.writeByteNTimes(' ', indent);
958 try writer.splatByteAll(' ', indent);
959959 try writer.writeAll(popup.begin_token.slice(tree.source));
960960 try writer.writeAll("\n");
961961 for (popup.items) |item| {
962962 try item.dump(tree, writer, indent + 1);
963963 }
964 try writer.writeByteNTimes(' ', indent);
964 try writer.splatByteAll(' ', indent);
965965 try writer.writeAll(popup.end_token.slice(tree.source));
966966 try writer.writeAll("\n");
967967 },
......@@ -971,13 +971,13 @@ pub const Node = struct {
971971 for (version_info.fixed_info) |fixed_info| {
972972 try fixed_info.dump(tree, writer, indent + 1);
973973 }
974 try writer.writeByteNTimes(' ', indent);
974 try writer.splatByteAll(' ', indent);
975975 try writer.writeAll(version_info.begin_token.slice(tree.source));
976976 try writer.writeAll("\n");
977977 for (version_info.block_statements) |block| {
978978 try block.dump(tree, writer, indent + 1);
979979 }
980 try writer.writeByteNTimes(' ', indent);
980 try writer.splatByteAll(' ', indent);
981981 try writer.writeAll(version_info.end_token.slice(tree.source));
982982 try writer.writeAll("\n");
983983 },
......@@ -994,13 +994,13 @@ pub const Node = struct {
994994 for (block.values) |value| {
995995 try value.dump(tree, writer, indent + 1);
996996 }
997 try writer.writeByteNTimes(' ', indent);
997 try writer.splatByteAll(' ', indent);
998998 try writer.writeAll(block.begin_token.slice(tree.source));
999999 try writer.writeAll("\n");
10001000 for (block.children) |child| {
10011001 try child.dump(tree, writer, indent + 1);
10021002 }
1003 try writer.writeByteNTimes(' ', indent);
1003 try writer.splatByteAll(' ', indent);
10041004 try writer.writeAll(block.end_token.slice(tree.source));
10051005 try writer.writeAll("\n");
10061006 },
......@@ -1025,13 +1025,13 @@ pub const Node = struct {
10251025 for (string_table.optional_statements) |statement| {
10261026 try statement.dump(tree, writer, indent + 1);
10271027 }
1028 try writer.writeByteNTimes(' ', indent);
1028 try writer.splatByteAll(' ', indent);
10291029 try writer.writeAll(string_table.begin_token.slice(tree.source));
10301030 try writer.writeAll("\n");
10311031 for (string_table.strings) |string| {
10321032 try string.dump(tree, writer, indent + 1);
10331033 }
1034 try writer.writeByteNTimes(' ', indent);
1034 try writer.splatByteAll(' ', indent);
10351035 try writer.writeAll(string_table.end_token.slice(tree.source));
10361036 try writer.writeAll("\n");
10371037 },
......@@ -1039,7 +1039,7 @@ pub const Node = struct {
10391039 try writer.writeAll("\n");
10401040 const string: *const Node.StringTableString = @alignCast(@fieldParentPtr("base", node));
10411041 try string.id.dump(tree, writer, indent + 1);
1042 try writer.writeByteNTimes(' ', indent + 1);
1042 try writer.splatByteAll(' ', indent + 1);
10431043 try writer.print("{s}\n", .{string.string.slice(tree.source)});
10441044 },
10451045 .language_statement => {
......@@ -1051,12 +1051,12 @@ pub const Node = struct {
10511051 .font_statement => {
10521052 const font: *const Node.FontStatement = @alignCast(@fieldParentPtr("base", node));
10531053 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);
10551055 try writer.writeAll("point_size:\n");
10561056 try font.point_size.dump(tree, writer, indent + 2);
10571057 inline for (.{ "weight", "italic", "char_set" }) |arg| {
10581058 if (@field(font, arg)) |arg_node| {
1059 try writer.writeByteNTimes(' ', indent + 1);
1059 try writer.splatByteAll(' ', indent + 1);
10601060 try writer.writeAll(arg ++ ":\n");
10611061 try arg_node.dump(tree, writer, indent + 2);
10621062 }
......@@ -1071,7 +1071,7 @@ pub const Node = struct {
10711071 const invalid: *const Node.Invalid = @alignCast(@fieldParentPtr("base", node));
10721072 try writer.print(" context.len: {}\n", .{invalid.context.len});
10731073 for (invalid.context) |context_token| {
1074 try writer.writeByteNTimes(' ', indent + 1);
1074 try writer.splatByteAll(' ', indent + 1);
10751075 try writer.print("{s}:{s}", .{ @tagName(context_token.id), context_token.slice(tree.source) });
10761076 try writer.writeByte('\n');
10771077 }
lib/compiler/resinator/bmp.zig+25-15
......@@ -27,6 +27,7 @@ pub const windows_format_id = std.mem.readInt(u16, "BM", native_endian);
2727pub const file_header_len = 14;
2828
2929pub const ReadError = error{
30 ReadFailed,
3031 UnexpectedEOF,
3132 InvalidFileHeader,
3233 ImpossiblePixelDataOffset,
......@@ -94,9 +95,12 @@ pub const BitmapInfo = struct {
9495 }
9596};
9697
97pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {
98pub fn read(reader: *std.Io.Reader, max_size: u64) ReadError!BitmapInfo {
9899 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
101105 const id = std.mem.readInt(u16, file_header[0..2], native_endian);
102106 if (id != windows_format_id) return error.InvalidFileHeader;
......@@ -104,14 +108,17 @@ pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {
104108 bitmap_info.pixel_data_offset = std.mem.readInt(u32, file_header[10..14], .little);
105109 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;
108112 if (bitmap_info.pixel_data_offset < file_header_len + bitmap_info.dib_header_size) return error.ImpossiblePixelDataOffset;
109113 const dib_version = BitmapHeader.Version.get(bitmap_info.dib_header_size);
110114 switch (dib_version) {
111115 .@"nt3.1", .@"nt4.0", .@"nt5.0" => {
112116 var dib_header_buf: [@sizeOf(BITMAPINFOHEADER)]u8 align(@alignOf(BITMAPINFOHEADER)) = undefined;
113117 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 };
115122 var dib_header: *BITMAPINFOHEADER = @ptrCast(&dib_header_buf);
116123 structFieldsLittleToNative(BITMAPINFOHEADER, dib_header);
117124
......@@ -126,7 +133,10 @@ pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {
126133 .@"win2.0" => {
127134 var dib_header_buf: [@sizeOf(BITMAPCOREHEADER)]u8 align(@alignOf(BITMAPCOREHEADER)) = undefined;
128135 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 };
130140 const dib_header: *BITMAPCOREHEADER = @ptrCast(&dib_header_buf);
131141 structFieldsLittleToNative(BITMAPCOREHEADER, dib_header);
132142
......@@ -238,26 +248,26 @@ fn structFieldsLittleToNative(comptime T: type, x: *T) void {
238248
239249test "read" {
240250 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
243253 {
244 const bitmap = try read(fbs.reader(), bmp_data.len);
254 const bitmap = try read(&fbs, bmp_data.len);
245255 try std.testing.expectEqual(@as(u32, BitmapHeader.Version.@"nt3.1".len()), bitmap.dib_header_size);
246256 }
247257
248258 {
249 fbs.reset();
259 fbs.seek = 0;
250260 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
253263 // restore
254264 bmp_data[file_header_len] = BitmapHeader.Version.@"nt3.1".len();
255265 }
256266
257267 {
258 fbs.reset();
268 fbs.seek = 0;
259269 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
262272 // restore
263273 bmp_data[0] = 'B';
......@@ -265,13 +275,13 @@ test "read" {
265275
266276 {
267277 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]);
269 try std.testing.expectError(error.UnexpectedEOF, read(dib_cutoff_fbs.reader(), bmp_data.len));
278 var dib_cutoff_fbs: std.Io.Reader = .fixed(bmp_data[0..cutoff_len]);
279 try std.testing.expectError(error.UnexpectedEOF, read(&dib_cutoff_fbs, bmp_data.len));
270280 }
271281
272282 {
273283 const cutoff_len = file_header_len - 1;
274 var bmp_cutoff_fbs = std.io.fixedBufferStream(bmp_data[0..cutoff_len]);
275 try std.testing.expectError(error.UnexpectedEOF, read(bmp_cutoff_fbs.reader(), bmp_data.len));
284 var bmp_cutoff_fbs: std.Io.Reader = .fixed(bmp_data[0..cutoff_len]);
285 try std.testing.expectError(error.UnexpectedEOF, read(&bmp_cutoff_fbs, bmp_data.len));
276286 }
277287}
lib/compiler/resinator/cli.zig+13-13
......@@ -80,20 +80,20 @@ pub const usage_string_after_command_name =
8080 \\
8181;
8282
83pub fn writeUsage(writer: anytype, command_name: []const u8) !void {
83pub fn writeUsage(writer: *std.Io.Writer, command_name: []const u8) !void {
8484 try writer.writeAll("Usage: ");
8585 try writer.writeAll(command_name);
8686 try writer.writeAll(usage_string_after_command_name);
8787}
8888
8989pub const Diagnostics = struct {
90 errors: std.ArrayListUnmanaged(ErrorDetails) = .empty,
90 errors: std.ArrayList(ErrorDetails) = .empty,
9191 allocator: Allocator,
9292
9393 pub const ErrorDetails = struct {
9494 arg_index: usize,
9595 arg_span: ArgSpan = .{},
96 msg: std.ArrayListUnmanaged(u8) = .empty,
96 msg: std.ArrayList(u8) = .empty,
9797 type: Type = .err,
9898 print_args: bool = true,
9999
......@@ -148,7 +148,7 @@ pub const Options = struct {
148148 allocator: Allocator,
149149 input_source: IoSource = .{ .filename = &[_]u8{} },
150150 output_source: IoSource = .{ .filename = &[_]u8{} },
151 extra_include_paths: std.ArrayListUnmanaged([]const u8) = .empty,
151 extra_include_paths: std.ArrayList([]const u8) = .empty,
152152 ignore_include_env_var: bool = false,
153153 preprocess: Preprocess = .yes,
154154 default_language_id: ?u16 = null,
......@@ -295,7 +295,7 @@ pub const Options = struct {
295295 }
296296 }
297297
298 pub fn dumpVerbose(self: *const Options, writer: anytype) !void {
298 pub fn dumpVerbose(self: *const Options, writer: *std.Io.Writer) !void {
299299 const input_source_name = switch (self.input_source) {
300300 .stdio => "<stdin>",
301301 .filename => |filename| filename,
......@@ -1230,19 +1230,19 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
12301230}
12311231
12321232pub fn filepathWithExtension(allocator: Allocator, path: []const u8, ext: []const u8) ![]const u8 {
1233 var buf = std.array_list.Managed(u8).init(allocator);
1234 errdefer buf.deinit();
1233 var buf: std.ArrayList(u8) = .empty;
1234 errdefer buf.deinit(allocator);
12351235 if (std.fs.path.dirname(path)) |dirname| {
12361236 var end_pos = dirname.len;
12371237 // We want to ensure that we write a path separator at the end, so if the dirname
12381238 // doesn't end with a path sep then include the char after the dirname
12391239 // which must be a path sep.
12401240 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]);
12421242 }
1243 try buf.appendSlice(std.fs.path.stem(path));
1244 try buf.appendSlice(ext);
1245 return try buf.toOwnedSlice();
1243 try buf.appendSlice(allocator, std.fs.path.stem(path));
1244 try buf.appendSlice(allocator, ext);
1245 return try buf.toOwnedSlice(allocator);
12461246}
12471247
12481248pub fn isSupportedInputExtension(ext: []const u8) bool {
......@@ -1476,7 +1476,7 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti
14761476 var options = parse(std.testing.allocator, args, &diagnostics) catch |err| switch (err) {
14771477 error.ParseError => {
14781478 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());
14801480 return null;
14811481 },
14821482 else => |e| return e,
......@@ -1484,7 +1484,7 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti
14841484 errdefer options.deinit();
14851485
14861486 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());
14881488 return options;
14891489}
14901490
lib/compiler/resinator/compile.zig+189-221
......@@ -35,10 +35,7 @@ pub const CompileOptions = struct {
3535 diagnostics: *Diagnostics,
3636 source_mappings: ?*SourceMappings = null,
3737 /// 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 be
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,
38 dependencies: ?*Dependencies = null,
4239 default_code_page: SupportedCodePage = .windows1252,
4340 /// If true, the first #pragma code_page directive only sets the input code page, but not the output code page.
4441 /// This check must be done before comments are removed from the file.
......@@ -61,6 +58,25 @@ pub const CompileOptions = struct {
6158 warn_instead_of_error_on_invalid_code_page: bool = false,
6259};
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
6480pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer, options: CompileOptions) !void {
6581 var lexer = lex.Lexer.init(source, .{
6682 .default_code_page = options.default_code_page,
......@@ -74,12 +90,12 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,
7490 var tree = try parser.parse(allocator, options.diagnostics);
7591 defer tree.deinit();
7692
77 var search_dirs = std.array_list.Managed(SearchDir).init(allocator);
93 var search_dirs: std.ArrayList(SearchDir) = .empty;
7894 defer {
7995 for (search_dirs.items) |*search_dir| {
8096 search_dir.deinit(allocator);
8197 }
82 search_dirs.deinit();
98 search_dirs.deinit(allocator);
8399 }
84100
85101 if (options.source_mappings) |source_mappings| {
......@@ -89,7 +105,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,
89105 if (std.fs.path.dirname(root_path)) |root_dir_path| {
90106 var root_dir = try options.cwd.openDir(root_dir_path, .{});
91107 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) });
93109 }
94110 }
95111 // 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,
111127 });
112128 return error.CompileError;
113129 };
114 try search_dirs.append(.{ .dir = cwd_dir, .path = null });
130 try search_dirs.append(allocator, .{ .dir = cwd_dir, .path = null });
115131 for (options.extra_include_paths) |extra_include_path| {
116132 var dir = openSearchPathDir(options.cwd, extra_include_path) catch {
117133 // TODO: maybe a warning that the search path is skipped?
118134 continue;
119135 };
120136 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) });
122138 }
123139 for (options.system_include_paths) |system_include_path| {
124140 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,
126142 continue;
127143 };
128144 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) });
130146 }
131147 if (!options.ignore_include_env_var) {
132148 const INCLUDE = std.process.getEnvVarOwned(allocator, "INCLUDE") catch "";
......@@ -142,7 +158,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,
142158 while (it.next()) |search_path| {
143159 var dir = openSearchPathDir(options.cwd, search_path) catch continue;
144160 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) });
146162 }
147163 }
148164
......@@ -156,7 +172,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer,
156172 .allocator = allocator,
157173 .cwd = options.cwd,
158174 .diagnostics = options.diagnostics,
159 .dependencies_list = options.dependencies_list,
175 .dependencies = options.dependencies,
160176 .input_code_pages = &tree.input_code_pages,
161177 .output_code_pages = &tree.output_code_pages,
162178 // This is only safe because we know search_dirs won't be modified past this point
......@@ -178,7 +194,7 @@ pub const Compiler = struct {
178194 cwd: std.fs.Dir,
179195 state: State = .{},
180196 diagnostics: *Diagnostics,
181 dependencies_list: ?*std.array_list.Managed([]const u8),
197 dependencies: ?*Dependencies,
182198 input_code_pages: *const CodePageLookup,
183199 output_code_pages: *const CodePageLookup,
184200 search_dirs: []SearchDir,
......@@ -279,32 +295,32 @@ pub const Compiler = struct {
279295 .literal, .number => {
280296 const slice = literal_node.token.slice(self.source);
281297 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);
283 errdefer buf.deinit();
298 var buf = try std.ArrayList(u8).initCapacity(self.allocator, slice.len);
299 errdefer buf.deinit(self.allocator);
284300
285301 var index: usize = 0;
286302 while (code_page.codepointAt(index, slice)) |codepoint| : (index += codepoint.byte_len) {
287303 const c = codepoint.value;
288304 if (c == code_pages.Codepoint.invalid) {
289 try buf.appendSlice("�");
305 try buf.appendSlice(self.allocator, "�");
290306 } else {
291307 // Anything that is not returned as an invalid codepoint must be encodable as UTF-8.
292308 const utf8_len = std.unicode.utf8CodepointSequenceLength(c) catch unreachable;
293 try buf.ensureUnusedCapacity(utf8_len);
309 try buf.ensureUnusedCapacity(self.allocator, utf8_len);
294310 _ = std.unicode.utf8Encode(c, buf.unusedCapacitySlice()) catch unreachable;
295311 buf.items.len += utf8_len;
296312 }
297313 }
298314
299 return buf.toOwnedSlice();
315 return buf.toOwnedSlice(self.allocator);
300316 },
301317 .quoted_ascii_string, .quoted_wide_string => {
302318 const slice = literal_node.token.slice(self.source);
303319 const column = literal_node.token.calculateColumn(self.source, 8, null);
304320 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);
307 errdefer buf.deinit();
322 var buf: std.ArrayList(u8) = .empty;
323 errdefer buf.deinit(self.allocator);
308324
309325 // Filenames are sort-of parsed as if they were wide strings, but the max escape width of
310326 // 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 {
320336 while (try parser.nextUnchecked()) |parsed| {
321337 const c = parsed.codepoint;
322338 if (c == code_pages.Codepoint.invalid) {
323 try buf.appendSlice("�");
339 try buf.appendSlice(self.allocator, "�");
324340 } else {
325341 var codepoint_buf: [4]u8 = undefined;
326342 // If the codepoint cannot be encoded, we fall back to �
327343 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]);
329345 } else |_| {
330 try buf.appendSlice("�");
346 try buf.appendSlice(self.allocator, "�");
331347 }
332348 }
333349 }
334350
335 return buf.toOwnedSlice();
351 return buf.toOwnedSlice(self.allocator);
336352 },
337353 else => unreachable, // no other token types should be in a filename literal node
338354 }
......@@ -386,10 +402,10 @@ pub const Compiler = struct {
386402 const file = try utils.openFileNotDir(std.fs.cwd(), path, .{});
387403 errdefer file.close();
388404
389 if (self.dependencies_list) |dependencies_list| {
390 const duped_path = try dependencies_list.allocator.dupe(u8, path);
391 errdefer dependencies_list.allocator.free(duped_path);
392 try dependencies_list.append(duped_path);
405 if (self.dependencies) |dependencies| {
406 const duped_path = try dependencies.allocator.dupe(u8, path);
407 errdefer dependencies.allocator.free(duped_path);
408 try dependencies.list.append(dependencies.allocator, duped_path);
393409 }
394410 }
395411
......@@ -398,12 +414,12 @@ pub const Compiler = struct {
398414 if (utils.openFileNotDir(search_dir.dir, path, .{})) |file| {
399415 errdefer file.close();
400416
401 if (self.dependencies_list) |dependencies_list| {
402 const searched_file_path = try std.fs.path.join(dependencies_list.allocator, &.{
417 if (self.dependencies) |dependencies| {
418 const searched_file_path = try std.fs.path.join(dependencies.allocator, &.{
403419 search_dir.path orelse "", path,
404420 });
405 errdefer dependencies_list.allocator.free(searched_file_path);
406 try dependencies_list.append(searched_file_path);
421 errdefer dependencies.allocator.free(searched_file_path);
422 try dependencies.list.append(dependencies.allocator, searched_file_path);
407423 }
408424
409425 return file;
......@@ -421,8 +437,8 @@ pub const Compiler = struct {
421437 const bytes = self.sourceBytesForToken(token);
422438 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);
425 errdefer buf.deinit();
440 var buf = try std.ArrayList(u8).initCapacity(self.allocator, bytes.slice.len);
441 errdefer buf.deinit(self.allocator);
426442
427443 var iterative_parser = literals.IterativeStringParser.init(bytes, .{
428444 .start_column = token.calculateColumn(self.source, 8, null),
......@@ -444,11 +460,11 @@ pub const Compiler = struct {
444460 switch (iterative_parser.declared_string_type) {
445461 .wide => {
446462 if (windows1252.bestFitFromCodepoint(c)) |best_fit| {
447 try buf.append(best_fit);
463 try buf.append(self.allocator, best_fit);
448464 } 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, '?');
450466 } else {
451 try buf.appendSlice("??");
467 try buf.appendSlice(self.allocator, "??");
452468 }
453469 },
454470 .ascii => {
......@@ -456,27 +472,27 @@ pub const Compiler = struct {
456472 const truncated: u8 = @truncate(c);
457473 switch (output_code_page) {
458474 .utf8 => switch (truncated) {
459 0...0x7F => try buf.append(truncated),
460 else => try buf.append('?'),
475 0...0x7F => try buf.append(self.allocator, truncated),
476 else => try buf.append(self.allocator, '?'),
461477 },
462478 .windows1252 => {
463 try buf.append(truncated);
479 try buf.append(self.allocator, truncated);
464480 },
465481 }
466482 } else {
467483 if (windows1252.bestFitFromCodepoint(c)) |best_fit| {
468 try buf.append(best_fit);
484 try buf.append(self.allocator, best_fit);
469485 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid) {
470 try buf.append('?');
486 try buf.append(self.allocator, '?');
471487 } else {
472 try buf.appendSlice("??");
488 try buf.appendSlice(self.allocator, "??");
473489 }
474490 }
475491 },
476492 }
477493 }
478494
479 return buf.toOwnedSlice();
495 return buf.toOwnedSlice(self.allocator);
480496 }
481497
482498 pub fn writeResourceExternal(self: *Compiler, node: *Node.ResourceExternal, writer: *std.Io.Writer) !void {
......@@ -572,7 +588,7 @@ pub const Compiler = struct {
572588 switch (predefined_type) {
573589 .GROUP_ICON, .GROUP_CURSOR => {
574590 // Check for animated icon first
575 if (ani.isAnimatedIcon(file_reader.interface.adaptToOldInterface())) {
591 if (ani.isAnimatedIcon(&file_reader.interface)) {
576592 // Animated icons are just put into the resource unmodified,
577593 // and the resource type changes to ANIICON/ANICURSOR
578594
......@@ -584,7 +600,12 @@ pub const Compiler = struct {
584600 header.type_value.ordinal = @intFromEnum(new_predefined_type);
585601 header.memory_flags = MemoryFlags.defaults(new_predefined_type);
586602 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
589610 try header.write(writer, self.errContext(node.id));
590611 try file_reader.seekTo(0);
......@@ -595,7 +616,7 @@ pub const Compiler = struct {
595616 // isAnimatedIcon moved the file cursor so reset to the start
596617 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) {
599620 error.OutOfMemory => |e| return e,
600621 else => |e| {
601622 return self.iconReadError(
......@@ -861,7 +882,7 @@ pub const Compiler = struct {
861882 header.applyMemoryFlags(node.common_resource_attributes, self.source);
862883 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| {
865886 const filename_string_index = try self.diagnostics.putString(filename_utf8);
866887 return self.addErrorDetailsAndFail(.{
867888 .err = .bmp_read_error,
......@@ -969,13 +990,19 @@ pub const Compiler = struct {
969990 header.data_size = @intCast(file_size);
970991 try header.write(writer, self.errContext(node.id));
971992
972 var header_slurping_reader = headerSlurpingReader(148, file_reader.interface.adaptToOldInterface());
973 var adapter = header_slurping_reader.reader().adaptToNewApi(&.{});
974 try writeResourceData(writer, &adapter.new_interface, header.data_size);
993 // Slurp the first 148 bytes separately so we can store them in the FontDir
994 var font_dir_header_buf: [148]u8 = @splat(0);
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
9761003 try self.state.font_dir.add(self.arena, FontDir.Font{
9771004 .id = header.name_value.ordinal,
978 .header_bytes = header_slurping_reader.slurped_header,
1005 .header_bytes = font_dir_header_buf,
9791006 }, node.id);
9801007 return;
9811008 },
......@@ -1053,7 +1080,7 @@ pub const Compiler = struct {
10531080 }
10541081 }
10551082
1056 pub fn write(self: Data, writer: anytype) !void {
1083 pub fn write(self: Data, writer: *std.Io.Writer) !void {
10571084 switch (self) {
10581085 .number => |number| switch (number.is_long) {
10591086 false => try writer.writeInt(WORD, number.asWord(), .little),
......@@ -1225,36 +1252,30 @@ pub const Compiler = struct {
12251252 }
12261253 }
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 {
12291256 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
12301257 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
12351259 for (node.raw_data) |expression| {
12361260 const data = try self.evaluateDataExpression(expression);
12371261 defer data.deinit(self.allocator);
1238 data.write(data_writer) catch |err| switch (err) {
1239 error.WriteFailed => {
1240 return self.addErrorDetailsAndFail(.{
1241 .err = .resource_data_size_exceeds_max,
1242 .token = node.id,
1243 });
1244 },
1245 };
1262 try data.write(&data_buffer.writer);
12461263 }
12471264
1248 // This intCast can't fail because the limitedWriter above guarantees that
1249 // we will never write more than maxInt(u32) bytes.
1250 const data_len: u32 = @intCast(data_buffer.written().len);
1265 // TODO: Limit data_buffer in some way to error when writing more than u32 max bytes
1266 const data_len: u32 = std.math.cast(u32, data_buffer.written().len) orelse {
1267 return self.addErrorDetailsAndFail(.{
1268 .err = .resource_data_size_exceeds_max,
1269 .token = node.id,
1270 });
1271 };
12511272 try self.writeResourceHeader(writer, node.id, node.type, data_len, node.common_resource_attributes, self.state.language);
12521273
12531274 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
12541275 try writeResourceData(writer, &data_fbs, data_len);
12551276 }
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 {
12581279 var header = try self.resourceHeader(id_token, type_token, .{
12591280 .language = language,
12601281 .data_size = data_size,
......@@ -1270,7 +1291,7 @@ pub const Compiler = struct {
12701291 try data_reader.streamExact(writer, data_size);
12711292 }
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 {
12741295 try writeResourceDataNoPadding(writer, data_reader, data_size);
12751296 try writeDataPadding(writer, data_size);
12761297 }
......@@ -1303,27 +1324,19 @@ pub const Compiler = struct {
13031324 }
13041325 }
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 {
13071328 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
13081329 defer data_buffer.deinit();
13091330
1310 // The header's data length field is a u32 so limit the resource's data size so that
1311 // we know we can always specify the real size.
1312 const data_writer = &data_buffer.writer;
1331 try self.writeAcceleratorsData(node, &data_buffer.writer);
13131332
1314 self.writeAcceleratorsData(node, data_writer) catch |err| switch (err) {
1315 error.WriteFailed => {
1316 return self.addErrorDetailsAndFail(.{
1317 .err = .resource_data_size_exceeds_max,
1318 .token = node.id,
1319 });
1320 },
1321 else => |e| return e,
1333 // TODO: Limit data_buffer in some way to error when writing more than u32 max bytes
1334 const data_size: u32 = std.math.cast(u32, data_buffer.written().len) orelse {
1335 return self.addErrorDetailsAndFail(.{
1336 .err = .resource_data_size_exceeds_max,
1337 .token = node.id,
1338 });
13221339 };
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);
13271340 var header = try self.resourceHeader(node.id, node.type, .{
13281341 .data_size = data_size,
13291342 });
......@@ -1340,7 +1353,7 @@ pub const Compiler = struct {
13401353
13411354 /// Expects `data_writer` to be a LimitedWriter limited to u32, meaning all writes to
13421355 /// 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 {
13441357 for (node.accelerators, 0..) |accel_node, i| {
13451358 const accelerator: *Node.Accelerator = @alignCast(@fieldParentPtr("base", accel_node));
13461359 var modifiers = res.AcceleratorModifiers{};
......@@ -1401,12 +1414,9 @@ pub const Compiler = struct {
14011414 caption: ?Token = null,
14021415 };
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 {
14051418 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
14061419 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
14111421 const resource = ResourceType.fromString(.{
14121422 .slice = node.type.slice(self.source),
......@@ -1667,21 +1677,18 @@ pub const Compiler = struct {
16671677 optional_statement_values.style |= res.WS.CAPTION;
16681678 }
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(
16711683 node,
1672 data_writer,
1684 &data_buffer.writer,
16731685 resource,
16741686 &optional_statement_values,
16751687 x,
16761688 y,
16771689 width,
16781690 height,
1679 ) catch |err| switch (err) {
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 };
1691 );
16851692
16861693 var controls_by_id = std.AutoHashMap(u32, *const Node.ControlStatement).init(self.allocator);
16871694 // Number of controls are guaranteed by the parser to be within maxInt(u16).
......@@ -1691,27 +1698,26 @@ pub const Compiler = struct {
16911698 for (node.controls) |control_node| {
16921699 const control: *Node.ControlStatement = @alignCast(@fieldParentPtr("base", control_node));
16931700
1694 self.writeDialogControl(
1701 try self.writeDialogControl(
16951702 control,
1696 data_writer,
1703 &data_buffer.writer,
16971704 resource,
16981705 // We know the data_buffer len is limited to u32 max.
16991706 @intCast(data_buffer.written().len),
17001707 &controls_by_id,
1701 ) catch |err| switch (err) {
1702 error.WriteFailed => {
1703 try self.addErrorDetails(.{
1704 .err = .resource_data_size_exceeds_max,
1705 .token = node.id,
1706 });
1707 return self.addErrorDetailsAndFail(.{
1708 .err = .resource_data_size_exceeds_max,
1709 .type = .note,
1710 .token = control.type,
1711 });
1712 },
1713 else => |e| return e,
1714 };
1708 );
1709
1710 if (data_buffer.written().len > std.math.maxInt(u32)) {
1711 try self.addErrorDetails(.{
1712 .err = .resource_data_size_exceeds_max,
1713 .token = node.id,
1714 });
1715 return self.addErrorDetailsAndFail(.{
1716 .err = .resource_data_size_exceeds_max,
1717 .type = .note,
1718 .token = control.type,
1719 });
1720 }
17151721 }
17161722
17171723 // We know the data_buffer len is limited to u32 max.
......@@ -1733,7 +1739,7 @@ pub const Compiler = struct {
17331739 fn writeDialogHeaderAndStrings(
17341740 self: *Compiler,
17351741 node: *Node.Dialog,
1736 data_writer: anytype,
1742 data_writer: *std.Io.Writer,
17371743 resource: ResourceType,
17381744 optional_statement_values: *const DialogOptionalStatementValues,
17391745 x: Number,
......@@ -1793,7 +1799,7 @@ pub const Compiler = struct {
17931799 fn writeDialogControl(
17941800 self: *Compiler,
17951801 control: *Node.ControlStatement,
1796 data_writer: anytype,
1802 data_writer: *std.Io.Writer,
17971803 resource: ResourceType,
17981804 bytes_written_so_far: u32,
17991805 controls_by_id: *std.AutoHashMap(u32, *const Node.ControlStatement),
......@@ -1969,28 +1975,26 @@ pub const Compiler = struct {
19691975 try NameOrOrdinal.writeEmpty(data_writer);
19701976 }
19711977
1978 // The extra data byte length must be able to fit within a u16.
19721979 var extra_data_buf: std.Io.Writer.Allocating = .init(self.allocator);
19731980 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;
19761981 for (control.extra_data) |data_expression| {
19771982 const data = try self.evaluateDataExpression(data_expression);
19781983 defer data.deinit(self.allocator);
1979 data.write(extra_data_writer) catch |err| switch (err) {
1980 error.WriteFailed => {
1981 try self.addErrorDetails(.{
1982 .err = .control_extra_data_size_exceeds_max,
1983 .token = control.type,
1984 });
1985 return self.addErrorDetailsAndFail(.{
1986 .err = .control_extra_data_size_exceeds_max,
1987 .type = .note,
1988 .token = data_expression.getFirstToken(),
1989 .token_span_end = data_expression.getLastToken(),
1990 });
1991 },
1992 else => |e| return e,
1993 };
1984 try data.write(&extra_data_buf.writer);
1985
1986 if (extra_data_buf.written().len > std.math.maxInt(u16)) {
1987 try self.addErrorDetails(.{
1988 .err = .control_extra_data_size_exceeds_max,
1989 .token = control.type,
1990 });
1991 return self.addErrorDetailsAndFail(.{
1992 .err = .control_extra_data_size_exceeds_max,
1993 .type = .note,
1994 .token = data_expression.getFirstToken(),
1995 .token_span_end = data_expression.getLastToken(),
1996 });
1997 }
19941998 }
19951999 // We know the extra_data_buf size fits within a u16.
19962000 const extra_data_size: u16 = @intCast(extra_data_buf.written().len);
......@@ -1998,7 +2002,7 @@ pub const Compiler = struct {
19982002 try data_writer.writeAll(extra_data_buf.written());
19992003 }
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 {
20022006 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
20032007 defer data_buffer.deinit();
20042008 const data_writer = &data_buffer.writer;
......@@ -2051,7 +2055,7 @@ pub const Compiler = struct {
20512055 node: *Node.FontStatement,
20522056 };
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 {
20552059 const node = values.node;
20562060 const point_size = evaluateNumberExpression(node.point_size, self.source, self.input_code_pages);
20572061 try writer.writeInt(u16, point_size.asWord(), .little);
......@@ -2076,12 +2080,9 @@ pub const Compiler = struct {
20762080 try writer.writeAll(std.mem.sliceAsBytes(typeface[0 .. typeface.len + 1]));
20772081 }
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 {
20802084 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
20812085 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
20862087 const type_bytes = SourceBytes{
20872088 .slice = node.type.slice(self.source),
......@@ -2090,19 +2091,15 @@ pub const Compiler = struct {
20902091 const resource = ResourceType.fromString(type_bytes);
20912092 std.debug.assert(resource == .menu or resource == .menuex);
20922093
2093 self.writeMenuData(node, data_writer, resource) catch |err| switch (err) {
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 };
2094 try self.writeMenuData(node, &data_buffer.writer, resource);
21022095
2103 // This intCast can't fail because the limitedWriter above guarantees that
2104 // we will never write more than maxInt(u32) bytes.
2105 const data_size: u32 = @intCast(data_buffer.written().len);
2096 // TODO: Limit data_buffer in some way to error when writing more than u32 max bytes
2097 const data_size: u32 = std.math.cast(u32, data_buffer.written().len) orelse {
2098 return self.addErrorDetailsAndFail(.{
2099 .err = .resource_data_size_exceeds_max,
2100 .token = node.id,
2101 });
2102 };
21062103 var header = try self.resourceHeader(node.id, node.type, .{
21072104 .data_size = data_size,
21082105 });
......@@ -2256,11 +2253,10 @@ pub const Compiler = struct {
22562253 }
22572254 }
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
22602258 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
22612259 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.
22642260 const data_writer = &data_buffer.writer;
22652261
22662262 try data_writer.writeInt(u16, 0, .little); // placeholder size
......@@ -2345,25 +2341,29 @@ pub const Compiler = struct {
23452341 try fixed_file_info.write(data_writer);
23462342
23472343 for (node.block_statements) |statement| {
2348 self.writeVersionNode(statement, data_writer, &data_buffer) catch |err| switch (err) {
2349 error.WriteFailed => {
2350 try self.addErrorDetails(.{
2351 .err = .version_node_size_exceeds_max,
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 });
2344 var overflow = false;
2345 self.writeVersionNode(statement, data_writer) catch |err| switch (err) {
2346 error.NoSpaceLeft => {
2347 overflow = true;
23602348 },
23612349 else => |e| return e,
23622350 };
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 }
23632363 }
23642364
2365 // We know that data_buffer.items.len is within the limits of a u16, since we
2366 // limited the writer to maxInt(u16)
2365 // We know that data_buffer len is within the limits of a u16, since we check in the block
2366 // statements loop above which is the only place it can overflow.
23672367 const data_size: u16 = @intCast(data_buffer.written().len);
23682368 // And now that we know the full size of this node (including its children), set its size
23692369 std.mem.writeInt(u16, data_buffer.written()[0..2], data_size, .little);
......@@ -2381,18 +2381,17 @@ pub const Compiler = struct {
23812381 try writeResourceData(writer, &data_fbs, data_size);
23822382 }
23832383
2384 /// Expects writer to be a LimitedWriter limited to u16, meaning all writes to
2385 /// the writer within this function could return error.NoSpaceLeft, and that buf.items.len
2386 /// will never be able to exceed maxInt(u16).
2387 pub fn writeVersionNode(self: *Compiler, node: *Node, writer: *std.Io.Writer, buf: *std.Io.Writer.Allocating) !void {
2384 /// Assumes that writer is Writer.Allocating (specifically, that buffered() gets the entire data)
2385 /// TODO: This function could be nicer if writer was guaranteed to fail if it wrote more than u16 max bytes
2386 pub fn writeVersionNode(self: *Compiler, node: *Node, writer: *std.Io.Writer) !void {
23882387 // 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;
23922391 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;
23942393 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;
23962395 // Data type is string unless the node contains values that are numbers.
23972396 try writer.writeInt(u16, res.VersionNode.type_string, .little);
23982397
......@@ -2422,7 +2421,7 @@ pub const Compiler = struct {
24222421 // during parsing, so we can just do the correct thing here.
24232422 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
24272426 for (block_or_value.values, 0..) |value_value_node_uncasted, i| {
24282427 const value_value_node = value_value_node_uncasted.cast(.block_value_value).?;
......@@ -2461,26 +2460,26 @@ pub const Compiler = struct {
24612460 }
24622461 }
24632462 }
2464 var data_size_slice = buf.written()[data_size_offset..];
2463 var data_size_slice = writer.buffered()[data_size_offset..];
24652464 std.mem.writeInt(u16, data_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(values_size)), .little);
24662465
24672466 if (has_number_value) {
2468 const data_type_slice = buf.written()[data_type_offset..];
2467 const data_type_slice = writer.buffered()[data_type_offset..];
24692468 std.mem.writeInt(u16, data_type_slice[0..@sizeOf(u16)], res.VersionNode.type_binary, .little);
24702469 }
24712470
24722471 if (node_type == .block) {
24732472 const block = block_or_value;
24742473 for (block.children) |child| {
2475 try self.writeVersionNode(child, writer, buf);
2474 try self.writeVersionNode(child, writer);
24762475 }
24772476 }
24782477 },
24792478 else => unreachable,
24802479 }
24812480
2482 const node_and_children_size = buf.written().len - node_and_children_size_offset;
2483 const node_and_children_size_slice = buf.written()[node_and_children_size_offset..];
2481 const node_and_children_size = writer.buffered().len - node_and_children_size_offset;
2482 const node_and_children_size_slice = writer.buffered()[node_and_children_size_offset..];
24842483 std.mem.writeInt(u16, node_and_children_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(node_and_children_size)), .little);
24852484 }
24862485
......@@ -2673,11 +2672,11 @@ pub const Compiler = struct {
26732672 return .{ .bytes = header_size, .padding_after_name = padding_after_name };
26742673 }
26752674
2676 pub fn writeAssertNoOverflow(self: ResourceHeader, writer: anytype) !void {
2675 pub fn writeAssertNoOverflow(self: ResourceHeader, writer: *std.Io.Writer) !void {
26772676 return self.writeSizeInfo(writer, self.calcSize() catch unreachable);
26782677 }
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 {
26812680 const size_info = self.calcSize() catch {
26822681 try err_ctx.diagnostics.append(.{
26832682 .err = .resource_data_size_exceeds_max,
......@@ -2815,7 +2814,7 @@ pub const Compiler = struct {
28152814 return null;
28162815 }
28172816
2818 pub fn writeEmptyResource(writer: anytype) !void {
2817 pub fn writeEmptyResource(writer: *std.Io.Writer) !void {
28192818 const header = ResourceHeader{
28202819 .name_value = .{ .ordinal = 0 },
28212820 .type_value = .{ .ordinal = 0 },
......@@ -2932,39 +2931,8 @@ pub const SearchDir = struct {
29322931 }
29332932};
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
29662934pub const FontDir = struct {
2967 fonts: std.ArrayListUnmanaged(Font) = .empty,
2935 fonts: std.ArrayList(Font) = .empty,
29682936 /// To keep track of which ids are set and where they were set from
29692937 ids: std.AutoHashMapUnmanaged(u16, Token) = .empty,
29702938
......@@ -2982,7 +2950,7 @@ pub const FontDir = struct {
29822950 try self.fonts.append(allocator, font);
29832951 }
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 {
29862954 if (self.fonts.items.len == 0) return;
29872955
29882956 // We know the number of fonts is limited to maxInt(u16) because fonts
......@@ -3106,7 +3074,7 @@ pub const StringTable = struct {
31063074 blocks: std.AutoArrayHashMapUnmanaged(u16, Block) = .empty,
31073075
31083076 pub const Block = struct {
3109 strings: std.ArrayListUnmanaged(Token) = .empty,
3077 strings: std.ArrayList(Token) = .empty,
31103078 set_indexes: std.bit_set.IntegerBitSet(16) = .{ .mask = 0 },
31113079 memory_flags: MemoryFlags = MemoryFlags.defaults(res.RT.STRING),
31123080 characteristics: u32,
......@@ -3187,7 +3155,7 @@ pub const StringTable = struct {
31873155 try std.testing.expectEqualStrings("a", trimToDoubleNUL(u8, "a\x00\x00b"));
31883156 }
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 {
31913159 var data_buffer: std.Io.Writer.Allocating = .init(compiler.allocator);
31923160 defer data_buffer.deinit();
31933161 const data_writer = &data_buffer.writer;
lib/compiler/resinator/cvtres.zig+12-12
......@@ -43,7 +43,7 @@ pub const Resource = struct {
4343};
4444
4545pub const ParsedResources = struct {
46 list: std.ArrayListUnmanaged(Resource) = .empty,
46 list: std.ArrayList(Resource) = .empty,
4747 allocator: Allocator,
4848
4949 pub fn init(allocator: Allocator) ParsedResources {
......@@ -157,7 +157,7 @@ pub fn parseNameOrOrdinal(allocator: Allocator, reader: *std.Io.Reader) !NameOrO
157157 const ordinal_value = try reader.takeInt(u16, .little);
158158 return .{ .ordinal = ordinal_value };
159159 }
160 var name_buf = try std.ArrayListUnmanaged(u16).initCapacity(allocator, 16);
160 var name_buf = try std.ArrayList(u16).initCapacity(allocator, 16);
161161 errdefer name_buf.deinit(allocator);
162162 var code_unit = first_code_unit;
163163 while (code_unit != 0) {
......@@ -373,7 +373,7 @@ pub fn writeCoff(allocator: Allocator, writer: *std.Io.Writer, resources: []cons
373373 try writer.writeAll(string_table.bytes.items);
374374}
375375
376fn writeSymbol(writer: anytype, symbol: std.coff.Symbol) !void {
376fn writeSymbol(writer: *std.Io.Writer, symbol: std.coff.Symbol) !void {
377377 try writer.writeAll(&symbol.name);
378378 try writer.writeInt(u32, symbol.value, .little);
379379 try writer.writeInt(u16, @intFromEnum(symbol.section_number), .little);
......@@ -383,7 +383,7 @@ fn writeSymbol(writer: anytype, symbol: std.coff.Symbol) !void {
383383 try writer.writeInt(u8, symbol.number_of_aux_symbols, .little);
384384}
385385
386fn writeSectionDefinition(writer: anytype, def: std.coff.SectionDefinition) !void {
386fn writeSectionDefinition(writer: *std.Io.Writer, def: std.coff.SectionDefinition) !void {
387387 try writer.writeInt(u32, def.length, .little);
388388 try writer.writeInt(u16, def.number_of_relocations, .little);
389389 try writer.writeInt(u16, def.number_of_linenumbers, .little);
......@@ -417,7 +417,7 @@ pub const ResourceDirectoryEntry = extern struct {
417417 to_subdirectory: bool,
418418 },
419419
420 pub fn writeCoff(self: ResourceDirectoryEntry, writer: anytype) !void {
420 pub fn writeCoff(self: ResourceDirectoryEntry, writer: *std.Io.Writer) !void {
421421 try writer.writeInt(u32, @bitCast(self.entry), .little);
422422 try writer.writeInt(u32, @bitCast(self.offset), .little);
423423 }
......@@ -435,7 +435,7 @@ const ResourceTree = struct {
435435 type_to_name_map: std.ArrayHashMapUnmanaged(NameOrOrdinal, NameToLanguageMap, NameOrOrdinalHashContext, true),
436436 rsrc_string_table: std.ArrayHashMapUnmanaged(NameOrOrdinal, void, NameOrOrdinalHashContext, true),
437437 deduplicated_data: std.StringArrayHashMapUnmanaged(u32),
438 data_offsets: std.ArrayListUnmanaged(u32),
438 data_offsets: std.ArrayList(u32),
439439 rsrc02_len: u32,
440440 coff_options: CoffOptions,
441441 allocator: Allocator,
......@@ -675,13 +675,13 @@ const ResourceTree = struct {
675675 return &.{};
676676 }
677677
678 var level2_list: std.ArrayListUnmanaged(*const NameToLanguageMap) = .empty;
678 var level2_list: std.ArrayList(*const NameToLanguageMap) = .empty;
679679 defer level2_list.deinit(allocator);
680680
681 var level3_list: std.ArrayListUnmanaged(*const LanguageToResourceMap) = .empty;
681 var level3_list: std.ArrayList(*const LanguageToResourceMap) = .empty;
682682 defer level3_list.deinit(allocator);
683683
684 var resources_list: std.ArrayListUnmanaged(*const RelocatableResource) = .empty;
684 var resources_list: std.ArrayList(*const RelocatableResource) = .empty;
685685 defer resources_list.deinit(allocator);
686686
687687 var relocations = Relocations.init(allocator);
......@@ -896,7 +896,7 @@ const ResourceTree = struct {
896896 return symbols;
897897 }
898898
899 fn writeRelocation(writer: anytype, relocation: std.coff.Relocation) !void {
899 fn writeRelocation(writer: *std.Io.Writer, relocation: std.coff.Relocation) !void {
900900 try writer.writeInt(u32, relocation.virtual_address, .little);
901901 try writer.writeInt(u32, relocation.symbol_table_index, .little);
902902 try writer.writeInt(u16, relocation.type, .little);
......@@ -928,7 +928,7 @@ const Relocation = struct {
928928
929929const Relocations = struct {
930930 allocator: Allocator,
931 list: std.ArrayListUnmanaged(Relocation) = .empty,
931 list: std.ArrayList(Relocation) = .empty,
932932 cur_symbol_index: u32 = 5,
933933
934934 pub fn init(allocator: Allocator) Relocations {
......@@ -952,7 +952,7 @@ const Relocations = struct {
952952/// Does not do deduplication (only because there's no chance of duplicate strings in this
953953/// instance).
954954const StringTable = struct {
955 bytes: std.ArrayListUnmanaged(u8) = .empty,
955 bytes: std.ArrayList(u8) = .empty,
956956
957957 pub fn deinit(self: *StringTable, allocator: Allocator) void {
958958 self.bytes.deinit(allocator);
lib/compiler/resinator/errors.zig+25-26
......@@ -15,10 +15,10 @@ const builtin = @import("builtin");
1515const native_endian = builtin.cpu.arch.endian();
1616
1717pub const Diagnostics = struct {
18 errors: std.ArrayListUnmanaged(ErrorDetails) = .empty,
18 errors: std.ArrayList(ErrorDetails) = .empty,
1919 /// Append-only, cannot handle removing strings.
2020 /// Expects to own all strings within the list.
21 strings: std.ArrayListUnmanaged([]const u8) = .empty,
21 strings: std.ArrayList([]const u8) = .empty,
2222 allocator: std.mem.Allocator,
2323
2424 pub fn init(allocator: std.mem.Allocator) Diagnostics {
......@@ -256,7 +256,7 @@ pub const ErrorDetails = struct {
256256 .{ "literal", "unquoted literal" },
257257 });
258258
259 pub fn writeCommaSeparated(self: ExpectedTypes, writer: anytype) !void {
259 pub fn writeCommaSeparated(self: ExpectedTypes, writer: *std.Io.Writer) !void {
260260 const struct_info = @typeInfo(ExpectedTypes).@"struct";
261261 const num_real_fields = struct_info.fields.len - 1;
262262 const num_padding_bits = @bitSizeOf(ExpectedTypes) - num_real_fields;
......@@ -441,7 +441,7 @@ pub const ErrorDetails = struct {
441441 } };
442442 }
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 {
445445 switch (self.err) {
446446 .unfinished_string_literal => {
447447 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,
987987 if (corresponding_span != null and corresponding_file != null) {
988988 var worth_printing_lines: bool = true;
989989 var initial_lines_err: ?anyerror = null;
990 var file_reader_buf: [max_source_line_bytes * 2]u8 = undefined;
990991 var corresponding_lines: ?CorrespondingLines = CorrespondingLines.init(
991992 cwd,
992993 err_details,
993994 source_line_for_display.line,
994995 corresponding_span.?,
995996 corresponding_file.?,
997 &file_reader_buf,
996998 ) catch |err| switch (err) {
997999 error.NotWorthPrintingLines => blk: {
9981000 worth_printing_lines = false;
......@@ -1078,10 +1080,17 @@ const CorrespondingLines = struct {
10781080 at_eof: bool = false,
10791081 span: SourceMappings.CorrespondingSpan,
10801082 file: std.fs.File,
1081 buffered_reader: std.fs.File.Reader,
1083 file_reader: std.fs.File.Reader,
10821084 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 {
10851094 // We don't do line comparison for this error, so don't print the note if the line
10861095 // number is different
10871096 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 {
10961105 var corresponding_lines = CorrespondingLines{
10971106 .span = corresponding_span,
10981107 .file = try utils.openFileNotDir(cwd, corresponding_file, .{}),
1099 .buffered_reader = undefined,
11001108 .code_page = err_details.code_page,
1109 .file_reader = undefined,
11011110 };
1102 corresponding_lines.buffered_reader = corresponding_lines.file.reader(&.{});
1111 corresponding_lines.file_reader = corresponding_lines.file.reader(file_reader_buf);
11031112 errdefer corresponding_lines.deinit();
11041113
1105 var writer: std.Io.Writer = .fixed(&corresponding_lines.line_buf);
1106
11071114 try corresponding_lines.writeLineFromStreamVerbatim(
1108 &writer,
1109 corresponding_lines.buffered_reader.interface.adaptToOldInterface(),
1115 &corresponding_lines.file_reader.interface,
11101116 corresponding_span.start_line,
11111117 );
11121118
......@@ -1144,11 +1150,8 @@ const CorrespondingLines = struct {
11441150 self.line_len = 0;
11451151 self.visual_line_len = 0;
11461152
1147 var writer: std.Io.Writer = .fixed(&self.line_buf);
1148
11491153 try self.writeLineFromStreamVerbatim(
1150 &writer,
1151 self.buffered_reader.interface.adaptToOldInterface(),
1154 &self.file_reader.interface,
11521155 self.line_num,
11531156 );
11541157
......@@ -1162,7 +1165,7 @@ const CorrespondingLines = struct {
11621165 return visual_line;
11631166 }
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 {
11661169 while (try readByteOrEof(input)) |byte| {
11671170 switch (byte) {
11681171 '\n', '\r' => {
......@@ -1182,13 +1185,9 @@ const CorrespondingLines = struct {
11821185 }
11831186 },
11841187 else => {
1185 if (self.line_num == line_num) {
1186 if (writer.writeByte(byte)) {
1187 self.line_len += 1;
1188 } else |err| switch (err) {
1189 error.WriteFailed => {},
1190 else => |e| return e,
1191 }
1188 if (self.line_num == line_num and self.line_len < self.line_buf.len) {
1189 self.line_buf[self.line_len] = byte;
1190 self.line_len += 1;
11921191 }
11931192 },
11941193 }
......@@ -1199,8 +1198,8 @@ const CorrespondingLines = struct {
11991198 self.line_num += 1;
12001199 }
12011200
1202 fn readByteOrEof(reader: anytype) !?u8 {
1203 return reader.readByte() catch |err| switch (err) {
1201 fn readByteOrEof(reader: *std.Io.Reader) !?u8 {
1202 return reader.takeByte() catch |err| switch (err) {
12041203 error.EndOfStream => return null,
12051204 else => |e| return e,
12061205 };
lib/compiler/resinator/ico.zig+43-57
......@@ -8,80 +8,66 @@ const std = @import("std");
88const builtin = @import("builtin");
99const native_endian = builtin.cpu.arch.endian();
1010
11pub const ReadError = std.mem.Allocator.Error || error{ InvalidHeader, InvalidImageType, ImpossibleDataSize, UnexpectedEOF, ReadError };
12
13pub fn read(allocator: std.mem.Allocator, reader: anytype, max_size: u64) ReadError!IconDir {
14 // Some Reader implementations have an empty ReadError error set which would
15 // cause 'unreachable else' if we tried to use an else in the switch, so we
16 // need to detect this case and not try to translate to ReadError
17 const anyerror_reader_errorset = @TypeOf(reader).Error == anyerror;
18 const empty_reader_errorset = @typeInfo(@TypeOf(reader).Error).error_set == null or @typeInfo(@TypeOf(reader).Error).error_set.?.len == 0;
19 if (empty_reader_errorset and !anyerror_reader_errorset) {
20 return readAnyError(allocator, reader, max_size) catch |err| switch (err) {
21 error.EndOfStream => error.UnexpectedEOF,
22 else => |e| return e,
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 }
11pub const ReadError = std.mem.Allocator.Error || error{ InvalidHeader, InvalidImageType, ImpossibleDataSize, UnexpectedEOF, ReadFailed };
12
13pub fn read(allocator: std.mem.Allocator, reader: *std.Io.Reader, max_size: u64) ReadError!IconDir {
14 return readInner(allocator, reader, max_size) catch |err| switch (err) {
15 error.OutOfMemory,
16 error.InvalidHeader,
17 error.InvalidImageType,
18 error.ImpossibleDataSize,
19 error.ReadFailed,
20 => |e| return e,
21 error.EndOfStream => error.UnexpectedEOF,
22 };
3723}
3824
3925// TODO: This seems like a somewhat strange pattern, could be a better way
4026// to do this. Maybe it makes more sense to handle the translation
4127// at the call site instead of having a helper function here.
42pub fn readAnyError(allocator: std.mem.Allocator, reader: anytype, max_size: u64) !IconDir {
43 const reserved = try reader.readInt(u16, .little);
28fn readInner(allocator: std.mem.Allocator, reader: *std.Io.Reader, max_size: u64) !IconDir {
29 const reserved = try reader.takeInt(u16, .little);
4430 if (reserved != 0) {
4531 return error.InvalidHeader;
4632 }
4733
48 const image_type = reader.readEnum(ImageType, .little) catch |err| switch (err) {
49 error.InvalidValue => return error.InvalidImageType,
34 const image_type = reader.takeEnum(ImageType, .little) catch |err| switch (err) {
35 error.InvalidEnumTag => return error.InvalidImageType,
5036 else => |e| return e,
5137 };
5238
53 const num_images = try reader.readInt(u16, .little);
39 const num_images = try reader.takeInt(u16, .little);
5440
5541 // To avoid over-allocation in the case of a file that says it has way more
5642 // entries than it actually does, we use an ArrayList with a conservatively
5743 // limited initial capacity instead of allocating the entire slice at once.
5844 const initial_capacity = @min(num_images, 8);
59 var entries = try std.array_list.Managed(Entry).initCapacity(allocator, initial_capacity);
60 errdefer entries.deinit();
45 var entries = try std.ArrayList(Entry).initCapacity(allocator, initial_capacity);
46 errdefer entries.deinit(allocator);
6147
6248 var i: usize = 0;
6349 while (i < num_images) : (i += 1) {
6450 var entry: Entry = undefined;
65 entry.width = try reader.readByte();
66 entry.height = try reader.readByte();
67 entry.num_colors = try reader.readByte();
68 entry.reserved = try reader.readByte();
51 entry.width = try reader.takeByte();
52 entry.height = try reader.takeByte();
53 entry.num_colors = try reader.takeByte();
54 entry.reserved = try reader.takeByte();
6955 switch (image_type) {
7056 .icon => {
7157 entry.type_specific_data = .{ .icon = .{
72 .color_planes = try reader.readInt(u16, .little),
73 .bits_per_pixel = try reader.readInt(u16, .little),
58 .color_planes = try reader.takeInt(u16, .little),
59 .bits_per_pixel = try reader.takeInt(u16, .little),
7460 } };
7561 },
7662 .cursor => {
7763 entry.type_specific_data = .{ .cursor = .{
78 .hotspot_x = try reader.readInt(u16, .little),
79 .hotspot_y = try reader.readInt(u16, .little),
64 .hotspot_x = try reader.takeInt(u16, .little),
65 .hotspot_y = try reader.takeInt(u16, .little),
8066 } };
8167 },
8268 }
83 entry.data_size_in_bytes = try reader.readInt(u32, .little);
84 entry.data_offset_from_start_of_file = try reader.readInt(u32, .little);
69 entry.data_size_in_bytes = try reader.takeInt(u32, .little);
70 entry.data_offset_from_start_of_file = try reader.takeInt(u32, .little);
8571 // Validate that the offset/data size is feasible
8672 if (@as(u64, entry.data_offset_from_start_of_file) + entry.data_size_in_bytes > max_size) {
8773 return error.ImpossibleDataSize;
......@@ -101,12 +87,12 @@ pub fn readAnyError(allocator: std.mem.Allocator, reader: anytype, max_size: u64
10187 if (entry.data_size_in_bytes < 16) {
10288 return error.ImpossibleDataSize;
10389 }
104 try entries.append(entry);
90 try entries.append(allocator, entry);
10591 }
10692
10793 return .{
10894 .image_type = image_type,
109 .entries = try entries.toOwnedSlice(),
95 .entries = try entries.toOwnedSlice(allocator),
11096 .allocator = allocator,
11197 };
11298}
......@@ -135,7 +121,7 @@ pub const IconDir = struct {
135121 return @intCast(IconDir.res_header_byte_len + self.entries.len * Entry.res_byte_len);
136122 }
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 {
139125 try writer.writeInt(u16, 0, .little);
140126 try writer.writeInt(u16, @intFromEnum(self.image_type), .little);
141127 // We know that entries.len must fit into a u16
......@@ -173,7 +159,7 @@ pub const Entry = struct {
173159
174160 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 {
177163 switch (self.type_specific_data) {
178164 .icon => |icon_data| {
179165 try writer.writeInt(u8, @as(u8, @truncate(self.width)), .little);
......@@ -198,8 +184,8 @@ pub const Entry = struct {
198184
199185test "icon" {
200186 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);
202 const icon = try read(std.testing.allocator, fbs.reader(), data.len);
187 var fbs: std.Io.Reader = .fixed(data);
188 const icon = try read(std.testing.allocator, &fbs, data.len);
203189 defer icon.deinit();
204190
205191 try std.testing.expectEqual(ImageType.icon, icon.image_type);
......@@ -211,26 +197,26 @@ test "icon too many images" {
211197 // it's not possible to hit EOF when looking for more RESDIR structures, since they are
212198 // themselves 16 bytes long, so we'll always hit ImpossibleDataSize instead.
213199 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);
215 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));
200 var fbs: std.Io.Reader = .fixed(data);
201 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
216202}
217203
218204test "icon data size past EOF" {
219205 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);
221 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));
206 var fbs: std.Io.Reader = .fixed(data);
207 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
222208}
223209
224210test "icon data offset past EOF" {
225211 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);
227 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));
212 var fbs: std.Io.Reader = .fixed(data);
213 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
228214}
229215
230216test "icon data size too small" {
231217 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);
233 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));
218 var fbs: std.Io.Reader = .fixed(data);
219 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
234220}
235221
236222pub const ImageFormat = enum(u2) {
lib/compiler/resinator/lang.zig+6-5
......@@ -119,6 +119,7 @@ test tagToId {
119119}
120120
121121test "exhaustive tagToId" {
122 @setEvalBranchQuota(2000);
122123 inline for (@typeInfo(LanguageId).@"enum".fields) |field| {
123124 const id = tagToId(field.name) catch |err| {
124125 std.debug.print("tag: {s}\n", .{field.name});
......@@ -131,8 +132,8 @@ test "exhaustive tagToId" {
131132 }
132133 var buf: [32]u8 = undefined;
133134 inline for (valid_alternate_sorts) |parsed_sort| {
134 var fbs = std.io.fixedBufferStream(&buf);
135 const writer = fbs.writer();
135 var fbs: std.Io.Writer = .fixed(&buf);
136 const writer = &fbs;
136137 writer.writeAll(parsed_sort.language_code) catch unreachable;
137138 writer.writeAll("-") catch unreachable;
138139 writer.writeAll(parsed_sort.country_code.?) catch unreachable;
......@@ -146,12 +147,12 @@ test "exhaustive tagToId" {
146147 break :field name_buf;
147148 };
148149 const expected = @field(LanguageId, &expected_field_name);
149 const id = tagToId(fbs.getWritten()) catch |err| {
150 std.debug.print("tag: {s}\n", .{fbs.getWritten()});
150 const id = tagToId(fbs.buffered()) catch |err| {
151 std.debug.print("tag: {s}\n", .{fbs.buffered()});
151152 return err;
152153 };
153154 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 });
155156 return error.TestExpectedEqual;
156157 });
157158 }
lib/compiler/resinator/literals.zig+22-22
......@@ -469,8 +469,8 @@ pub fn parseQuotedString(
469469 const T = if (literal_type == .ascii) u8 else u16;
470470 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);
473 errdefer buf.deinit();
472 var buf = try std.ArrayList(T).initCapacity(allocator, bytes.slice.len);
473 errdefer buf.deinit(allocator);
474474
475475 var iterative_parser = IterativeStringParser.init(bytes, options);
476476
......@@ -480,13 +480,13 @@ pub fn parseQuotedString(
480480 .ascii => switch (options.output_code_page) {
481481 .windows1252 => {
482482 if (parsed.from_escaped_integer) {
483 try buf.append(@truncate(c));
483 try buf.append(allocator, @truncate(c));
484484 } else if (windows1252.bestFitFromCodepoint(c)) |best_fit| {
485 try buf.append(best_fit);
485 try buf.append(allocator, best_fit);
486486 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid) {
487 try buf.append('?');
487 try buf.append(allocator, '?');
488488 } else {
489 try buf.appendSlice("??");
489 try buf.appendSlice(allocator, "??");
490490 }
491491 },
492492 .utf8 => {
......@@ -500,35 +500,35 @@ pub fn parseQuotedString(
500500 }
501501 var utf8_buf: [4]u8 = undefined;
502502 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]);
504504 },
505505 },
506506 .wide => {
507507 // Parsing any string type as a wide string is handled separately, see parseQuotedStringAsWideString
508508 std.debug.assert(iterative_parser.declared_string_type == .wide);
509509 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)));
511511 } else if (c == code_pages.Codepoint.invalid) {
512 try buf.append(std.mem.nativeToLittle(u16, '�'));
512 try buf.append(allocator, std.mem.nativeToLittle(u16, '�'));
513513 } else if (c < 0x10000) {
514514 const short: u16 = @intCast(c);
515 try buf.append(std.mem.nativeToLittle(u16, short));
515 try buf.append(allocator, std.mem.nativeToLittle(u16, short));
516516 } else {
517517 if (!parsed.escaped_surrogate_pair) {
518518 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));
520520 }
521521 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));
523523 }
524524 },
525525 }
526526 }
527527
528528 if (literal_type == .wide) {
529 return buf.toOwnedSliceSentinel(0);
529 return buf.toOwnedSliceSentinel(allocator, 0);
530530 } else {
531 return buf.toOwnedSlice();
531 return buf.toOwnedSlice(allocator);
532532 }
533533}
534534
......@@ -564,8 +564,8 @@ pub fn parseQuotedStringAsWideString(allocator: std.mem.Allocator, bytes: Source
564564 // Note: We're only handling the case of parsing an ASCII string into a wide string from here on out.
565565 // 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);
568 errdefer buf.deinit();
567 var buf = try std.ArrayList(u16).initCapacity(allocator, bytes.slice.len);
568 errdefer buf.deinit(allocator);
569569
570570 var iterative_parser = IterativeStringParser.init(bytes, options);
571571
......@@ -578,23 +578,23 @@ pub fn parseQuotedStringAsWideString(allocator: std.mem.Allocator, bytes: Source
578578 .windows1252 => windows1252.toCodepoint(byte_to_interpret),
579579 .utf8 => if (byte_to_interpret > 0x7F) '�' else byte_to_interpret,
580580 };
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));
582582 } else if (c == code_pages.Codepoint.invalid) {
583 try buf.append(std.mem.nativeToLittle(u16, '�'));
583 try buf.append(allocator, std.mem.nativeToLittle(u16, '�'));
584584 } else if (c < 0x10000) {
585585 const short: u16 = @intCast(c);
586 try buf.append(std.mem.nativeToLittle(u16, short));
586 try buf.append(allocator, std.mem.nativeToLittle(u16, short));
587587 } else {
588588 if (!parsed.escaped_surrogate_pair) {
589589 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));
591591 }
592592 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));
594594 }
595595 }
596596
597 return buf.toOwnedSliceSentinel(0);
597 return buf.toOwnedSliceSentinel(allocator, 0);
598598}
599599
600600test "parse quoted ascii string" {
lib/compiler/resinator/main.zig+23-27
......@@ -3,6 +3,7 @@ const builtin = @import("builtin");
33const removeComments = @import("comments.zig").removeComments;
44const parseAndRemoveLineCommands = @import("source_mapping.zig").parseAndRemoveLineCommands;
55const compile = @import("compile.zig").compile;
6const Dependencies = @import("compile.zig").Dependencies;
67const Diagnostics = @import("errors.zig").Diagnostics;
78const cli = @import("cli.zig");
89const preprocess = @import("preprocess.zig");
......@@ -13,8 +14,6 @@ const hasDisjointCodePage = @import("disjoint_code_page.zig").hasDisjointCodePag
1314const fmtResourceType = @import("res.zig").NameOrOrdinal.fmtResourceType;
1415const aro = @import("aro");
1516
16var stdout_buffer: [1024]u8 = undefined;
17
1817pub fn main() !void {
1918 var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
2019 defer std.debug.assert(gpa.deinit() == .ok);
......@@ -43,11 +42,13 @@ pub fn main() !void {
4342 cli_args = args[3..];
4443 }
4544
45 var stdout_buffer: [1024]u8 = undefined;
4646 var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
47 const stdout = &stdout_writer.interface;
4748 var error_handler: ErrorHandler = switch (zig_integration) {
4849 true => .{
4950 .server = .{
50 .out = &stdout_writer.interface,
51 .out = stdout,
5152 .in = undefined, // won't be receiving messages
5253 },
5354 },
......@@ -83,8 +84,8 @@ pub fn main() !void {
8384 defer options.deinit();
8485
8586 if (options.print_help_and_exit) {
86 try cli.writeUsage(&stdout_writer.interface, "zig rc");
87 try stdout_writer.interface.flush();
87 try cli.writeUsage(stdout, "zig rc");
88 try stdout.flush();
8889 return;
8990 }
9091
......@@ -92,19 +93,14 @@ pub fn main() !void {
9293 options.verbose = false;
9394
9495 if (options.verbose) {
95 try options.dumpVerbose(&stdout_writer.interface);
96 try stdout_writer.interface.writeByte('\n');
97 try stdout_writer.interface.flush();
96 try options.dumpVerbose(stdout);
97 try stdout.writeByte('\n');
98 try stdout.flush();
9899 }
99100
100 var dependencies_list = std.array_list.Managed([]const u8).init(allocator);
101 defer {
102 for (dependencies_list.items) |item| {
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;
101 var dependencies = Dependencies.init(allocator);
102 defer dependencies.deinit();
103 const maybe_dependencies: ?*Dependencies = if (options.depfile_path != null) &dependencies else null;
108104
109105 var include_paths = LazyIncludePaths{
110106 .arena = arena,
......@@ -127,27 +123,27 @@ pub fn main() !void {
127123 var comp = aro.Compilation.init(aro_arena, std.fs.cwd());
128124 defer comp.deinit();
129125
130 var argv = std.array_list.Managed([]const u8).init(comp.gpa);
131 defer argv.deinit();
126 var argv: std.ArrayList([]const u8) = .empty;
127 defer argv.deinit(aro_arena);
132128
133 try argv.append("arocc"); // dummy command name
129 try argv.append(aro_arena, "arocc"); // dummy command name
134130 const resolved_include_paths = try include_paths.get(&error_handler);
135131 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) {
137133 .stdio => "-",
138134 .filename => |filename| filename,
139135 });
140136
141137 if (options.verbose) {
142 try stdout_writer.interface.writeAll("Preprocessor: arocc (built-in)\n");
138 try stdout.writeAll("Preprocessor: arocc (built-in)\n");
143139 for (argv.items[0 .. argv.items.len - 1]) |arg| {
144 try stdout_writer.interface.print("{s} ", .{arg});
140 try stdout.print("{s} ", .{arg});
145141 }
146 try stdout_writer.interface.print("{s}\n\n", .{argv.items[argv.items.len - 1]});
147 try stdout_writer.interface.flush();
142 try stdout.print("{s}\n\n", .{argv.items[argv.items.len - 1]});
143 try stdout.flush();
148144 }
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) {
151147 error.GeneratedSourceError => {
152148 try error_handler.emitAroDiagnostics(allocator, "failed during preprocessor setup (this is always a bug):", &comp);
153149 std.process.exit(1);
......@@ -258,7 +254,7 @@ pub fn main() !void {
258254 .cwd = std.fs.cwd(),
259255 .diagnostics = &diagnostics,
260256 .source_mappings = &mapping_results.mappings,
261 .dependencies_list = maybe_dependencies_list,
257 .dependencies = maybe_dependencies,
262258 .ignore_include_env_var = options.ignore_include_env_var,
263259 .extra_include_paths = options.extra_include_paths.items,
264260 .system_include_paths = try include_paths.get(&error_handler),
......@@ -305,7 +301,7 @@ pub fn main() !void {
305301 };
306302
307303 try write_stream.beginArray();
308 for (dependencies_list.items) |dep_path| {
304 for (dependencies.list.items) |dep_path| {
309305 try write_stream.write(dep_path);
310306 }
311307 try write_stream.endArray();
lib/compiler/resinator/parse.zig+26-26
......@@ -82,8 +82,8 @@ pub const Parser = struct {
8282 }
8383
8484 fn parseRoot(self: *Self) Error!*Node {
85 var statements = std.array_list.Managed(*Node).init(self.state.allocator);
86 defer statements.deinit();
85 var statements: std.ArrayList(*Node) = .empty;
86 defer statements.deinit(self.state.allocator);
8787
8888 try self.parseStatements(&statements);
8989 try self.check(.eof);
......@@ -95,7 +95,7 @@ pub const Parser = struct {
9595 return &node.base;
9696 }
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 {
9999 while (true) {
100100 try self.nextToken(.whitespace_delimiter_only);
101101 if (self.state.token.id == .eof) break;
......@@ -105,7 +105,7 @@ pub const Parser = struct {
105105 // (usually it will end up with bogus things like 'file
106106 // not found: {')
107107 const statement = try self.parseStatement();
108 try statements.append(statement);
108 try statements.append(self.state.allocator, statement);
109109 }
110110 }
111111
......@@ -115,7 +115,7 @@ pub const Parser = struct {
115115 /// current token is unchanged.
116116 /// The returned slice is allocated by the parser's arena
117117 fn parseCommonResourceAttributes(self: *Self) ![]Token {
118 var common_resource_attributes: std.ArrayListUnmanaged(Token) = .empty;
118 var common_resource_attributes: std.ArrayList(Token) = .empty;
119119 while (true) {
120120 const maybe_common_resource_attribute = try self.lookaheadToken(.normal);
121121 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 {
135135 /// current token is unchanged.
136136 /// The returned slice is allocated by the parser's arena
137137 fn parseOptionalStatements(self: *Self, resource: ResourceType) ![]*Node {
138 var optional_statements: std.ArrayListUnmanaged(*Node) = .empty;
138 var optional_statements: std.ArrayList(*Node) = .empty;
139139
140140 const num_statement_types = @typeInfo(rc.OptionalStatements).@"enum".fields.len;
141141 var statement_type_has_duplicates = [_]bool{false} ** num_statement_types;
......@@ -355,8 +355,8 @@ pub const Parser = struct {
355355 const begin_token = self.state.token;
356356 try self.check(.begin);
357357
358 var strings = std.array_list.Managed(*Node).init(self.state.allocator);
359 defer strings.deinit();
358 var strings: std.ArrayList(*Node) = .empty;
359 defer strings.deinit(self.state.allocator);
360360 while (true) {
361361 const maybe_end_token = try self.lookaheadToken(.normal);
362362 switch (maybe_end_token.id) {
......@@ -392,7 +392,7 @@ pub const Parser = struct {
392392 .maybe_comma = comma_token,
393393 .string = self.state.token,
394394 };
395 try strings.append(&string_node.base);
395 try strings.append(self.state.allocator, &string_node.base);
396396 }
397397
398398 if (strings.items.len == 0) {
......@@ -501,7 +501,7 @@ pub const Parser = struct {
501501 const begin_token = self.state.token;
502502 try self.check(.begin);
503503
504 var accelerators: std.ArrayListUnmanaged(*Node) = .empty;
504 var accelerators: std.ArrayList(*Node) = .empty;
505505
506506 while (true) {
507507 const lookahead = try self.lookaheadToken(.normal);
......@@ -519,7 +519,7 @@ pub const Parser = struct {
519519
520520 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;
523523 while (true) {
524524 if (!(try self.parseOptionalToken(.comma))) break;
525525
......@@ -584,7 +584,7 @@ pub const Parser = struct {
584584 const begin_token = self.state.token;
585585 try self.check(.begin);
586586
587 var controls: std.ArrayListUnmanaged(*Node) = .empty;
587 var controls: std.ArrayList(*Node) = .empty;
588588 defer controls.deinit(self.state.allocator);
589589 while (try self.parseControlStatement(resource)) |control_node| {
590590 // The number of controls must fit in a u16 in order for it to
......@@ -643,7 +643,7 @@ pub const Parser = struct {
643643 const begin_token = self.state.token;
644644 try self.check(.begin);
645645
646 var buttons: std.ArrayListUnmanaged(*Node) = .empty;
646 var buttons: std.ArrayList(*Node) = .empty;
647647 defer buttons.deinit(self.state.allocator);
648648 while (try self.parseToolbarButtonStatement()) |button_node| {
649649 // The number of buttons must fit in a u16 in order for it to
......@@ -701,7 +701,7 @@ pub const Parser = struct {
701701 const begin_token = self.state.token;
702702 try self.check(.begin);
703703
704 var items: std.ArrayListUnmanaged(*Node) = .empty;
704 var items: std.ArrayList(*Node) = .empty;
705705 defer items.deinit(self.state.allocator);
706706 while (try self.parseMenuItemStatement(resource, id_token, 1)) |item_node| {
707707 try items.append(self.state.allocator, item_node);
......@@ -735,7 +735,7 @@ pub const Parser = struct {
735735 // common resource attributes must all be contiguous and come before optional-statements
736736 const common_resource_attributes = try self.parseCommonResourceAttributes();
737737
738 var fixed_info: std.ArrayListUnmanaged(*Node) = .empty;
738 var fixed_info: std.ArrayList(*Node) = .empty;
739739 while (try self.parseVersionStatement()) |version_statement| {
740740 try fixed_info.append(self.state.arena, version_statement);
741741 }
......@@ -744,7 +744,7 @@ pub const Parser = struct {
744744 const begin_token = self.state.token;
745745 try self.check(.begin);
746746
747 var block_statements: std.ArrayListUnmanaged(*Node) = .empty;
747 var block_statements: std.ArrayList(*Node) = .empty;
748748 while (try self.parseVersionBlockOrValue(id_token, 1)) |block_node| {
749749 try block_statements.append(self.state.arena, block_node);
750750 }
......@@ -852,8 +852,8 @@ pub const Parser = struct {
852852 /// Expects the current token to be a begin token.
853853 /// After return, the current token will be the end token.
854854 fn parseRawDataBlock(self: *Self) Error![]*Node {
855 var raw_data = std.array_list.Managed(*Node).init(self.state.allocator);
856 defer raw_data.deinit();
855 var raw_data: std.ArrayList(*Node) = .empty;
856 defer raw_data.deinit(self.state.allocator);
857857 while (true) {
858858 const maybe_end_token = try self.lookaheadToken(.normal);
859859 switch (maybe_end_token.id) {
......@@ -888,7 +888,7 @@ pub const Parser = struct {
888888 else => {},
889889 }
890890 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
893893 if (expression.isNumberExpression()) {
894894 const maybe_close_paren = try self.lookaheadToken(.normal);
......@@ -1125,7 +1125,7 @@ pub const Parser = struct {
11251125
11261126 _ = try self.parseOptionalToken(.comma);
11271127
1128 var options: std.ArrayListUnmanaged(Token) = .empty;
1128 var options: std.ArrayList(Token) = .empty;
11291129 while (true) {
11301130 const option_token = try self.lookaheadToken(.normal);
11311131 if (!rc.MenuItem.Option.map.has(option_token.slice(self.lexer.buffer))) {
......@@ -1160,7 +1160,7 @@ pub const Parser = struct {
11601160 }
11611161 try self.skipAnyCommas();
11621162
1163 var options: std.ArrayListUnmanaged(Token) = .empty;
1163 var options: std.ArrayList(Token) = .empty;
11641164 while (true) {
11651165 const option_token = try self.lookaheadToken(.normal);
11661166 if (!rc.MenuItem.Option.map.has(option_token.slice(self.lexer.buffer))) {
......@@ -1175,7 +1175,7 @@ pub const Parser = struct {
11751175 const begin_token = self.state.token;
11761176 try self.check(.begin);
11771177
1178 var items: std.ArrayListUnmanaged(*Node) = .empty;
1178 var items: std.ArrayList(*Node) = .empty;
11791179 while (try self.parseMenuItemStatement(resource, top_level_menu_id_token, nesting_level + 1)) |item_node| {
11801180 try items.append(self.state.arena, item_node);
11811181 }
......@@ -1245,7 +1245,7 @@ pub const Parser = struct {
12451245 const begin_token = self.state.token;
12461246 try self.check(.begin);
12471247
1248 var items: std.ArrayListUnmanaged(*Node) = .empty;
1248 var items: std.ArrayList(*Node) = .empty;
12491249 while (try self.parseMenuItemStatement(resource, top_level_menu_id_token, nesting_level + 1)) |item_node| {
12501250 try items.append(self.state.arena, item_node);
12511251 }
......@@ -1322,7 +1322,7 @@ pub const Parser = struct {
13221322 switch (statement_type) {
13231323 .file_version, .product_version => {
13241324 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
13271327 while (true) {
13281328 const value = try self.parseExpression(.{ .allowed_types = .{ .number = true } });
......@@ -1402,7 +1402,7 @@ pub const Parser = struct {
14021402 const begin_token = self.state.token;
14031403 try self.check(.begin);
14041404
1405 var children: std.ArrayListUnmanaged(*Node) = .empty;
1405 var children: std.ArrayList(*Node) = .empty;
14061406 while (try self.parseVersionBlockOrValue(top_level_version_id_token, nesting_level + 1)) |value_node| {
14071407 try children.append(self.state.arena, value_node);
14081408 }
......@@ -1435,7 +1435,7 @@ pub const Parser = struct {
14351435 }
14361436
14371437 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;
14391439 var seen_number: bool = false;
14401440 var first_string_value: ?*Node = null;
14411441 while (true) {
lib/compiler/resinator/preprocess.zig+19-18
......@@ -2,16 +2,17 @@ const std = @import("std");
22const builtin = @import("builtin");
33const Allocator = std.mem.Allocator;
44const cli = @import("cli.zig");
5const Dependencies = @import("compile.zig").Dependencies;
56const aro = @import("aro");
67
78const PreprocessError = error{ ArgError, GeneratedSourceError, PreprocessError, StreamTooLong, OutOfMemory };
89
910pub fn preprocess(
1011 comp: *aro.Compilation,
11 writer: anytype,
12 writer: *std.Io.Writer,
1213 /// Expects argv[0] to be the command name
1314 argv: []const []const u8,
14 maybe_dependencies_list: ?*std.array_list.Managed([]const u8),
15 maybe_dependencies: ?*Dependencies,
1516) PreprocessError!void {
1617 try comp.addDefaultPragmaHandlers();
1718
......@@ -66,13 +67,13 @@ pub fn preprocess(
6667 error.WriteFailed => return error.OutOfMemory,
6768 };
6869
69 if (maybe_dependencies_list) |dependencies_list| {
70 if (maybe_dependencies) |dependencies| {
7071 for (comp.sources.values()) |comp_source| {
7172 if (comp_source.id == builtin_macros.id or comp_source.id == user_macros.id) continue;
7273 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 errdefer dependencies_list.allocator.free(duped_path);
75 try dependencies_list.append(duped_path);
74 const duped_path = try dependencies.allocator.dupe(u8, comp_source.path);
75 errdefer dependencies.allocator.free(duped_path);
76 try dependencies.list.append(dependencies.allocator, duped_path);
7677 }
7778 }
7879}
......@@ -92,8 +93,8 @@ fn hasAnyErrors(comp: *aro.Compilation) bool {
9293
9394/// `arena` is used for temporary -D argument strings and the INCLUDE environment variable.
9495/// 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 {
96 try argv.appendSlice(&.{
96pub fn appendAroArgs(arena: Allocator, argv: *std.ArrayList([]const u8), options: cli.Options, system_include_paths: []const []const u8) !void {
97 try argv.appendSlice(arena, &.{
9798 "-E",
9899 "--comments",
99100 "-fuse-line-directives",
......@@ -104,13 +105,13 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)
104105 "-D_WIN32", // undocumented, but defined by default
105106 });
106107 for (options.extra_include_paths.items) |extra_include_path| {
107 try argv.append("-I");
108 try argv.append(extra_include_path);
108 try argv.append(arena, "-I");
109 try argv.append(arena, extra_include_path);
109110 }
110111
111112 for (system_include_paths) |include_path| {
112 try argv.append("-isystem");
113 try argv.append(include_path);
113 try argv.append(arena, "-isystem");
114 try argv.append(arena, include_path);
114115 }
115116
116117 if (!options.ignore_include_env_var) {
......@@ -124,8 +125,8 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)
124125 };
125126 var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);
126127 while (it.next()) |include_path| {
127 try argv.append("-isystem");
128 try argv.append(include_path);
128 try argv.append(arena, "-isystem");
129 try argv.append(arena, include_path);
129130 }
130131 }
131132
......@@ -133,13 +134,13 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)
133134 while (symbol_it.next()) |entry| {
134135 switch (entry.value_ptr.*) {
135136 .define => |value| {
136 try argv.append("-D");
137 try argv.append(arena, "-D");
137138 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);
139140 },
140141 .undefine => {
141 try argv.append("-U");
142 try argv.append(entry.key_ptr.*);
142 try argv.append(arena, "-U");
143 try argv.append(arena, entry.key_ptr.*);
143144 },
144145 }
145146 }
lib/compiler/resinator/res.zig+11-11
......@@ -258,7 +258,7 @@ pub const NameOrOrdinal = union(enum) {
258258 }
259259 }
260260
261 pub fn write(self: NameOrOrdinal, writer: anytype) !void {
261 pub fn write(self: NameOrOrdinal, writer: *std.Io.Writer) !void {
262262 switch (self) {
263263 .name => |name| {
264264 try writer.writeAll(std.mem.sliceAsBytes(name[0 .. name.len + 1]));
......@@ -270,7 +270,7 @@ pub const NameOrOrdinal = union(enum) {
270270 }
271271 }
272272
273 pub fn writeEmpty(writer: anytype) !void {
273 pub fn writeEmpty(writer: *std.Io.Writer) !void {
274274 try writer.writeInt(u16, 0, .little);
275275 }
276276
......@@ -283,8 +283,8 @@ pub const NameOrOrdinal = union(enum) {
283283
284284 pub fn nameFromString(allocator: Allocator, bytes: SourceBytes) !NameOrOrdinal {
285285 // 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));
287 errdefer buf.deinit();
286 var buf = try std.ArrayList(u16).initCapacity(allocator, @min(257, bytes.slice.len));
287 errdefer buf.deinit(allocator);
288288
289289 var i: usize = 0;
290290 while (bytes.code_page.codepointAt(i, bytes.slice)) |codepoint| : (i += codepoint.byte_len) {
......@@ -292,27 +292,27 @@ pub const NameOrOrdinal = union(enum) {
292292
293293 const c = codepoint.value;
294294 if (c == Codepoint.invalid) {
295 try buf.append(std.mem.nativeToLittle(u16, '�'));
295 try buf.append(allocator, std.mem.nativeToLittle(u16, '�'));
296296 } else if (c < 0x7F) {
297297 // 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))));
299299 } else if (c < 0x10000) {
300300 const short: u16 = @intCast(c);
301 try buf.append(std.mem.nativeToLittle(u16, short));
301 try buf.append(allocator, std.mem.nativeToLittle(u16, short));
302302 } else {
303303 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
306306 // Note: This can cut-off in the middle of a UTF-16 surrogate pair,
307307 // i.e. it can make the string end with an unpaired high surrogate
308308 if (buf.items.len == 256) break;
309309
310310 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));
312312 }
313313 }
314314
315 return NameOrOrdinal{ .name = try buf.toOwnedSliceSentinel(0) };
315 return NameOrOrdinal{ .name = try buf.toOwnedSliceSentinel(allocator, 0) };
316316 }
317317
318318 /// Returns `null` if the bytes do not form a valid number.
......@@ -1079,7 +1079,7 @@ pub const FixedFileInfo = struct {
10791079 }
10801080 };
10811081
1082 pub fn write(self: FixedFileInfo, writer: anytype) !void {
1082 pub fn write(self: FixedFileInfo, writer: *std.Io.Writer) !void {
10831083 try writer.writeInt(u32, signature, .little);
10841084 try writer.writeInt(u32, version, .little);
10851085 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 {
1010
1111const CurrentMapping = struct {
1212 line_num: usize = 1,
13 filename: std.ArrayListUnmanaged(u8) = .empty,
13 filename: std.ArrayList(u8) = .empty,
1414 pending: bool = true,
1515 ignore_contents: bool = false,
1616};
......@@ -574,8 +574,8 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva
574574 escape_u,
575575 };
576576
577 var filename = try std.array_list.Managed(u8).initCapacity(allocator, str.len);
578 errdefer filename.deinit();
577 var filename = try std.ArrayList(u8).initCapacity(allocator, str.len);
578 errdefer filename.deinit(allocator);
579579 var state: State = .string;
580580 var index: usize = 0;
581581 var escape_len: usize = undefined;
......@@ -693,7 +693,7 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva
693693 }
694694 }
695695
696 return filename.toOwnedSlice();
696 return filename.toOwnedSlice(allocator);
697697}
698698
699699fn testParseFilename(expected: []const u8, input: []const u8) !void {
......@@ -927,7 +927,7 @@ test "SourceMappings collapse" {
927927
928928/// Same thing as StringTable in Zig's src/Wasm.zig
929929pub const StringTable = struct {
930 data: std.ArrayListUnmanaged(u8) = .empty,
930 data: std.ArrayList(u8) = .empty,
931931 map: std.HashMapUnmanaged(u32, void, std.hash_map.StringIndexContext, std.hash_map.default_max_load_percentage) = .empty,
932932
933933 pub fn deinit(self: *StringTable, allocator: Allocator) void {
lib/compiler/resinator/windows1252.zig-45
......@@ -1,36 +1,5 @@
11const 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
343/// https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/bestfit1252.txt
354pub fn toCodepoint(c: u8) u16 {
365 return switch (c) {
......@@ -572,17 +541,3 @@ pub fn bestFitFromCodepoint(codepoint: u21) ?u8 {
572541 else => null,
573542 };
574543}
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}