diff options
-rw-r--r-- | src/main.zig | 233 |
1 files changed, 67 insertions, 166 deletions
diff --git a/src/main.zig b/src/main.zig index 653003b..6d78709 100644 --- a/src/main.zig +++ b/src/main.zig @@ -29,8 +29,8 @@ const ZipFile = struct { } else { return error.EndOfCentralDirectoryRecordNotFound; } - const eocdr = try EndOfCentralDirectoryRecord.read(allocator, file_or_stream); - errdefer eocdr.deinit(); + var eocdr = try EndOfCentralDirectoryRecord.read(allocator, file_or_stream); + errdefer eocdr.deinit(allocator); if (eocdr.disk_number_this != 0 or eocdr.disk_number_central_dir_start != 0) return error.SpansNotSupported; if (eocdr.total_central_dir_entries != eocdr.total_central_dir_entries_on_this_disk) return error.SpansNotSupported; @@ -40,7 +40,7 @@ const ZipFile = struct { for (0..eocdr.total_central_dir_entries) |i| { central_directory_headers[i] = try CentralDirectoryHeader.read(allocator, file_or_stream); } - + return ZipFile{ .allocator = allocator, .end_of_central_directory_record = eocdr, @@ -48,9 +48,9 @@ const ZipFile = struct { }; } fn deinit(self: *ZipFile) void { - self.end_of_central_directory_record.deinit(); + self.end_of_central_directory_record.deinit(self.allocator); for (0..self.central_directory_headers.len) |i| { - self.central_directory_headers[i].deinit(); + self.central_directory_headers[i].deinit(self.allocator); } self.allocator.free(self.central_directory_headers); } @@ -77,45 +77,57 @@ const ZipFile = struct { // [end of central directory record] }; -// const LocalFileHeader = struct { -// const GPBF = packed struct(u16) { -// encrypted: bool = false, -// }; -// const SIG: [4]u8 = @bitCast(@as(u32, 0x04034b50)); -// sig: [4]u8 = SIG, -// // version needed to extract 2 bytes -// general_purpose_bit_flag: GPBF, -// // compression method 2 bytes -// // last mod file time 2 bytes -// // last mod file date 2 bytes -// // crc-32 4 bytes -// // compressed size 4 bytes -// // uncompressed size 4 bytes -// // file name length 2 bytes -// // extra field length 2 bytes -// // file name (variable size) -// // extra field (variable size) -// }; - -// const DataDescriptor = struct { -// const SIG: [4]u8 = @bitCast(@as(u32, 0x08074b50)); -// sig: [4]u8 = SIG, -// // crc-32 4 bytes -// // compressed size 4 bytes -// // uncompressed size 4 bytes -// }; - -// const ArchiveExtraDataRecord = struct { -// const SIG: [4]u8 = @bitCast(@as(u32, 0x08064b50)); -// sig: [4]u8 = SIG, -// // extra field length 4 bytes -// // extra field data (variable size) +const Dynamic = struct { + field_name: []const u8, + length_field_name: []const u8, +}; -// }; +fn read2( + allocator: std.mem.Allocator, + stream_or_file: anytype, + comptime T: type, + comptime sig: u32, + comptime dynamics: []const Dynamic, +) !T { + const ti = @typeInfo(T); + if (ti != .Struct) @compileError("read2 expects type parameter T to be a struct, but it was a " ++ @typeName(T)); + const si = ti.Struct; + + var reader = stream_or_file.reader(); + const sig_actual = try reader.readIntLittle(u32); + if (sig_actual != sig) { + std.log.err("invalid signature expected {x} got {x}", .{ sig, sig_actual }); + return error.InvalidSignature; + } + var t: T = undefined; + inline for (si.fields) |field| { + const fti = @typeInfo(field.type); + dynamic: inline for (dynamics) |dyn| { + if (comptime std.mem.eql(u8, dyn.field_name, field.name)) { + if (fti != .Pointer) @compileError("field " ++ field.name ++ " is marked dynamic but isn't a pointer. Instead it's a " ++ @typeName(field.type)); + const pi = fti.Pointer; + if (pi.size != .Slice) @compileError("field " ++ field.name ++ " is marked dynamic, but isn't a slice, instead it's sized " ++ @tagName(pi.size)); + const len = @field(t, dyn.length_field_name); + var buf = try allocator.alloc(pi.child, len); + // TODO how to errdefer in a loop, not sure where the scope ends. + _ = try reader.readAll(buf); + @field(t, field.name) = buf; + break :dynamic; + } + } else { + switch (fti) { + .Int => { + @field(t, field.name) = try reader.readIntLittle(field.type); + }, + else => @compileError("don't know how to handle field " ++ field.name ++ " of type " ++ @tagName(fti)), + } + } + } + return t; +} const CentralDirectoryHeader = struct { const SIG: u32 = @as(u32, 0x02014b50); - allocator: std.mem.Allocator, version_made_by: u16, version_needed_to_extract: u16, general_purpose_bit_flag: u16, @@ -137,110 +149,22 @@ const CentralDirectoryHeader = struct { file_comment: []const u8, fn read(allocator: std.mem.Allocator, stream_or_file: anytype) !CentralDirectoryHeader { - var reader = stream_or_file.reader(); - const sig = try reader.readIntLittle(u32); - if (sig != CentralDirectoryHeader.SIG) { - std.log.err("invalid signature expected {x} got {x}", .{CentralDirectoryHeader.SIG, sig}); - return error.InvalidSignature; - } - const version_made_by = try reader.readIntLittle(u16); - const version_needed_to_extract = try reader.readIntLittle(u16); - const general_purpose_bit_flag = try reader.readIntLittle(u16); - const compression_method = try reader.readIntLittle(u16); - const last_mod_file_time = try reader.readIntLittle(u16); - const last_mod_file_date = try reader.readIntLittle(u16); - const crc32 = try reader.readIntLittle(u32); - const compressed_size = try reader.readIntLittle(u32); - const uncompressed_size = try reader.readIntLittle(u32); - const file_name_length = try reader.readIntLittle(u16); - const extra_field_length = try reader.readIntLittle(u16); - const file_comment_length = try reader.readIntLittle(u16); - const disk_number_start = try reader.readIntLittle(u16); - const internal_file_attributes = try reader.readIntLittle(u16); - const external_file_attributes = try reader.readIntLittle(u32); - const relative_offset_of_local_header = try reader.readIntLittle(u32); - const file_name = try allocator.alloc(u8, file_name_length); - errdefer allocator.free(file_name); - _ = try reader.readAll(file_name); - const extra_field = try allocator.alloc(u8, extra_field_length); - errdefer allocator.free(extra_field); - _ = try reader.readAll(extra_field); - - const file_comment = try allocator.alloc(u8, file_comment_length); - errdefer allocator.free(file_comment); - _ = try reader.readAll(file_comment); - return CentralDirectoryHeader{ - .allocator = allocator, - .version_made_by = version_made_by, - .version_needed_to_extract = version_needed_to_extract, - .general_purpose_bit_flag = general_purpose_bit_flag, - .compression_method = compression_method, - .last_mod_file_time = last_mod_file_time, - .last_mod_file_date = last_mod_file_date, - .crc32 = crc32, - .compressed_size = compressed_size, - .uncompressed_size = uncompressed_size, - .file_name_length = file_name_length, - .extra_field_length = extra_field_length, - .file_comment_length = file_comment_length, - .disk_number_start = disk_number_start, - .internal_file_attributes = internal_file_attributes, - .external_file_attributes = external_file_attributes, - .relative_offset_of_local_header = relative_offset_of_local_header, - .file_name = file_name, - .extra_field = extra_field, - .file_comment = file_comment, - }; + return read2(allocator, stream_or_file, CentralDirectoryHeader, CentralDirectoryHeader.SIG, &[_]Dynamic{ + .{ .field_name = "file_name", .length_field_name = "file_name_length" }, + .{ .field_name = "extra_field", .length_field_name = "extra_field_length" }, + .{ .field_name = "file_comment", .length_field_name = "file_comment_length" }, + }); } - fn deinit(self: *CentralDirectoryHeader) void { - self.allocator.free(self.file_name); - self.allocator.free(self.extra_field); - self.allocator.free(self.file_comment); + + fn deinit(self: *CentralDirectoryHeader, allocator: std.mem.Allocator) void { + allocator.free(self.file_name); + allocator.free(self.extra_field); + allocator.free(self.file_comment); } }; -// const DigitalSignature = struct { -// const SIG: [4]u8 = @bitCast(@as(u32, 0x05054b50)); -// sig: [4]u8 = SIG, -// // size of data 2 bytes -// // signature data (variable size) -// }; - -// const Zip64EndOfCentralDirectoryRecord = struct { -// const SIG: [4]u8 = @bitCast(@as(u32, 0x06064b50)); -// sig: [4]u8 = SIG, -// // size of zip64 end of central -// // directory record 8 bytes -// // version made by 2 bytes -// // version needed to extract 2 bytes -// // number of this disk 4 bytes -// // number of the disk with the -// // start of the central directory 4 bytes -// // total number of entries in the -// // central directory on this disk 8 bytes -// // total number of entries in the -// // central directory 8 bytes -// // size of the central directory 8 bytes -// // offset of start of central -// // directory with respect to -// // the starting disk number 8 bytes -// // zip64 extensible data sector (variable size) -// }; - -// const Zip64EndOfCentralDirectoryLocator = struct { -// const SIG: [4]u8 = @bitCast(@as(u32, 0x07064b50)); -// sig: [4]u8 = SIG, -// // number of the disk with the -// // start of the zip64 end of -// // central directory 4 bytes -// // relative offset of the zip64 -// // end of central directory record 8 bytes -// // total number of disks 4 bytes -// }; - const EndOfCentralDirectoryRecord = struct { const SIG: u32 = @as(u32, 0x06054b50); - allocator: std.mem.Allocator, disk_number_this: u16, disk_number_central_dir_start: u16, total_central_dir_entries_on_this_disk: u16, @@ -251,36 +175,13 @@ const EndOfCentralDirectoryRecord = struct { comment: []const u8, fn read(allocator: std.mem.Allocator, file_or_stream: anytype) !EndOfCentralDirectoryRecord { - var reader = file_or_stream.reader(); - const sig = try reader.readIntLittle(u32); - if (sig != EndOfCentralDirectoryRecord.SIG) { - std.log.err("invalid signature expected {x} got {x}", .{EndOfCentralDirectoryRecord.SIG, sig}); - return error.InvalidSignature; - } - const disk_number_this = try reader.readIntLittle(u16); - const disk_number_central_dir_start = try reader.readIntLittle(u16); - const total_central_dir_entries_on_this_disk = try reader.readIntLittle(u16); - const total_central_dir_entries = try reader.readIntLittle(u16); - const size_of_central_dir = try reader.readIntLittle(u32); - const central_dir_offset = try reader.readIntLittle(u32); - const comment_length = try reader.readIntLittle(u16); - var comment = try allocator.alloc(u8, comment_length); - _ = try reader.readAll(comment); - return EndOfCentralDirectoryRecord{ - .allocator = allocator, - .disk_number_this = disk_number_this, - .disk_number_central_dir_start = disk_number_central_dir_start, - .total_central_dir_entries_on_this_disk = total_central_dir_entries_on_this_disk, - .total_central_dir_entries = total_central_dir_entries, - .size_of_central_dir = size_of_central_dir, - .central_dir_offset = central_dir_offset, - .comment_length = comment_length, - .comment = comment, - }; + return read2(allocator, file_or_stream, EndOfCentralDirectoryRecord, EndOfCentralDirectoryRecord.SIG, &[_]Dynamic{ + .{ .field_name = "comment", .length_field_name = "comment_length" }, + }); } - fn deinit(self: *EndOfCentralDirectoryRecord) void { - self.allocator.free(self.comment); + fn deinit(self: *EndOfCentralDirectoryRecord, allocator: std.mem.Allocator) void { + allocator.free(self.comment); } }; |