Move maximum compressed size computation to algorithms.
diff --git a/developer-xcode/libzip.xcodeproj/project.pbxproj b/developer-xcode/libzip.xcodeproj/project.pbxproj
index ae980ee..5a2de5e 100644
--- a/developer-xcode/libzip.xcodeproj/project.pbxproj
+++ b/developer-xcode/libzip.xcodeproj/project.pbxproj
@@ -189,6 +189,7 @@
4B93995E24631B3E00AEBDA4 /* zip_source_file.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B93995924631B3E00AEBDA4 /* zip_source_file.h */; };
4B972050188EBE85002FAFAD /* zip_file_get_external_attributes.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B97204D188EBE85002FAFAD /* zip_file_get_external_attributes.c */; };
4B972052188EBE85002FAFAD /* zip_file_set_external_attributes.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B97204E188EBE85002FAFAD /* zip_file_set_external_attributes.c */; };
+ 4B9E577C24C7202000CEE0D6 /* zip_algorithm_zstd.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B9E577A24C7026B00CEE0D6 /* zip_algorithm_zstd.c */; };
4BACD59315BC2CFA00920691 /* libzip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D68B15B2F3F1002D5007 /* libzip.framework */; };
4BACD59415BC2D0800920691 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D70815B2F4CF002D5007 /* libz.dylib */; };
4BACD5BB15BC2DC900920691 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D70815B2F4CF002D5007 /* libz.dylib */; };
@@ -1979,6 +1980,7 @@
4B01D6D015B2F46B002D5007 /* zip_get_num_files.c in Sources */,
4B01D6D115B2F46B002D5007 /* zip_memdup.c in Sources */,
4B01D6D215B2F46B002D5007 /* zip_name_locate.c in Sources */,
+ 4B9E577C24C7202000CEE0D6 /* zip_algorithm_zstd.c in Sources */,
4B01D6D315B2F46B002D5007 /* zip_new.c in Sources */,
4B01D6D415B2F46B002D5007 /* zip_open.c in Sources */,
4B01D6D515B2F46B002D5007 /* zip_rename.c in Sources */,
diff --git a/lib/zip_algorithm_bzip2.c b/lib/zip_algorithm_bzip2.c
index a4f27e5..c114987 100644
--- a/lib/zip_algorithm_bzip2.c
+++ b/lib/zip_algorithm_bzip2.c
@@ -46,6 +46,16 @@
};
+static zip_uint64_t maximum_compressed_size(zip_uint64_t uncompressed_size) {
+ zip_uint64_t compressed_size = (zip_uint64_t)((double)uncompressed_size * 1.006);
+
+ if (compressed_size < uncompressed_size) {
+ return ZIP_UINT64_MAX;
+ }
+ return compressed_size;
+}
+
+
static void *
allocate(bool compress, int compression_flags, zip_error_t *error) {
struct ctx *ctx;
@@ -245,6 +255,7 @@
/* clang-format off */
zip_compression_algorithm_t zip_algorithm_bzip2_compress = {
+ maximum_compressed_size,
compress_allocate,
deallocate,
general_purpose_bit_flags,
@@ -258,6 +269,7 @@
zip_compression_algorithm_t zip_algorithm_bzip2_decompress = {
+ maximum_compressed_size,
decompress_allocate,
deallocate,
general_purpose_bit_flags,
diff --git a/lib/zip_algorithm_deflate.c b/lib/zip_algorithm_deflate.c
index d28a1ac..c108e43 100644
--- a/lib/zip_algorithm_deflate.c
+++ b/lib/zip_algorithm_deflate.c
@@ -34,6 +34,7 @@
#include "zipint.h"
#include <limits.h>
+#include <math.h>
#include <stdlib.h>
#include <zlib.h>
@@ -46,6 +47,18 @@
};
+static zip_uint64_t maximum_compressed_size(zip_uint64_t uncompressed_size) {
+ /* max deflate size increase: size + ceil(size/16k)*5+6 */
+
+ zip_uint64_t compressed_size = uncompressed_size + (zip_uint64_t)ceil((double)uncompressed_size/(16*1024) * 5) + 6;
+
+ if (compressed_size < uncompressed_size) {
+ return ZIP_UINT64_MAX;
+ }
+ return compressed_size;
+}
+
+
static void *
allocate(bool compress, int compression_flags, zip_error_t *error) {
struct ctx *ctx;
@@ -223,6 +236,7 @@
/* clang-format off */
zip_compression_algorithm_t zip_algorithm_deflate_compress = {
+ maximum_compressed_size,
compress_allocate,
deallocate,
general_purpose_bit_flags,
@@ -236,6 +250,7 @@
zip_compression_algorithm_t zip_algorithm_deflate_decompress = {
+ maximum_compressed_size,
decompress_allocate,
deallocate,
general_purpose_bit_flags,
diff --git a/lib/zip_algorithm_xz.c b/lib/zip_algorithm_xz.c
index 945ab4e..1920566 100644
--- a/lib/zip_algorithm_xz.c
+++ b/lib/zip_algorithm_xz.c
@@ -49,6 +49,25 @@
};
+static zip_uint64_t maximum_compressed_size(zip_uint64_t uncompressed_size) {
+ /*
+ According to https://sourceforge.net/p/sevenzip/discussion/45797/thread/b6bd62f8/
+
+ 1) you can use
+ outSize = 1.10 * originalSize + 64 KB.
+ in most cases outSize is less then 1.02 from originalSize.
+ 2) You can try LZMA2, where
+ outSize can be = 1.001 * originalSize + 1 KB.
+ */
+ zip_uint64_t compressed_size = (zip_uint64_t)((double)uncompressed_size * 1.1) + 64 * 1024;
+
+ if (compressed_size < uncompressed_size) {
+ return ZIP_UINT64_MAX;
+ }
+ return compressed_size;
+}
+
+
static void *
allocate(bool compress, int compression_flags, zip_error_t *error, zip_uint16_t method) {
struct ctx *ctx;
@@ -222,6 +241,7 @@
/* clang-format off */
zip_compression_algorithm_t zip_algorithm_xz_compress = {
+ maximum_compressed_size,
compress_allocate,
deallocate,
general_purpose_bit_flags,
@@ -235,6 +255,7 @@
zip_compression_algorithm_t zip_algorithm_xz_decompress = {
+ maximum_compressed_size,
decompress_allocate,
deallocate,
general_purpose_bit_flags,
diff --git a/lib/zip_algorithm_zstd.c b/lib/zip_algorithm_zstd.c
index 025a46d..3272956 100644
--- a/lib/zip_algorithm_zstd.c
+++ b/lib/zip_algorithm_zstd.c
@@ -49,6 +49,10 @@
ZSTD_inBuffer in;
};
+static zip_uint64_t maximum_compressed_size(zip_uint64_t uncompressed_size) {
+ return ZSTD_compressBound(uncompressed_size);
+}
+
static void *
allocate(bool compress, int compression_flags, zip_error_t *error) {
@@ -260,6 +264,7 @@
does not unpack it if the value is not 20. */
zip_compression_algorithm_t zip_algorithm_zstd_compress = {
+ maximum_compressed_size,
compress_allocate,
deallocate,
general_purpose_bit_flags,
@@ -273,6 +278,7 @@
zip_compression_algorithm_t zip_algorithm_zstd_decompress = {
+ maximum_compressed_size,
decompress_allocate,
deallocate,
general_purpose_bit_flags,
diff --git a/lib/zip_close.c b/lib/zip_close.c
index e90e839..fb47f0a 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -333,29 +333,23 @@
data_length = (zip_int64_t)st.size;
if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {
- zip_uint64_t max_size;
+ zip_uint64_t max_compressed_size;
+ zip_uint16_t compression_method = ZIP_CM_ACTUAL(de->comp_method);
- switch (ZIP_CM_ACTUAL(de->comp_method)) {
- case ZIP_CM_BZIP2:
- /* computed by looking at increase of 10 random files of size 1MB when
- * compressed with bzip2, rounded up: 1.006 */
- max_size = 4269351188u;
- break;
+ if (compression_method == ZIP_CM_STORE) {
+ max_compressed_size = st.size;
+ }
+ else {
+ zip_compression_algorithm_t *algorithm = _zip_get_compression_algorithm(compression_method, true);
+ if (algorithm == NULL) {
+ max_compressed_size = ZIP_UINT64_MAX;
+ }
+ else {
+ max_compressed_size = algorithm->maximum_compressed_size(st.size);
+ }
+ }
- case ZIP_CM_DEFLATE:
- /* max deflate size increase: size + ceil(size/16k)*5+6 */
- max_size = 4293656963u;
- break;
-
- case ZIP_CM_STORE:
- max_size = 0xffffffffu;
- break;
-
- default:
- max_size = 0;
- }
-
- if (st.size > max_size) {
+ if (max_compressed_size > 0xffffffffu) {
flags |= ZIP_FL_FORCE_ZIP64;
}
}
diff --git a/lib/zip_source_compress.c b/lib/zip_source_compress.c
index 1c4c8bd..a304322 100644
--- a/lib/zip_source_compress.c
+++ b/lib/zip_source_compress.c
@@ -89,8 +89,8 @@
static struct context *context_new(zip_int32_t method, bool compress, int compression_flags, zip_compression_algorithm_t *algorithm);
static zip_int64_t compress_read(zip_source_t *, struct context *, void *, zip_uint64_t);
-static zip_compression_algorithm_t *
-get_algorithm(zip_int32_t method, bool compress) {
+zip_compression_algorithm_t *
+_zip_get_compression_algorithm(zip_int32_t method, bool compress) {
size_t i;
zip_uint16_t real_method = ZIP_CM_ACTUAL(method);
@@ -113,7 +113,7 @@
if (method == ZIP_CM_STORE) {
return 1;
}
- return get_algorithm(method, compress) != NULL;
+ return _zip_get_compression_algorithm(method, compress) != NULL;
}
zip_source_t *
@@ -138,7 +138,7 @@
return NULL;
}
- if ((algorithm = get_algorithm(method, compress)) == NULL) {
+ if ((algorithm = _zip_get_compression_algorithm(method, compress)) == NULL) {
zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
return NULL;
}
diff --git a/lib/zipint.h b/lib/zipint.h
index 139eb98..0dbb507 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -121,6 +121,9 @@
typedef enum zip_compression_status zip_compression_status_t;
struct zip_compression_algorithm {
+ /* Return maxiumum compressed size for uncompressed data of given size. */
+ zip_uint64_t (*maximum_compressed_size)(zip_uint64_t uncompressed_size);
+
/* called once to create new context */
void *(*allocate)(zip_uint16_t method, int compression_flags, zip_error_t *error);
/* called once to free context */
@@ -156,6 +159,7 @@
extern zip_compression_algorithm_t zip_algorithm_zstd_compress;
extern zip_compression_algorithm_t zip_algorithm_zstd_decompress;
+zip_compression_algorithm_t *_zip_get_compression_algorithm(zip_int32_t method, bool compress);
/* This API is not final yet, but we need it internally, so it's private for now. */