Merge pull request #163 from farindk/master

fix compiler warning for double macro definition
diff --git a/NEWS.md b/NEWS.md
index 30bd14b..ba8a793 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -4,6 +4,7 @@
 * Add support for encrypting using traditional PKWare encryption.
 * Add `zip_compression_method_supported()`.
 * Add `zip_encryption_method_supported()`.
+* Add the `ZIP_SOURCE_GET_FILE_ATTRIBUTES` source command
 
 1.6.1 [2020-02-03]
 ==================
diff --git a/developer-xcode/libzip.xcodeproj/project.pbxproj b/developer-xcode/libzip.xcodeproj/project.pbxproj
index 9500044..2e360f3 100644
--- a/developer-xcode/libzip.xcodeproj/project.pbxproj
+++ b/developer-xcode/libzip.xcodeproj/project.pbxproj
@@ -165,7 +165,6 @@
 		4B01D72615B2F57F002D5007 /* zipmerge.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B01D72215B2F572002D5007 /* zipmerge.c */; };
 		4B01D73215B2F5EE002D5007 /* zipconf.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BDC729E15B1B4E900236D3C /* zipconf.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		4B01D73C15B2F6AF002D5007 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D70815B2F4CF002D5007 /* libz.dylib */; };
-		4B0454B81E8E3E02002FA1F9 /* zip_source_get_compression_flags.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B71E8E3DF7002FA1F9 /* zip_source_get_compression_flags.c */; };
 		4B0454BA1E8E3E08002FA1F9 /* zip_source_compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B61E8E3DF7002FA1F9 /* zip_source_compress.c */; };
 		4B0454BC1E8E3E24002FA1F9 /* zip_algorithm_bzip2.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B41E8E3DF7002FA1F9 /* zip_algorithm_bzip2.c */; };
 		4B0454BD1E8E3E24002FA1F9 /* zip_algorithm_deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B51E8E3DF7002FA1F9 /* zip_algorithm_deflate.c */; };
@@ -180,6 +179,7 @@
 		4B51DDC21FDAE25F00C5CA85 /* ziptool_regress.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B51DDB31FDAE1DB00C5CA85 /* ziptool_regress.c */; };
 		4B51DDC31FDAE26600C5CA85 /* source_hole.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD6CB5C19E6A5D900710654 /* source_hole.c */; };
 		4B542C2C22B12E3900960B38 /* zip_random_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 736ED9B81E3D688C00C36873 /* zip_random_unix.c */; };
+		4B5D0CD5244B154E006C2E93 /* zip_source_get_file_attributes.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B5D0CD4244B154E006C2E93 /* zip_source_get_file_attributes.c */; };
 		4B69E6EE2032F18B0001EEE7 /* zip_winzip_aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B69E6ED2032F1870001EEE7 /* zip_winzip_aes.c */; };
 		4B82CED519915F360097BC18 /* zip_file_set_mtime.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B82CED319915F360097BC18 /* zip_file_set_mtime.c */; };
 		4B908F532385BE6D00886355 /* zip_libzip_version.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B908F502385BE6C00886355 /* zip_libzip_version.c */; };
@@ -528,7 +528,6 @@
 		4B0454B41E8E3DF7002FA1F9 /* zip_algorithm_bzip2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_algorithm_bzip2.c; sourceTree = "<group>"; };
 		4B0454B51E8E3DF7002FA1F9 /* zip_algorithm_deflate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_algorithm_deflate.c; sourceTree = "<group>"; };
 		4B0454B61E8E3DF7002FA1F9 /* zip_source_compress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_source_compress.c; sourceTree = "<group>"; };
-		4B0454B71E8E3DF7002FA1F9 /* zip_source_get_compression_flags.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_source_get_compression_flags.c; sourceTree = "<group>"; };
 		4B1ABD1A1A2E5DA700C93867 /* links */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = links; sourceTree = "<group>"; };
 		4B1ABD1B1A2E5E4D00C93867 /* handle_links */ = {isa = PBXFileReference; explicitFileType = text.script.perl; fileEncoding = 4; path = handle_links; sourceTree = "<group>"; };
 		4B1E46E51A08CB7600A376D2 /* zip_error_code_system.mdoc */ = {isa = PBXFileReference; lastKnownFileType = text; path = zip_error_code_system.mdoc; sourceTree = "<group>"; };
@@ -613,6 +612,7 @@
 		4B51DDB21FDADEDF00C5CA85 /* INSTALL.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = INSTALL.md; sourceTree = "<group>"; };
 		4B51DDB31FDAE1DB00C5CA85 /* ziptool_regress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ziptool_regress.c; sourceTree = "<group>"; };
 		4B51DDC01FDAE20A00C5CA85 /* ziptool_regress */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ziptool_regress; sourceTree = BUILT_PRODUCTS_DIR; };
+		4B5D0CD4244B154E006C2E93 /* zip_source_get_file_attributes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_source_get_file_attributes.c; sourceTree = "<group>"; };
 		4B69E6ED2032F1870001EEE7 /* zip_winzip_aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_winzip_aes.c; sourceTree = "<group>"; };
 		4B69E6F020330D460001EEE7 /* zip_crypto_gnutls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_crypto_gnutls.c; sourceTree = "<group>"; };
 		4B69E6F2203341D50001EEE7 /* zip_crypto_gnutls.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = zip_crypto_gnutls.h; sourceTree = "<group>"; };
@@ -1485,7 +1485,7 @@
 				4BDC722E15B1B25E00236D3C /* zip_source_filep.c */,
 				4BDC722F15B1B25E00236D3C /* zip_source_free.c */,
 				4BDC723015B1B25E00236D3C /* zip_source_function.c */,
-				4B0454B71E8E3DF7002FA1F9 /* zip_source_get_compression_flags.c */,
+				4B5D0CD4244B154E006C2E93 /* zip_source_get_file_attributes.c */,
 				4BE402AC19D94AE400298248 /* zip_source_is_deleted.c */,
 				4BDC723115B1B25E00236D3C /* zip_source_layered.c */,
 				4BDC723215B1B25E00236D3C /* zip_source_open.c */,
@@ -1896,7 +1896,6 @@
 				4B01D6AC15B2F46B002D5007 /* zip_dirent.c in Sources */,
 				4B00CA24242F59D700E0B71C /* zip_source_pkware_decode.c in Sources */,
 				4B01D6AD15B2F46B002D5007 /* zip_discard.c in Sources */,
-				4B0454B81E8E3E02002FA1F9 /* zip_source_get_compression_flags.c in Sources */,
 				4B00CA25242F59D700E0B71C /* zip_pkware.c in Sources */,
 				4B01D6AE15B2F46B002D5007 /* zip_entry.c in Sources */,
 				4B01D6AF15B2F46B002D5007 /* zip_err_str.c in Sources */,
@@ -1937,6 +1936,7 @@
 				4B01D6C815B2F46B002D5007 /* zip_fread.c in Sources */,
 				736ED9BF1E3D6B7C00C36873 /* zip_file_set_encryption.c in Sources */,
 				4B01D6C915B2F46B002D5007 /* zip_get_archive_comment.c in Sources */,
+				4B5D0CD5244B154E006C2E93 /* zip_source_get_file_attributes.c in Sources */,
 				4B01D6CA15B2F46B002D5007 /* zip_get_archive_flag.c in Sources */,
 				4BE92AB5203597D700509BC8 /* zip_crypto_commoncrypto.c in Sources */,
 				4B0454BC1E8E3E24002FA1F9 /* zip_algorithm_bzip2.c in Sources */,
