resinator: a few more updates/fixes

Just enough to get things working correctly again
This commit is contained in:
Ryan Liptak 2025-08-06 01:11:00 -07:00 committed by Andrew Kelley
parent 5a743be6b4
commit 858716aa4d
4 changed files with 32 additions and 37 deletions

View file

@ -1141,6 +1141,8 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
} }
output_format = .res; output_format = .res;
} }
} else {
output_format_source = .output_format_arg;
} }
options.output_source = .{ .filename = try filepathWithExtension(allocator, options.input_source.filename, output_format.?.extension()) }; options.output_source = .{ .filename = try filepathWithExtension(allocator, options.input_source.filename, output_format.?.extension()) };
} else { } else {
@ -1529,21 +1531,21 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti
var diagnostics = Diagnostics.init(std.testing.allocator); var diagnostics = Diagnostics.init(std.testing.allocator);
defer diagnostics.deinit(); defer diagnostics.deinit();
var output = std.ArrayList(u8).init(std.testing.allocator); var output: std.io.Writer.Allocating = .init(std.testing.allocator);
defer output.deinit(); defer output.deinit();
var options = parse(std.testing.allocator, args, &diagnostics) catch |err| switch (err) { var options = parse(std.testing.allocator, args, &diagnostics) catch |err| switch (err) {
error.ParseError => { error.ParseError => {
try diagnostics.renderToWriter(args, output.writer(), .no_color); try diagnostics.renderToWriter(args, &output.writer, .no_color);
try std.testing.expectEqualStrings(expected_output, output.items); try std.testing.expectEqualStrings(expected_output, output.getWritten());
return null; return null;
}, },
else => |e| return e, else => |e| return e,
}; };
errdefer options.deinit(); errdefer options.deinit();
try diagnostics.renderToWriter(args, output.writer(), .no_color); try diagnostics.renderToWriter(args, &output.writer, .no_color);
try std.testing.expectEqualStrings(expected_output, output.items); try std.testing.expectEqualStrings(expected_output, output.getWritten());
return options; return options;
} }

View file

