From e4e6c90292b92bdb392519121293e368535e982f Mon Sep 17 00:00:00 2001 From: penguindark <57967770+penguindark@users.noreply.github.com> Date: Sun, 25 Jul 2021 20:29:51 +0200 Subject: [PATCH] zip: read in memory (#10960) --- vlib/szip/szip.v | 22 +++++++++++++++++ vlib/szip/szip_test.v | 55 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/vlib/szip/szip.v b/vlib/szip/szip.v index 059c98547b..9cb157d2e5 100644 --- a/vlib/szip/szip.v +++ b/vlib/szip/szip.v @@ -17,6 +17,8 @@ fn C.zip_close(&Zip) fn C.zip_entry_open(&Zip, &byte) int +fn C.zip_entry_openbyindex(&Zip, int) int + fn C.zip_entry_close(&Zip) int fn C.zip_entry_name(&Zip) &byte @@ -35,6 +37,8 @@ fn C.zip_entry_fwrite(&Zip, &char) int fn C.zip_entry_read(&Zip, &voidptr, &size_t) int +fn C.zip_entry_noallocread(&Zip, voidptr, size_t) int + fn C.zip_entry_fread(&Zip, &char) int fn C.zip_total_entries(&Zip) int @@ -108,6 +112,14 @@ pub fn (mut zentry Zip) open_entry(name string) ? { } } +// open_entry_by_index opens an entry by index in the archive. +pub fn (mut z Zip) open_entry_by_index(index int) ? { + res := C.zip_entry_openbyindex(z, index) + if res == -1 { + return error('szip: cannot open archive entry at index $index') + } +} + // close_entry closes a zip entry, flushes buffer and releases resources. [inline] pub fn (mut zentry Zip) close_entry() { @@ -192,6 +204,16 @@ pub fn (mut zentry Zip) read_entry() ?voidptr { return buf } +// read_entry_buf extracts the current zip entry into user specified buffer +pub fn (mut zentry Zip) read_entry_buf(buf voidptr, in_bsize int) ?int { + bsize := size_t(in_bsize) + res := C.zip_entry_noallocread(zentry, buf, bsize) + if res == -1 { + return error('szip: cannot read properly data from entry') + } + return res +} + // extract_entry extracts the current zip entry into output file. pub fn (mut zentry Zip) extract_entry(path string) ? { if !os.is_file(path) { diff --git a/vlib/szip/szip_test.v b/vlib/szip/szip_test.v index a391758895..a20f638569 100644 --- a/vlib/szip/szip_test.v +++ b/vlib/szip/szip_test.v @@ -4,8 +4,10 @@ import os const ( test_out_zip = 'v_test_zip.zip' test_path = 'zip files' - fpath1 = os.join_path(test_path, 'file_1.txt') - fpath2 = os.join_path(test_path, 'file_2.txt') + fname1 = 'file_1.txt' + fpath1 = os.join_path(test_path, fname1) + fname2 = 'file_2.txt' + fpath2 = os.join_path(test_path, fname2) ) fn test_szip_create_temp_files() ? { @@ -35,3 +37,52 @@ fn test_extract_zipped_files() ? { os.rmdir_all(test_path) ? os.rm(test_out_zip) or {} } + +fn test_reading_zipping_files() ? { + n_files := 2 + mut file_name_list := []string{} + for i in 0 .. n_files { + file_name_list << 'file_${i:02}.txt' + } + + os.chdir(os.temp_dir()) + os.rmdir_all(test_path) or {} + os.mkdir(test_path) ? + for c, f_name in file_name_list { + tmp_path := os.join_path(test_path, f_name) + os.write_file(tmp_path, 'file ${c:02}') ? + assert os.exists(tmp_path) + } + files := (os.ls(test_path) ?).map(os.join_path(test_path, it)) + + szip.zip_files(files, test_out_zip) ? + assert os.exists(test_out_zip) + + mut zp := szip.open(test_out_zip, szip.CompressionLevel.no_compression, szip.OpenMode.read_only) ? + n_entries := zp.total() ? + assert n_entries == n_files + + unsafe { + data_len := 'file XX'.len + buf_size := 32 + buf := malloc(data_len * 2) + + for _ in 0 .. n_files { + zp.open_entry_by_index(0) ? + name := zp.name() + assert name in file_name_list + + zp.read_entry_buf(buf, buf_size) ? + buf[data_len] = 0 + tmp_str := tos(buf, data_len) + + assert tmp_str[0..4] == 'file' + assert tmp_str[5..7] == name[5..7] + + zp.close_entry() + } + + free(buf) + } + zp.close() +}