@@ -2642,6 +2642,7 @@
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				HEADER_SEARCH_PATHS = (
 					/opt/pkg/include,
+					/usr/local/include,
 					../lib,
 					.,
 					../src,
@@ -2698,6 +2699,7 @@
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				HEADER_SEARCH_PATHS = (
 					/opt/pkg/include,
+					/usr/local/include,
 					../lib,
 					.,
 					../src,
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 8ac6af5..7683aed 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -133,12 +133,12 @@
   zip_source_filep.c
   zip_source_free.c
   zip_source_function.c
-  zip_source_get_compression_flags.c
+  zip_source_get_file_attributes.c
   zip_source_is_deleted.c
   zip_source_layered.c
   zip_source_open.c
-  zip_source_pkware_encode.c
   zip_source_pkware_decode.c
+  zip_source_pkware_encode.c
   zip_source_read.c
   zip_source_remove.c
   zip_source_rollback_write.c
diff --git a/lib/zip.h b/lib/zip.h
index ebedc1f..a90776d 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -161,8 +161,8 @@
 /* 13 - Reserved by PKWARE */
 #define ZIP_CM_LZMA 14 /* LZMA (EFS) */
 /* 15-17 - Reserved by PKWARE */
-#define ZIP_CM_TERSE 18   /* compressed using IBM TERSE (new) */
-#define ZIP_CM_LZ77 19    /* IBM LZ77 z Architecture (PFS) */
+#define ZIP_CM_TERSE 18 /* compressed using IBM TERSE (new) */
+#define ZIP_CM_LZ77 19  /* IBM LZ77 z Architecture (PFS) */
 #define ZIP_CM_LZMA2 33
 #define ZIP_CM_XZ 95      /* XZ compressed data */
 #define ZIP_CM_JPEG 96    /* Compressed Jpeg data */
@@ -214,25 +214,26 @@
 
 
 enum zip_source_cmd {
-    ZIP_SOURCE_OPEN,                  /* prepare for reading */
-    ZIP_SOURCE_READ,                  /* read data */
-    ZIP_SOURCE_CLOSE,                 /* reading is done */
-    ZIP_SOURCE_STAT,                  /* get meta information */
-    ZIP_SOURCE_ERROR,                 /* get error information */
-    ZIP_SOURCE_FREE,                  /* cleanup and free resources */
-    ZIP_SOURCE_SEEK,                  /* set position for reading */
-    ZIP_SOURCE_TELL,                  /* get read position */
-    ZIP_SOURCE_BEGIN_WRITE,           /* prepare for writing */
-    ZIP_SOURCE_COMMIT_WRITE,          /* writing is done */
-    ZIP_SOURCE_ROLLBACK_WRITE,        /* discard written changes */
-    ZIP_SOURCE_WRITE,                 /* write data */
-    ZIP_SOURCE_SEEK_WRITE,            /* set position for writing */
-    ZIP_SOURCE_TELL_WRITE,            /* get write position */
-    ZIP_SOURCE_SUPPORTS,              /* check whether source supports command */
-    ZIP_SOURCE_REMOVE,                /* remove file */
-    ZIP_SOURCE_GET_COMPRESSION_FLAGS, /* get compression flags, internal only */
-    ZIP_SOURCE_BEGIN_WRITE_CLONING,   /* like ZIP_SOURCE_BEGIN_WRITE, but keep part of original file */
-    ZIP_SOURCE_ACCEPT_EMPTY           /* whether empty files are valid archives */
+    ZIP_SOURCE_OPEN,                /* prepare for reading */
+    ZIP_SOURCE_READ,                /* read data */
+    ZIP_SOURCE_CLOSE,               /* reading is done */
+    ZIP_SOURCE_STAT,                /* get meta information */
+    ZIP_SOURCE_ERROR,               /* get error information */
+    ZIP_SOURCE_FREE,                /* cleanup and free resources */
+    ZIP_SOURCE_SEEK,                /* set position for reading */
+    ZIP_SOURCE_TELL,                /* get read position */
+    ZIP_SOURCE_BEGIN_WRITE,         /* prepare for writing */
+    ZIP_SOURCE_COMMIT_WRITE,        /* writing is done */
+    ZIP_SOURCE_ROLLBACK_WRITE,      /* discard written changes */
+    ZIP_SOURCE_WRITE,               /* write data */
+    ZIP_SOURCE_SEEK_WRITE,          /* set position for writing */
+    ZIP_SOURCE_TELL_WRITE,          /* get write position */
+    ZIP_SOURCE_SUPPORTS,            /* check whether source supports command */
+    ZIP_SOURCE_REMOVE,              /* remove file */
+    ZIP_SOURCE_RESERVED_1,          /* previously used internally */
+    ZIP_SOURCE_BEGIN_WRITE_CLONING, /* like ZIP_SOURCE_BEGIN_WRITE, but keep part of original file */
+    ZIP_SOURCE_ACCEPT_EMPTY,        /* whether empty files are valid archives */
+    ZIP_SOURCE_GET_FILE_ATTRIBUTES  /* get additional file attributes */
 };
 typedef enum zip_source_cmd zip_source_cmd_t;
 
@@ -276,9 +277,9 @@
 /* error information */
 /* use zip_error_*() to access */
 struct zip_error {
-    int zip_err; /* libzip error code (ZIP_ER_*) */
-    int sys_err; /* copy of errno (E*) or zlib error code */
-    char * _Nullable str;   /* string representation or NULL */
+    int zip_err;         /* libzip error code (ZIP_ER_*) */
+    int sys_err;         /* copy of errno (E*) or zlib error code */
+    char *_Nullable str; /* string representation or NULL */
 };
 
 #define ZIP_STAT_NAME 0x0001u
@@ -293,7 +294,7 @@
 
 struct zip_stat {
     zip_uint64_t valid;             /* which fields have valid values */
-    const char * _Nullable name;               /* name of the file */
+    const char *_Nullable name;     /* name of the file */
     zip_uint64_t index;             /* index within archive */
     zip_uint64_t size;              /* size of file (uncompressed) */
     zip_uint64_t comp_size;         /* size of file (compressed) */
@@ -305,10 +306,27 @@
 };
 
 struct zip_buffer_fragment {
-    zip_uint8_t * _Nonnull data;
+    zip_uint8_t *_Nonnull data;
     zip_uint64_t length;
 };
 
+struct zip_file_attributes {
+    zip_uint64_t valid;                     /* which fields have valid values */
+    zip_uint8_t version;                    /* version of this struct, currently 1 */
+    zip_uint8_t host_system;                /* host system on which file was created */
+    zip_uint8_t ascii;                      /* flag whether file is ASCII text */
+    zip_uint8_t version_needed;             /* minimum version needed to extract file */
+    zip_uint32_t external_file_attributes;  /* external file attributes (host-system specific) */
+    zip_uint16_t general_purpose_bit_flags; /* general purpose big flags, only some bits are honored */
+    zip_uint16_t general_purpose_bit_mask;  /* which bits in general_purpose_bit_flags are valid */
+};
+
+#define ZIP_FILE_ATTRIBUTES_HOST_SYSTEM 0x0001u
+#define ZIP_FILE_ATTRIBUTES_ASCII 0x0002u
+#define ZIP_FILE_ATTRIBUTES_VERSION_NEEDED 0x0004u
+#define ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES 0x0008u
+#define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS 0x0010u
+
 struct zip;
 struct zip_file;
 struct zip_source;
@@ -316,121 +334,124 @@
 typedef struct zip zip_t;
 typedef struct zip_error zip_error_t;
 typedef struct zip_file zip_file_t;
+typedef struct zip_file_attributes zip_file_attributes_t;
 typedef struct zip_source zip_source_t;
 typedef struct zip_stat zip_stat_t;
 typedef struct zip_buffer_fragment zip_buffer_fragment_t;
 
 typedef zip_uint32_t zip_flags_t;
 
-typedef zip_int64_t (*zip_source_callback)(void * _Nullable, void * _Nullable, zip_uint64_t, zip_source_cmd_t);
-typedef void (*zip_progress_callback)(zip_t * _Nonnull, double, void * _Nullable);
-typedef int (*zip_cancel_callback)(zip_t * _Nonnull, void * _Nullable);
+typedef zip_int64_t (*zip_source_callback)(void *_Nullable, void *_Nullable, zip_uint64_t, zip_source_cmd_t);
+typedef void (*zip_progress_callback)(zip_t *_Nonnull, double, void *_Nullable);
+typedef int (*zip_cancel_callback)(zip_t *_Nonnull, void *_Nullable);
 
 #ifndef ZIP_DISABLE_DEPRECATED
 typedef void (*zip_progress_callback_t)(double);
-ZIP_EXTERN void zip_register_progress_callback(zip_t * _Nonnull, zip_progress_callback_t _Nullable); /* use zip_register_progress_callback_with_state */
+ZIP_EXTERN void zip_register_progress_callback(zip_t *_Nonnull, zip_progress_callback_t _Nullable); /* use zip_register_progress_callback_with_state */
 
-ZIP_EXTERN zip_int64_t zip_add(zip_t * _Nonnull, const char * _Nonnull, zip_source_t * _Nonnull);          /* use zip_file_add */
-ZIP_EXTERN zip_int64_t zip_add_dir(zip_t * _Nonnull, const char * _Nonnull);                      /* use zip_dir_add */
-ZIP_EXTERN const char * _Nullable zip_get_file_comment(zip_t * _Nonnull, zip_uint64_t, int * _Nullable, int); /* use zip_file_get_comment */
-ZIP_EXTERN int zip_get_num_files(zip_t * _Nonnull);                                      /* use zip_get_num_entries instead */
-ZIP_EXTERN int zip_rename(zip_t * _Nonnull, zip_uint64_t, const char * _Nonnull);                 /* use zip_file_rename */
-ZIP_EXTERN int zip_replace(zip_t * _Nonnull, zip_uint64_t, zip_source_t * _Nonnull);              /* use zip_file_replace */
-ZIP_EXTERN int zip_set_file_comment(zip_t * _Nonnull, zip_uint64_t, const char * _Nullable, int);  /* use zip_file_set_comment */
-ZIP_EXTERN int zip_error_get_sys_type(int);                                     /* use zip_error_system_type */
-ZIP_EXTERN void zip_error_get(zip_t * _Nonnull, int * _Nullable, int * _Nullable);                           /* use zip_get_error, zip_error_code_zip / zip_error_code_system */
-ZIP_EXTERN int zip_error_to_str(char * _Nonnull, zip_uint64_t, int, int);                /* use zip_error_init_with_code / zip_error_strerror */
-ZIP_EXTERN void zip_file_error_get(zip_file_t * _Nonnull, int * _Nullable, int * _Nullable);                 /* use zip_file_get_error, zip_error_code_zip / zip_error_code_system */
+ZIP_EXTERN zip_int64_t zip_add(zip_t *_Nonnull, const char *_Nonnull, zip_source_t *_Nonnull);             /* use zip_file_add */
+ZIP_EXTERN zip_int64_t zip_add_dir(zip_t *_Nonnull, const char *_Nonnull);                                 /* use zip_dir_add */
+ZIP_EXTERN const char *_Nullable zip_get_file_comment(zip_t *_Nonnull, zip_uint64_t, int *_Nullable, int); /* use zip_file_get_comment */
+ZIP_EXTERN int zip_get_num_files(zip_t *_Nonnull);                                                         /* use zip_get_num_entries instead */
+ZIP_EXTERN int zip_rename(zip_t *_Nonnull, zip_uint64_t, const char *_Nonnull);                            /* use zip_file_rename */
+ZIP_EXTERN int zip_replace(zip_t *_Nonnull, zip_uint64_t, zip_source_t *_Nonnull);                         /* use zip_file_replace */
+ZIP_EXTERN int zip_set_file_comment(zip_t *_Nonnull, zip_uint64_t, const char *_Nullable, int);            /* use zip_file_set_comment */
+ZIP_EXTERN int zip_error_get_sys_type(int);                                                                /* use zip_error_system_type */
+ZIP_EXTERN void zip_error_get(zip_t *_Nonnull, int *_Nullable, int *_Nullable);                            /* use zip_get_error, zip_error_code_zip / zip_error_code_system */
+ZIP_EXTERN int zip_error_to_str(char *_Nonnull, zip_uint64_t, int, int);                                   /* use zip_error_init_with_code / zip_error_strerror */
+ZIP_EXTERN void zip_file_error_get(zip_file_t *_Nonnull, int *_Nullable, int *_Nullable);                  /* use zip_file_get_error, zip_error_code_zip / zip_error_code_system */
 #endif
 
-ZIP_EXTERN int zip_close(zip_t * _Nonnull);
-ZIP_EXTERN int zip_delete(zip_t * _Nonnull, zip_uint64_t);
-ZIP_EXTERN zip_int64_t zip_dir_add(zip_t * _Nonnull, const char * _Nonnull, zip_flags_t);
-ZIP_EXTERN void zip_discard(zip_t * _Nonnull);
+ZIP_EXTERN int zip_close(zip_t *_Nonnull);
+ZIP_EXTERN int zip_delete(zip_t *_Nonnull, zip_uint64_t);
+ZIP_EXTERN zip_int64_t zip_dir_add(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t);
+ZIP_EXTERN void zip_discard(zip_t *_Nonnull);
 
-ZIP_EXTERN zip_error_t * _Nonnull zip_get_error(zip_t * _Nonnull);
-ZIP_EXTERN void zip_error_clear(zip_t * _Nonnull);
-ZIP_EXTERN int zip_error_code_zip(const zip_error_t * _Nonnull);
-ZIP_EXTERN int zip_error_code_system(const zip_error_t * _Nonnull);
-ZIP_EXTERN void zip_error_fini(zip_error_t * _Nonnull);
-ZIP_EXTERN void zip_error_init(zip_error_t * _Nonnull);
-ZIP_EXTERN void zip_error_init_with_code(zip_error_t * _Nonnull, int);
-ZIP_EXTERN void zip_error_set(zip_error_t * _Nullable, int, int);
-ZIP_EXTERN const char * _Nonnull zip_error_strerror(zip_error_t * _Nonnull);
-ZIP_EXTERN int zip_error_system_type(const zip_error_t * _Nonnull);
-ZIP_EXTERN zip_int64_t zip_error_to_data(const zip_error_t * _Nonnull, void * _Nonnull, zip_uint64_t);
+ZIP_EXTERN zip_error_t *_Nonnull zip_get_error(zip_t *_Nonnull);
+ZIP_EXTERN void zip_error_clear(zip_t *_Nonnull);
+ZIP_EXTERN int zip_error_code_zip(const zip_error_t *_Nonnull);
+ZIP_EXTERN int zip_error_code_system(const zip_error_t *_Nonnull);
+ZIP_EXTERN void zip_error_fini(zip_error_t *_Nonnull);
+ZIP_EXTERN void zip_error_init(zip_error_t *_Nonnull);
+ZIP_EXTERN void zip_error_init_with_code(zip_error_t *_Nonnull, int);
+ZIP_EXTERN void zip_error_set(zip_error_t *_Nullable, int, int);
+ZIP_EXTERN const char *_Nonnull zip_error_strerror(zip_error_t *_Nonnull);
+ZIP_EXTERN int zip_error_system_type(const zip_error_t *_Nonnull);
+ZIP_EXTERN zip_int64_t zip_error_to_data(const zip_error_t *_Nonnull, void *_Nonnull, zip_uint64_t);
 
-ZIP_EXTERN int zip_fclose(zip_file_t * _Nonnull);
-ZIP_EXTERN zip_t * _Nullable zip_fdopen(int, int, int * _Nullable);
-ZIP_EXTERN zip_int64_t zip_file_add(zip_t * _Nonnull, const char * _Nonnull, zip_source_t * _Nonnull, zip_flags_t);
-ZIP_EXTERN void zip_file_error_clear(zip_file_t * _Nonnull);
-ZIP_EXTERN int zip_file_extra_field_delete(zip_t * _Nonnull, zip_uint64_t, zip_uint16_t, zip_flags_t);
-ZIP_EXTERN int zip_file_extra_field_delete_by_id(zip_t * _Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t);
-ZIP_EXTERN int zip_file_extra_field_set(zip_t * _Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, const zip_uint8_t * _Nullable, zip_uint16_t, zip_flags_t);
-ZIP_EXTERN zip_int16_t zip_file_extra_fields_count(zip_t * _Nonnull, zip_uint64_t, zip_flags_t);
-ZIP_EXTERN zip_int16_t zip_file_extra_fields_count_by_id(zip_t * _Nonnull, zip_uint64_t, zip_uint16_t, zip_flags_t);
-ZIP_EXTERN const zip_uint8_t * _Nullable zip_file_extra_field_get(zip_t * _Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t * _Nullable, zip_uint16_t * _Nullable, zip_flags_t);
-ZIP_EXTERN const zip_uint8_t * _Nullable zip_file_extra_field_get_by_id(zip_t * _Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_uint16_t * _Nullable, zip_flags_t);
-ZIP_EXTERN const char * _Nullable zip_file_get_comment(zip_t * _Nonnull, zip_uint64_t, zip_uint32_t * _Nullable, zip_flags_t);
-ZIP_EXTERN zip_error_t * _Nonnull zip_file_get_error(zip_file_t * _Nonnull);
-ZIP_EXTERN int zip_file_get_external_attributes(zip_t * _Nonnull, zip_uint64_t, zip_flags_t, zip_uint8_t * _Nullable, zip_uint32_t * _Nullable);
-ZIP_EXTERN int zip_file_rename(zip_t * _Nonnull, zip_uint64_t, const char * _Nonnull, zip_flags_t);
-ZIP_EXTERN int zip_file_replace(zip_t * _Nonnull, zip_uint64_t, zip_source_t * _Nonnull, zip_flags_t);
-ZIP_EXTERN int zip_file_set_comment(zip_t * _Nonnull, zip_uint64_t, const char * _Nullable, zip_uint16_t, zip_flags_t);
-ZIP_EXTERN int zip_file_set_dostime(zip_t * _Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t);
-ZIP_EXTERN int zip_file_set_encryption(zip_t * _Nonnull, zip_uint64_t, zip_uint16_t, const char * _Nullable);
-ZIP_EXTERN int zip_file_set_external_attributes(zip_t * _Nonnull, zip_uint64_t, zip_flags_t, zip_uint8_t, zip_uint32_t);
-ZIP_EXTERN int zip_file_set_mtime(zip_t * _Nonnull, zip_uint64_t, time_t, zip_flags_t);
-ZIP_EXTERN const char * _Nonnull zip_file_strerror(zip_file_t * _Nonnull);
-ZIP_EXTERN zip_file_t * _Nullable zip_fopen(zip_t * _Nonnull, const char * _Nonnull, zip_flags_t);
-ZIP_EXTERN zip_file_t * _Nullable zip_fopen_encrypted(zip_t * _Nonnull, const char * _Nonnull, zip_flags_t, const char * _Nullable);
-ZIP_EXTERN zip_file_t * _Nullable zip_fopen_index(zip_t * _Nonnull, zip_uint64_t, zip_flags_t);
-ZIP_EXTERN zip_file_t * _Nullable zip_fopen_index_encrypted(zip_t * _Nonnull, zip_uint64_t, zip_flags_t, const char * _Nullable);
-ZIP_EXTERN zip_int64_t zip_fread(zip_file_t * _Nonnull, void * _Nonnull, zip_uint64_t);
-ZIP_EXTERN zip_int8_t zip_fseek(zip_file_t * _Nonnull, zip_int64_t, int);
-ZIP_EXTERN zip_int64_t zip_ftell(zip_file_t * _Nonnull);
-ZIP_EXTERN const char * _Nullable zip_get_archive_comment(zip_t * _Nonnull, int * _Nullable, zip_flags_t);
-ZIP_EXTERN int zip_get_archive_flag(zip_t * _Nonnull, zip_flags_t, zip_flags_t);
-ZIP_EXTERN const char * _Nullable zip_get_name(zip_t * _Nonnull, zip_uint64_t, zip_flags_t);
-ZIP_EXTERN zip_int64_t zip_get_num_entries(zip_t * _Nonnull, zip_flags_t);
-ZIP_EXTERN const char * _Nonnull zip_libzip_version(void);
-ZIP_EXTERN zip_int64_t zip_name_locate(zip_t * _Nonnull, const char * _Nonnull, zip_flags_t);
-ZIP_EXTERN zip_t * _Nullable zip_open(const char * _Nonnull, int, int * _Nullable);
-ZIP_EXTERN zip_t * _Nullable zip_open_from_source(zip_source_t * _Nonnull, int, zip_error_t * _Nullable);
-ZIP_EXTERN int zip_register_progress_callback_with_state(zip_t * _Nonnull, double, zip_progress_callback _Nullable, void (* _Nullable)(void * _Nullable), void * _Nullable);
-ZIP_EXTERN int zip_register_cancel_callback_with_state(zip_t * _Nonnull, zip_cancel_callback _Nullable, void (* _Nullable)(void * _Nullable), void * _Nullable);
-ZIP_EXTERN int zip_set_archive_comment(zip_t * _Nonnull, const char * _Nullable, zip_uint16_t);
-ZIP_EXTERN int zip_set_archive_flag(zip_t * _Nonnull, zip_flags_t, int);
-ZIP_EXTERN int zip_set_default_password(zip_t * _Nonnull, const char * _Nullable);
-ZIP_EXTERN int zip_set_file_compression(zip_t * _Nonnull, zip_uint64_t, zip_int32_t, zip_uint32_t);
-ZIP_EXTERN int zip_source_begin_write(zip_source_t * _Nonnull);
-ZIP_EXTERN int zip_source_begin_write_cloning(zip_source_t * _Nonnull, zip_uint64_t);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_buffer(zip_t * _Nonnull, const void * _Nullable, zip_uint64_t, int);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_buffer_create(const void * _Nullable, zip_uint64_t, int, zip_error_t * _Nullable);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_buffer_fragment(zip_t * _Nonnull, const zip_buffer_fragment_t * _Nonnull, zip_uint64_t, int);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_buffer_fragment_create(const zip_buffer_fragment_t * _Nullable, zip_uint64_t, int, zip_error_t * _Nullable);
-ZIP_EXTERN int zip_source_close(zip_source_t * _Nonnull);
-ZIP_EXTERN int zip_source_commit_write(zip_source_t * _Nonnull);
-ZIP_EXTERN zip_error_t * _Nonnull zip_source_error(zip_source_t * _Nonnull);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_file(zip_t * _Nonnull, const char * _Nonnull, zip_uint64_t, zip_int64_t);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_file_create(const char * _Nonnull, zip_uint64_t, zip_int64_t, zip_error_t * _Nullable);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_filep(zip_t * _Nonnull, FILE * _Nonnull, zip_uint64_t, zip_int64_t);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_filep_create(FILE * _Nonnull, zip_uint64_t, zip_int64_t, zip_error_t * _Nullable);
-ZIP_EXTERN void zip_source_free(zip_source_t * _Nullable);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_function(zip_t * _Nonnull, zip_source_callback _Nonnull , void * _Nullable);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_function_create(zip_source_callback _Nonnull , void * _Nullable, zip_error_t * _Nullable);
-ZIP_EXTERN int zip_source_is_deleted(zip_source_t * _Nonnull);
-ZIP_EXTERN void zip_source_keep(zip_source_t * _Nonnull);
+ZIP_EXTERN int zip_fclose(zip_file_t *_Nonnull);
+ZIP_EXTERN zip_t *_Nullable zip_fdopen(int, int, int *_Nullable);
+ZIP_EXTERN zip_int64_t zip_file_add(zip_t *_Nonnull, const char *_Nonnull, zip_source_t *_Nonnull, zip_flags_t);
+ZIP_EXTERN void zip_file_attributes_init(zip_file_attributes_t *_Nonnull);
+ZIP_EXTERN void zip_file_error_clear(zip_file_t *_Nonnull);
+ZIP_EXTERN int zip_file_extra_field_delete(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN int zip_file_extra_field_delete_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN int zip_file_extra_field_set(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, const zip_uint8_t *_Nullable, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN zip_int16_t zip_file_extra_fields_count(zip_t *_Nonnull, zip_uint64_t, zip_flags_t);
+ZIP_EXTERN zip_int16_t zip_file_extra_fields_count_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN const zip_uint8_t *_Nullable zip_file_extra_field_get(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t *_Nullable, zip_uint16_t *_Nullable, zip_flags_t);
+ZIP_EXTERN const zip_uint8_t *_Nullable zip_file_extra_field_get_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_uint16_t *_Nullable, zip_flags_t);
+ZIP_EXTERN const char *_Nullable zip_file_get_comment(zip_t *_Nonnull, zip_uint64_t, zip_uint32_t *_Nullable, zip_flags_t);
+ZIP_EXTERN zip_error_t *_Nonnull zip_file_get_error(zip_file_t *_Nonnull);
+ZIP_EXTERN int zip_file_get_external_attributes(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint8_t *_Nullable, zip_uint32_t *_Nullable);
+ZIP_EXTERN int zip_file_rename(zip_t *_Nonnull, zip_uint64_t, const char *_Nonnull, zip_flags_t);
+ZIP_EXTERN int zip_file_replace(zip_t *_Nonnull, zip_uint64_t, zip_source_t *_Nonnull, zip_flags_t);
+ZIP_EXTERN int zip_file_set_comment(zip_t *_Nonnull, zip_uint64_t, const char *_Nullable, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN int zip_file_set_dostime(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN int zip_file_set_encryption(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, const char *_Nullable);
+ZIP_EXTERN int zip_file_set_external_attributes(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint8_t, zip_uint32_t);
+ZIP_EXTERN int zip_file_set_mtime(zip_t *_Nonnull, zip_uint64_t, time_t, zip_flags_t);
+ZIP_EXTERN const char *_Nonnull zip_file_strerror(zip_file_t *_Nonnull);
+ZIP_EXTERN zip_file_t *_Nullable zip_fopen(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t);
+ZIP_EXTERN zip_file_t *_Nullable zip_fopen_encrypted(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t, const char *_Nullable);
+ZIP_EXTERN zip_file_t *_Nullable zip_fopen_index(zip_t *_Nonnull, zip_uint64_t, zip_flags_t);
+ZIP_EXTERN zip_file_t *_Nullable zip_fopen_index_encrypted(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, const char *_Nullable);
+ZIP_EXTERN zip_int64_t zip_fread(zip_file_t *_Nonnull, void *_Nonnull, zip_uint64_t);
+ZIP_EXTERN zip_int8_t zip_fseek(zip_file_t *_Nonnull, zip_int64_t, int);
+ZIP_EXTERN zip_int64_t zip_ftell(zip_file_t *_Nonnull);
+ZIP_EXTERN const char *_Nullable zip_get_archive_comment(zip_t *_Nonnull, int *_Nullable, zip_flags_t);
+ZIP_EXTERN int zip_get_archive_flag(zip_t *_Nonnull, zip_flags_t, zip_flags_t);
+ZIP_EXTERN const char *_Nullable zip_get_name(zip_t *_Nonnull, zip_uint64_t, zip_flags_t);
+ZIP_EXTERN zip_int64_t zip_get_num_entries(zip_t *_Nonnull, zip_flags_t);
+ZIP_EXTERN const char *_Nonnull zip_libzip_version(void);
+ZIP_EXTERN zip_int64_t zip_name_locate(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t);
+ZIP_EXTERN zip_t *_Nullable zip_open(const char *_Nonnull, int, int *_Nullable);
+ZIP_EXTERN zip_t *_Nullable zip_open_from_source(zip_source_t *_Nonnull, int, zip_error_t *_Nullable);
+ZIP_EXTERN int zip_register_progress_callback_with_state(zip_t *_Nonnull, double, zip_progress_callback _Nullable, void (*_Nullable)(void *_Nullable), void *_Nullable);
+ZIP_EXTERN int zip_register_cancel_callback_with_state(zip_t *_Nonnull, zip_cancel_callback _Nullable, void (*_Nullable)(void *_Nullable), void *_Nullable);
+ZIP_EXTERN int zip_set_archive_comment(zip_t *_Nonnull, const char *_Nullable, zip_uint16_t);
+ZIP_EXTERN int zip_set_archive_flag(zip_t *_Nonnull, zip_flags_t, int);
+ZIP_EXTERN int zip_set_default_password(zip_t *_Nonnull, const char *_Nullable);
+ZIP_EXTERN int zip_set_file_compression(zip_t *_Nonnull, zip_uint64_t, zip_int32_t, zip_uint32_t);
+ZIP_EXTERN int zip_source_begin_write(zip_source_t *_Nonnull);
+ZIP_EXTERN int zip_source_begin_write_cloning(zip_source_t *_Nonnull, zip_uint64_t);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_buffer(zip_t *_Nonnull, const void *_Nullable, zip_uint64_t, int);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_buffer_create(const void *_Nullable, zip_uint64_t, int, zip_error_t *_Nullable);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_buffer_fragment(zip_t *_Nonnull, const zip_buffer_fragment_t *_Nonnull, zip_uint64_t, int);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_buffer_fragment_create(const zip_buffer_fragment_t *_Nullable, zip_uint64_t, int, zip_error_t *_Nullable);
+ZIP_EXTERN int zip_source_close(zip_source_t *_Nonnull);
+ZIP_EXTERN int zip_source_commit_write(zip_source_t *_Nonnull);
+ZIP_EXTERN zip_error_t *_Nonnull zip_source_error(zip_source_t *_Nonnull);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_file(zip_t *_Nonnull, const char *_Nonnull, zip_uint64_t, zip_int64_t);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_file_create(const char *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_filep(zip_t *_Nonnull, FILE *_Nonnull, zip_uint64_t, zip_int64_t);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_filep_create(FILE *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable);
+ZIP_EXTERN void zip_source_free(zip_source_t *_Nullable);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_function(zip_t *_Nonnull, zip_source_callback _Nonnull, void *_Nullable);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_function_create(zip_source_callback _Nonnull, void *_Nullable, zip_error_t *_Nullable);
+ZIP_EXTERN int zip_source_get_file_attributes(zip_source_t *_Nonnull, zip_file_attributes_t *_Nonnull);
+ZIP_EXTERN int zip_source_is_deleted(zip_source_t *_Nonnull);
+ZIP_EXTERN void zip_source_keep(zip_source_t *_Nonnull);
 ZIP_EXTERN zip_int64_t zip_source_make_command_bitmap(zip_source_cmd_t, ...);
-ZIP_EXTERN int zip_source_open(zip_source_t * _Nonnull);
-ZIP_EXTERN zip_int64_t zip_source_read(zip_source_t * _Nonnull, void * _Nonnull, zip_uint64_t);
-ZIP_EXTERN void zip_source_rollback_write(zip_source_t * _Nonnull);
-ZIP_EXTERN int zip_source_seek(zip_source_t * _Nonnull, zip_int64_t, int);
-ZIP_EXTERN zip_int64_t zip_source_seek_compute_offset(zip_uint64_t, zip_uint64_t, void * _Nonnull, zip_uint64_t, zip_error_t * _Nullable);
-ZIP_EXTERN int zip_source_seek_write(zip_source_t * _Nonnull, zip_int64_t, int);
-ZIP_EXTERN int zip_source_stat(zip_source_t * _Nonnull, zip_stat_t * _Nonnull);
-ZIP_EXTERN zip_int64_t zip_source_tell(zip_source_t * _Nonnull);
-ZIP_EXTERN zip_int64_t zip_source_tell_write(zip_source_t * _Nonnull);
+ZIP_EXTERN int zip_source_open(zip_source_t *_Nonnull);
+ZIP_EXTERN zip_int64_t zip_source_read(zip_source_t *_Nonnull, void *_Nonnull, zip_uint64_t);
+ZIP_EXTERN void zip_source_rollback_write(zip_source_t *_Nonnull);
+ZIP_EXTERN int zip_source_seek(zip_source_t *_Nonnull, zip_int64_t, int);
+ZIP_EXTERN zip_int64_t zip_source_seek_compute_offset(zip_uint64_t, zip_uint64_t, void *_Nonnull, zip_uint64_t, zip_error_t *_Nullable);
+ZIP_EXTERN int zip_source_seek_write(zip_source_t *_Nonnull, zip_int64_t, int);
+ZIP_EXTERN int zip_source_stat(zip_source_t *_Nonnull, zip_stat_t *_Nonnull);
+ZIP_EXTERN zip_int64_t zip_source_tell(zip_source_t *_Nonnull);
+ZIP_EXTERN zip_int64_t zip_source_tell_write(zip_source_t *_Nonnull);
 #ifdef _WIN32
 ZIP_EXTERN zip_source_t *zip_source_win32a(zip_t *, const char *, zip_uint64_t, zip_int64_t);
 ZIP_EXTERN zip_source_t *zip_source_win32a_create(const char *, zip_uint64_t, zip_int64_t, zip_error_t *);
@@ -439,15 +460,15 @@
 ZIP_EXTERN zip_source_t *zip_source_win32w(zip_t *, const wchar_t *, zip_uint64_t, zip_int64_t);
 ZIP_EXTERN zip_source_t *zip_source_win32w_create(const wchar_t *, zip_uint64_t, zip_int64_t, zip_error_t *);
 #endif
-ZIP_EXTERN zip_int64_t zip_source_write(zip_source_t * _Nonnull, const void * _Nullable, zip_uint64_t);
-ZIP_EXTERN zip_source_t * _Nullable zip_source_zip(zip_t * _Nonnull, zip_t * _Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t);
-ZIP_EXTERN int zip_stat(zip_t * _Nonnull, const char * _Nonnull, zip_flags_t, zip_stat_t * _Nonnull);
-ZIP_EXTERN int zip_stat_index(zip_t * _Nonnull, zip_uint64_t, zip_flags_t, zip_stat_t * _Nonnull);
-ZIP_EXTERN void zip_stat_init( zip_stat_t * _Nonnull);
-ZIP_EXTERN const char * _Nonnull zip_strerror(zip_t * _Nonnull);
-ZIP_EXTERN int zip_unchange(zip_t * _Nonnull, zip_uint64_t);
-ZIP_EXTERN int zip_unchange_all(zip_t * _Nonnull);
-ZIP_EXTERN int zip_unchange_archive(zip_t * _Nonnull);
+ZIP_EXTERN zip_int64_t zip_source_write(zip_source_t *_Nonnull, const void *_Nullable, zip_uint64_t);
+ZIP_EXTERN zip_source_t *_Nullable zip_source_zip(zip_t *_Nonnull, zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t);
+ZIP_EXTERN int zip_stat(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t, zip_stat_t *_Nonnull);
+ZIP_EXTERN int zip_stat_index(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_stat_t *_Nonnull);
+ZIP_EXTERN void zip_stat_init(zip_stat_t *_Nonnull);
+ZIP_EXTERN const char *_Nonnull zip_strerror(zip_t *_Nonnull);
+ZIP_EXTERN int zip_unchange(zip_t *_Nonnull, zip_uint64_t);
+ZIP_EXTERN int zip_unchange_all(zip_t *_Nonnull);
+ZIP_EXTERN int zip_unchange_archive(zip_t *_Nonnull);
 ZIP_EXTERN int zip_compression_method_supported(zip_int32_t method, int compress);
 ZIP_EXTERN int zip_encryption_method_supported(zip_uint16_t method, int encode);
 
diff --git a/lib/zip_algorithm_bzip2.c b/lib/zip_algorithm_bzip2.c
index a1d2898..a4f27e5 100644
--- a/lib/zip_algorithm_bzip2.c
+++ b/lib/zip_algorithm_bzip2.c
@@ -90,8 +90,8 @@
 }
 
 
-static int
-compression_flags(void *ud) {
+static zip_uint16_t
+general_purpose_bit_flags(void *ud) {
     return 0;
 }
 
@@ -247,7 +247,8 @@
 zip_compression_algorithm_t zip_algorithm_bzip2_compress = {
     compress_allocate,
     deallocate,
-    compression_flags,
+    general_purpose_bit_flags,
+    46,
     start,
     end,
     input,
@@ -259,7 +260,8 @@
 zip_compression_algorithm_t zip_algorithm_bzip2_decompress = {
     decompress_allocate,
     deallocate,
-    compression_flags,
+    general_purpose_bit_flags,
+    46,
     start,
     end,
     input,
diff --git a/lib/zip_algorithm_deflate.c b/lib/zip_algorithm_deflate.c
index daf4a2c..d28a1ac 100644
--- a/lib/zip_algorithm_deflate.c
+++ b/lib/zip_algorithm_deflate.c
@@ -91,8 +91,8 @@
 }
 
 
-static int
-compression_flags(void *ud) {
+static zip_uint16_t
+general_purpose_bit_flags(void *ud) {
     struct ctx *ctx = (struct ctx *)ud;
 
     if (!ctx->compress) {
@@ -100,10 +100,10 @@
     }
 
     if (ctx->compression_flags < 3) {
-	return 2;
+	return 2 << 1;
     }
     else if (ctx->compression_flags > 7) {
-	return 1;
+	return 1 << 1;
     }
     return 0;
 }
@@ -225,7 +225,8 @@
 zip_compression_algorithm_t zip_algorithm_deflate_compress = {
     compress_allocate,
     deallocate,
-    compression_flags,
+    general_purpose_bit_flags,
+    20,
     start,
     end,
     input,
@@ -237,7 +238,8 @@
 zip_compression_algorithm_t zip_algorithm_deflate_decompress = {
     decompress_allocate,
     deallocate,
-    compression_flags,
+    general_purpose_bit_flags,
+    20,
     start,
     end,
     input,
diff --git a/lib/zip_algorithm_xz.c b/lib/zip_algorithm_xz.c
index 821ac12..026575a 100644
--- a/lib/zip_algorithm_xz.c
+++ b/lib/zip_algorithm_xz.c
@@ -35,8 +35,8 @@
 #include "zipint.h"
 
 #include <limits.h>
-#include <stdlib.h>
 #include <lzma.h>
+#include <stdlib.h>
 
 struct ctx {
     zip_error_t *error;
@@ -51,10 +51,10 @@
 static void *
 allocate(bool compress, int compression_flags, zip_error_t *error, zip_uint16_t method) {
     struct ctx *ctx;
-    
+
     if (compression_flags < 0) {
-        zip_error_set(error, ZIP_ER_INVAL, 0);
-        return NULL;
+	zip_error_set(error, ZIP_ER_INVAL, 0);
+	return NULL;
     }
 
     if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {
@@ -92,8 +92,8 @@
 }
 
 
-static int
-compression_flags(void *ud) {
+static zip_uint16_t
+general_purpose_bit_flags(void *ud) {
     /* struct ctx *ctx = (struct ctx *)ud; */
     return 0;
 }
@@ -101,17 +101,17 @@
 static int
 map_error(lzma_ret ret) {
     switch (ret) {
-      case LZMA_UNSUPPORTED_CHECK:
-        return ZIP_ER_COMPRESSED_DATA;
+    case LZMA_UNSUPPORTED_CHECK:
+	return ZIP_ER_COMPRESSED_DATA;
 
-      case LZMA_MEM_ERROR:
-        return ZIP_ER_MEMORY;
+    case LZMA_MEM_ERROR:
+	return ZIP_ER_MEMORY;
 
-      case LZMA_OPTIONS_ERROR:
-        return ZIP_ER_INVAL;
+    case LZMA_OPTIONS_ERROR:
+	return ZIP_ER_INVAL;
 
-      default:
-        return ZIP_ER_INTERNAL;
+    default:
+	return ZIP_ER_INTERNAL;
     }
 }
 
@@ -124,8 +124,8 @@
     lzma_options_lzma opt_lzma;
     lzma_lzma_preset(&opt_lzma, ctx->compression_flags);
     lzma_filter filters[] = {
-      { .id = (ctx->method == ZIP_CM_LZMA ? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2), .options = &opt_lzma},
-      { .id = LZMA_VLI_UNKNOWN, .options = NULL },
+	{.id = (ctx->method == ZIP_CM_LZMA ? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2), .options = &opt_lzma},
+	{.id = LZMA_VLI_UNKNOWN, .options = NULL},
     };
 
     ctx->zstr.avail_in = 0;
@@ -134,20 +134,21 @@
     ctx->zstr.next_out = NULL;
 
     if (ctx->compress) {
-      if (ctx->method == ZIP_CM_LZMA)
-        ret = lzma_alone_encoder(&ctx->zstr, filters[0].options);
-      else
-        ret = lzma_stream_encoder(&ctx->zstr, filters, LZMA_CHECK_CRC64);
-    } else {
-     if (ctx->method == ZIP_CM_LZMA)
-       ret = lzma_alone_decoder(&ctx->zstr, UINT64_MAX);
-     else
-      ret = lzma_stream_decoder(&ctx->zstr, UINT64_MAX, LZMA_CONCATENATED);
+	if (ctx->method == ZIP_CM_LZMA)
+	    ret = lzma_alone_encoder(&ctx->zstr, filters[0].options);
+	else
+	    ret = lzma_stream_encoder(&ctx->zstr, filters, LZMA_CHECK_CRC64);
+    }
+    else {
+	if (ctx->method == ZIP_CM_LZMA)
+	    ret = lzma_alone_decoder(&ctx->zstr, UINT64_MAX);
+	else
+	    ret = lzma_stream_decoder(&ctx->zstr, UINT64_MAX, LZMA_CONCATENATED);
     }
 
     if (ret != LZMA_OK) {
-      zip_error_set(ctx->error, map_error(ret), 0);
-      return false;
+	zip_error_set(ctx->error, map_error(ret), 0);
+	return false;
     }
 
     return true;
@@ -168,8 +169,8 @@
     struct ctx *ctx = (struct ctx *)ud;
 
     if (length > UINT_MAX || ctx->zstr.avail_in > 0) {
-      zip_error_set(ctx->error, ZIP_ER_INVAL, 0);
-      return false;
+	zip_error_set(ctx->error, ZIP_ER_INVAL, 0);
+	return false;
     }
 
     ctx->zstr.avail_in = (uInt)length;
@@ -200,10 +201,10 @@
 
     switch (ret) {
     case LZMA_OK:
-        return ZIP_COMPRESSION_OK;
+	return ZIP_COMPRESSION_OK;
 
     case LZMA_STREAM_END:
-        return ZIP_COMPRESSION_END;
+	return ZIP_COMPRESSION_END;
 
     case LZMA_BUF_ERROR:
 	if (ctx->zstr.avail_in == 0) {
@@ -222,7 +223,8 @@
 zip_compression_algorithm_t zip_algorithm_xz_compress = {
     compress_allocate,
     deallocate,
-    compression_flags,
+    general_purpose_bit_flags,
+    63,
     start,
     end,
     input,
@@ -234,7 +236,8 @@
 zip_compression_algorithm_t zip_algorithm_xz_decompress = {
     decompress_allocate,
     deallocate,
-    compression_flags,
+    general_purpose_bit_flags,
+    63,
     start,
     end,
     input,
diff --git a/lib/zip_close.c b/lib/zip_close.c
index d7a86ca..fd3b0e0 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -51,7 +51,7 @@
 #endif
 
 
-static int add_data(zip_t *, zip_source_t *, zip_dirent_t *);
+static int add_data(zip_t *, zip_source_t *, zip_dirent_t *, zip_uint32_t);
 static int copy_data(zip_t *, zip_uint64_t);
 static int copy_source(zip_t *, zip_source_t *, zip_int64_t);
 static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t);
@@ -222,7 +222,7 @@
 	    }
 
 	    /* add_data writes dirent */
-	    if (add_data(za, zs ? zs : entry->source, de) < 0) {
+	    if (add_data(za, zs ? zs : entry->source, de, entry->changes ? entry->changes->changed : 0) < 0) {
 		error = 1;
 		if (zs)
 		    zip_source_free(zs);
@@ -235,7 +235,7 @@
 	    zip_uint64_t offset;
 
 	    if (de->encryption_method != ZIP_EM_TRAD_PKWARE) {
-                /* when copying data, all sizes are known -> no data descriptor needed */
+		/* when copying data, all sizes are known -> no data descriptor needed */
 		/* except for PKWare encryption, where removing the data descriptor breaks password validation */
 		de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
 	    }
@@ -264,7 +264,6 @@
 		}
 	    }
 	}
-
     }
 
     if (!error) {
@@ -294,14 +293,14 @@
 
 
 static int
-add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) {
+add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de, zip_uint32_t changed) {
     zip_int64_t offstart, offdata, offend, data_length;
-    struct zip_stat st;
+    zip_stat_t st;
+    zip_file_attributes_t attributes;
     zip_source_t *src_final, *src_tmp;
     int ret;
     int is_zip64;
     zip_flags_t flags;
-    zip_int8_t compression_flags;
     bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt;
 
     if (zip_source_stat(src, &st) < 0) {
@@ -465,9 +464,9 @@
 	    zip_source_free(src_final);
 	    return -1;
 	}
-        if (de->encryption_method == ZIP_EM_TRAD_PKWARE) {
+	if (de->encryption_method == ZIP_EM_TRAD_PKWARE) {
 	    de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR;
-        }
+	}
 
 	zip_source_free(src_final);
 	src_final = src_tmp;
@@ -486,7 +485,7 @@
 	ret = -1;
     }
 
-    if ((compression_flags = zip_source_get_compression_flags(src_final)) < 0) {
+    if (zip_source_get_file_attributes(src_final, &attributes) != 0) {
 	_zip_error_set_from_source(&za->error, src_final);
 	ret = -1;
     }
@@ -522,8 +521,7 @@
     de->crc = st.crc;
     de->uncomp_size = st.size;
     de->comp_size = (zip_uint64_t)(offend - offdata);
-    de->bitflags = (zip_uint16_t)((de->bitflags & (zip_uint16_t)~6) | ((zip_uint8_t)compression_flags << 1));
-    _zip_dirent_set_version_needed(de, (flags & ZIP_FL_FORCE_ZIP64) != 0);
+    _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0, changed);
 
     if ((ret = _zip_dirent_write(za, de, flags)) < 0)
 	return -1;
diff --git a/lib/zip_crypto_gnutls.h b/lib/zip_crypto_gnutls.h
index 484ddbb..81fcd42 100644
--- a/lib/zip_crypto_gnutls.h
+++ b/lib/zip_crypto_gnutls.h
@@ -39,8 +39,8 @@
 #include <nettle/aes.h>
 #include <nettle/pbkdf2.h>
 
-#include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>
+#include <gnutls/gnutls.h>
 
 typedef struct {
     union {
diff --git a/lib/zip_crypto_mbedtls.c b/lib/zip_crypto_mbedtls.c
index f0049ea..c348ad2 100644
--- a/lib/zip_crypto_mbedtls.c
+++ b/lib/zip_crypto_mbedtls.c
@@ -34,6 +34,7 @@
 #include <stdlib.h>
 
 #include "zipint.h"
+
 #include "zip_crypto.h"
 
 #include <mbedtls/ctr_drbg.h>
diff --git a/lib/zip_crypto_win.c b/lib/zip_crypto_win.c
index abdd7e0..7eb42c3 100644
--- a/lib/zip_crypto_win.c
+++ b/lib/zip_crypto_win.c
@@ -40,6 +40,7 @@
 #define NOCRYPT
 
 #include <windows.h>
+
 #include <bcrypt.h>
 
 #pragma comment(lib, "bcrypt.lib")
@@ -216,7 +217,7 @@
 }
 
 static void
-xor(LPBYTE ptr1, LPBYTE ptr2, DWORD dwLen) {
+myxor(LPBYTE ptr1, LPBYTE ptr2, DWORD dwLen) {
     while (dwLen--)
 	*ptr1++ ^= *ptr2++;
 }
@@ -267,7 +268,7 @@
 		goto PBKDF2_end;
 	    }
 
-	    xor(Ti, V, DIGEST_SIZE);
+	    myxor(Ti, V, DIGEST_SIZE);
 	}
 
 	if (i != l) {
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c
index 2bbb63d..1916e90 100644
--- a/lib/zip_dirent.c
+++ b/lib/zip_dirent.c
@@ -867,9 +867,9 @@
     _zip_buffer_put(buffer, (flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 4);
 
     if ((flags & ZIP_FL_LOCAL) == 0) {
-	_zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_madeby));
+	_zip_buffer_put_16(buffer, de->version_madeby);
     }
-    _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_needed));
+    _zip_buffer_put_16(buffer, ZIP_MAX(is_really_zip64 ? 45 : 0, de->version_needed));
     _zip_buffer_put_16(buffer, de->bitflags);
     if (is_winzip_aes) {
 	_zip_buffer_put_16(buffer, ZIP_CM_WINZIP_AES);
@@ -1074,7 +1074,7 @@
     tpm = localtime(&intime);
 #endif
     if (tpm == NULL) {
-        /* if localtime() fails, return an arbitrary date (1980-01-01 00:00:00) */
+	/* if localtime() fails, return an arbitrary date (1980-01-01 00:00:00) */
 	*ddate = (1 << 5) + 1;
 	*dtime = 0;
 	return;
@@ -1091,36 +1091,49 @@
 
 
 void
-_zip_dirent_set_version_needed(zip_dirent_t *de, bool force_zip64) {
+_zip_dirent_apply_attributes(zip_dirent_t *de, zip_file_attributes_t *attributes, bool force_zip64, zip_uint32_t changed) {
     zip_uint16_t length;
 
+    if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) {
+	zip_uint16_t mask = attributes->general_purpose_bit_mask & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK;
+	de->bitflags = (de->bitflags & ~mask) | (attributes->general_purpose_bit_flags & mask);
+    }
+    if (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) {
+	de->int_attrib = (de->int_attrib & ~0x1) | (attributes->ascii ? 1 : 0);
+    }
+    /* manually set attributes are preferred over attributes provided by source */
+    if ((changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES)) {
+	de->ext_attrib = attributes->external_file_attributes;
+    }
+
     if (de->comp_method == ZIP_CM_LZMA) {
 	de->version_needed = 63;
-	return;
     }
-
-    if (de->comp_method == ZIP_CM_BZIP2) {
+    else if (de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256) {
+	de->version_needed = 51;
+    }
+    else if (de->comp_method == ZIP_CM_BZIP2) {
 	de->version_needed = 46;
-	return;
     }
-
-    if (force_zip64 || _zip_dirent_needs_zip64(de, 0)) {
+    else if (force_zip64 || _zip_dirent_needs_zip64(de, 0)) {
 	de->version_needed = 45;
-	return;
     }
-
-    if (de->comp_method == ZIP_CM_DEFLATE || de->encryption_method == ZIP_EM_TRAD_PKWARE) {
+    else if (de->comp_method == ZIP_CM_DEFLATE || de->encryption_method == ZIP_EM_TRAD_PKWARE) {
 	de->version_needed = 20;
-	return;
+    }
+    else if ((length = _zip_string_length(de->filename)) > 0 && de->filename->raw[length - 1] == '/') {
+	de->version_needed = 20;
+    }
+    else {
+	de->version_needed = 10;
     }
 
-    /* directory */
-    if ((length = _zip_string_length(de->filename)) > 0) {
-	if (de->filename->raw[length - 1] == '/') {
-	    de->version_needed = 20;
-	    return;
-	}
+    if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) {
+        de->version_needed = ZIP_MAX(de->version_needed, attributes->version_needed);
     }
 
-    de->version_needed = 10;
+    de->version_madeby = 63 | (de->version_madeby & 0xff00);
+    if ((changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM)) {
+	de->version_madeby = (de->version_madeby & 0xff) | (zip_uint16_t)(attributes->host_system << 8);
+    }
 }
diff --git a/lib/zip_err_str.c b/lib/zip_err_str.c
index e0a04a9..3a7c9ef 100644
--- a/lib/zip_err_str.c
+++ b/lib/zip_err_str.c
@@ -5,80 +5,16 @@
 
 #include "zipint.h"
 
-const char * const _zip_err_str[] = {
-    "No error",
-    "Multi-disk zip archives not supported",
-    "Renaming temporary file failed",
-    "Closing zip archive failed",
-    "Seek error",
-    "Read error",
-    "Write error",
-    "CRC error",
-    "Containing zip archive was closed",
-    "No such file",
-    "File already exists",
-    "Can't open file",
-    "Failure to create temporary file",
-    "Zlib error",
-    "Malloc failure",
-    "Entry has been changed",
-    "Compression method not supported",
-    "Premature end of file",
-    "Invalid argument",
-    "Not a zip archive",
-    "Internal error",
-    "Zip archive inconsistent",
-    "Can't remove file",
-    "Entry has been deleted",
-    "Encryption method not supported",
-    "Read-only archive",
-    "No password provided",
-    "Wrong password provided",
-    "Operation not supported",
-    "Resource still in use",
-    "Tell error",
-    "Compressed data invalid",
-    "Operation cancelled",
+const char *const _zip_err_str[] = {
+    "No error", "Multi-disk zip archives not supported", "Renaming temporary file failed", "Closing zip archive failed", "Seek error", "Read error", "Write error", "CRC error", "Containing zip archive was closed", "No such file", "File already exists", "Can't open file", "Failure to create temporary file", "Zlib error", "Malloc failure", "Entry has been changed", "Compression method not supported", "Premature end of file", "Invalid argument", "Not a zip archive", "Internal error", "Zip archive inconsistent", "Can't remove file", "Entry has been deleted", "Encryption method not supported", "Read-only archive", "No password provided", "Wrong password provided", "Operation not supported", "Resource still in use", "Tell error", "Compressed data invalid", "Operation cancelled",
 };
 
-const int _zip_nerr_str = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]);
+const int _zip_nerr_str = sizeof(_zip_err_str) / sizeof(_zip_err_str[0]);
 
 #define N ZIP_ET_NONE
 #define S ZIP_ET_SYS
 #define Z ZIP_ET_ZLIB
 
 const int _zip_err_type[] = {
-    N,
-    N,
-    S,
-    S,
-    S,
-    S,
-    S,
-    N,
-    N,
-    N,
-    N,
-    S,
-    S,
-    Z,
-    N,
-    N,
-    N,
-    N,
-    N,
-    N,
-    N,
-    N,
-    S,
-    N,
-    N,
-    N,
-    N,
-    N,
-    N,
-    N,
-    S,
-    N,
-    N,
+    N, N, S, S, S, S, S, N, N, N, N, S, S, Z, N, N, N, N, N, N, N, N, S, N, N, N, N, N, N, N, S, N, N,
 };
diff --git a/lib/zip_get_encryption_implementation.c b/lib/zip_get_encryption_implementation.c
index 54456ad..3909e6f 100644
--- a/lib/zip_get_encryption_implementation.c
+++ b/lib/zip_get_encryption_implementation.c
@@ -39,24 +39,24 @@
 _zip_get_encryption_implementation(zip_uint16_t em, int operation) {
     switch (em) {
     case ZIP_EM_TRAD_PKWARE:
-        return operation == ZIP_CODEC_DECODE ? zip_source_pkware_decode : zip_source_pkware_encode;
+	return operation == ZIP_CODEC_DECODE ? zip_source_pkware_decode : zip_source_pkware_encode;
 
 #if defined(HAVE_CRYPTO)
     case ZIP_EM_AES_128:
     case ZIP_EM_AES_192:
     case ZIP_EM_AES_256:
-        return operation == ZIP_CODEC_DECODE ? zip_source_winzip_aes_decode : zip_source_winzip_aes_encode;
+	return operation == ZIP_CODEC_DECODE ? zip_source_winzip_aes_decode : zip_source_winzip_aes_encode;
 #endif
 
     default:
-        return NULL;
+	return NULL;
     }
 }
 
 ZIP_EXTERN int
 zip_encryption_method_supported(zip_uint16_t method, int encode) {
     if (method == ZIP_EM_NONE) {
-        return 1;
+	return 1;
     }
     return _zip_get_encryption_implementation(method, encode ? ZIP_CODEC_ENCODE : ZIP_CODEC_DECODE) != NULL;
 }
diff --git a/lib/zip_mkstempm.c b/lib/zip_mkstempm.c
index a38ba61..e6f148c 100644
--- a/lib/zip_mkstempm.c
+++ b/lib/zip_mkstempm.c
@@ -31,11 +31,11 @@
   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-#include <sys/stat.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 
 #include "zipint.h"
 
@@ -65,18 +65,18 @@
     start++;
 
     for (;;) {
-        zip_uint32_t value = zip_random_uint32();
+	zip_uint32_t value = zip_random_uint32();
 
 	xs = start;
 
 	while (xs < end) {
-            char digit = value % 36;
-            if (digit < 10) {
-                *(xs++) = digit + '0';
-            }
-            else {
-                *(xs++) = digit - 10 + 'a';
-            }
+	    char digit = value % 36;
+	    if (digit < 10) {
+		*(xs++) = digit + '0';
+	    }
+	    else {
+		*(xs++) = digit - 10 + 'a';
+	    }
 	    value /= 36;
 	}
 
diff --git a/lib/zip_open.c b/lib/zip_open.c
index 4e29c5b..5956138 100644
--- a/lib/zip_open.c
+++ b/lib/zip_open.c
@@ -40,11 +40,7 @@
 
 #include "zipint.h"
 
-typedef enum {
-    EXISTS_ERROR = -1,
-    EXISTS_NOT = 0,
-    EXISTS_OK
-} exists_t;
+typedef enum { EXISTS_ERROR = -1, EXISTS_NOT = 0, EXISTS_OK } exists_t;
 static zip_t *_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error);
 static zip_int64_t _zip_checkcons(zip_t *za, zip_cdir_t *cdir, zip_error_t *error);
 static zip_cdir_t *_zip_find_central_dir(zip_t *za, zip_uint64_t len);
diff --git a/lib/zip_progress.c b/lib/zip_progress.c
index aac0175..ddb47c7 100644
--- a/lib/zip_progress.c
+++ b/lib/zip_progress.c
@@ -210,7 +210,7 @@
 ZIP_EXTERN int
 zip_register_progress_callback_with_state(zip_t *za, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) {
     if (callback != NULL) {
-        if (za->progress == NULL) {
+	if (za->progress == NULL) {
 	    if ((za->progress = _zip_progress_new(za)) == NULL) {
 		return -1;
 	    }
@@ -237,7 +237,7 @@
 ZIP_EXTERN int
 zip_register_cancel_callback_with_state(zip_t *za, zip_cancel_callback callback, void (*ud_free)(void *), void *ud) {
     if (callback != NULL) {
-        if (za->progress == NULL) {
+	if (za->progress == NULL) {
 	    if ((za->progress = _zip_progress_new(za)) == NULL) {
 		return -1;
 	    }
diff --git a/lib/zip_random_unix.c b/lib/zip_random_unix.c
index 24c7c1f..1c8111b 100644
--- a/lib/zip_random_unix.c
+++ b/lib/zip_random_unix.c
@@ -87,17 +87,17 @@
 zip_uint32_t
 zip_random_uint32(void) {
     static bool seeded = false;
-    
+
     zip_uint32_t value;
-    
+
     if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) {
-        return value;
+	return value;
     }
-    
+
     if (!seeded) {
-        srandom((unsigned int)time(NULL));
+	srandom((unsigned int)time(NULL));
     }
-    
+
     return (zip_uint32_t)random();
 }
 #endif
diff --git a/lib/zip_random_uwp.c b/lib/zip_random_uwp.c
index cec7ec6..b51569a 100644
--- a/lib/zip_random_uwp.c
+++ b/lib/zip_random_uwp.c
@@ -72,11 +72,11 @@
     zip_uint32_t value;
 
     if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) {
-        return value;
+	return value;
     }
 
     if (!seeded) {
-        srand((unsigned int)time(NULL));
+	srand((unsigned int)time(NULL));
     }
 
     return (zip_uint32_t)rand();
diff --git a/lib/zip_random_win32.c b/lib/zip_random_win32.c
index 052bd4f..b9fe800 100644
--- a/lib/zip_random_win32.c
+++ b/lib/zip_random_win32.c
@@ -68,11 +68,11 @@
     zip_uint32_t value;
 
     if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) {
-        return value;
+	return value;
     }
 
     if (!seeded) {
-        srand((unsigned int)time(NULL));
+	srand((unsigned int)time(NULL));
     }
 
     return (zip_uint32_t)rand();
diff --git a/lib/zip_source_buffer.c b/lib/zip_source_buffer.c
index 0685fb3..2b87f01 100644
--- a/lib/zip_source_buffer.c
+++ b/lib/zip_source_buffer.c
@@ -61,6 +61,7 @@
 struct read_data {
     zip_error_t error;
     time_t mtime;
+    zip_file_attributes_t attributes;
     buffer_t *in;
     buffer_t *out;
 };
@@ -79,33 +80,42 @@
 
 static zip_int64_t read_data(void *, void *, zip_uint64_t, zip_source_cmd_t);
 
+zip_source_t *zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error);
+zip_source_t *zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error);
+
 
 ZIP_EXTERN zip_source_t *
 zip_source_buffer(zip_t *za, const void *data, zip_uint64_t len, int freep) {
     if (za == NULL)
 	return NULL;
 
-    return zip_source_buffer_create(data, len, freep, &za->error);
+    return zip_source_buffer_with_attributes_create(data, len, freep, NULL, &za->error);
 }
 
 
 ZIP_EXTERN zip_source_t *
 zip_source_buffer_create(const void *data, zip_uint64_t len, int freep, zip_error_t *error) {
+    return zip_source_buffer_with_attributes_create(data, len, freep, NULL, error);
+}
+
+
+zip_source_t *
+zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error) {
     zip_buffer_fragment_t fragment;
 
     if (data == NULL) {
-        if (len > 0) {
-            zip_error_set(error, ZIP_ER_INVAL, 0);
-            return NULL;
-        }
+	if (len > 0) {
+	    zip_error_set(error, ZIP_ER_INVAL, 0);
+	    return NULL;
+	}
 
-        return zip_source_buffer_fragment_create(NULL, 0, freep, error);
+	return zip_source_buffer_fragment_create(NULL, 0, freep, error);
     }
 
     fragment.data = (zip_uint8_t *)data;
     fragment.length = len;
 
-    return zip_source_buffer_fragment_create(&fragment, 1, freep, error);
+    return zip_source_buffer_fragment_with_attributes_create(&fragment, 1, freep, attributes, error);
 }
 
 
@@ -115,12 +125,17 @@
 	return NULL;
     }
 
-    return zip_source_buffer_fragment_create(fragments, nfragments, freep, &za->error);
+    return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, &za->error);
 }
 
 
 ZIP_EXTERN zip_source_t *
 zip_source_buffer_fragment_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_error_t *error) {
+    return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, error);
+}
+
+zip_source_t *
+zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error) {
     struct read_data *ctx;
     zip_source_t *zs;
     buffer_t *buffer;
@@ -143,6 +158,12 @@
     ctx->in = buffer;
     ctx->out = NULL;
     ctx->mtime = time(NULL);
+    if (attributes) {
+	memcpy(&ctx->attributes, attributes, sizeof(ctx->attributes));
+    }
+    else {
+	zip_file_attributes_init(&ctx->attributes);
+    }
     zip_error_init(&ctx->error);
 
     if ((zs = zip_source_function_create(read_data, ctx, error)) == NULL) {
@@ -155,6 +176,11 @@
 }
 
 
+zip_source_t *
+zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes) {
+    return zip_source_buffer_with_attributes_create(data, len, freep, attributes, &za->error);
+}
+
 static zip_int64_t
 read_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
     struct read_data *ctx = (struct read_data *)state;
diff --git a/lib/zip_source_compress.c b/lib/zip_source_compress.c
index 4c318e0..1ca270f 100644
--- a/lib/zip_source_compress.c
+++ b/lib/zip_source_compress.c
@@ -68,12 +68,12 @@
     {ZIP_CM_BZIP2, &zip_algorithm_bzip2_compress, &zip_algorithm_bzip2_decompress},
 #endif
 #if defined(HAVE_LIBLZMA)
-/*  Disabled - because 7z isn't able to unpack ZIP+LZMA ZIP+LZMA2
-    archives made this way - and vice versa.
+    /*  Disabled - because 7z isn't able to unpack ZIP+LZMA ZIP+LZMA2
+	archives made this way - and vice versa.
 
-    {ZIP_CM_LZMA, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},
-    {ZIP_CM_LZMA2, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},
-*/
+	{ZIP_CM_LZMA, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},
+	{ZIP_CM_LZMA2, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},
+    */
     {ZIP_CM_XZ, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},
 #endif
 
@@ -357,9 +357,6 @@
     }
 	return 0;
 
-    case ZIP_SOURCE_GET_COMPRESSION_FLAGS:
-	return ctx->is_stored ? 0 : ctx->algorithm->compression_flags(ctx->ud);
-
     case ZIP_SOURCE_ERROR:
 	return zip_error_to_data(&ctx->error, data, len);
 
@@ -367,8 +364,25 @@
 	context_free(ctx);
 	return 0;
 
+    case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {
+	zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;
+
+	if (len < sizeof(*attributes)) {
+            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
+	    return -1;
+	}
+
+        attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED |
+        ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;
+        attributes->version_needed = ctx->algorithm->version_needed;
+	attributes->general_purpose_bit_mask = ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK;
+	attributes->general_purpose_bit_flags = (ctx->is_stored ? 0 : ctx->algorithm->general_purpose_bit_flags(ctx->ud));
+
+	return sizeof(*attributes);
+    }
+
     case ZIP_SOURCE_SUPPORTS:
-	return ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_GET_COMPRESSION_FLAGS, -1);
+	return ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1);
 
     default:
 	zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
diff --git a/lib/zip_source_crc.c b/lib/zip_source_crc.c
index 56572c0..0dc5d9d 100644
--- a/lib/zip_source_crc.c
+++ b/lib/zip_source_crc.c
@@ -167,7 +167,7 @@
 	    return -1;
 	}
 
-	return mask & ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_GET_COMPRESSION_FLAGS, -1);
+	return mask & ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1);
     }
 
     case ZIP_SOURCE_SEEK: {
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c
index 1d89c1d..4337ff8 100644
--- a/lib/zip_source_filep.c
+++ b/lib/zip_source_filep.c
@@ -35,8 +35,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 
 #include "zipint.h"
 
@@ -60,13 +60,14 @@
     zip_int64_t supports;
 
     /* reading */
-    char *fname;            /* name of file to read from */
-    FILE *f;                /* file to read from */
-    struct zip_stat st;     /* stat information passed in */
-    zip_error_t stat_error; /* error returned for stat */
-    zip_uint64_t start;     /* start offset of data to read */
-    zip_uint64_t end;       /* end offset of data to read relative to start, 0 for up to EOF */
-    zip_uint64_t current;   /* current offset relative to start (0 is beginning of part we read) */
+    char *fname;                      /* name of file to read from */
+    FILE *f;                          /* file to read from */
+    zip_stat_t st;                    /* stat information passed in */
+    zip_file_attributes_t attributes; /* additional file attributes */
+    zip_error_t stat_error;           /* error returned for stat */
+    zip_uint64_t start;               /* start offset of data to read */
+    zip_uint64_t end;                 /* end offset of data to read relative to start, 0 for up to EOF */
+    zip_uint64_t current;             /* current offset relative to start (0 is beginning of part we read) */
 
     /* writing */
     char *tmpname;
@@ -159,6 +160,7 @@
     ctx->fout = NULL;
 
     zip_error_init(&ctx->error);
+    zip_file_attributes_init(&ctx->attributes);
 
     ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1);
 
@@ -202,6 +204,14 @@
 		}
 	    }
 	}
+
+	/* We're using UNIX file API, even on Windows; thus, we supply external file attributes with Unix values. */
+	/* TODO: This could be improved on Windows by providing Windows-specific file attributes */
+	ctx->attributes.valid = ZIP_FILE_ATTRIBUTES_HOST_SYSTEM | ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES;
+	ctx->attributes.host_system = ZIP_OPSYS_UNIX;
+	ctx->attributes.external_file_attributes = (((zip_uint32_t)sb.st_mode) << 16) | ((sb.st_mode & S_IWUSR) ? 0 : 1);
+
+	ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_FILE_ATTRIBUTES);
     }
 
     ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ACCEPT_EMPTY);
