summaryrefslogtreecommitdiff
path: root/src/main.zig
diff options
context:
space:
mode:
authorMartin Ashby <martin@ashbysoft.com>2023-09-15 07:22:41 +0100
committerMartin Ashby <martin@ashbysoft.com>2023-09-15 07:22:41 +0100
commitd20ca2ef83fd4e137207c8425080147352997457 (patch)
tree05a78626f471bd9ae470bda423b0734a5c9bd903 /src/main.zig
parent41735c890cafb0fbc42cb785eb784c0162f22402 (diff)
downloadzip-zig-d20ca2ef83fd4e137207c8425080147352997457.tar.gz
zip-zig-d20ca2ef83fd4e137207c8425080147352997457.tar.bz2
zip-zig-d20ca2ef83fd4e137207c8425080147352997457.tar.xz
zip-zig-d20ca2ef83fd4e137207c8425080147352997457.zip
Replace boilerplate serialization with some proper generic code
Delete commented code
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig233
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);
}
};