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
- findBuffer (Function)
- FindBufferError (Error Set)
- findFile (Function)
- FindFileError (Error Set)
- need_zip64 (Function)
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;
}
}
}