@@ -432,6 +442,14 @@
 	free(ctx);
 	return 0;
 
+    case ZIP_SOURCE_GET_FILE_ATTRIBUTES:
+	if (len < sizeof(ctx->attributes)) {
+            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
+	    return -1;
+	}
+	memcpy(data, &ctx->attributes, sizeof(ctx->attributes));
+	return sizeof(ctx->attributes);
+
     case ZIP_SOURCE_OPEN:
 	if (ctx->fname) {
 	    if ((ctx->f = _zip_fopen(ctx->fname, false)) == NULL) {
@@ -639,8 +657,7 @@
  * but e.g. macOS doesn't.
  */
 static FILE *
-_zip_fopen(const char *name, bool writeable)
-{
+_zip_fopen(const char *name, bool writeable) {
     int fd;
     int flags;
     FILE *fp;
diff --git a/lib/zip_source_get_compression_flags.c b/lib/zip_source_get_compression_flags.c
deleted file mode 100644
index 7e04bed..0000000
--- a/lib/zip_source_get_compression_flags.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-  zip_source_get_compression_flags.c -- get compression flags for entry
-  Copyright (C) 2017-2019 Dieter Baron and Thomas Klausner
-
-  This file is part of libzip, a library to manipulate ZIP archives.
-  The authors can be contacted at <libzip@nih.at>
-
-  Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions
-  are met:
-  1. Redistributions of source code must retain the above copyright
-     notice, this list of conditions and the following disclaimer.
-  2. Redistributions in binary form must reproduce the above copyright
-     notice, this list of conditions and the following disclaimer in
-     the documentation and/or other materials provided with the
-     distribution.
-  3. The names of the authors may not be used to endorse or promote
-     products derived from this software without specific prior
-     written permission.
-
-  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
-  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
-  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
-  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-
-#include "zipint.h"
-
-#define ZIP_COMPRESSION_BITFLAG_MAX 3
-
-zip_int8_t
-zip_source_get_compression_flags(zip_source_t *src) {
-    while (src) {
-	if ((src->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_COMPRESSION_FLAGS))) {
-	    zip_int64_t ret = _zip_source_call(src, NULL, 0, ZIP_SOURCE_GET_COMPRESSION_FLAGS);
-	    if (ret < 0) {
-		return -1;
-	    }
-	    if (ret > ZIP_COMPRESSION_BITFLAG_MAX) {
-		zip_error_set(&src->error, ZIP_ER_INTERNAL, 0);
-		return -1;
-	    }
-	    return (zip_int8_t)ret;
-	}
-	src = src->src;
-    }
-
-    return 0;
-}
diff --git a/lib/zip_source_get_file_attributes.c b/lib/zip_source_get_file_attributes.c
new file mode 100644
index 0000000..acbede1
--- /dev/null
+++ b/lib/zip_source_get_file_attributes.c
@@ -0,0 +1,104 @@
+/*
+  zip_source_get_file_attributes.c -- get attributes for file from source
+  Copyright (C) 2020 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zipint.h"
+
+ZIP_EXTERN void
+zip_file_attributes_init(zip_file_attributes_t *attributes) {
+    attributes->valid = 0;
+    attributes->version = 1;
+}
+
+int
+zip_source_get_file_attributes(zip_source_t *src, zip_file_attributes_t *attributes) {
+    if (src->source_closed) {
+	return -1;
+    }
+    if (attributes == NULL) {
+	zip_error_set(&src->error, ZIP_ER_INVAL, 0);
+	return -1;
+    }
+
+    zip_file_attributes_init(attributes);
+
+    if (src->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_FILE_ATTRIBUTES)) {
+	if (_zip_source_call(src, attributes, sizeof(*attributes), ZIP_SOURCE_GET_FILE_ATTRIBUTES) < 0) {
+	    return -1;
+	}
+    }
+
+    if (ZIP_SOURCE_IS_LAYERED(src)) {
+	zip_file_attributes_t lower_attributes;
+
+	if (zip_source_get_file_attributes(src->src, &lower_attributes) < 0) {
+	    _zip_error_set_from_source(&src->error, src->src);
+	    return -1;
+	}
+
+	if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM) && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM) == 0) {
+	    attributes->host_system = lower_attributes.host_system;
+	    attributes->valid |= ZIP_FILE_ATTRIBUTES_HOST_SYSTEM;
+	}
+	if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_ASCII) && (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) == 0) {
+	    attributes->ascii = lower_attributes.ascii;
+	    attributes->valid |= ZIP_FILE_ATTRIBUTES_ASCII;
+	}
+	if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED)) {
+	    if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) {
+		attributes->version_needed = ZIP_MAX(lower_attributes.version_needed, attributes->version_needed);
+	    }
+	    else {
+		attributes->version_needed = lower_attributes.version_needed;
+		attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED;
+	    }
+	}
+	if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES) && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES) == 0) {
+	    attributes->external_file_attributes = lower_attributes.external_file_attributes;
+	    attributes->valid |= ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES;
+	}
+	if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS)) {
+	    if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) {
+		attributes->general_purpose_bit_flags &= ~lower_attributes.general_purpose_bit_mask;
+		attributes->general_purpose_bit_flags |= lower_attributes.general_purpose_bit_flags & lower_attributes.general_purpose_bit_mask;
+		attributes->general_purpose_bit_mask |= lower_attributes.general_purpose_bit_mask;
+	    }
+	    else {
+		attributes->valid |= ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;
+		attributes->general_purpose_bit_flags = lower_attributes.general_purpose_bit_flags;
+		attributes->general_purpose_bit_mask = lower_attributes.general_purpose_bit_mask;
+	    }
+	}
+    }
+
+    return 0;
+}
diff --git a/lib/zip_source_pkware_encode.c b/lib/zip_source_pkware_encode.c
index 5516bad..6288d52 100644
--- a/lib/zip_source_pkware_encode.c
+++ b/lib/zip_source_pkware_encode.c
@@ -185,9 +185,21 @@
 
 	return 0;
     }
+            
+    case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {
+        zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;
+        if (length < sizeof(*attributes)) {
+            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
+            return -1;
+        }
+        attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED;
+        attributes->version_needed = 20;
+        
+        return 0;
+    }
 
     case ZIP_SOURCE_SUPPORTS:
-	return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, -1);
+	return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1);
 
     case ZIP_SOURCE_ERROR:
 	return zip_error_to_data(&ctx->error, data, length);
diff --git a/lib/zip_source_window.c b/lib/zip_source_window.c
index 1276485..41e7d44 100644
--- a/lib/zip_source_window.c
+++ b/lib/zip_source_window.c
@@ -48,7 +48,7 @@
     zip_uint64_t offset; /* offset in src for next read */
 
     zip_stat_t stat;
-    zip_int8_t compression_flags;
+    zip_file_attributes_t attributes;
     zip_error_t error;
     zip_int64_t supports;
     bool needs_seek;
@@ -64,7 +64,7 @@
 
 
 zip_source_t *
-_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_int8_t compression_flags, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error) {
+_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_file_attributes_t *attributes, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error) {
     struct window *ctx;
 
     if (src == NULL || start + length < start || (source_archive == NULL && source_index != 0)) {
@@ -80,11 +80,16 @@
     ctx->start = start;
     ctx->end = start + length;
     zip_stat_init(&ctx->stat);
-    ctx->compression_flags = compression_flags;
+    if (attributes != NULL) {
+	memcpy(&ctx->attributes, attributes, sizeof(ctx->attributes));
+    }
+    else {
+	zip_file_attributes_init(&ctx->attributes);
+    }
     ctx->source_archive = source_archive;
     ctx->source_index = source_index;
     zip_error_init(&ctx->error);
-    ctx->supports = (zip_source_supports(src) & ZIP_SOURCE_SUPPORTS_SEEKABLE) | (zip_source_make_command_bitmap(ZIP_SOURCE_GET_COMPRESSION_FLAGS, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1));
+    ctx->supports = (zip_source_supports(src) & ZIP_SOURCE_SUPPORTS_SEEKABLE) | (zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1));
     ctx->needs_seek = (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) ? true : false;
 
     if (st) {
@@ -173,7 +178,7 @@
 		    return -1;
 		}
 	    }
-	    
+
 	    byte_array_fini(b);
 	}
 
@@ -231,8 +236,14 @@
 	return 0;
     }
 
