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. */