diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | build.zig | 27 | ||||
-rw-r--r-- | build.zig.zon | 4 | ||||
-rw-r--r-- | src/hello.zip | bin | 0 -> 179 bytes | |||
-rw-r--r-- | src/main.zig | 204 |
5 files changed, 236 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3cef7be --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +zig-cache/ diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..cfc292c --- /dev/null +++ b/build.zig @@ -0,0 +1,27 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const lib = b.addStaticLibrary(.{ + .name = "zip-zig", + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + b.installArtifact(lib); + // For zig package manager, module must be named + _ = b.addModule("zip", .{ .source_file = .{ .path = "src/main.zig" } }); + + const main_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + const run_main_tests = b.addRunArtifact(main_tests); + const test_step = b.step("test", "Run library tests"); + test_step.dependOn(&run_main_tests.step); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..3abddcd --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,4 @@ +.{ + .name = "zip", + .version = "0.0.1", +}
\ No newline at end of file diff --git a/src/hello.zip b/src/hello.zip Binary files differnew file mode 100644 index 0000000..d17d176 --- /dev/null +++ b/src/hello.zip diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..d5345f0 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,204 @@ +const std = @import("std"); +const testing = std.testing; + +const ZipFile = struct { + // [local file header 1] + // [encryption header 1] + // [file data 1] + // [data descriptor 1] + // . + // . + // . + // [local file header n] + // [encryption header n] + // [file data n] + // [data descriptor n] + // [archive decryption header] + // [archive extra data record] + // [central directory header 1] + // . + // . + // . + // [central directory header n] + // [zip64 end of central directory record] + // [zip64 end of central directory locator] + // [end of central directory record] +}; + +const LocalFileHeader = packed struct { + const GPBF = packed struct(u16) { + encrypted: bool = false, + }; + const SIG: u32 = 0x04034b50; + sig: u32 = 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: u32 = 0x08074b50; + sig: u32 = SIG, + // crc-32 4 bytes + // compressed size 4 bytes + // uncompressed size 4 bytes +}; + +const ArchiveExtraDataRecord = struct { + const SIG: u32 = 0x08064b50; + sig: u32 = SIG, + // extra field length 4 bytes + // extra field data (variable size) + +}; + +const CentralDirectoryHeader = packed struct { + const SIG: u32 = 0x02014b50; + // central file header signature 4 bytes () + sig: u32 = SIG, + // version made by 2 bytes + version_made_by: u16, + // version needed to extract 2 bytes + version_needed_to_extract: u16, + // general purpose bit flag 2 bytes + general_purpose_bit_flag: u16, + // compression method 2 bytes + compression_method: u16, + // last mod file time 2 bytes + last_mod_file_time: u16, + // last mod file date 2 bytes + last_mod_file_date: u16, + // crc-32 4 bytes + crc32: u32, + // compressed size 4 bytes + compressed_size: u32, + // uncompressed size 4 bytes + uncompressed_size: u32, + // file name length 2 bytes + file_name_length: u16, + // extra field length 2 bytes + extra_field_length: u16, + // file comment length 2 bytes + file_comment_length: u16, + // disk number start 2 bytes + disk_number_start: u16, + // internal file attributes 2 bytes + internal_file_attributes: u16, + // external file attributes 4 bytes + external_file_attributes: u32, + // relative offset of local header 4 bytes + relative_offset_of_local_header: u16, + + // file name (variable size) + // extra field (variable size) + // file comment (variable size) +}; + +const DigitalSignature = struct { + const SIG: u32 = 0x05054b50; + sig: u32 = SIG, + // size of data 2 bytes + // signature data (variable size) +}; + +const Zip64EndOfCentralDirectoryRecord = struct { + const SIG: u32 = 0x06064b50; + sig: u32 = 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: u32 = 0x07064b50; + sig: u32 = 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 = packed struct { + const SIG: u32 = 0x06054b50; + // end of central dir signature 4 bytes (0x06054b50) + sig: u32 = SIG, + // number of this disk 2 bytes + disk_number_this: u16, + // number of the disk with the + // start of the central directory 2 bytes + disk_number_central_dir_start: u16, + // total number of entries in the + // central directory on this disk 2 bytes + total_central_dir_entries_on_this_disk: u16, + // total number of entries in + // the central directory 2 bytes + total_central_dir_entries: u16, + // size of the central directory 4 bytes + size_of_central_dir: u32, + // offset of start of central + // directory with respect to + // the starting disk number 4 bytes + central_dir_offset: u32, + // .ZIP file comment length 2 bytes + comment_length: u16, + // .ZIP file comment (variable size) + // comment: [*]u8, + + // fn comment_slice(self: EndOfCentralDirectoryRecord) []u8 { + // return self.comment[0..self.comment_length]; + // } +}; + +test "foo" { + var mapped_mem: ?[]align(std.mem.page_size) u8 = null; + { + var file = try std.fs.cwd().openFile("src/hello.zip", .{}); + errdefer file.close(); + const file_len = std.math.cast(usize, try file.getEndPos()) orelse std.math.maxInt(usize); + mapped_mem = try std.os.mmap( + null, + file_len, + std.os.PROT.READ, + std.os.MAP.SHARED, + file.handle, + 0, + ); + file.close(); + } + var mm = mapped_mem orelse return error.MMapFailed; + defer std.os.munmap(mm); + const cdr_search_start = if (mm.len < 64_000) 0 else mm.len - 64_000; + const needle: [4]u8 = @bitCast(CentralDirectoryHeader.SIG); + const eocdr_start = std.mem.indexOf(u8, mm[cdr_search_start..], &needle) orelse return error.EocdrNotFound; + const eocdr: *EndOfCentralDirectoryRecord = @ptrCast(@alignCast(mm[eocdr_start .. eocdr_start + @sizeOf(EndOfCentralDirectoryRecord)])); + std.log.err("needle: {} eocdr_start {} comment_length {}", .{ std.fmt.fmtSliceHexLower(&needle), eocdr_start, eocdr.comment_length }); + + const hh_p: *u32 = @ptrCast(mm[0..4].ptr); + const hh = hh_p.*; + try std.testing.expectEqual(LocalFileHeader.SIG, hh); + // std.log.err("mapped_mem len {} first 5 bytes {}", .{mm.len, std.fmt.fmtSliceHexUpper(mm[0..5])}); +} |