Merge pull request #3160 from GeorgH93/fix_zipx_streaming_non_seekable

Fix zipx reading with ZIP_LENGTH_AT_END flag from non-seekable source
This commit is contained in:
Dustin L. Howett authored and GitHub committed 2026-06-24 08:42:37 -05:00
commit 6b468d68d1
4 files changed
+259 -101

No files matched your search

+1
View File
@@ -1121,6 +1121,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_zip_padded2.zip.uu \
libarchive/test/test_read_format_zip_padded3.zip.uu \
libarchive/test/test_read_format_zip_ppmd8.zipx.uu \
libarchive/test/test_read_format_zip_ppmd8_aes256_streaming.zipx.uu \
libarchive/test/test_read_format_zip_ppmd8_crash_1.zipx.uu \
libarchive/test/test_read_format_zip_ppmd8_crash_2.zipx.uu \
libarchive/test/test_read_format_zip_ppmd8_multi.zipx.uu \
+108 -52
View File
@@ -482,6 +482,13 @@ zip_read_decrypt(struct zip *zip, const void *compressed_buff,
{
*sp = compressed_buff;
/* Safety check to prevent potential OOB reads if something went wrong
* previously. We should not have a negative bytes_avail count here.
* If we do, set them to zero so that reading the ZIP will fail later,
* safely as corrupted instead of crashing. */
if (bytes_avail < 0)
bytes_avail = 0;
if (zip->tctx_valid || zip->cctx_valid) {
if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) {
size_t buff_remaining =
@@ -1683,6 +1690,26 @@ consume_end_of_file_marker(struct archive_read *a, struct zip *zip)
return;
}
/* None of the exact patterns matched. If entry size was unknown
* (ZIP_LENGTH_AT_END flag), before treating this as
* corruption, check whether the next ZIP record follows the data
* immediately: a length-at-end entry whose compression format has
* its own end-of-stream marker (e.g. PPMd) may be written with no
* data descriptor at all. In that case the byte counts we measured
* during decompression are authoritative, so trust them and leave
* the stream untouched. */
if (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
{
const uint32_t sig = archive_le32dec(p);
if (sig == 0x04034b50U /* Local file header */
|| sig == 0x02014b50U /* Central directory record */
|| sig == 0x06054b50U) /* End of central directory */ {
zip->entry->compressed_size = compressed_actual;
zip->entry->uncompressed_size = uncompressed_actual;
return;
}
}
/* If none of the above patterns gives us a full exact match,
* then there's something definitely amiss. The fallback code
* below will parse out some plausible values for error
@@ -1986,7 +2013,13 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)
*/
/* Read magic1,magic2,lzma_params from the ZIPX stream. */
if(zip->entry_bytes_remaining < 9) {
/* When the compressed size is unknown (e.g. ZIP_LENGTH_AT_END read
* from a non-seekable source), entry_bytes_remaining is 0 or negative
* here. We can still attempt to read the 9-byte header; if the data
* is truly truncated, the __archive_read_ahead calls below will catch
* it. */
if(zip->entry_bytes_remaining > 0
&& zip->entry_bytes_remaining < 9) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated lzma data");
return (ARCHIVE_FATAL);
@@ -2060,8 +2093,10 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)
/* We've already consumed some bytes, so take this into account. */
__archive_read_consume(a, 9);
zip->entry_bytes_remaining -= 9;
zip->entry_compressed_bytes_read += 9;
if (zip->entry_bytes_remaining > 0) {
zip->entry_bytes_remaining -= 9;
}
zip->decompress_init = 1;
return (ARCHIVE_OK);
@@ -2076,7 +2111,7 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
lzma_ret lz_ret;
const void* compressed_buf;
const void* sp;
ssize_t bytes_avail, in_bytes, to_consume = 0;
ssize_t bytes_avail, to_consume = 0;
(void) offset; /* UNUSED */
@@ -2088,19 +2123,21 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
}
compressed_buf = sp = __archive_read_ahead(a, 1, &bytes_avail);
if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
&& bytes_avail > zip->entry_bytes_remaining) {
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
}
if (bytes_avail < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated xz file body");
return (ARCHIVE_FATAL);
}
in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
zip_read_decrypt(zip, compressed_buf, in_bytes,
&compressed_buf, &in_bytes, &sp);
zip_read_decrypt(zip, compressed_buf, bytes_avail,
&compressed_buf, &bytes_avail, &sp);
zip->zipx_lzma_stream.next_in = compressed_buf;
zip->zipx_lzma_stream.avail_in = in_bytes;
zip->zipx_lzma_stream.avail_in = bytes_avail;
zip->zipx_lzma_stream.total_in = 0;
zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;
zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;
@@ -2127,8 +2164,10 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
lzma_end(&zip->zipx_lzma_stream);
zip->zipx_lzma_valid = 0;
if((int64_t) zip->zipx_lzma_stream.total_in !=
zip->entry_bytes_remaining)
/* This assertion is only possible if the size of the compressed data
* stream is known -> !ZIP_LENGTH_AT_END */
if((int64_t) zip->zipx_lzma_stream.total_in != zip->entry_bytes_remaining
&& !(zip->entry->zip_flags & ZIP_LENGTH_AT_END))
{
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
@@ -2172,7 +2211,7 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
lzma_ret lz_ret;
const void* compressed_buf;
const void* sp;
ssize_t bytes_avail, in_bytes, to_consume;
ssize_t bytes_avail, to_consume;
(void) offset; /* UNUSED */
@@ -2192,29 +2231,38 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
* data.
*/
compressed_buf = __archive_read_ahead(a, 1, &bytes_avail);
if (zip->entry_bytes_remaining > 0
&& bytes_avail > zip->entry_bytes_remaining) {
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
}
if (bytes_avail < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated lzma file body");
return (ARCHIVE_FATAL);
}
/* Set decompressor parameters. */
in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
zip_read_decrypt(zip, compressed_buf, in_bytes,
&compressed_buf, &in_bytes, &sp);
zip_read_decrypt(zip, compressed_buf, bytes_avail,
&compressed_buf, &bytes_avail, &sp);
zip->zipx_lzma_stream.next_in = compressed_buf;
zip->zipx_lzma_stream.avail_in = in_bytes;
zip->zipx_lzma_stream.avail_in = bytes_avail;
zip->zipx_lzma_stream.total_in = 0;
zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;
zip->zipx_lzma_stream.avail_out =
/* These lzma_alone streams lack end of stream marker, so let's
* make sure the unpacker won't try to unpack more than it's
* supposed to. */
(size_t)zipmin((int64_t) zip->uncompressed_buffer_size,
zip->entry->uncompressed_size -
zip->entry_uncompressed_bytes_read);
/* These lzma_alone streams lack an end of stream marker in some
* cases, so when the uncompressed size is known we cap avail_out to
* make sure the unpacker won't try to unpack more than it's supposed
* to. When the compressed size is unknown (entry_bytes_remaining <= 0,
* e.g. ZIP_LENGTH_AT_END from a non-seekable source) we must use the
* full buffer and rely on the LZMA stream end marker to detect the end
* of the entry. */
if (zip->entry_bytes_remaining <= 0) {
zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;
} else {
zip->zipx_lzma_stream.avail_out =
(size_t)zipmin((int64_t) zip->uncompressed_buffer_size,
zip->entry->uncompressed_size -
zip->entry_uncompressed_bytes_read);
}
zip->zipx_lzma_stream.total_out = 0;
/* Perform the decompression. */
@@ -2228,8 +2276,11 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
/* This case is optional in lzma alone format. It can happen,
* but most of the files don't have it. (GitHub #1257) */
case LZMA_STREAM_END:
/* This assertion is only possible if the size of the
* compressed data stream is known. */
if((int64_t) zip->zipx_lzma_stream.total_in !=
zip->entry_bytes_remaining)
zip->entry_bytes_remaining
&& zip->entry_bytes_remaining > 0)
{
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
@@ -2245,7 +2296,13 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
case LZMA_BUF_ERROR:
if (zip->zipx_lzma_stream.avail_out == 0) {
zip->end_of_entry = 1;
/* The output buffer was filled exactly. When
* the uncompressed size is known this means we
* have decompressed all expected bytes. When
* the size is unknown a full buffer just means
* we need another iteration. */
if (zip->entry_bytes_remaining > 0)
zip->end_of_entry = 1;
break;
}
/* FALL THROUGH */
@@ -2259,14 +2316,16 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
/* Update pointers. */
__archive_read_consume(a, to_consume);
zip->entry_bytes_remaining -= to_consume;
zip->entry_compressed_bytes_read += to_consume;
zip->entry_uncompressed_bytes_read += zip->zipx_lzma_stream.total_out;
zip_read_decrypt_update(zip, to_consume, sp);
if(zip->entry_bytes_remaining == 0) {
zip->end_of_entry = 1;
if(zip->entry_bytes_remaining > 0) {
zip->entry_bytes_remaining -= to_consume;
if(zip->entry_bytes_remaining == 0) {
zip->end_of_entry = 1;
}
}
if(zip->end_of_entry && zip->entry_bytes_remaining > 0) {
@@ -2537,7 +2596,7 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
struct zip *zip = (struct zip *)(a->format->data);
ssize_t bytes_avail = 0, in_bytes, to_consume;
ssize_t bytes_avail = 0, to_consume;
const void *compressed_buff;
const void *sp;
int r;
@@ -2554,30 +2613,26 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
/* Fetch more compressed bytes. */
compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
if(bytes_avail < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated bzip2 file body");
return (ARCHIVE_FATAL);
if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
&& bytes_avail > zip->entry_bytes_remaining) {
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
}
in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
if(in_bytes < 1) {
if(bytes_avail < 1) {
/* libbz2 doesn't complain when caller feeds avail_in == 0.
* It will actually return success in this case, which is
* undesirable. This is why we need to make this check
* manually. */
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated bzip2 file body");
return (ARCHIVE_FATAL);
}
zip_read_decrypt(zip, compressed_buff, in_bytes,
&compressed_buff, &in_bytes, &sp);
zip_read_decrypt(zip, compressed_buff, bytes_avail,
&compressed_buff, &bytes_avail, &sp);
/* Setup buffer boundaries. */
zip->bzstream.next_in = (char*)(uintptr_t) compressed_buff;
zip->bzstream.avail_in = (uint32_t)in_bytes;
zip->bzstream.avail_in = (uint32_t)bytes_avail;
zip->bzstream.total_in_hi32 = 0;
zip->bzstream.total_in_lo32 = 0;
zip->bzstream.next_out = (char*) zip->uncompressed_buffer;
@@ -2692,7 +2747,7 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
struct zip *zip = (struct zip *)(a->format->data);
ssize_t bytes_avail = 0, in_bytes, to_consume;
ssize_t bytes_avail = 0, to_consume;
const void *compressed_buff;
const void *sp;
int r;
@@ -2712,14 +2767,11 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
/* Fetch more compressed bytes */
compressed_buff = sp = __archive_read_ahead(a, 1, &bytes_avail);
if(bytes_avail < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated zstd file body");
return (ARCHIVE_FATAL);
if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
&& bytes_avail > zip->entry_bytes_remaining) {
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
}
in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
if(in_bytes < 1) {
if(bytes_avail < 1) {
/* zstd doesn't complain when caller feeds avail_in == 0.
* It will actually return success in this case, which is
* undesirable. This is why we need to make this check
@@ -2729,12 +2781,12 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
return (ARCHIVE_FATAL);
}
zip_read_decrypt(zip, compressed_buff, in_bytes,
&compressed_buff, &in_bytes, &sp);
zip_read_decrypt(zip, compressed_buff, bytes_avail,
&compressed_buff, &bytes_avail, &sp);
/* Setup buffer boundaries */
in.src = compressed_buff;
in.size = in_bytes;
in.size = bytes_avail;
in.pos = 0;
out = (ZSTD_outBuffer) { zip->uncompressed_buffer, zip->uncompressed_buffer_size, 0 };
@@ -2746,6 +2798,10 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
ZSTD_getErrorName(ret));
return (ARCHIVE_FATAL);
}
/* End of stream handling for zips with ZIP_LENGTH_AT_END flag */
if (ret == 0 && (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {
zip->end_of_entry = 1;
}
/* Check end of the stream. */
if (ret == 0) {
@@ -0,0 +1,16 @@
begin 644 test_read_format_zip_ppmd8_aes256_streaming.zipx
M4$L#!#\`"0!C`+:\T%P````````````````2``L`96YC<GEP=&5D7V9I;&4N
M='AT`9D'``(`044#8@!0DU<O)`#\`^#5`+;![K',-BB=Y1/1$;^7ZX-Z>LH8
MT/WJTW6S)$X63"#%E92J_MH4!H:N8BQR;/??F]NDA!],NJ07_%G39I2[AOO)
MYVZ#VPVEDCRXSI217JP'Y5PF\GZUC'Z0\:2YWQ%@E`R4]($CP5)2^!8BFGSV
M%7)I0I\5+7./\#\(K@D&[QFV49JSSRFT+'=%<EWYK'Z!?]H)\O_ZA#),OLL[
MI9V1VN;\2<,&*+O)OUCF`M)<?BWXN=/A7G6*X\@[X-A5S`*RLV5V"JN@V]75
ML`D296YS&G>/`U%6A=SSF`$C`-&F8B[77W4P?*7N.-*`4'TYPI,H?X)Q8^+2
MP5KY,(.%H:+XGUL@GS'E21\)U^/?G5Y',@X&98JH@1Z=4FLZ";,H6@I%\%?Q
MA6LR]Y$MP7@AJEH]5-QAOF:OX*)*7C/H23QFQ\--HU#7^K<J?3:?<SB9EMF8
M;))S,7%<T"+;Y@I8-61DVLX;J/%+!5!+`0(_`S\``0!C`+:\T%P`````<`$`
M`/\!```2`"\`````````(("D@0````!E;F-R>7!T961?9FEL92YT>'0*`"``
M``````$`&`!TGW-<V/W<`>UY<US8_=P!=)]S7-C]W`$!F0<``@!!10-B`%!+
4!08``````0`!`&\```"K`0``````
`
end
@@ -37,9 +37,26 @@ static const char file_data[] =
"discotheques provide jukeboxes. Crazy Frederick bought many very\n"
"exquisite opal jewels. We promptly judged antique ivory buckles\n"
"for the next prize. Sixty zippers were quickly picked from the bag.\n";
static const size_t file_size = sizeof(file_data) - 1;
struct streaming_buffer {
const char *data;
la_ssize_t len;
size_t pos;
int served;
};
static la_ssize_t read_streaming_buffer(struct archive *a, void *_client_data, const void **buffer) {
(void)a;
struct streaming_buffer *buff = _client_data;
if (buff->served) return 0;
*buffer = buff->data;
buff->served = 1;
return buff->len;
}
static void
validate_entry_read(struct archive *a, const char* msg)
validate_entry_read(struct archive *a, const char* msg, const int streaming_reader)
{
struct archive_entry *ae;
size_t total_read;
@@ -48,8 +65,10 @@ validate_entry_read(struct archive *a, const char* msg)
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("encrypted_file.txt", archive_entry_pathname(ae));
assertEqualInt((int)(sizeof(file_data) - 1),
archive_entry_size(ae));
if (!streaming_reader)
assertEqualInt((int)file_size, (int)archive_entry_size(ae));
else
assertEqualInt(archive_entry_size(ae), 0);
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
total_read = 0;
@@ -65,18 +84,79 @@ validate_entry_read(struct archive *a, const char* msg)
assertEqualMem(readbuf, file_data + total_read, (size_t)r);
total_read += (size_t)r;
}
assertEqualInt((int)total_read, (int)(sizeof(file_data) - 1));
assertEqualInt((int)total_read, (int)file_size);
}
static void
test_encrypted_zipx(const char *compression_name)
test_encrypted_zipx_read_mem(char* buff, size_t used)
{
struct archive *a;
struct archive_entry *ae;
char readbuf[1024];
/* ---- Read back without password — should fail ---- */
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("encrypted_file.txt", archive_entry_pathname(ae));
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, readbuf, sizeof(readbuf)));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/* ---- Read back with correct password ---- */
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_add_passphrase(a, password));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
validate_entry_read(a, "archive_read_data returned %d: %s", 0);
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/* ---- Seeking reader with correct password ---- */
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_add_passphrase(a, password));
assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, buff, used, 7));
validate_entry_read(a, "seek: archive_read_data returned %d: %s", 0);
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
static void
test_encrypted_zipx_read_callback(const char* buff, const size_t used)
{
struct archive *a;
struct streaming_buffer stream_buffer = { buff, used, 0, 0 };
/* ---- Read back with correct password ---- */
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_add_passphrase(a, password));
/* NOTE: archive_read_open2 with read callback only -> NON-seekable. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_open2(a, &stream_buffer, NULL, read_streaming_buffer, NULL, NULL));
validate_entry_read(a, "archive_read_data returned %d: %s", 1);
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
static void
test_encrypted_zipx(const char *compression_name, const int streaming_entry)
{
struct archive *a;
struct archive_entry *ae;
size_t used;
size_t buffsize = 1000000;
char *buff;
char readbuf[1024];
buff = malloc(buffsize);
assert(buff != NULL);
@@ -109,74 +189,79 @@ test_encrypted_zipx(const char *compression_name)
archive_entry_set_mtime(ae, 1, 0);
archive_entry_copy_pathname(ae, "encrypted_file.txt");
archive_entry_set_mode(ae, AE_IFREG | 0644);
archive_entry_set_size(ae, sizeof(file_data) - 1);
if (!streaming_entry)
archive_entry_set_size(ae, file_size);
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
assertEqualInt(sizeof(file_data) - 1, archive_write_data(a, file_data, sizeof(file_data) - 1));
assertEqualInt(file_size, archive_write_data(a, file_data, file_size));
archive_entry_free(ae);
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
/* ---- Read back without password — should fail ---- */
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("encrypted_file.txt", archive_entry_pathname(ae));
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, readbuf, sizeof(readbuf)));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/* ---- Read back with correct password ---- */
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_add_passphrase(a, password));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
validate_entry_read(a, "archive_read_data returned %d: %s");
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/* ---- Seeking reader with correct password ---- */
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_add_passphrase(a, password));
assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, buff, used, 7));
validate_entry_read(a, "seek: archive_read_data returned %d: %s");
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
test_encrypted_zipx_read_mem(buff, used);
test_encrypted_zipx_read_callback(buff, used);
free(buff);
}
DEFINE_TEST(test_read_format_zip_deflate_encrypted)
{
test_encrypted_zipx("zip:compression=deflate");
test_encrypted_zipx("zip:compression=deflate", 0);
}
DEFINE_TEST(test_read_format_zip_zipx_bzip2_encrypted)
{
test_encrypted_zipx("zip:compression=bzip2");
test_encrypted_zipx("zip:compression=bzip2", 0);
}
DEFINE_TEST(test_read_format_zip_zipx_lzma_encrypted)
{
test_encrypted_zipx("zip:compression=lzma");
test_encrypted_zipx("zip:compression=lzma", 0);
}
DEFINE_TEST(test_read_format_zip_zipx_xz_encrypted)
{
test_encrypted_zipx("zip:compression=xz");
test_encrypted_zipx("zip:compression=xz", 0);
}
DEFINE_TEST(test_read_format_zip_zipx_zstd_encrypted)
{
test_encrypted_zipx("zip:compression=zstd");
test_encrypted_zipx("zip:compression=zstd", 0);
}
DEFINE_TEST(test_read_format_zip_deflate_encrypted_streaming)
{
test_encrypted_zipx("zip:compression=deflate", 1);
}
DEFINE_TEST(test_read_format_zip_zipx_bzip2_encrypted_streaming)
{
test_encrypted_zipx("zip:compression=bzip2", 1);
}
DEFINE_TEST(test_read_format_zip_zipx_lzma_encrypted_streaming)
{
test_encrypted_zipx("zip:compression=lzma", 1);
}
DEFINE_TEST(test_read_format_zip_zipx_xz_encrypted_streaming)
{
test_encrypted_zipx("zip:compression=xz", 1);
}
DEFINE_TEST(test_read_format_zip_zipx_zstd_encrypted_streaming)
{
test_encrypted_zipx("zip:compression=zstd", 1);
}
DEFINE_TEST(test_read_format_zip_ppmd8_aes256_streaming)
{
const char *refname = "test_read_format_zip_ppmd8_aes256_streaming.zipx";
size_t used;
char buff[600];
extract_reference_file(refname);
FILE *f = fopen(refname, "rb");
used = fread(buff, 1, sizeof(buff), f);
fclose(f);
test_encrypted_zipx_read_mem(buff, used);
test_encrypted_zipx_read_callback(buff, used);
}