extern struct EndRecord [src]

Fields

signature: [4]u8 align(1)
disk_number: u16 align(1)
central_directory_disk_number: u16 align(1)
record_count_disk: u16 align(1)
record_count_total: u16 align(1)
central_directory_size: u32 align(1)
central_directory_offset: u32 align(1)
comment_len: u16 align(1)

Members

Source

pub const EndRecord = extern struct { signature: [4]u8 align(1), disk_number: u16 align(1), central_directory_disk_number: u16 align(1), record_count_disk: u16 align(1), record_count_total: u16 align(1), central_directory_size: u32 align(1), central_directory_offset: u32 align(1), comment_len: u16 align(1), pub fn need_zip64(self: EndRecord) bool { return isMaxInt(self.record_count_disk) or isMaxInt(self.record_count_total) or isMaxInt(self.central_directory_size) or isMaxInt(self.central_directory_offset); } pub const FindBufferError = error{ ZipNoEndRecord, ZipTruncated }; /// TODO audit this logic pub fn findBuffer(buffer: []const u8) FindBufferError!EndRecord { const pos = std.mem.lastIndexOf(u8, buffer, &end_record_sig) orelse return error.ZipNoEndRecord; if (pos + @sizeOf(EndRecord) > buffer.len) return error.EndOfStream; const record_ptr: *EndRecord = @ptrCast(buffer[pos..][0..@sizeOf(EndRecord)]); var record = record_ptr.*; if (!is_le) std.mem.byteSwapAllFields(EndRecord, &record); return record; } pub const FindFileError = File.Reader.SizeError || File.SeekError || File.ReadError || error{ ZipNoEndRecord, EndOfStream, ReadFailed, }; pub fn findFile(fr: *File.Reader) FindFileError!EndRecord { const end_pos = try fr.getSize(); var buf: [@sizeOf(EndRecord) + std.math.maxInt(u16)]u8 = undefined; const record_len_max = @min(end_pos, buf.len); var loaded_len: u32 = 0; var comment_len: u16 = 0; while (true) { const record_len: u32 = @as(u32, comment_len) + @sizeOf(EndRecord); if (record_len > record_len_max) return error.ZipNoEndRecord; if (record_len > loaded_len) { const new_loaded_len = @min(loaded_len + 300, record_len_max); const read_len = new_loaded_len - loaded_len; try fr.seekTo(end_pos - @as(u64, new_loaded_len)); const read_buf: []u8 = buf[buf.len - new_loaded_len ..][0..read_len]; fr.interface.readSliceAll(read_buf) catch |err| switch (err) { error.ReadFailed => return fr.err.?, error.EndOfStream => return error.EndOfStream, }; loaded_len = new_loaded_len; } const record_bytes = buf[buf.len - record_len ..][0..@sizeOf(EndRecord)]; if (std.mem.eql(u8, record_bytes[0..4], &end_record_sig) and std.mem.readInt(u16, record_bytes[20..22], .little) == comment_len) { const record: *align(1) EndRecord = @ptrCast(record_bytes.ptr); if (!is_le) std.mem.byteSwapAllFields(EndRecord, record); return record.*; } if (comment_len == std.math.maxInt(u16)) return error.ZipNoEndRecord; comment_len += 1; } } }