@ -65,7 +65,7 @@ pub const ParseResOptions = struct {
}; };
/// The returned ParsedResources should be freed by calling its `deinit` function. /// The returned ParsedResources should be freed by calling its `deinit` function.
pub fn parseRes(allocator: Allocator, reader: anytype, options: ParseResOptions) !ParsedResources { pub fn parseRes(allocator: Allocator, reader: *std.Io.Reader, options: ParseResOptions) !ParsedResources {
var resources = ParsedResources.init(allocator); var resources = ParsedResources.init(allocator);
errdefer resources.deinit(); errdefer resources.deinit();
@ -74,7 +74,7 @@ pub fn parseRes(allocator: Allocator, reader: anytype, options: ParseResOptions)
return resources; return resources;
} }
pub fn parseResInto(resources: *ParsedResources, reader: anytype, options: ParseResOptions) !void { pub fn parseResInto(resources: *ParsedResources, reader: *std.Io.Reader, options: ParseResOptions) !void {
const allocator = resources.allocator; const allocator = resources.allocator;
var bytes_remaining: u64 = options.max_size; var bytes_remaining: u64 = options.max_size;
{ {
@ -103,45 +103,38 @@ pub const ResourceAndSize = struct {
total_size: u64, total_size: u64,
}; };
pub fn parseResource(allocator: Allocator, reader: anytype, max_size: u64) !ResourceAndSize { pub fn parseResource(allocator: Allocator, reader: *std.Io.Reader, max_size: u64) !ResourceAndSize {
var header_counting_reader = std.io.countingReader(reader); const data_size = try reader.takeInt(u32, .little);
var buffer: [1024]u8 = undefined; const header_size = try reader.takeInt(u32, .little);
var header_reader_adapter = header_counting_reader.reader().adaptToNewApi(&buffer);
const header_reader = &header_reader_adapter.new_interface;
const data_size = try header_reader.takeInt(u32, .little);
const header_size = try header_reader.takeInt(u32, .little);
const total_size: u64 = @as(u64, header_size) + data_size; const total_size: u64 = @as(u64, header_size) + data_size;
if (total_size > max_size) return error.ImpossibleSize; if (total_size > max_size) return error.ImpossibleSize;
var header_bytes_available = header_size -| 8; const remaining_header_bytes = try reader.take(header_size -| 8);
var type_reader: std.Io.Reader = .fixed(try header_reader.take(header_bytes_available)); var remaining_header_reader: std.Io.Reader = .fixed(remaining_header_bytes);
const type_value = try parseNameOrOrdinal(allocator, &type_reader); const type_value = try parseNameOrOrdinal(allocator, &remaining_header_reader);
errdefer type_value.deinit(allocator); errdefer type_value.deinit(allocator);
header_bytes_available -|= @intCast(type_value.byteLen()); const name_value = try parseNameOrOrdinal(allocator, &remaining_header_reader);
var name_reader: std.Io.Reader = .fixed(try header_reader.take(header_bytes_available));
const name_value = try parseNameOrOrdinal(allocator, &name_reader);
errdefer name_value.deinit(allocator); errdefer name_value.deinit(allocator);
const padding_after_name = numPaddingBytesNeeded(@intCast(header_counting_reader.bytes_read)); const padding_after_name = numPaddingBytesNeeded(@intCast(remaining_header_reader.seek));
try header_reader.discardAll(padding_after_name); try remaining_header_reader.discardAll(padding_after_name);
std.debug.assert(header_counting_reader.bytes_read % 4 == 0); std.debug.assert(remaining_header_reader.seek % 4 == 0);
const data_version = try header_reader.takeInt(u32, .little); const data_version = try remaining_header_reader.takeInt(u32, .little);
const memory_flags: MemoryFlags = @bitCast(try header_reader.takeInt(u16, .little)); const memory_flags: MemoryFlags = @bitCast(try remaining_header_reader.takeInt(u16, .little));
const language: Language = @bitCast(try header_reader.takeInt(u16, .little)); const language: Language = @bitCast(try remaining_header_reader.takeInt(u16, .little));
const version = try header_reader.takeInt(u32, .little); const version = try remaining_header_reader.takeInt(u32, .little);
const characteristics = try header_reader.takeInt(u32, .little); const characteristics = try remaining_header_reader.takeInt(u32, .little);
const header_bytes_read = header_counting_reader.bytes_read; if (remaining_header_reader.seek != remaining_header_reader.end) return error.HeaderSizeMismatch;
if (header_size != header_bytes_read) return error.HeaderSizeMismatch;
const data = try allocator.alloc(u8, data_size); const data = try allocator.alloc(u8, data_size);
errdefer allocator.free(data); errdefer allocator.free(data);
try reader.readNoEof(data); try reader.readSliceAll(data);
const padding_after_data = numPaddingBytesNeeded(@intCast(data_size)); const padding_after_data = numPaddingBytesNeeded(@intCast(data_size));
try reader.skipBytes(padding_after_data, .{ .buf_size = 3 }); try reader.discardAll(padding_after_data);
return .{ return .{
.resource = .{ .resource = .{

View file

@ -14,12 +14,12 @@ pub fn read(allocator: std.mem.Allocator, reader: anytype, max_size: u64) ReadEr
// Some Reader implementations have an empty ReadError error set which would // Some Reader implementations have an empty ReadError error set which would
// cause 'unreachable else' if we tried to use an else in the switch, so we // cause 'unreachable else' if we tried to use an else in the switch, so we
// need to detect this case and not try to translate to ReadError // need to detect this case and not try to translate to ReadError
const anyerror_reader_errorset = @TypeOf(reader).Error == anyerror;
const empty_reader_errorset = @typeInfo(@TypeOf(reader).Error).error_set == null or @typeInfo(@TypeOf(reader).Error).error_set.?.len == 0; const empty_reader_errorset = @typeInfo(@TypeOf(reader).Error).error_set == null or @typeInfo(@TypeOf(reader).Error).error_set.?.len == 0;
if (empty_reader_errorset) { if (empty_reader_errorset and !anyerror_reader_errorset) {
return readAnyError(allocator, reader, max_size) catch |err| switch (err) { return readAnyError(allocator, reader, max_size) catch |err| switch (err) {
error.EndOfStream => error.UnexpectedEOF, error.EndOfStream => error.UnexpectedEOF,
error.OutOfMemory, error.InvalidHeader, error.InvalidImageType, error.ImpossibleDataSize, error.UnexpectedEOF, error.ReadError => |e| return e, else => |e| return e,
else => return error.ReadError,
}; };
} else { } else {
return readAnyError(allocator, reader, max_size) catch |err| switch (err) { return readAnyError(allocator, reader, max_size) catch |err| switch (err) {

View file

@ -325,8 +325,8 @@ pub fn main() !void {
std.debug.assert(options.output_format == .coff); std.debug.assert(options.output_format == .coff);
// TODO: Maybe use a buffered file reader instead of reading file into memory -> fbs // TODO: Maybe use a buffered file reader instead of reading file into memory -> fbs
var fbs = std.io.fixedBufferStream(res_data.bytes); var res_reader: std.Io.Reader = .fixed(res_data.bytes);
break :resources cvtres.parseRes(allocator, fbs.reader(), .{ .max_size = res_data.bytes.len }) catch |err| { break :resources cvtres.parseRes(allocator, &res_reader, .{ .max_size = res_data.bytes.len }) catch |err| {
// TODO: Better errors // TODO: Better errors
try error_handler.emitMessage(allocator, .err, "unable to parse res from '{s}': {s}", .{ res_stream.name, @errorName(err) }); try error_handler.emitMessage(allocator, .err, "unable to parse res from '{s}': {s}", .{ res_stream.name, @errorName(err) });
std.process.exit(1); std.process.exit(1);