-    case ZIP_SOURCE_GET_COMPRESSION_FLAGS:
-	return ctx->compression_flags;
+    case ZIP_SOURCE_GET_FILE_ATTRIBUTES:
+        if (len < sizeof(ctx->attributes)) {
+            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
+            return -1;
+        }
+
+	memcpy(data, &ctx->attributes, sizeof(ctx->attributes));
+	return sizeof(ctx->attributes);
 
     case ZIP_SOURCE_SUPPORTS:
 	return ctx->supports;
diff --git a/lib/zip_source_winzip_aes_encode.c b/lib/zip_source_winzip_aes_encode.c
index 7df5faf..a45e33e 100644
--- a/lib/zip_source_winzip_aes_encode.c
+++ b/lib/zip_source_winzip_aes_encode.c
@@ -184,8 +184,20 @@
 	return 0;
     }
 
+    case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {
+         zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;
+         if (length < sizeof(*attributes)) {
+             zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
+             return -1;
+         }
+         attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED;
+         attributes->version_needed = 51;
+         
+         return 0;
+    }
+
     case ZIP_SOURCE_SUPPORTS:
-	return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, -1);
+	return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1);
 
     case ZIP_SOURCE_ERROR:
 	return zip_error_to_data(&ctx->error, data, length);
diff --git a/lib/zip_source_zip_new.c b/lib/zip_source_zip_new.c
index f36609b..6d547f0 100644
--- a/lib/zip_source_zip_new.c
+++ b/lib/zip_source_zip_new.c
@@ -36,15 +36,19 @@
 
 #include "zipint.h"
 
+static void _zip_file_attributes_from_dirent(zip_file_attributes_t *attributes, zip_dirent_t *de);
 
 zip_source_t *
 _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_uint64_t len, const char *password) {
     zip_source_t *src, *s2;
-    struct zip_stat st;
+    zip_stat_t st;
+    zip_file_attributes_t attributes;
+    zip_dirent_t *de;
     bool partial_data, needs_crc, needs_decrypt, needs_decompress;
 
-    if (za == NULL)
+    if (za == NULL) {
 	return NULL;
+    }
 
     if (srcza == NULL || srcidx >= srcza->nentry) {
 	zip_error_set(&za->error, ZIP_ER_INVAL, 0);
@@ -61,8 +65,9 @@
 	return NULL;
     }
 
-    if (flags & ZIP_FL_ENCRYPTED)
+    if (flags & ZIP_FL_ENCRYPTED) {
 	flags |= ZIP_FL_COMPRESSED;
+    }
 
     if ((start > 0 || len > 0) && (flags & ZIP_FL_COMPRESSED)) {
 	zip_error_set(&za->error, ZIP_ER_INVAL, 0);
@@ -95,8 +100,13 @@
 	}
     }
 
+    if ((de = _zip_get_dirent(srcza, srcidx, flags, &za->error)) == NULL) {
+	return NULL;
+    }
+    _zip_file_attributes_from_dirent(&attributes, de);
+
     if (st.comp_size == 0) {
-	return zip_source_buffer(za, NULL, 0, 0);
+	return zip_source_buffer_with_attributes(za, NULL, 0, 0, &attributes);
     }
 
     if (partial_data && !needs_decrypt && !needs_decompress) {
@@ -108,17 +118,12 @@
 	st2.mtime = st.mtime;
 	st2.valid = ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_MTIME;
 
-	if ((src = _zip_source_window_new(srcza->src, start, len, &st2, 0, srcza, srcidx, &za->error)) == NULL) {
+	if ((src = _zip_source_window_new(srcza->src, start, len, &st2, &attributes, srcza, srcidx, &za->error)) == NULL) {
 	    return NULL;
 	}
     }
     else {
-	zip_dirent_t *de;
-
-	if ((de = _zip_get_dirent(srcza, srcidx, flags, &za->error)) == NULL) {
-	    return NULL;
-	}
-	if ((src = _zip_source_window_new(srcza->src, 0, st.comp_size, &st, (de->bitflags >> 1) & 3, srcza, srcidx, &za->error)) == NULL) {
+	if ((src = _zip_source_window_new(srcza->src, 0, st.comp_size, &st, &attributes, srcza, srcidx, &za->error)) == NULL) {
 	    return NULL;
 	}
     }
@@ -173,3 +178,14 @@
 
     return src;
 }
+
+static void
+_zip_file_attributes_from_dirent(zip_file_attributes_t *attributes, zip_dirent_t *de) {
+    zip_file_attributes_init(attributes);
+    attributes->valid = ZIP_FILE_ATTRIBUTES_ASCII | ZIP_FILE_ATTRIBUTES_HOST_SYSTEM | ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;
+    attributes->ascii = de->int_attrib & 1;
+    attributes->host_system = de->version_madeby >> 8;
+    attributes->external_file_attributes = de->ext_attrib;
+    attributes->general_purpose_bit_flags = de->bitflags;
+    attributes->general_purpose_bit_mask = ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK;
+}
diff --git a/lib/zip_stat_index.c b/lib/zip_stat_index.c
index 71f8049..7799325 100644
--- a/lib/zip_stat_index.c
+++ b/lib/zip_stat_index.c
@@ -48,7 +48,7 @@
 
 
     if ((flags & ZIP_FL_UNCHANGED) == 0 && ZIP_ENTRY_DATA_CHANGED(za->entry + index)) {
-	zip_entry_t *entry = za->entry+index;
+	zip_entry_t *entry = za->entry + index;
 
 	if (zip_source_stat(entry->source, st) < 0) {
 	    zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
diff --git a/lib/zipint.h b/lib/zipint.h
index 4cb7e73..01fdc22 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -98,6 +98,7 @@
 /* according to unzip-6.0's zipinfo.c, this corresponds to a directory with rwx permissions for everyone */
 #define ZIP_EXT_ATTRIB_DEFAULT_DIR (0040777u << 16)
 
+#define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK 0x0836
 
 #define ZIP_MAX(a, b) ((a) > (b) ? (a) : (b))
 #define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b))
@@ -131,7 +132,9 @@
     void (*deallocate)(void *ctx);
 
     /* get compression specific general purpose bitflags */
-    int (*compression_flags)(void *ctx);
+    zip_uint16_t (*general_purpose_bit_flags)(void *ctx);
+    /* minimum version needed when using this algorithm */
+    zip_uint8_t version_needed;
 
     /* start processing */
     bool (*start)(void *ctx);
@@ -178,7 +181,7 @@
 zip_source_t *zip_source_window(zip_t *, zip_source_t *, zip_uint64_t, zip_uint64_t);
 zip_source_t *zip_source_winzip_aes_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
 zip_source_t *zip_source_winzip_aes_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
-
+zip_source_t *zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes);
 
 /* error source for layered sources */
 
@@ -383,13 +386,13 @@
    for those, use malloc()/free() */
 
 #ifdef ZIP_ALLOCATE_BUFFER
-#define DEFINE_BYTE_ARRAY(buf, size)	zip_uint8_t *buf
-#define byte_array_init(buf, size)	(((buf) = (zip_uint8_t *)malloc(size)) != NULL)
-#define byte_array_fini(buf)	(free(buf))
+#define DEFINE_BYTE_ARRAY(buf, size) zip_uint8_t *buf
+#define byte_array_init(buf, size) (((buf) = (zip_uint8_t *)malloc(size)) != NULL)
+#define byte_array_fini(buf) (free(buf))
 #else
-#define DEFINE_BYTE_ARRAY(buf, size)	zip_uint8_t buf[size]
-#define byte_array_init(buf, size)	(1)
-#define byte_array_fini(buf)	((void)0)
+#define DEFINE_BYTE_ARRAY(buf, size) zip_uint8_t buf[size]
+#define byte_array_init(buf, size) (1)
+#define byte_array_fini(buf) ((void)0)
 #endif
 
 
@@ -481,6 +484,7 @@
 time_t _zip_d2u_time(zip_uint16_t, zip_uint16_t);
 void _zip_deregister_source(zip_t *za, zip_source_t *src);
 
+void _zip_dirent_apply_attributes(zip_dirent_t *, zip_file_attributes_t *, bool, zip_uint32_t);
 zip_dirent_t *_zip_dirent_clone(const zip_dirent_t *);
 void _zip_dirent_free(zip_dirent_t *);
 void _zip_dirent_finalize(zip_dirent_t *);
@@ -561,12 +565,11 @@
 zip_int64_t _zip_source_call(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command);
 bool _zip_source_eof(zip_source_t *);
 zip_source_t *_zip_source_file_or_p(const char *, FILE *, zip_uint64_t, zip_int64_t, const zip_stat_t *, zip_error_t *error);
-zip_int8_t zip_source_get_compression_flags(zip_source_t *);
 bool _zip_source_had_error(zip_source_t *);
 void _zip_source_invalidate(zip_source_t *src);
 zip_source_t *_zip_source_new(zip_error_t *error);
 int _zip_source_set_source_archive(zip_source_t *, zip_t *);
-zip_source_t *_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_int8_t compression_flags, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error);
+zip_source_t *_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_file_attributes_t *attributes, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error);
 zip_source_t *_zip_source_zip_new(zip_t *, zip_t *, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_uint64_t, const char *);
 
 int _zip_stat_merge(zip_stat_t *dst, const zip_stat_t *src, zip_error_t *error);
diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt
index 19d57bc..d0a46cb 100644
--- a/man/CMakeLists.txt
+++ b/man/CMakeLists.txt
@@ -25,6 +25,7 @@
   zip_fclose.3
   zip_fdopen.3
   zip_file_add.3
+  zip_file_attributes_init.3
   zip_file_extra_field_delete.3
   zip_file_extra_field_get.3
   zip_file_extra_field_set.3
diff --git a/man/libzip.man b/man/libzip.man
index aac756e..b3a2bb6 100644
--- a/man/libzip.man
+++ b/man/libzip.man
@@ -30,7 +30,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.TH "LIBZIP" "3" "January 7, 2020" "NiH" "Library Functions Manual"
+.TH "LIBZIP" "3" "April 17, 2020" "NiH" "Library Functions Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -120,6 +120,12 @@
 .PD 0
 .TP 4n
 \fB\(bu\fR
+zip_compression_method_supported(3)
+.TP 4n
+\fB\(bu\fR
+zip_encryption_method_supported(3)
+.TP 4n
+\fB\(bu\fR
 zip_file_get_comment(3)
 .TP 4n
 \fB\(bu\fR
@@ -249,10 +255,13 @@
 .SS "miscellaneous (writing)"
 .TP 4n
 \fB\(bu\fR
-zip_libzip_version(3)
+zip_file_attributes_init(3)
 .PD 0
 .TP 4n
 \fB\(bu\fR
+zip_libzip_version(3)
+.TP 4n
+\fB\(bu\fR
 zip_register_progress_callback_with_state(3)
 .TP 4n
 \fB\(bu\fR
diff --git a/man/libzip.mdoc b/man/libzip.mdoc
index 70917db..ec2fd6c 100644
--- a/man/libzip.mdoc
+++ b/man/libzip.mdoc
@@ -29,7 +29,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd April 2, 2020
+.Dd April 17, 2020
 .Dt LIBZIP 3
 .Os
 .Sh NAME
@@ -209,6 +209,8 @@
 .Ss miscellaneous (writing)
 .Bl -bullet -compact
 .It
+.Xr zip_file_attributes_init 3
+.It
 .Xr zip_libzip_version 3
 .It
 .Xr zip_register_progress_callback_with_state 3
diff --git a/man/zip_compression_method_supported.man b/man/zip_compression_method_supported.man
new file mode 100644
index 0000000..44811f2
--- /dev/null
+++ b/man/zip_compression_method_supported.man
@@ -0,0 +1,70 @@
+.\" Automatically generated from an mdoc input file.  Do not edit.
+.\" zip_compression_method_supported.mdoc -- return if compression method is supported
+.\" Copyright (C) 2020 Dieter Baron and Thomas Klausner
+.\"
+.\" This file is part of libzip, a library to manipulate ZIP files.
+.\" The authors can be contacted at <libzip@nih.at>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in
+.\"    the documentation and/or other materials provided with the
+.\"    distribution.
+.\" 3. The names of the authors may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.TH "ZIP_COMPRESSION_METHOD_SUPPORTED" "3" "April 2, 2020" "NiH" "Library Functions Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBzip_compression_method_supported\fR
+\- return if a compression method is supported
+.SH "LIBRARY"
+libzip (-lzip)
+.SH "SYNOPSIS"
+\fB#include <zip.h>\fR
+.sp
+\fIint\fR
+.br
+.PD 0
+.HP 4n
+\fBzip_compression_method_supported\fR(\fIzip_int32_t\ method\fR, \fIint\ compress\fR);
+.PD
+.SH "DESCRIPTION"
+The
+\fBzip_compression_method_supported\fR()
+returns if the compression method
+\fImethod\fR
+is supported for compression (if
+\fIcompress\fR
+is zero) or decompression (otherwise).
+.SH "RETURN VALUES"
+Returns 1 if the method is supported, 0 otherwise.
+.SH "SEE ALSO"
+libzip(3),
+zip_encryption_method_supported(3),
+zip_set_file_compression(3)
+.SH "HISTORY"
+\fBzip_compression_method_supported\fR()
+was added in libzip 1.7.0.
+.SH "AUTHORS"
+Dieter Baron <\fIdillo@nih.at\fR>
+and
+Thomas Klausner <\fItk@giga.or.at\fR>
diff --git a/man/zip_encryption_method_supported.man b/man/zip_encryption_method_supported.man
new file mode 100644
index 0000000..4ab4e3b
--- /dev/null
+++ b/man/zip_encryption_method_supported.man
@@ -0,0 +1,70 @@
+.\" Automatically generated from an mdoc input file.  Do not edit.
+.\" zip_encryption_method_supported.mdoc -- return if encryption method is supported
+.\" Copyright (C) 2020 Dieter Baron and Thomas Klausner
+.\"
+.\" This file is part of libzip, a library to manipulate ZIP files.
+.\" The authors can be contacted at <libzip@nih.at>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in
+.\"    the documentation and/or other materials provided with the
+.\"    distribution.
+.\" 3. The names of the authors may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.TH "ZIP_ENCRYPTION_METHOD_SUPPORTED" "3" "April 2, 2020" "NiH" "Library Functions Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBzip_encryption_method_supported\fR
+\- return if an encryption method is supported
+.SH "LIBRARY"
+libzip (-lzip)
+.SH "SYNOPSIS"
+\fB#include <zip.h>\fR
+.sp
+\fIint\fR
+.br
+.PD 0
+.HP 4n
+\fBzip_encryption_method_supported\fR(\fIzip_int16_t\ method\fR, \fIint\ encrypt\fR);
+.PD
+.SH "DESCRIPTION"
+The
+\fBzip_encryption_method_supported\fR()
+returns if the encryption method
+\fImethod\fR
+is supported for encryption (if
+\fIencrypt\fR
+is zero) or decryption (otherwise).
+.SH "RETURN VALUES"
+Returns 1 if the method is supported, 0 otherwise.
+.SH "SEE ALSO"
+libzip(3),
+zip_compression_method_supported(3),
+zip_file_set_encryption(3)
+.SH "HISTORY"
+\fBzip_encryption_method_supported\fR()
+was added in libzip 1.7.0.
+.SH "AUTHORS"
+Dieter Baron <\fIdillo@nih.at\fR>
+and
+Thomas Klausner <\fItk@giga.or.at\fR>
diff --git a/man/zip_error_set.man b/man/zip_error_set.man
index 250b97f..9bc4cb8 100644
--- a/man/zip_error_set.man
+++ b/man/zip_error_set.man
@@ -30,7 +30,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.TH "ZIP_ERROR_SET" "3" "December 18, 2017" "NiH" "Library Functions Manual"
+.TH "ZIP_ERROR_SET" "3" "April 2, 2020" "NiH" "Library Functions Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -59,7 +59,7 @@
 .PP
 \fIze\fR
 must be allocated and initialized with
-zip_error_fini(3)
+zip_error_init(3)
 before calling
 \fBzip_error\fR(\fIset\fR).
 .SH "SEE ALSO"
diff --git a/man/zip_file_attributes_init.man b/man/zip_file_attributes_init.man
new file mode 100644
index 0000000..20036c9
--- /dev/null
+++ b/man/zip_file_attributes_init.man
@@ -0,0 +1,66 @@
+.\" Automatically generated from an mdoc input file.  Do not edit.
+.\" zip_file_attributes_init.mdoc -- initialize attributes structure
+.\" Copyright (C) 2020 Dieter Baron and Thomas Klausner
+.\"
+.\" This file is part of libzip, a library to manipulate ZIP files.
+.\" The authors can be contacted at <libzip@nih.at>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in
+.\"    the documentation and/or other materials provided with the
+.\"    distribution.
+.\" 3. The names of the authors may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.TH "ZIP_FILE_ATTRIBUTES_INIT" "" "April 17, 2020" "NiH" "LOCAL"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBzip_file_attributes_init\fR
+\- initialize zip file attributes structure
+.SH "LIBRARY"
+libzip (-lzip)
+.SH "SYNOPSIS"
+\fB#include <zip.h>\fR
+.sp
+\fIvoid\fR
+.br
+.PD 0
+.HP 4n
+\fBzip_file_attributes_init\fR(\fIzip_file_attributes_t\ *attributes\fR);
+.PD
+.SH "DESCRIPTION"
+The
+\fBzip_file_attributes_init\fR()
+initializes a
+\fIzip_file_attributes_t\fR
+structure with default values.
+It must be called before modifying such a structure for the first time.
+.SH "SEE ALSO"
+libzip(3),
+zip_source_function(3)
+.SH "HISTORY"
+\fBzip_file_attributes_init\fR()
+was added in libzip 1.7.0.
+.SH "AUTHORS"
+Dieter Baron <\fIdillo@nih.at\fR>
+and
+Thomas Klausner <\fItk@giga.or.at\fR>
diff --git a/man/zip_file_attributes_init.mdoc b/man/zip_file_attributes_init.mdoc
new file mode 100644
index 0000000..93d2981
--- /dev/null
+++ b/man/zip_file_attributes_init.mdoc
@@ -0,0 +1,61 @@
+.\" zip_file_attributes_init.mdoc -- initialize attributes structure
+.\" Copyright (C) 2020 Dieter Baron and Thomas Klausner
+.\"
+.\" This file is part of libzip, a library to manipulate ZIP files.
+.\" The authors can be contacted at <libzip@nih.at>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in
+.\"    the documentation and/or other materials provided with the
+.\"    distribution.
+.\" 3. The names of the authors may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd April 17, 2020
+.Dt ZIP_FILE_ATTRIBUTES_INIT
+.Os
+.Sh NAME
+.Nm zip_file_attributes_init
+.Nd initialize zip file attributes structure
+.Sh LIBRARY
+libzip (-lzip)
+.Sh SYNOPSIS
+.In zip.h
+.Ft void
+.Fn zip_file_attributes_init "zip_file_attributes_t *attributes"
+.Sh DESCRIPTION
+The
+.Fn zip_file_attributes_init
+initializes a
+.Vt zip_file_attributes_t
+structure with default values.
+It must be called before modifying such a structure for the first time.
+.Sh SEE ALSO
+.Xr libzip 3 ,
+.Xr zip_source_function 3
+.Sh HISTORY
+.Fn zip_file_attributes_init
+was added in libzip 1.7.0.
+.Sh AUTHORS
+.An -nosplit
+.An Dieter Baron Aq Mt dillo@nih.at
+and
+.An Thomas Klausner Aq Mt tk@giga.or.at
diff --git a/man/zip_file_set_encryption.man b/man/zip_file_set_encryption.man
index d82e28e..da983f9 100644
--- a/man/zip_file_set_encryption.man
+++ b/man/zip_file_set_encryption.man
@@ -30,7 +30,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.TH "ZIP_FILE_SET_ENCRYPTION" "3" "December 18, 2017" "NiH" "Library Functions Manual"
+.TH "ZIP_FILE_SET_ENCRYPTION" "3" "April 2, 2020" "NiH" "Library Functions Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -75,6 +75,12 @@
 .TP 19n
 \fRZIP_EM_AES_256\fR
 Winzip AES-256 encryption.
+.TP 19n
+\fRZIP_EM_TRAD_PKWARE\fR
+.br
+Traditional PKWare encryption.
+Do not use this method, it is not secure.
+It is only provided for backwards compatibility.
 .PP
 If
 \fIpassword\fR
@@ -112,6 +118,9 @@
 Read-only zip file, no changes allowed.
 .SH "SEE ALSO"
 libzip(3),
+zip_encryption_method_supported(3),
+zip_fopen_encrypted(3),
+zip_fopen_index_encrypted(3),
 zip_set_default_password(3),
 zip_stat(3)
 .SH "HISTORY"
diff --git a/man/zip_set_file_compression.man b/man/zip_set_file_compression.man
index 759309b..15bacde 100644
--- a/man/zip_set_file_compression.man
+++ b/man/zip_set_file_compression.man
@@ -30,7 +30,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.TH "ZIP_SET_FILE_COMPRESSION" "3" "December 18, 2017" "NiH" "Library Functions Manual"
+.TH "ZIP_SET_FILE_COMPRESSION" "3" "April 2, 2020" "NiH" "Library Functions Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -121,6 +121,7 @@
 Read-only zip file, no changes allowed.
 .SH "SEE ALSO"
 libzip(3),
+zip_compression_method_supported(3),
 zip_stat(3)
 .SH "HISTORY"
 \fBzip_set_file_compression\fR()
diff --git a/man/zip_source_function.man b/man/zip_source_function.man
index 4901694..4d43f99 100644
--- a/man/zip_source_function.man
+++ b/man/zip_source_function.man
@@ -30,7 +30,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.TH "ZIP_SOURCE_FUNCTION" "3" "September 17, 2019" "NiH" "Library Functions Manual"
+.TH "ZIP_SOURCE_FUNCTION" "3" "April 17, 2020" "NiH" "Library Functions Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -163,6 +163,65 @@
 Clean up and free all resources, including
 \fIuserdata\fR.
 The callback function will not be called again.
+.SS "\fRZIP_SOURCE_GET_FILE_ATTRIBUTES\fR"
+Provide information about various data.
+Then the data should be put in the appropriate entry in the passed
+\fIzip_file_attributes_t\fR
+argument, and the appropriate
+\fRZIP_FILE_ATTRIBUTES_*\fR
+value must be or'ed into the
+\fIvalid\fR
+member to denote that the corresponding data has been provided.
+A
+\fIzip_file_attributes_t\fR
+structure can be initialized using
+zip_file_attributes_init(3).
+.TP 12n
+ASCII mode
+If a file is a plaintext file in ASCII.
+Can be used by extraction tools to automatically convert line endings
+(part of the interal file attributes).
+Member
+\fIascii\fR,
+flag
+\fRZIP_FILE_ATTRIBUTES_ASCII\fR.
+.TP 12n
+General Purpose Bit Flags (limited to Compression Flags)
+The general purpose bit flag in the zip in the local and central
+directory headers contain information about the compression method.
+Member
+\fIgeneral_purpose_bit_flags\fR
+and
+\fIgeneral_purpose_bit_mask\fR
+to denote which members have been set;
+flag
+\fRZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS\fR.
+.TP 12n
+External File Attributes
+The external file attributes (usually operating system-specific).
+Member
+\fIexternal_file_attributes\fR,
+flag
+\fRZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES\fR.
+.TP 12n
+Version Needed
+A minimum version needed required to unpack this entry (in the usual
+"major * 10 + minor" format).
+Member
+\fIversion_needed\fR,
+flag
+\fRZIP_FILE_ATTRIBUTES_VERSION_NEEDED\fR.
+.TP 12n
+Operating System
+One of the operating systems as defined by the
+\fRZIP_OPSYS_*\fR
+variables (see
+\fIzip.h\fR).
+This value affects the interpretation of the external file attributes.
+Member
+\fIhost_system\fR,
+flag
+\fRZIP_FILE_ATTRIBUTES_HOST_SYSTEM\fR.
 .SS "\fRZIP_SOURCE_OPEN\fR"
 Prepare for reading.
 .SS "\fRZIP_SOURCE_READ\fR"
@@ -293,6 +352,9 @@
 \fRZIP_SOURCE_ROLLBACK_WRITE\fR
 will be called.
 .PP
+\fRZIP_SOURCE_ACCEPT_EMPTY\fR,
+\fRZIP_SOURCE_GET_FILE_ATTRIBUTES\fR,
+and
 \fRZIP_SOURCE_STAT\fR
 can be issued at any time.
 .PP
@@ -336,6 +398,7 @@
 .SH "SEE ALSO"
 libzip(3),
 zip_file_add(3),
+zip_file_attributes_init(3),
 zip_file_replace(3),
 zip_source(3),
 zip_stat_init(3)
diff --git a/man/zip_source_function.mdoc b/man/zip_source_function.mdoc
index 9a9cc4b..aeb31f5 100644
--- a/man/zip_source_function.mdoc
+++ b/man/zip_source_function.mdoc
@@ -29,7 +29,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd September 17, 2019
+.Dd April 17, 2020
 .Dt ZIP_SOURCE_FUNCTION 3
 .Os
 .Sh NAME
@@ -153,6 +153,62 @@
 Clean up and free all resources, including
 .Ar userdata .
 The callback function will not be called again.
+.Ss Dv ZIP_SOURCE_GET_FILE_ATTRIBUTES
+Provide information about various data.
+Then the data should be put in the appropriate entry in the passed
+.Vt zip_file_attributes_t
+argument, and the appropriate
+.Dv ZIP_FILE_ATTRIBUTES_*
+value must be or'ed into the
+.Ar valid
+member to denote that the corresponding data has been provided.
+A
+.Vt zip_file_attributes_t
+structure can be initialized using
+.Xr zip_file_attributes_init 3 .
+.Bl -tag -width 10n
+.It ASCII mode
+If a file is a plaintext file in ASCII.
+Can be used by extraction tools to automatically convert line endings
+(part of the interal file attributes).
+Member
+.Ar ascii ,
+flag
+.Dv ZIP_FILE_ATTRIBUTES_ASCII .
+.It General Purpose Bit Flags (limited to Compression Flags)
+The general purpose bit flag in the zip in the local and central
+directory headers contain information about the compression method.
+Member
+.Ar general_purpose_bit_flags
+and
+.Ar general_purpose_bit_mask
+to denote which members have been set;
+flag
+.Dv ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS .
+.It External File Attributes
+The external file attributes (usually operating system-specific).
+Member
+.Ar external_file_attributes ,
+flag
+.Dv ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES .
+.It Version Needed
+A minimum version needed required to unpack this entry (in the usual
+"major * 10 + minor" format).
+Member
+.Ar version_needed ,
+flag
+.Dv ZIP_FILE_ATTRIBUTES_VERSION_NEEDED .
+.It Operating System
+One of the operating systems as defined by the
+.Dv ZIP_OPSYS_*
+variables (see
+.Pa zip.h ) .
+This value affects the interpretation of the external file attributes.
+Member
+.Ar host_system ,
+flag
+.Dv ZIP_FILE_ATTRIBUTES_HOST_SYSTEM .
+.El
 .Ss Dv ZIP_SOURCE_OPEN
 Prepare for reading.
 .Ss Dv ZIP_SOURCE_READ
@@ -280,6 +336,9 @@
 .Dv ZIP_SOURCE_ROLLBACK_WRITE
 will be called.
 .Pp
+.Dv ZIP_SOURCE_ACCEPT_EMPTY ,
+.Dv ZIP_SOURCE_GET_FILE_ATTRIBUTES ,
+and
 .Dv ZIP_SOURCE_STAT
 can be issued at any time.
 .Pp
@@ -324,6 +383,7 @@
 .Sh SEE ALSO
 .Xr libzip 3 ,
 .Xr zip_file_add 3 ,
+.Xr zip_file_attributes_init 3 ,
 .Xr zip_file_replace 3 ,
 .Xr zip_source 3 ,
 .Xr zip_stat_init 3
diff --git a/regress/bigstored.zh b/regress/bigstored.zh
index 359a943..2a53bff 100644
--- a/regress/bigstored.zh
+++ b/regress/bigstored.zh
Binary files differ
diff --git a/regress/encrypt-aes128-noentropy.zip b/regress/encrypt-aes128-noentropy.zip
index c588fc9..01d5bc6 100644
--- a/regress/encrypt-aes128-noentropy.zip
+++ b/regress/encrypt-aes128-noentropy.zip
Binary files differ
diff --git a/regress/encrypt-aes192-noentropy.zip b/regress/encrypt-aes192-noentropy.zip
index 59605a0..0a9ad4b 100644
--- a/regress/encrypt-aes192-noentropy.zip
+++ b/regress/encrypt-aes192-noentropy.zip
Binary files differ
diff --git a/regress/encrypt-aes256-noentropy.zip b/regress/encrypt-aes256-noentropy.zip
index 742ada6..b3a6cad 100644
--- a/regress/encrypt-aes256-noentropy.zip
+++ b/regress/encrypt-aes256-noentropy.zip
Binary files differ
diff --git a/regress/encrypt-none.zip b/regress/encrypt-none.zip
index 0a2f770..c7ba696 100644
--- a/regress/encrypt-none.zip
+++ b/regress/encrypt-none.zip
Binary files differ
diff --git a/regress/encrypt-pkware-noentropy.zip b/regress/encrypt-pkware-noentropy.zip
index ee0833d..e0c39a7 100644
--- a/regress/encrypt-pkware-noentropy.zip
+++ b/regress/encrypt-pkware-noentropy.zip
Binary files differ
diff --git a/regress/gap-add.zip b/regress/gap-add.zip
index d70bfbd..e1a0159 100644
--- a/regress/gap-add.zip
+++ b/regress/gap-add.zip
Binary files differ
diff --git a/regress/gap-replace.zip b/regress/gap-replace.zip
index 610ca06..27e0580 100644
--- a/regress/gap-replace.zip
+++ b/regress/gap-replace.zip
Binary files differ
diff --git a/regress/utf-8-standardization-output.zip b/regress/utf-8-standardization-output.zip
index 2507a76..266027f 100644
--- a/regress/utf-8-standardization-output.zip
+++ b/regress/utf-8-standardization-output.zip
Binary files differ