jun7572 5 lat temu
rodzic
commit
05e5dec5c6
45 zmienionych plików z 12465 dodań i 28 usunięć
  1. 1 8
      example/ios/Podfile.lock
  2. 1 1
      example/ios/Runner/Runner-Bridging-Header.h
  3. 9 7
      example/lib/main.dart
  4. 19 3
      ios/Classes/FlutterzipPlugin.m
  5. 120 0
      ios/Classes/SSZipArchive/SSZipArchive.h
  6. 1024 0
      ios/Classes/SSZipArchive/SSZipArchive.m
  7. 65 0
      ios/Classes/SSZipArchive/SSZipCommon.h
  8. 19 0
      ios/Classes/SSZipArchive/ZipArchive.h
  9. 270 0
      ios/Classes/SSZipArchive/minizip/aes/aes.h
  10. 687 0
      ios/Classes/SSZipArchive/minizip/aes/aes_ni.c
  11. 59 0
      ios/Classes/SSZipArchive/minizip/aes/aes_ni.h
  12. 301 0
      ios/Classes/SSZipArchive/minizip/aes/aescrypt.c
  13. 554 0
      ios/Classes/SSZipArchive/minizip/aes/aeskey.c
  14. 776 0
      ios/Classes/SSZipArchive/minizip/aes/aesopt.h
  15. 418 0
      ios/Classes/SSZipArchive/minizip/aes/aestab.c
  16. 173 0
      ios/Classes/SSZipArchive/minizip/aes/aestab.h
  17. 127 0
      ios/Classes/SSZipArchive/minizip/aes/brg_endian.h
  18. 191 0
      ios/Classes/SSZipArchive/minizip/aes/brg_types.h
  19. 145 0
      ios/Classes/SSZipArchive/minizip/aes/fileenc.c
  20. 121 0
      ios/Classes/SSZipArchive/minizip/aes/fileenc.h
  21. 209 0
      ios/Classes/SSZipArchive/minizip/aes/hmac.c
  22. 119 0
      ios/Classes/SSZipArchive/minizip/aes/hmac.h
  23. 155 0
      ios/Classes/SSZipArchive/minizip/aes/prng.c
  24. 82 0
      ios/Classes/SSZipArchive/minizip/aes/prng.h
  25. 181 0
      ios/Classes/SSZipArchive/minizip/aes/pwd2key.c
  26. 45 0
      ios/Classes/SSZipArchive/minizip/aes/pwd2key.h
  27. 283 0
      ios/Classes/SSZipArchive/minizip/aes/sha1.c
  28. 72 0
      ios/Classes/SSZipArchive/minizip/aes/sha1.h
  29. 161 0
      ios/Classes/SSZipArchive/minizip/crypt.c
  30. 64 0
      ios/Classes/SSZipArchive/minizip/crypt.h
  31. 353 0
      ios/Classes/SSZipArchive/minizip/ioapi.c
  32. 148 0
      ios/Classes/SSZipArchive/minizip/ioapi.h
  33. 461 0
      ios/Classes/SSZipArchive/minizip/ioapi_buf.c
  34. 52 0
      ios/Classes/SSZipArchive/minizip/ioapi_buf.h
  35. 167 0
      ios/Classes/SSZipArchive/minizip/ioapi_mem.c
  36. 52 0
      ios/Classes/SSZipArchive/minizip/ioapi_mem.h
  37. 292 0
      ios/Classes/SSZipArchive/minizip/minishared.c
  38. 51 0
      ios/Classes/SSZipArchive/minizip/minishared.h
  39. 1978 0
      ios/Classes/SSZipArchive/minizip/unzip.c
  40. 252 0
      ios/Classes/SSZipArchive/minizip/unzip.h
  41. 1982 0
      ios/Classes/SSZipArchive/minizip/zip.c
  42. 200 0
      ios/Classes/SSZipArchive/minizip/zip.h
  43. 9 7
      ios/Classes/SwiftFlutterzipPlugin.swift
  44. 16 0
      ios/Classes/flutterzip-Bridging-Header.h
  45. 1 2
      ios/flutterzip.podspec

+ 1 - 8
example/ios/Podfile.lock

@@ -2,14 +2,12 @@ PODS:
   - Flutter (1.0.0)
   - flutterzip (0.0.1):
     - Flutter
-    - SSZipArchive (~> 2.0.7)
   - path_provider (0.0.1):
     - Flutter
   - path_provider_linux (0.0.1):
     - Flutter
   - path_provider_macos (0.0.1):
     - Flutter
-  - SSZipArchive (2.0.8)
 
 DEPENDENCIES:
   - Flutter (from `Flutter`)
@@ -18,10 +16,6 @@ DEPENDENCIES:
   - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`)
   - path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`)
 
-SPEC REPOS:
-  trunk:
-    - SSZipArchive
-
 EXTERNAL SOURCES:
   Flutter:
     :path: Flutter
@@ -36,11 +30,10 @@ EXTERNAL SOURCES:
 
 SPEC CHECKSUMS:
   Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
-  flutterzip: a8971d695daf2b81861b8f314a83e9c25d66f1d9
+  flutterzip: 8fc124115a0105514642ac325a3433a2ddf8067b
   path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
   path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4
   path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0
-  SSZipArchive: e6ab66e1936fac7e3b5073e9f5eb364d91dfbfc7
 
 PODFILE CHECKSUM: 084be47092790d3d5f09fbc6f87a2e8bf7177d4a
 

+ 1 - 1
example/ios/Runner/Runner-Bridging-Header.h

@@ -1,2 +1,2 @@
 #import "GeneratedPluginRegistrant.h"
-#import "SSZipArchive.h"
+//#import "SSZipArchive.h"

+ 9 - 7
example/lib/main.dart

@@ -60,10 +60,11 @@ class _MyAppState extends State<MyApp> {
   String  s="http://139.199.153.108:8080/2-05%20The%20Go-Kart.zip";
    directory = await getTemporaryDirectory();
 
-//  var savePath=directory.path+"/2-05 The Go-Kart.zip";
+  var savePath=directory.path+"/2-05 The Go-Kart.zip";
    unzipPath=directory.path+"/2-05 The Go-Kart.zip";
     outPath=directory.path+"/2-05 The Go-Kart";
-//  var response = await Dio().download(s,savePath);
+  var response = await Dio().download(s,savePath);
+  print("download====ok");
 
   //查看文件
 //   print("response.toString()=="+response.toString());
@@ -88,11 +89,12 @@ class _MyAppState extends State<MyApp> {
               child: Text('Running on: $_platformVersion\n'),
             ),
             RaisedButton(
-              onPressed: (){
-                  Flutterzip.unpack(unzipPath, outPath);
-                  Flutterzip.onProcessChange.stream.listen((event) {
-                    print("========="+event.toString());
-                  });
+              onPressed: ()async{
+                 await Flutterzip.unpack(unzipPath, outPath);
+                 print("okokoko");
+//                  Flutterzip.onProcessChange.stream.listen((event) {
+//                    print("========="+event.toString());
+//                  });
               },
               child: Text("解压"),
             ),

+ 19 - 3
ios/Classes/FlutterzipPlugin.m

@@ -7,10 +7,26 @@
 // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
 #import "flutterzip-Swift.h"
 #endif
-
+#import "SSZipArchive/ZipArchive.h"
 @implementation FlutterzipPlugin
 + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
-  [SwiftFlutterzipPlugin registerWithRegistrar:registrar];
-    
+//  [SwiftFlutterzipPlugin registerWithRegistrar:registrar];
+    FlutterMethodChannel* channel = [FlutterMethodChannel  methodChannelWithName:@"flutterzip" binaryMessenger:[registrar messenger]];
+    FlutterzipPlugin* instance = [[FlutterzipPlugin alloc] init];
+    [registrar addMethodCallDelegate:instance channel:channel];
+}
+
+- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
+  if ([@"getPlatformVersion" isEqualToString:call.method]) {
+    result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
+  } else if ([@"unpack" isEqualToString:call.method]){
+     NSString *outPath = call.arguments[@"outPath"];
+      NSString *unzipPath = call.arguments[@"unzipPath"];
+       BOOL success = [SSZipArchive unzipFileAtPath:unzipPath toDestination:outPath];
+      if(success){
+           result(@"ok");
+      }
+  }
 }
+
 @end

+ 120 - 0
ios/Classes/SSZipArchive/SSZipArchive.h

@@ -0,0 +1,120 @@
+//
+//  SSZipArchive.h
+//  SSZipArchive
+//
+//  Created by Sam Soffes on 7/21/10.
+//  Copyright (c) Sam Soffes 2010-2015. All rights reserved.
+//
+
+#ifndef _SSZIPARCHIVE_H
+#define _SSZIPARCHIVE_H
+
+#import <Foundation/Foundation.h>
+#include "SSZipCommon.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+extern NSString *const SSZipArchiveErrorDomain;
+typedef NS_ENUM(NSInteger, SSZipArchiveErrorCode) {
+    SSZipArchiveErrorCodeFailedOpenZipFile      = -1,
+    SSZipArchiveErrorCodeFailedOpenFileInZip    = -2,
+    SSZipArchiveErrorCodeFileInfoNotLoadable    = -3,
+    SSZipArchiveErrorCodeFileContentNotReadable = -4,
+    SSZipArchiveErrorCodeFailedToWriteFile      = -5,
+    SSZipArchiveErrorCodeInvalidArguments       = -6,
+};
+
+@protocol SSZipArchiveDelegate;
+
+@interface SSZipArchive : NSObject
+
+// Password check
++ (BOOL)isFilePasswordProtectedAtPath:(NSString *)path;
++ (BOOL)isPasswordValidForArchiveAtPath:(NSString *)path password:(NSString *)pw error:(NSError * _Nullable * _Nullable)error NS_SWIFT_NOTHROW;
+
+// Unzip
++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination;
++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(nullable id<SSZipArchiveDelegate>)delegate;
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+          toDestination:(NSString *)destination
+              overwrite:(BOOL)overwrite
+               password:(nullable NSString *)password
+                  error:(NSError * *)error;
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+          toDestination:(NSString *)destination
+              overwrite:(BOOL)overwrite
+               password:(nullable NSString *)password
+                  error:(NSError * *)error
+               delegate:(nullable id<SSZipArchiveDelegate>)delegate NS_REFINED_FOR_SWIFT;
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+          toDestination:(NSString *)destination
+     preserveAttributes:(BOOL)preserveAttributes
+              overwrite:(BOOL)overwrite
+               password:(nullable NSString *)password
+                  error:(NSError * *)error
+               delegate:(nullable id<SSZipArchiveDelegate>)delegate;
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+          toDestination:(NSString *)destination
+        progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+      completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+          toDestination:(NSString *)destination
+              overwrite:(BOOL)overwrite
+               password:(nullable NSString *)password
+        progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+      completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;
+
+// Zip
+
+// without password
++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths;
++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath;
+
++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory;
+
+// with password, password could be nil
++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(nullable NSString *)password;
++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath withPassword:(nullable NSString *)password;
++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory withPassword:(nullable NSString *)password;
++ (BOOL)createZipFileAtPath:(NSString *)path
+    withContentsOfDirectory:(NSString *)directoryPath
+        keepParentDirectory:(BOOL)keepParentDirectory
+               withPassword:(nullable NSString *)password
+         andProgressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler;
+
+- (instancetype)init NS_UNAVAILABLE;
+- (instancetype)initWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER;
+- (BOOL)open;
+- (BOOL)writeFile:(NSString *)path withPassword:(nullable NSString *)password;
+- (BOOL)writeFolderAtPath:(NSString *)path withFolderName:(NSString *)folderName withPassword:(nullable NSString *)password;
+- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName withPassword:(nullable NSString *)password;
+- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename withPassword:(nullable NSString *)password;
+- (BOOL)close;
+
+@end
+
+@protocol SSZipArchiveDelegate <NSObject>
+
+@optional
+
+- (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo;
+- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath;
+
+- (BOOL)zipArchiveShouldUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
+- (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
+- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
+- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath unzippedFilePath:(NSString *)unzippedFilePath;
+
+- (void)zipArchiveProgressEvent:(unsigned long long)loaded total:(unsigned long long)total;
+- (void)zipArchiveDidUnzipArchiveFile:(NSString *)zipFile entryPath:(NSString *)entryPath destPath:(NSString *)destPath;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif /* _SSZIPARCHIVE_H */

+ 1024 - 0
ios/Classes/SSZipArchive/SSZipArchive.m

@@ -0,0 +1,1024 @@
+//
+//  SSZipArchive.m
+//  SSZipArchive
+//
+//  Created by Sam Soffes on 7/21/10.
+//  Copyright (c) Sam Soffes 2010-2015. All rights reserved.
+//
+
+#import "SSZipArchive.h"
+#include "unzip.h"
+#include "zip.h"
+#include "minishared.h"
+
+#include <sys/stat.h>
+
+NSString *const SSZipArchiveErrorDomain = @"SSZipArchiveErrorDomain";
+
+#define CHUNK 16384
+
+#ifndef API_AVAILABLE
+// Xcode 7- compatibility
+#define API_AVAILABLE(...)
+#endif
+
+@interface NSData(SSZipArchive)
+- (NSString *)_base64RFC4648 API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));
+- (NSString *)_hexString;
+@end
+
+@interface SSZipArchive ()
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+@end
+
+@implementation SSZipArchive
+{
+    /// path for zip file
+    NSString *_path;
+    zipFile _zip;
+}
+
+#pragma mark - Password check
+
++ (BOOL)isFilePasswordProtectedAtPath:(NSString *)path {
+    // Begin opening
+    zipFile zip = unzOpen(path.fileSystemRepresentation);
+    if (zip == NULL) {
+        return NO;
+    }
+    
+    int ret = unzGoToFirstFile(zip);
+    if (ret == UNZ_OK) {
+        do {
+            ret = unzOpenCurrentFile(zip);
+            if (ret != UNZ_OK) {
+                return NO;
+            }
+            unz_file_info fileInfo = {0};
+            ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
+            if (ret != UNZ_OK) {
+                return NO;
+            } else if ((fileInfo.flag & 1) == 1) {
+                return YES;
+            }
+            
+            unzCloseCurrentFile(zip);
+            ret = unzGoToNextFile(zip);
+        } while (ret == UNZ_OK && UNZ_OK != UNZ_END_OF_LIST_OF_FILE);
+    }
+    
+    return NO;
+}
+
++ (BOOL)isPasswordValidForArchiveAtPath:(NSString *)path password:(NSString *)pw error:(NSError **)error {
+    if (error) {
+        *error = nil;
+    }
+
+    zipFile zip = unzOpen(path.fileSystemRepresentation);
+    if (zip == NULL) {
+        if (error) {
+            *error = [NSError errorWithDomain:SSZipArchiveErrorDomain
+                                         code:SSZipArchiveErrorCodeFailedOpenZipFile
+                                     userInfo:@{NSLocalizedDescriptionKey: @"failed to open zip file"}];
+        }
+        return NO;
+    }
+
+    int ret = unzGoToFirstFile(zip);
+    if (ret == UNZ_OK) {
+        do {
+            if (pw.length == 0) {
+                ret = unzOpenCurrentFile(zip);
+            } else {
+                ret = unzOpenCurrentFilePassword(zip, [pw cStringUsingEncoding:NSUTF8StringEncoding]);
+            }
+            if (ret != UNZ_OK) {
+                if (ret != UNZ_BADPASSWORD) {
+                    if (error) {
+                        *error = [NSError errorWithDomain:SSZipArchiveErrorDomain
+                                                     code:SSZipArchiveErrorCodeFailedOpenFileInZip
+                                                 userInfo:@{NSLocalizedDescriptionKey: @"failed to open first file in zip file"}];
+                    }
+                }
+                return NO;
+            }
+            unz_file_info fileInfo = {0};
+            ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
+            if (ret != UNZ_OK) {
+                if (error) {
+                    *error = [NSError errorWithDomain:SSZipArchiveErrorDomain
+                                                 code:SSZipArchiveErrorCodeFileInfoNotLoadable
+                                             userInfo:@{NSLocalizedDescriptionKey: @"failed to retrieve info for file"}];
+                }
+                return NO;
+            } else if ((fileInfo.flag & 1) == 1) {
+                unsigned char buffer[10] = {0};
+                int readBytes = unzReadCurrentFile(zip, buffer, (unsigned)MIN(10UL,fileInfo.uncompressed_size));
+                if (readBytes < 0) {
+                    // Let's assume the invalid password caused this error
+                    if (readBytes != Z_DATA_ERROR) {
+                        if (error) {
+                            *error = [NSError errorWithDomain:SSZipArchiveErrorDomain
+                                                         code:SSZipArchiveErrorCodeFileContentNotReadable
+                                                     userInfo:@{NSLocalizedDescriptionKey: @"failed to read contents of file entry"}];
+                        }
+                    }
+                    return NO;
+                }
+                return YES;
+            }
+            
+            unzCloseCurrentFile(zip);
+            ret = unzGoToNextFile(zip);
+        } while (ret == UNZ_OK && UNZ_OK != UNZ_END_OF_LIST_OF_FILE);
+    }
+
+    // No password required
+    return YES;
+}
+
+#pragma mark - Unzipping
+
++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination
+{
+    return [self unzipFileAtPath:path toDestination:destination delegate:nil];
+}
+
++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(nullable NSString *)password error:(NSError **)error
+{
+    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:overwrite password:password error:error delegate:nil progressHandler:nil completionHandler:nil];
+}
+
++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(nullable id<SSZipArchiveDelegate>)delegate
+{
+    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:YES password:nil error:nil delegate:delegate progressHandler:nil completionHandler:nil];
+}
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+          toDestination:(NSString *)destination
+              overwrite:(BOOL)overwrite
+               password:(nullable NSString *)password
+                  error:(NSError **)error
+               delegate:(nullable id<SSZipArchiveDelegate>)delegate
+{
+    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:overwrite password:password error:error delegate:delegate progressHandler:nil completionHandler:nil];
+}
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+          toDestination:(NSString *)destination
+              overwrite:(BOOL)overwrite
+               password:(NSString *)password
+        progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+      completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler
+{
+    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:overwrite password:password error:nil delegate:nil progressHandler:progressHandler completionHandler:completionHandler];
+}
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+          toDestination:(NSString *)destination
+        progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+      completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler
+{
+    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:YES password:nil error:nil delegate:nil progressHandler:progressHandler completionHandler:completionHandler];
+}
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+          toDestination:(NSString *)destination
+     preserveAttributes:(BOOL)preserveAttributes
+              overwrite:(BOOL)overwrite
+               password:(nullable NSString *)password
+                  error:(NSError * *)error
+               delegate:(nullable id<SSZipArchiveDelegate>)delegate
+{
+    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:preserveAttributes overwrite:overwrite password:password error:error delegate:delegate progressHandler:nil completionHandler:nil];
+}
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+          toDestination:(NSString *)destination
+     preserveAttributes:(BOOL)preserveAttributes
+              overwrite:(BOOL)overwrite
+               password:(nullable NSString *)password
+                  error:(NSError **)error
+               delegate:(id<SSZipArchiveDelegate>)delegate
+        progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+      completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler
+{
+    // Guard against empty strings
+    if (path.length == 0 || destination.length == 0)
+    {
+        NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"received invalid argument(s)"};
+        NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeInvalidArguments userInfo:userInfo];
+        if (error)
+        {
+            *error = err;
+        }
+        if (completionHandler)
+        {
+            completionHandler(nil, NO, err);
+        }
+        return NO;
+    }
+    
+    // Begin opening
+    zipFile zip = unzOpen(path.fileSystemRepresentation);
+    if (zip == NULL)
+    {
+        NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"failed to open zip file"};
+        NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFailedOpenZipFile userInfo:userInfo];
+        if (error)
+        {
+            *error = err;
+        }
+        if (completionHandler)
+        {
+            completionHandler(nil, NO, err);
+        }
+        return NO;
+    }
+    
+    NSDictionary * fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
+    unsigned long long fileSize = [fileAttributes[NSFileSize] unsignedLongLongValue];
+    unsigned long long currentPosition = 0;
+    
+    unz_global_info  globalInfo = {0ul, 0ul};
+    unzGetGlobalInfo(zip, &globalInfo);
+    
+    // Begin unzipping
+    if (unzGoToFirstFile(zip) != UNZ_OK)
+    {
+        NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"failed to open first file in zip file"};
+        NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFailedOpenFileInZip userInfo:userInfo];
+        if (error)
+        {
+            *error = err;
+        }
+        if (completionHandler)
+        {
+            completionHandler(nil, NO, err);
+        }
+        return NO;
+    }
+    
+    BOOL success = YES;
+    BOOL canceled = NO;
+    int ret = 0;
+    int crc_ret = 0;
+    unsigned char buffer[4096] = {0};
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    NSMutableArray<NSDictionary *> *directoriesModificationDates = [[NSMutableArray alloc] init];
+    
+    // Message delegate
+    if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipArchiveAtPath:zipInfo:)]) {
+        [delegate zipArchiveWillUnzipArchiveAtPath:path zipInfo:globalInfo];
+    }
+    if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {
+        [delegate zipArchiveProgressEvent:currentPosition total:fileSize];
+    }
+    
+    NSInteger currentFileNumber = 0;
+    NSError *unzippingError;
+    do {
+        @autoreleasepool {
+            if (password.length == 0) {
+                ret = unzOpenCurrentFile(zip);
+            } else {
+                ret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSUTF8StringEncoding]);
+            }
+            
+            if (ret != UNZ_OK) {
+                unzippingError = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:SSZipArchiveErrorCodeFailedOpenFileInZip userInfo:@{NSLocalizedDescriptionKey: @"failed to open file in zip file"}];
+                success = NO;
+                break;
+            }
+            
+            // Reading data and write to file
+            unz_file_info fileInfo;
+            memset(&fileInfo, 0, sizeof(unz_file_info));
+            
+            ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
+            if (ret != UNZ_OK) {
+                unzippingError = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:SSZipArchiveErrorCodeFileInfoNotLoadable userInfo:@{NSLocalizedDescriptionKey: @"failed to retrieve info for file"}];
+                success = NO;
+                unzCloseCurrentFile(zip);
+                break;
+            }
+            
+            currentPosition += fileInfo.compressed_size;
+            
+            // Message delegate
+            if ([delegate respondsToSelector:@selector(zipArchiveShouldUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {
+                if (![delegate zipArchiveShouldUnzipFileAtIndex:currentFileNumber
+                                                     totalFiles:(NSInteger)globalInfo.number_entry
+                                                    archivePath:path fileInfo:fileInfo]) {
+                    success = NO;
+                    canceled = YES;
+                    break;
+                }
+            }
+            if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {
+                [delegate zipArchiveWillUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry
+                                             archivePath:path fileInfo:fileInfo];
+            }
+            if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {
+                [delegate zipArchiveProgressEvent:(NSInteger)currentPosition total:(NSInteger)fileSize];
+            }
+            
+            char *filename = (char *)malloc(fileInfo.size_filename + 1);
+            if (filename == NULL)
+            {
+                success = NO;
+                break;
+            }
+            
+            unzGetCurrentFileInfo(zip, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
+            filename[fileInfo.size_filename] = '\0';
+            
+            //
+            // Determine whether this is a symbolic link:
+            // - File is stored with 'version made by' value of UNIX (3),
+            //   as per http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+            //   in the upper byte of the version field.
+            // - BSD4.4 st_mode constants are stored in the high 16 bits of the
+            //   external file attributes (defacto standard, verified against libarchive)
+            //
+            // The original constants can be found here:
+            //    http://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4BSD/usr/include/sys/stat.h
+            //
+            const uLong ZipUNIXVersion = 3;
+            const uLong BSD_SFMT = 0170000;
+            const uLong BSD_IFLNK = 0120000;
+            
+            BOOL fileIsSymbolicLink = NO;
+            if (((fileInfo.version >> 8) == ZipUNIXVersion) && BSD_IFLNK == (BSD_SFMT & (fileInfo.external_fa >> 16))) {
+                fileIsSymbolicLink = YES;
+            }
+            
+            NSString * strPath = @(filename);
+            if (!strPath) {
+                // if filename is non-unicode, detect and transform Encoding
+                NSData *data = [NSData dataWithBytes:(const void *)filename length:sizeof(unsigned char) * fileInfo.size_filename];
+#ifdef __MAC_10_13
+                // Xcode 9+
+                if (@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)) {
+#else
+                // Xcode 8-
+                if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_9_2) {
+#endif
+                    // supported encodings are in [NSString availableStringEncodings]
+                  NSArray<NSNumber *> *encodings = @[@(kCFStringEncodingMacChineseSimp), @(kCFStringEncodingShiftJIS)];
+                                       for (NSNumber *encoding in encodings) {
+                                           strPath = [NSString stringWithCString:filename encoding:(NSStringEncoding)CFStringConvertEncodingToNSStringEncoding(encoding.unsignedIntValue)];
+                                           if (strPath) {
+                                               break;
+                                           }
+                                       }
+                } else {
+                    // fallback to a simple manual detect for macOS 10.9 or older
+                    NSArray<NSNumber *> *encodings = @[@(kCFStringEncodingMacChineseSimp), @(kCFStringEncodingShiftJIS)];
+                    for (NSNumber *encoding in encodings) {
+                        strPath = [NSString stringWithCString:filename encoding:(NSStringEncoding)CFStringConvertEncodingToNSStringEncoding(encoding.unsignedIntValue)];
+                        if (strPath) {
+                            break;
+                        }
+                    }
+                }
+                if (!strPath) {
+                    // if filename encoding is non-detected, we default to something based on data
+                    // _hexString is more readable than _base64RFC4648 for debugging unknown encodings
+                    strPath = [data _hexString];
+                }
+            }
+            if (!strPath.length) {
+                // if filename data is unsalvageable, we default to currentFileNumber
+                strPath = @(currentFileNumber).stringValue;
+            }
+            
+            // Check if it contains directory
+            BOOL isDirectory = NO;
+            if (filename[fileInfo.size_filename-1] == '/' || filename[fileInfo.size_filename-1] == '\\') {
+                isDirectory = YES;
+            }
+            free(filename);
+            
+            // Contains a path
+            if ([strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location != NSNotFound) {
+                strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
+            }
+            
+            NSString *fullPath = [destination stringByAppendingPathComponent:strPath];
+            NSError *err = nil;
+            NSDictionary *directoryAttr;
+            if (preserveAttributes) {
+                NSDate *modDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dos_date];
+                directoryAttr = @{NSFileCreationDate: modDate, NSFileModificationDate: modDate};
+                [directoriesModificationDates addObject: @{@"path": fullPath, @"modDate": modDate}];
+            }
+            if (isDirectory) {
+                [fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:directoryAttr  error:&err];
+            } else {
+                [fileManager createDirectoryAtPath:fullPath.stringByDeletingLastPathComponent withIntermediateDirectories:YES attributes:directoryAttr error:&err];
+            }
+            if (nil != err) {
+                if ([err.domain isEqualToString:NSCocoaErrorDomain] &&
+                    err.code == 640) {
+                    unzippingError = err;
+                    unzCloseCurrentFile(zip);
+                    success = NO;
+                    break;
+                }
+                NSLog(@"[SSZipArchive] Error: %@", err.localizedDescription);
+            }
+            
+            if ([fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite) {
+                //FIXME: couldBe CRC Check?
+                unzCloseCurrentFile(zip);
+                ret = unzGoToNextFile(zip);
+                continue;
+            }
+            
+            if (!fileIsSymbolicLink) {
+                // ensure we are not creating stale file entries
+                int readBytes = unzReadCurrentFile(zip, buffer, 4096);
+                if (readBytes >= 0) {
+                    FILE *fp = fopen(fullPath.fileSystemRepresentation, "wb");
+                    while (fp) {
+                        if (readBytes > 0) {
+                            if (0 == fwrite(buffer, readBytes, 1, fp)) {
+                                if (ferror(fp)) {
+                                    NSString *message = [NSString stringWithFormat:@"Failed to write file (check your free space)"];
+                                    NSLog(@"[SSZipArchive] %@", message);
+                                    success = NO;
+                                    unzippingError = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:SSZipArchiveErrorCodeFailedToWriteFile userInfo:@{NSLocalizedDescriptionKey: message}];
+                                    break;
+                                }
+                            }
+                        } else {
+                            break;
+                        }
+                        readBytes = unzReadCurrentFile(zip, buffer, 4096);
+                    }
+
+                    if (fp) {
+                        if ([fullPath.pathExtension.lowercaseString isEqualToString:@"zip"]) {
+                            NSLog(@"Unzipping nested .zip file:  %@", fullPath.lastPathComponent);
+                            if ([self unzipFileAtPath:fullPath toDestination:fullPath.stringByDeletingLastPathComponent overwrite:overwrite password:password error:nil delegate:nil]) {
+                                [[NSFileManager defaultManager] removeItemAtPath:fullPath error:nil];
+                            }
+                        }
+
+                        fclose(fp);
+
+                        if (preserveAttributes) {
+
+                            // Set the original datetime property
+                            if (fileInfo.dos_date != 0) {
+                                NSDate *orgDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dos_date];
+                                NSDictionary *attr = @{NSFileModificationDate: orgDate};
+
+                                if (attr) {
+                                    if (![fileManager setAttributes:attr ofItemAtPath:fullPath error:nil]) {
+                                        // Can't set attributes
+                                        NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting modification date");
+                                    }
+                                }
+                            }
+
+                            // Set the original permissions on the file (+read/write to solve #293)
+                            uLong permissions = fileInfo.external_fa >> 16 | 0b110000000;
+                            if (permissions != 0) {
+                                // Store it into a NSNumber
+                                NSNumber *permissionsValue = @(permissions);
+
+                                // Retrieve any existing attributes
+                                NSMutableDictionary *attrs = [[NSMutableDictionary alloc] initWithDictionary:[fileManager attributesOfItemAtPath:fullPath error:nil]];
+
+                                // Set the value in the attributes dict
+                                attrs[NSFilePosixPermissions] = permissionsValue;
+
+                                // Update attributes
+                                if (![fileManager setAttributes:attrs ofItemAtPath:fullPath error:nil]) {
+                                    // Unable to set the permissions attribute
+                                    NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting permissions");
+                                }
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // if we couldn't open file descriptor we can validate global errno to see the reason
+                        if (errno == ENOSPC) {
+                            NSError *enospcError = [NSError errorWithDomain:NSPOSIXErrorDomain
+                                                                       code:ENOSPC
+                                                                   userInfo:nil];
+                            unzippingError = enospcError;
+                            unzCloseCurrentFile(zip);
+                            success = NO;
+                            break;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                // Assemble the path for the symbolic link
+                NSMutableString *destinationPath = [NSMutableString string];
+                int bytesRead = 0;
+                while ((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0)
+                {
+                    buffer[bytesRead] = (int)0;
+                    [destinationPath appendString:@((const char *)buffer)];
+                }
+                
+                // Check if the symlink exists and delete it if we're overwriting
+                if (overwrite)
+                {
+                    if ([fileManager fileExistsAtPath:fullPath])
+                    {
+                        NSError *error = nil;
+                        BOOL removeSuccess = [fileManager removeItemAtPath:fullPath error:&error];
+                        if (!removeSuccess)
+                        {
+                            NSString *message = [NSString stringWithFormat:@"Failed to delete existing symbolic link at \"%@\"", error.localizedDescription];
+                            NSLog(@"[SSZipArchive] %@", message);
+                            success = NO;
+                            unzippingError = [NSError errorWithDomain:SSZipArchiveErrorDomain code:error.code userInfo:@{NSLocalizedDescriptionKey: message}];
+                        }
+                    }
+                }
+                
+                // Create the symbolic link (making sure it stays relative if it was relative before)
+                int symlinkError = symlink([destinationPath cStringUsingEncoding:NSUTF8StringEncoding],
+                                           [fullPath cStringUsingEncoding:NSUTF8StringEncoding]);
+                
+                if (symlinkError != 0)
+                {
+                    // Bubble the error up to the completion handler
+                    NSString *message = [NSString stringWithFormat:@"Failed to create symbolic link at \"%@\" to \"%@\" - symlink() error code: %d", fullPath, destinationPath, errno];
+                    NSLog(@"[SSZipArchive] %@", message);
+                    success = NO;
+                    unzippingError = [NSError errorWithDomain:NSPOSIXErrorDomain code:symlinkError userInfo:@{NSLocalizedDescriptionKey: message}];
+                }
+            }
+            
+            crc_ret = unzCloseCurrentFile(zip);
+            if (crc_ret == UNZ_CRCERROR) {
+                //CRC ERROR
+                success = NO;
+                break;
+            }
+            ret = unzGoToNextFile(zip);
+            
+            // Message delegate
+            if ([delegate respondsToSelector:@selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {
+                [delegate zipArchiveDidUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry
+                                            archivePath:path fileInfo:fileInfo];
+            } else if ([delegate respondsToSelector: @selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:unzippedFilePath:)]) {
+                [delegate zipArchiveDidUnzipFileAtIndex: currentFileNumber totalFiles: (NSInteger)globalInfo.number_entry
+                                            archivePath:path unzippedFilePath: fullPath];
+            }
+            
+            currentFileNumber++;
+            if (progressHandler)
+            {
+                progressHandler(strPath, fileInfo, currentFileNumber, globalInfo.number_entry);
+            }
+        }
+    } while (ret == UNZ_OK && success);
+    
+    // Close
+    unzClose(zip);
+    
+    // The process of decompressing the .zip archive causes the modification times on the folders
+    // to be set to the present time. So, when we are done, they need to be explicitly set.
+    // set the modification date on all of the directories.
+    if (success && preserveAttributes) {
+        NSError * err = nil;
+        for (NSDictionary * d in directoriesModificationDates) {
+            if (![[NSFileManager defaultManager] setAttributes:@{NSFileModificationDate: d[@"modDate"]} ofItemAtPath:d[@"path"] error:&err]) {
+                NSLog(@"[SSZipArchive] Set attributes failed for directory: %@.", d[@"path"]);
+            }
+            if (err) {
+                NSLog(@"[SSZipArchive] Error setting directory file modification date attribute: %@", err.localizedDescription);
+            }
+        }
+    }
+    
+    // Message delegate
+    if (success && [delegate respondsToSelector:@selector(zipArchiveDidUnzipArchiveAtPath:zipInfo:unzippedPath:)]) {
+        [delegate zipArchiveDidUnzipArchiveAtPath:path zipInfo:globalInfo unzippedPath:destination];
+    }
+    // final progress event = 100%
+    if (!canceled && [delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {
+        [delegate zipArchiveProgressEvent:fileSize total:fileSize];
+    }
+    
+    NSError *retErr = nil;
+    if (crc_ret == UNZ_CRCERROR)
+    {
+        NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"crc check failed for file"};
+        retErr = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFileInfoNotLoadable userInfo:userInfo];
+    }
+    
+    if (error) {
+        if (unzippingError) {
+            *error = unzippingError;
+        }
+        else {
+            *error = retErr;
+        }
+    }
+    if (completionHandler)
+    {
+        if (unzippingError) {
+            completionHandler(path, success, unzippingError);
+        }
+        else
+        {
+            completionHandler(path, success, retErr);
+        }
+    }
+    return success;
+}
+
+#pragma mark - Zipping
++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths
+{
+    return [SSZipArchive createZipFileAtPath:path withFilesAtPaths:paths withPassword:nil];
+}
++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath {
+    return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath withPassword:nil];
+}
+
++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory {
+    return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:keepParentDirectory withPassword:nil];
+}
+
++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(NSString *)password
+{
+    SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path];
+    BOOL success = [zipArchive open];
+    if (success) {
+        for (NSString *filePath in paths) {
+            success &= [zipArchive writeFile:filePath withPassword:password];
+        }
+        success &= [zipArchive close];
+    }
+    return success;
+}
+
++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath withPassword:(nullable NSString *)password {
+    return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:NO withPassword:password];
+}
+
+
++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory withPassword:(nullable NSString *)password {
+    return [SSZipArchive createZipFileAtPath:path
+                     withContentsOfDirectory:directoryPath
+                         keepParentDirectory:keepParentDirectory
+                                withPassword:password
+                          andProgressHandler:nil
+            ];
+}
+
++ (BOOL)createZipFileAtPath:(NSString *)path
+    withContentsOfDirectory:(NSString *)directoryPath
+        keepParentDirectory:(BOOL)keepParentDirectory
+               withPassword:(nullable NSString *)password
+         andProgressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler {
+    
+    SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path];
+    BOOL success = [zipArchive open];
+    if (success) {
+        // use a local fileManager (queue/thread compatibility)
+        NSFileManager *fileManager = [[NSFileManager alloc] init];
+        NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:directoryPath];
+        NSArray<NSString *> *allObjects = dirEnumerator.allObjects;
+        NSUInteger total = allObjects.count, complete = 0;
+        NSString *fileName;
+        for (fileName in allObjects) {
+            BOOL isDir;
+            NSString *fullFilePath = [directoryPath stringByAppendingPathComponent:fileName];
+            [fileManager fileExistsAtPath:fullFilePath isDirectory:&isDir];
+            
+            if (keepParentDirectory)
+            {
+                fileName = [directoryPath.lastPathComponent stringByAppendingPathComponent:fileName];
+            }
+            
+            if (!isDir) {
+                success &= [zipArchive writeFileAtPath:fullFilePath withFileName:fileName withPassword:password];
+            }
+            else
+            {
+                if ([[NSFileManager defaultManager] subpathsOfDirectoryAtPath:fullFilePath error:nil].count == 0)
+                {
+                    NSString *tempFilePath = [self _temporaryPathForDiscardableFile];
+                    NSString *tempFileFilename = [fileName stringByAppendingPathComponent:tempFilePath.lastPathComponent];
+                    success &= [zipArchive writeFileAtPath:tempFilePath withFileName:tempFileFilename withPassword:password];
+                }
+            }
+            complete++;
+            if (progressHandler) {
+                progressHandler(complete, total);
+            }
+        }
+        success &= [zipArchive close];
+    }
+    return success;
+}
+
+// disabling `init` because designated initializer is `initWithPath:`
+- (instancetype)init { @throw nil; }
+
+// designated initializer
+- (instancetype)initWithPath:(NSString *)path
+{
+    if ((self = [super init])) {
+        _path = [path copy];
+    }
+    return self;
+}
+
+
+- (BOOL)open
+{
+    NSAssert((_zip == NULL), @"Attempting to open an archive which is already open");
+    _zip = zipOpen(_path.fileSystemRepresentation, APPEND_STATUS_CREATE);
+    return (NULL != _zip);
+}
+
+
+- (void)zipInfo:(zip_fileinfo *)zipInfo setDate:(NSDate *)date
+{
+    NSCalendar *currentCalendar = SSZipArchive._gregorian;
+    NSCalendarUnit flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
+    NSDateComponents *components = [currentCalendar components:flags fromDate:date];
+    struct tm tmz_date;
+    tmz_date.tm_sec = (unsigned int)components.second;
+    tmz_date.tm_min = (unsigned int)components.minute;
+    tmz_date.tm_hour = (unsigned int)components.hour;
+    tmz_date.tm_mday = (unsigned int)components.day;
+    // ISO/IEC 9899 struct tm is 0-indexed for January but NSDateComponents for gregorianCalendar is 1-indexed for January
+    tmz_date.tm_mon = (unsigned int)components.month - 1;
+    // ISO/IEC 9899 struct tm is 0-indexed for AD 1900 but NSDateComponents for gregorianCalendar is 1-indexed for AD 1
+    tmz_date.tm_year = (unsigned int)components.year - 1900;
+    zipInfo->dos_date = tm_to_dosdate(&tmz_date);
+}
+
+- (BOOL)writeFolderAtPath:(NSString *)path withFolderName:(NSString *)folderName withPassword:(nullable NSString *)password
+{
+    NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened");
+    
+    zip_fileinfo zipInfo = {0,0,0};
+    
+    NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error: nil];
+    if (attr)
+    {
+        NSDate *fileDate = (NSDate *)attr[NSFileModificationDate];
+        if (fileDate)
+        {
+            [self zipInfo:&zipInfo setDate: fileDate];
+        }
+        
+        // Write permissions into the external attributes, for details on this see here: http://unix.stackexchange.com/a/14727
+        // Get the permissions value from the files attributes
+        NSNumber *permissionsValue = (NSNumber *)attr[NSFilePosixPermissions];
+        if (permissionsValue != nil) {
+            // Get the short value for the permissions
+            short permissionsShort = permissionsValue.shortValue;
+            
+            // Convert this into an octal by adding 010000, 010000 being the flag for a regular file
+            NSInteger permissionsOctal = 0100000 + permissionsShort;
+            
+            // Convert this into a long value
+            uLong permissionsLong = @(permissionsOctal).unsignedLongValue;
+            
+            // Store this into the external file attributes once it has been shifted 16 places left to form part of the second from last byte
+            
+            // Casted back to an unsigned int to match type of external_fa in minizip
+            zipInfo.external_fa = (unsigned int)(permissionsLong << 16L);
+        }
+    }
+    
+    unsigned int len = 0;
+    zipOpenNewFileInZip3(_zip, [folderName stringByAppendingString:@"/"].fileSystemRepresentation, &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_NO_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL,
+                         Z_DEFAULT_STRATEGY, password.UTF8String, 0);
+    zipWriteInFileInZip(_zip, &len, 0);
+    zipCloseFileInZip(_zip);
+    return YES;
+}
+
+- (BOOL)writeFile:(NSString *)path withPassword:(nullable NSString *)password;
+{
+    return [self writeFileAtPath:path withFileName:nil withPassword:password];
+}
+
+// supports writing files with logical folder/directory structure
+// *path* is the absolute path of the file that will be compressed
+// *fileName* is the relative name of the file how it is stored within the zip e.g. /folder/subfolder/text1.txt
+- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName withPassword:(nullable NSString *)password
+{
+    NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened");
+    
+    FILE *input = fopen(path.fileSystemRepresentation, "r");
+    if (NULL == input) {
+        return NO;
+    }
+    
+    const char *aFileName;
+    if (!fileName) {
+        aFileName = path.lastPathComponent.fileSystemRepresentation;
+    }
+    else {
+        aFileName = fileName.fileSystemRepresentation;
+    }
+    
+    zip_fileinfo zipInfo = {0,0,0};
+    
+    NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error: nil];
+    if (attr)
+    {
+        NSDate *fileDate = (NSDate *)attr[NSFileModificationDate];
+        if (fileDate)
+        {
+            [self zipInfo:&zipInfo setDate: fileDate];
+        }
+        
+        // Write permissions into the external attributes, for details on this see here: http://unix.stackexchange.com/a/14727
+        // Get the permissions value from the files attributes
+        NSNumber *permissionsValue = (NSNumber *)attr[NSFilePosixPermissions];
+        if (permissionsValue != nil) {
+            // Get the short value for the permissions
+            short permissionsShort = permissionsValue.shortValue;
+            
+            // Convert this into an octal by adding 010000, 010000 being the flag for a regular file
+            NSInteger permissionsOctal = 0100000 + permissionsShort;
+            
+            // Convert this into a long value
+            uLong permissionsLong = @(permissionsOctal).unsignedLongValue;
+            
+            // Store this into the external file attributes once it has been shifted 16 places left to form part of the second from last byte
+            
+            // Casted back to an unsigned int to match type of external_fa in minizip
+            zipInfo.external_fa = (unsigned int)(permissionsLong << 16L);
+        }
+    }
+    
+    void *buffer = malloc(CHUNK);
+    if (buffer == NULL)
+    {
+        return NO;
+    }
+    
+    zipOpenNewFileInZip3(_zip, aFileName, &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, password.UTF8String, 0);
+    unsigned int len = 0;
+    
+    while (!feof(input) && !ferror(input))
+    {
+        len = (unsigned int) fread(buffer, 1, CHUNK, input);
+        zipWriteInFileInZip(_zip, buffer, len);
+    }
+    
+    zipCloseFileInZip(_zip);
+    free(buffer);
+    fclose(input);
+    return YES;
+}
+
+- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename withPassword:(nullable NSString *)password;
+{
+    if (!_zip) {
+        return NO;
+    }
+    if (!data) {
+        return NO;
+    }
+    zip_fileinfo zipInfo = {0,0,0};
+    [self zipInfo:&zipInfo setDate:[NSDate date]];
+    
+    zipOpenNewFileInZip3(_zip, filename.fileSystemRepresentation, &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, password.UTF8String, 0);
+    
+    zipWriteInFileInZip(_zip, data.bytes, (unsigned int)data.length);
+    
+    zipCloseFileInZip(_zip);
+    return YES;
+}
+
+
+- (BOOL)close
+{
+    NSAssert((_zip != NULL), @"[SSZipArchive] Attempting to close an archive which was never opened");
+    int error = zipClose(_zip, NULL);
+    _zip = nil;
+    return error == UNZ_OK;
+}
+
+#pragma mark - Private
+
++ (NSString *)_temporaryPathForDiscardableFile
+{
+    static NSString *discardableFileName = @".DS_Store";
+    static NSString *discardableFilePath = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        NSString *temporaryDirectoryName = [NSUUID UUID].UUIDString;
+        NSString *temporaryDirectory = [NSTemporaryDirectory() stringByAppendingPathComponent:temporaryDirectoryName];
+        BOOL directoryCreated = [[NSFileManager defaultManager] createDirectoryAtPath:temporaryDirectory withIntermediateDirectories:YES attributes:nil error:nil];
+        if (directoryCreated) {
+            discardableFilePath = [temporaryDirectory stringByAppendingPathComponent:discardableFileName];
+            [@"" writeToFile:discardableFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
+        }
+    });
+    return discardableFilePath;
+}
+
++ (NSCalendar *)_gregorian
+{
+    static NSCalendar *gregorian;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
+    });
+    
+    return gregorian;
+}
+
+// Format from http://newsgroups.derkeiler.com/Archive/Comp/comp.os.msdos.programmer/2009-04/msg00060.html
+// Two consecutive words, or a longword, YYYYYYYMMMMDDDDD hhhhhmmmmmmsssss
+// YYYYYYY is years from 1980 = 0
+// sssss is (seconds/2).
+//
+// 3658 = 0011 0110 0101 1000 = 0011011 0010 11000 = 27 2 24 = 2007-02-24
+// 7423 = 0111 0100 0010 0011 - 01110 100001 00011 = 14 33 3 = 14:33:06
++ (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime
+{
+    /*
+     // the whole `_dateWithMSDOSFormat:` method is equivalent but faster than this one line,
+     // essentially because `mktime` is slow:
+     NSDate *date = [NSDate dateWithTimeIntervalSince1970:dosdate_to_time_t(msdosDateTime)];
+    */
+    static const UInt32 kYearMask = 0xFE000000;
+    static const UInt32 kMonthMask = 0x1E00000;
+    static const UInt32 kDayMask = 0x1F0000;
+    static const UInt32 kHourMask = 0xF800;
+    static const UInt32 kMinuteMask = 0x7E0;
+    static const UInt32 kSecondMask = 0x1F;
+    
+    NSAssert(0xFFFFFFFF == (kYearMask | kMonthMask | kDayMask | kHourMask | kMinuteMask | kSecondMask), @"[SSZipArchive] MSDOS date masks don't add up");
+    
+    NSDateComponents *components = [[NSDateComponents alloc] init];
+    
+    components.year = 1980 + ((msdosDateTime & kYearMask) >> 25);
+    components.month = (msdosDateTime & kMonthMask) >> 21;
+    components.day = (msdosDateTime & kDayMask) >> 16;
+    components.hour = (msdosDateTime & kHourMask) >> 11;
+    components.minute = (msdosDateTime & kMinuteMask) >> 5;
+    components.second = (msdosDateTime & kSecondMask) * 2;
+    
+    NSDate *date = [self._gregorian dateFromComponents:components];
+    return date;
+}
+
+@end
+
+#pragma mark - Private tools for unreadable data
+
+@implementation NSData (SSZipArchive)
+
+// `base64EncodedStringWithOptions` uses a base64 alphabet with '+' and '/'.
+// we got those alternatives to make it compatible with filenames: https://en.wikipedia.org/wiki/Base64
+// * modified Base64 encoding for IMAP mailbox names (RFC 3501): uses '+' and ','
+// * modified Base64 for URL and filenames (RFC 4648): uses '-' and '_'
+- (NSString *)_base64RFC4648
+{
+    NSString *strName = [self base64EncodedStringWithOptions:0];
+    strName = [strName stringByReplacingOccurrencesOfString:@"+" withString:@"-"];
+    strName = [strName stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
+    return strName;
+}
+
+// initWithBytesNoCopy from NSProgrammer, Jan 25 '12: https://stackoverflow.com/a/9009321/1033581
+// hexChars from Peter, Aug 19 '14: https://stackoverflow.com/a/25378464/1033581
+// not implemented as too lengthy: a potential mapping improvement from Moose, Nov 3 '15: https://stackoverflow.com/a/33501154/1033581
+- (NSString *)_hexString
+{
+    const char *hexChars = "0123456789ABCDEF";
+    NSUInteger length = self.length;
+    const unsigned char *bytes = self.bytes;
+    char *chars = malloc(length * 2);
+    char *s = chars;
+    NSUInteger i = length;
+    while (i--) {
+        *s++ = hexChars[*bytes >> 4];
+        *s++ = hexChars[*bytes & 0xF];
+        bytes++;
+    }
+    NSString *str = [[NSString alloc] initWithBytesNoCopy:chars
+                                                   length:length * 2
+                                                 encoding:NSASCIIStringEncoding
+                                             freeWhenDone:YES];
+    return str;
+}
+
+@end

+ 65 - 0
ios/Classes/SSZipArchive/SSZipCommon.h

@@ -0,0 +1,65 @@
+#ifndef SSZipCommon
+#define SSZipCommon
+
+/* unz_global_info structure contain global data about the ZIPfile
+ These data comes from the end of central dir */
+typedef struct unz_global_info64_s
+{
+    uint64_t number_entry;          /* total number of entries in the central dir on this disk */
+    uint32_t number_disk_with_CD;   /* number the the disk with central dir, used for spanning ZIP*/
+    uint16_t size_comment;          /* size of the global comment of the zipfile */
+} unz_global_info64;
+
+typedef struct unz_global_info_s
+{
+    uint32_t number_entry;          /* total number of entries in the central dir on this disk */
+    uint32_t number_disk_with_CD;   /* number the the disk with central dir, used for spanning ZIP*/
+    uint16_t size_comment;          /* size of the global comment of the zipfile */
+} unz_global_info;
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info64_s
+{
+    uint16_t version;               /* version made by                 2 bytes */
+    uint16_t version_needed;        /* version needed to extract       2 bytes */
+    uint16_t flag;                  /* general purpose bit flag        2 bytes */
+    uint16_t compression_method;    /* compression method              2 bytes */
+    uint32_t dos_date;              /* last mod file date in Dos fmt   4 bytes */
+    uint32_t crc;                   /* crc-32                          4 bytes */
+    uint64_t compressed_size;       /* compressed size                 8 bytes */
+    uint64_t uncompressed_size;     /* uncompressed size               8 bytes */
+    uint16_t size_filename;         /* filename length                 2 bytes */
+    uint16_t size_file_extra;       /* extra field length              2 bytes */
+    uint16_t size_file_comment;     /* file comment length             2 bytes */
+    
+    uint32_t disk_num_start;        /* disk number start               4 bytes */
+    uint16_t internal_fa;           /* internal file attributes        2 bytes */
+    uint32_t external_fa;           /* external file attributes        4 bytes */
+    
+    uint64_t disk_offset;
+    
+    uint16_t size_file_extra_internal;
+} unz_file_info64;
+
+typedef struct unz_file_info_s
+{
+    uint16_t version;               /* version made by                 2 bytes */
+    uint16_t version_needed;        /* version needed to extract       2 bytes */
+    uint16_t flag;                  /* general purpose bit flag        2 bytes */
+    uint16_t compression_method;    /* compression method              2 bytes */
+    uint32_t dos_date;              /* last mod file date in Dos fmt   4 bytes */
+    uint32_t crc;                   /* crc-32                          4 bytes */
+    uint32_t compressed_size;       /* compressed size                 4 bytes */
+    uint32_t uncompressed_size;     /* uncompressed size               4 bytes */
+    uint16_t size_filename;         /* filename length                 2 bytes */
+    uint16_t size_file_extra;       /* extra field length              2 bytes */
+    uint16_t size_file_comment;     /* file comment length             2 bytes */
+    
+    uint16_t disk_num_start;        /* disk number start               2 bytes */
+    uint16_t internal_fa;           /* internal file attributes        2 bytes */
+    uint32_t external_fa;           /* external file attributes        4 bytes */
+    
+    uint64_t disk_offset;
+} unz_file_info;
+
+#endif

+ 19 - 0
ios/Classes/SSZipArchive/ZipArchive.h

@@ -0,0 +1,19 @@
+//
+//  ZipArchive.h
+//  ZipArchive
+//
+//  Created by Serhii Mumriak on 12/1/15.
+//  Copyright © 2015 smumryak. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+//! Project version number for ZipArchive.
+FOUNDATION_EXPORT double ZipArchiveVersionNumber;
+
+//! Project version string for ZipArchive.
+FOUNDATION_EXPORT const unsigned char ZipArchiveVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import <ZipArchive/SSZipArchive.h>
+
+#import "SSZipArchive.h"

+ 270 - 0
ios/Classes/SSZipArchive/minizip/aes/aes.h

@@ -0,0 +1,270 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+
+ This file contains the definitions required to use AES in C. See aesopt.h
+ for optimisation details.
+*/	
+
+#ifndef _AES_H
+#define _AES_H
+
+#include <stdlib.h>
+
+/*  This include is used to find 8 & 32 bit unsigned integer types  */
+#include "brg_types.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#define AES_128     /* if a fast 128 bit key scheduler is needed    */
+#define AES_192     /* if a fast 192 bit key scheduler is needed    */
+#define AES_256     /* if a fast 256 bit key scheduler is needed    */
+#define AES_VAR     /* if variable key size scheduler is needed     */
+#define AES_MODES   /* if support is needed for modes               */
+
+/* The following must also be set in assembler files if being used  */
+
+#define AES_ENCRYPT /* if support for encryption is needed          */
+#define AES_DECRYPT /* if support for decryption is needed          */
+
+#define AES_BLOCK_SIZE  16  /* the AES block size in bytes          */
+#define N_COLS           4  /* the number of columns in the state   */
+
+/* The key schedule length is 11, 13 or 15 16-byte blocks for 128,  */
+/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes  */
+/* or 44, 52 or 60 32-bit words.                                    */
+
+#if defined( AES_VAR ) || defined( AES_256 )
+#define KS_LENGTH       60
+#elif defined( AES_192 )
+#define KS_LENGTH       52
+#else
+#define KS_LENGTH       44
+#endif
+
+#define AES_RETURN INT_RETURN
+
+/* the character array 'inf' in the following structures is used    */
+/* to hold AES context information. This AES code uses cx->inf.b[0] */
+/* to hold the number of rounds multiplied by 16. The other three   */
+/* elements can be used by code that implements additional modes    */
+
+typedef union
+{   uint32_t l;
+    uint8_t b[4];
+} aes_inf;
+
+#ifdef _MSC_VER
+#  pragma warning( disable : 4324 )
+#endif
+
+#if defined(_MSC_VER) && defined(_WIN64)
+#define ALIGNED_(x) __declspec(align(x))
+#elif defined(__GNUC__) && defined(__x86_64__)
+#define ALIGNED_(x) __attribute__ ((aligned(x)))
+#else
+#define ALIGNED_(x)
+#endif
+
+typedef struct ALIGNED_(16)
+{   uint32_t ks[KS_LENGTH];
+    aes_inf inf;
+} aes_encrypt_ctx;
+
+typedef struct ALIGNED_(16)
+{   uint32_t ks[KS_LENGTH];
+    aes_inf inf;
+} aes_decrypt_ctx;
+
+#ifdef _MSC_VER
+#  pragma warning( default : 4324 )
+#endif
+
+/* This routine must be called before first use if non-static       */
+/* tables are being used                                            */
+
+AES_RETURN aes_init(void);
+
+/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */
+/* those in the range 128 <= key_len <= 256 are given in bits       */
+
+#if defined( AES_ENCRYPT )
+
+#if defined( AES_128 ) || defined( AES_VAR)
+AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_192 ) || defined( AES_VAR)
+AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_256 ) || defined( AES_VAR)
+AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_VAR )
+AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]);
+#endif
+
+AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]);
+
+#endif
+
+#if defined( AES_DECRYPT )
+
+#if defined( AES_128 ) || defined( AES_VAR)
+AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_192 ) || defined( AES_VAR)
+AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_256 ) || defined( AES_VAR)
+AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_VAR )
+AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]);
+#endif
+
+AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]);
+
+#endif
+
+#if defined( AES_MODES )
+
+/* Multiple calls to the following subroutines for multiple block   */
+/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */
+/* long messages incrementally provided that the context AND the iv */
+/* are preserved between all such calls.  For the ECB and CBC modes */
+/* each individual call within a series of incremental calls must   */
+/* process only full blocks (i.e. len must be a multiple of 16) but */
+/* the CFB, OFB and CTR mode calls can handle multiple incremental  */
+/* calls of any length.  Each mode is reset when a new AES key is   */
+/* set but ECB needs no reset and CBC can be reset without setting  */
+/* a new key by setting a new IV value.  To reset CFB, OFB and CTR  */
+/* without setting the key, aes_mode_reset() must be called and the */
+/* IV must be set.  NOTE: All these calls update the IV on exit so  */
+/* this has to be reset if a new operation with the same IV as the  */
+/* previous one is required (or decryption follows encryption with  */
+/* the same IV array).                                              */
+
+AES_RETURN aes_test_alignment_detection(unsigned int n);
+
+AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, const aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, const aes_decrypt_ctx cx[1]);
+
+AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, const aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, const aes_decrypt_ctx cx[1]);
+
+AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
+
+#define aes_ofb_encrypt aes_ofb_crypt
+#define aes_ofb_decrypt aes_ofb_crypt
+
+AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
+
+typedef void cbuf_inc(unsigned char *cbuf);
+
+#define aes_ctr_encrypt aes_ctr_crypt
+#define aes_ctr_decrypt aes_ctr_crypt
+
+AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,
+            int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]);
+
+#endif
+
+#if 0
+#  define ADD_AESNI_MODE_CALLS
+#endif
+
+#if 0 && defined( ADD_AESNI_MODE_CALLS )
+#  define USE_AES_CONTEXT
+#endif
+
+#ifdef ADD_AESNI_MODE_CALLS
+#  ifdef USE_AES_CONTEXT
+
+AES_RETURN aes_CBC_encrypt(const unsigned char *in,
+    unsigned char *out,
+    unsigned char ivec[16],
+    unsigned long length,
+    const aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_CBC_decrypt(const unsigned char *in,
+    unsigned char *out,
+    unsigned char ivec[16],
+    unsigned long length,
+    const aes_decrypt_ctx cx[1]);
+
+AES_RETURN AES_CTR_encrypt(const unsigned char *in,
+    unsigned char *out,
+    const unsigned char ivec[8],
+    const unsigned char nonce[4],
+    unsigned long length,
+    const aes_encrypt_ctx cx[1]);
+
+#  else
+
+void aes_CBC_encrypt(const unsigned char *in,
+    unsigned char *out,
+    unsigned char ivec[16],
+    unsigned long length,
+    unsigned char *key,
+    int number_of_rounds);
+
+void aes_CBC_decrypt(const unsigned char *in,
+    unsigned char *out,
+    unsigned char ivec[16],
+    unsigned long length,
+    unsigned char *key,
+    int number_of_rounds);
+
+void AES_CTR_encrypt(const unsigned char *in,
+    unsigned char *out,
+    const unsigned char ivec[8],
+    const unsigned char nonce[4],
+    unsigned long length,
+    const unsigned char *key,
+    int number_of_rounds);
+
+#  endif
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

+ 687 - 0
ios/Classes/SSZipArchive/minizip/aes/aes_ni.c

@@ -0,0 +1,687 @@
+/*
+Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 09/09/2014
+*/
+
+#include "aes_ni.h"
+
+#if defined( USE_INTEL_AES_IF_PRESENT )
+
+#if defined(_MSC_VER)
+
+#include <intrin.h>
+#pragma intrinsic(__cpuid)
+#define INLINE  __inline
+
+INLINE int has_aes_ni(void)
+{
+	static int test = -1;
+	if(test < 0)
+	{
+        int cpu_info[4];
+        __cpuid(cpu_info, 1);
+		test = cpu_info[2] & 0x02000000;
+	}
+	return test;
+}
+
+#elif defined( __GNUC__ )
+
+#include <cpuid.h>
+
+#if !defined(__clang__)
+#pragma GCC target ("ssse3")
+#pragma GCC target ("sse4.1")
+#pragma GCC target ("aes")
+#endif
+
+#include <x86intrin.h>
+#define INLINE  static __inline
+
+INLINE int has_aes_ni()
+{
+    static int test = -1;
+    if(test < 0)
+    {
+        unsigned int a, b, c, d;
+        if(!__get_cpuid(1, &a, &b, &c, &d))
+            test = 0;
+        else
+            test = (c & 0x2000000);
+    }
+    return test;
+}
+
+#else
+#error AES New Instructions require Microsoft, Intel, GNU C, or CLANG
+#endif
+
+INLINE __m128i aes_128_assist(__m128i t1, __m128i t2)
+{
+	__m128i t3;
+	t2 = _mm_shuffle_epi32(t2, 0xff);
+	t3 = _mm_slli_si128(t1, 0x4);
+	t1 = _mm_xor_si128(t1, t3);
+	t3 = _mm_slli_si128(t3, 0x4);
+	t1 = _mm_xor_si128(t1, t3);
+	t3 = _mm_slli_si128(t3, 0x4);
+	t1 = _mm_xor_si128(t1, t3);
+	t1 = _mm_xor_si128(t1, t2);
+	return t1;
+}
+
+AES_RETURN aes_ni(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1])
+{
+	__m128i t1, t2;
+	__m128i *ks = (__m128i*)cx->ks;
+
+	if(!has_aes_ni())
+	{
+		return aes_xi(encrypt_key128)(key, cx);
+	}
+
+	t1 = _mm_loadu_si128((__m128i*)key);
+
+	ks[0] = t1;
+
+	t2 = _mm_aeskeygenassist_si128(t1, 0x1);
+	t1 = aes_128_assist(t1, t2);
+	ks[1] = t1;
+
+	t2 = _mm_aeskeygenassist_si128(t1, 0x2);
+	t1 = aes_128_assist(t1, t2);
+	ks[2] = t1;
+
+	t2 = _mm_aeskeygenassist_si128(t1, 0x4);
+	t1 = aes_128_assist(t1, t2);
+	ks[3] = t1;
+
+	t2 = _mm_aeskeygenassist_si128(t1, 0x8);
+	t1 = aes_128_assist(t1, t2);
+	ks[4] = t1;
+
+	t2 = _mm_aeskeygenassist_si128(t1, 0x10);
+	t1 = aes_128_assist(t1, t2);
+	ks[5] = t1;
+
+	t2 = _mm_aeskeygenassist_si128(t1, 0x20);
+	t1 = aes_128_assist(t1, t2);
+	ks[6] = t1;
+
+	t2 = _mm_aeskeygenassist_si128(t1, 0x40);
+	t1 = aes_128_assist(t1, t2);
+	ks[7] = t1;
+
+	t2 = _mm_aeskeygenassist_si128(t1, 0x80);
+	t1 = aes_128_assist(t1, t2);
+	ks[8] = t1;
+
+	t2 = _mm_aeskeygenassist_si128(t1, 0x1b);
+	t1 = aes_128_assist(t1, t2);
+	ks[9] = t1;
+
+	t2 = _mm_aeskeygenassist_si128(t1, 0x36);
+	t1 = aes_128_assist(t1, t2);
+	ks[10] = t1;
+
+	cx->inf.l = 0;
+	cx->inf.b[0] = 10 * 16;
+	return EXIT_SUCCESS;
+}
+
+INLINE void aes_192_assist(__m128i* t1, __m128i * t2, __m128i * t3)
+{
+	__m128i t4;
+	*t2 = _mm_shuffle_epi32(*t2, 0x55);
+	t4 = _mm_slli_si128(*t1, 0x4);
+	*t1 = _mm_xor_si128(*t1, t4);
+	t4 = _mm_slli_si128(t4, 0x4);
+	*t1 = _mm_xor_si128(*t1, t4);
+	t4 = _mm_slli_si128(t4, 0x4);
+	*t1 = _mm_xor_si128(*t1, t4);
+	*t1 = _mm_xor_si128(*t1, *t2);
+	*t2 = _mm_shuffle_epi32(*t1, 0xff);
+	t4 = _mm_slli_si128(*t3, 0x4);
+	*t3 = _mm_xor_si128(*t3, t4);
+	*t3 = _mm_xor_si128(*t3, *t2);
+}
+
+AES_RETURN aes_ni(encrypt_key192)(const unsigned char *key, aes_encrypt_ctx cx[1])
+{
+	__m128i t1, t2, t3;
+	__m128i *ks = (__m128i*)cx->ks;
+
+	if(!has_aes_ni())
+	{
+		return aes_xi(encrypt_key192)(key, cx);
+	}
+
+	t1 = _mm_loadu_si128((__m128i*)key);
+	t3 = _mm_loadu_si128((__m128i*)(key + 16));
+
+	ks[0] = t1;
+	ks[1] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x1);
+	aes_192_assist(&t1, &t2, &t3);
+
+	ks[1] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(ks[1]), _mm_castsi128_pd(t1), 0));
+	ks[2] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(t1), _mm_castsi128_pd(t3), 1));
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x2);
+	aes_192_assist(&t1, &t2, &t3);
+	ks[3] = t1;
+	ks[4] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x4);
+	aes_192_assist(&t1, &t2, &t3);
+	ks[4] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(ks[4]), _mm_castsi128_pd(t1), 0));
+	ks[5] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(t1), _mm_castsi128_pd(t3), 1));
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x8);
+	aes_192_assist(&t1, &t2, &t3);
+	ks[6] = t1;
+	ks[7] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x10);
+	aes_192_assist(&t1, &t2, &t3);
+	ks[7] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(ks[7]), _mm_castsi128_pd(t1), 0));
+	ks[8] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(t1), _mm_castsi128_pd(t3), 1));
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x20);
+	aes_192_assist(&t1, &t2, &t3);
+	ks[9] = t1;
+	ks[10] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x40);
+	aes_192_assist(&t1, &t2, &t3);
+	ks[10] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(ks[10]), _mm_castsi128_pd(t1), 0));
+	ks[11] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(t1), _mm_castsi128_pd(t3), 1));
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x80);
+	aes_192_assist(&t1, &t2, &t3);
+	ks[12] = t1;
+
+	cx->inf.l = 0;
+	cx->inf.b[0] = 12 * 16;
+	return EXIT_SUCCESS;
+}
+
+INLINE void aes_256_assist1(__m128i* t1, __m128i * t2)
+{
+	__m128i t4;
+	*t2 = _mm_shuffle_epi32(*t2, 0xff);
+	t4 = _mm_slli_si128(*t1, 0x4);
+	*t1 = _mm_xor_si128(*t1, t4);
+	t4 = _mm_slli_si128(t4, 0x4);
+	*t1 = _mm_xor_si128(*t1, t4);
+	t4 = _mm_slli_si128(t4, 0x4);
+	*t1 = _mm_xor_si128(*t1, t4);
+	*t1 = _mm_xor_si128(*t1, *t2);
+}
+
+INLINE void aes_256_assist2(__m128i* t1, __m128i * t3)
+{
+	__m128i t2, t4;
+	t4 = _mm_aeskeygenassist_si128(*t1, 0x0);
+	t2 = _mm_shuffle_epi32(t4, 0xaa);
+	t4 = _mm_slli_si128(*t3, 0x4);
+	*t3 = _mm_xor_si128(*t3, t4);
+	t4 = _mm_slli_si128(t4, 0x4);
+	*t3 = _mm_xor_si128(*t3, t4);
+	t4 = _mm_slli_si128(t4, 0x4);
+	*t3 = _mm_xor_si128(*t3, t4);
+	*t3 = _mm_xor_si128(*t3, t2);
+}
+
+AES_RETURN aes_ni(encrypt_key256)(const unsigned char *key, aes_encrypt_ctx cx[1])
+{
+	__m128i t1, t2, t3;
+	__m128i *ks = (__m128i*)cx->ks;
+
+	if(!has_aes_ni())
+	{
+		return aes_xi(encrypt_key256)(key, cx);
+	}
+
+	t1 = _mm_loadu_si128((__m128i*)key);
+	t3 = _mm_loadu_si128((__m128i*)(key + 16));
+
+	ks[0] = t1;
+	ks[1] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x01);
+	aes_256_assist1(&t1, &t2);
+	ks[2] = t1;
+	aes_256_assist2(&t1, &t3);
+	ks[3] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x02);
+	aes_256_assist1(&t1, &t2);
+	ks[4] = t1;
+	aes_256_assist2(&t1, &t3);
+	ks[5] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x04);
+	aes_256_assist1(&t1, &t2);
+	ks[6] = t1;
+	aes_256_assist2(&t1, &t3);
+	ks[7] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x08);
+	aes_256_assist1(&t1, &t2);
+	ks[8] = t1;
+	aes_256_assist2(&t1, &t3);
+	ks[9] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x10);
+	aes_256_assist1(&t1, &t2);
+	ks[10] = t1;
+	aes_256_assist2(&t1, &t3);
+	ks[11] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x20);
+	aes_256_assist1(&t1, &t2);
+	ks[12] = t1;
+	aes_256_assist2(&t1, &t3);
+	ks[13] = t3;
+
+	t2 = _mm_aeskeygenassist_si128(t3, 0x40);
+	aes_256_assist1(&t1, &t2);
+	ks[14] = t1;
+
+	cx->inf.l = 0;
+	cx->inf.b[0] = 14 * 16;
+	return EXIT_SUCCESS;
+}
+
+INLINE void enc_to_dec(aes_decrypt_ctx cx[1])
+{
+	__m128i *ks = (__m128i*)cx->ks;
+	int j;
+
+	for( j = 1 ; j < (cx->inf.b[0] >> 4) ; ++j )
+		ks[j] = _mm_aesimc_si128(ks[j]);
+}
+
+AES_RETURN aes_ni(decrypt_key128)(const unsigned char *key, aes_decrypt_ctx cx[1])
+{
+	if(!has_aes_ni())
+	{
+		return aes_xi(decrypt_key128)(key, cx);
+	}
+
+	if(aes_ni(encrypt_key128)(key, (aes_encrypt_ctx*)cx) == EXIT_SUCCESS)
+	{
+		enc_to_dec(cx);
+		return EXIT_SUCCESS;
+	}
+	else
+		return EXIT_FAILURE;
+
+}
+
+AES_RETURN aes_ni(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1])
+{
+	if(!has_aes_ni())
+	{
+		return aes_xi(decrypt_key192)(key, cx);
+	}
+
+	if(aes_ni(encrypt_key192)(key, (aes_encrypt_ctx*)cx) == EXIT_SUCCESS)
+	{
+		enc_to_dec(cx);
+		return EXIT_SUCCESS;
+	}
+	else
+		return EXIT_FAILURE;
+}
+
+AES_RETURN aes_ni(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1])
+{
+	if(!has_aes_ni())
+	{
+		return aes_xi(decrypt_key256)(key, cx);
+	}
+
+	if(aes_ni(encrypt_key256)(key, (aes_encrypt_ctx*)cx) == EXIT_SUCCESS)
+	{
+		enc_to_dec(cx);
+		return EXIT_SUCCESS;
+	}
+	else
+		return EXIT_FAILURE;
+}
+
+AES_RETURN aes_ni(encrypt)(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1])
+{
+	__m128i *key = (__m128i*)cx->ks, t;
+
+	if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16)
+		return EXIT_FAILURE;
+
+	if(!has_aes_ni())
+	{
+		return aes_xi(encrypt)(in, out, cx);
+	}
+
+	t = _mm_xor_si128(_mm_loadu_si128((__m128i*)in), *(__m128i*)key);
+
+	switch(cx->inf.b[0])
+	{
+	case 14 * 16:
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+	case 12 * 16:
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+	case 10 * 16:
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenc_si128(t, *(__m128i*)++key);
+		t = _mm_aesenclast_si128(t, *(__m128i*)++key);
+	}
+
+	_mm_storeu_si128(&((__m128i*)out)[0], t);
+	return EXIT_SUCCESS;
+}
+
+AES_RETURN aes_ni(decrypt)(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1])
+{
+	__m128i *key = (__m128i*)cx->ks + (cx->inf.b[0] >> 4), t;
+
+	if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16)
+		return EXIT_FAILURE;
+
+	if(!has_aes_ni())
+	{
+		return aes_xi(decrypt)(in, out, cx);
+	}
+
+	t = _mm_xor_si128(_mm_loadu_si128((__m128i*)in), *(__m128i*)key);
+
+	switch(cx->inf.b[0])
+	{
+	case 14 * 16:
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+	case 12 * 16:
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+	case 10 * 16:
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdec_si128(t, *(__m128i*)--key);
+		t = _mm_aesdeclast_si128(t, *(__m128i*)--key);
+	}
+
+	_mm_storeu_si128((__m128i*)out, t);
+	return EXIT_SUCCESS;
+}
+
+#ifdef ADD_AESNI_MODE_CALLS
+#ifdef USE_AES_CONTEXT
+
+AES_RETURN aes_CBC_encrypt(const unsigned char *in,
+	unsigned char *out,
+	unsigned char ivec[16],
+	unsigned long length,
+    const aes_encrypt_ctx cx[1])
+{
+	__m128i feedback, data, *key = (__m128i*)cx->ks;
+	int number_of_rounds = cx->inf.b[0] >> 4, j;
+    unsigned long i;
+    
+    if(number_of_rounds != 10 && number_of_rounds != 12 && number_of_rounds != 14)
+        return EXIT_FAILURE;
+
+    if(!has_aes_ni())
+    {
+        return aes_cbc_encrypt(in, out, length, ivec, cx);
+    }
+
+    if(length % 16)
+		length = length / 16 + 1;
+	else length /= 16;
+	feedback = _mm_loadu_si128((__m128i*)ivec);
+	for(i = 0; i < length; i++)
+	{
+		data = _mm_loadu_si128(&((__m128i*)in)[i]);
+		feedback = _mm_xor_si128(data, feedback);
+		feedback = _mm_xor_si128(feedback, ((__m128i*)key)[0]);
+		for(j = 1; j <number_of_rounds; j++)
+			feedback = _mm_aesenc_si128(feedback, ((__m128i*)key)[j]);
+		feedback = _mm_aesenclast_si128(feedback, ((__m128i*)key)[j]);
+		_mm_storeu_si128(&((__m128i*)out)[i], feedback);
+	}
+    return EXIT_SUCCESS;
+}
+
+AES_RETURN aes_CBC_decrypt(const unsigned char *in,
+    unsigned char *out,
+    unsigned char ivec[16],
+    unsigned long length,
+    const aes_decrypt_ctx cx[1])
+{
+    __m128i data, feedback, last_in, *key = (__m128i*)cx->ks;
+    int number_of_rounds = cx->inf.b[0] >> 4, j;
+    unsigned long i;
+
+    if(number_of_rounds != 10 && number_of_rounds != 12 && number_of_rounds != 14)
+        return EXIT_FAILURE;
+
+    if(!has_aes_ni())
+    {
+        return aes_cbc_decrypt(in, out, length, ivec, cx);
+    }
+
+    if(length % 16)
+        length = length / 16 + 1;
+    else length /= 16;
+    feedback = _mm_loadu_si128((__m128i*)ivec);
+    for(i = 0; i < length; i++)
+    {
+        last_in = _mm_loadu_si128(&((__m128i*)in)[i]);
+        data = _mm_xor_si128(last_in, ((__m128i*)key)[number_of_rounds]);
+        for(j = number_of_rounds - 1; j > 0; j--)
+        {
+            data = _mm_aesdec_si128(data, ((__m128i*)key)[j]);
+        }
+        data = _mm_aesdeclast_si128(data, ((__m128i*)key)[0]);
+        data = _mm_xor_si128(data, feedback);
+        _mm_storeu_si128(&((__m128i*)out)[i], data);
+        feedback = last_in;
+    }
+    return EXIT_SUCCESS;
+}
+
+static void ctr_inc(unsigned char *ctr_blk)
+{
+    uint32_t c;
+
+    c = *(uint32_t*)(ctr_blk + 8);
+    c++;
+    *(uint32_t*)(ctr_blk + 8) = c;
+
+    if(!c)
+        *(uint32_t*)(ctr_blk + 12) = *(uint32_t*)(ctr_blk + 12) + 1;
+}
+
+AES_RETURN AES_CTR_encrypt(const unsigned char *in,
+    unsigned char *out,
+    const unsigned char ivec[8],
+    const unsigned char nonce[4],
+    unsigned long length,
+    const aes_encrypt_ctx cx[1])
+{
+    __m128i ctr_block = { 0 }, *key = (__m128i*)cx->ks, tmp, ONE, BSWAP_EPI64;
+    int number_of_rounds = cx->inf.b[0] >> 4, j;
+    unsigned long i;
+
+    if(number_of_rounds != 10 && number_of_rounds != 12 && number_of_rounds != 14)
+        return EXIT_FAILURE;
+
+    if(!has_aes_ni())
+    {
+        unsigned char ctr_blk[16];
+        *(uint64_t*)ctr_blk = *(uint64_t*)ivec;
+        *(uint32_t*)(ctr_blk + 8) = *(uint32_t*)nonce;
+        return aes_ctr_crypt(in, out, length, (unsigned char*)ctr_blk, ctr_inc, cx);
+    }
+
+    if(length % 16)
+        length = length / 16 + 1;
+    else length /= 16;
+    ONE = _mm_set_epi32(0, 1, 0, 0);
+    BSWAP_EPI64 = _mm_setr_epi8(7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8);
+#ifdef _MSC_VER
+    ctr_block = _mm_insert_epi64(ctr_block, *(long long*)ivec, 1);
+#else
+    ctr_block = _mm_set_epi64(*(__m64*)ivec, *(__m64*)&ctr_block);
+#endif
+    ctr_block = _mm_insert_epi32(ctr_block, *(long*)nonce, 1);
+    ctr_block = _mm_srli_si128(ctr_block, 4);
+    ctr_block = _mm_shuffle_epi8(ctr_block, BSWAP_EPI64);
+    ctr_block = _mm_add_epi64(ctr_block, ONE);
+    for(i = 0; i < length; i++)
+    {
+        tmp = _mm_shuffle_epi8(ctr_block, BSWAP_EPI64);
+        ctr_block = _mm_add_epi64(ctr_block, ONE);
+        tmp = _mm_xor_si128(tmp, ((__m128i*)key)[0]);
+        for(j = 1; j <number_of_rounds; j++)
+        {
+            tmp = _mm_aesenc_si128(tmp, ((__m128i*)key)[j]);
+        };
+        tmp = _mm_aesenclast_si128(tmp, ((__m128i*)key)[j]);
+        tmp = _mm_xor_si128(tmp, _mm_loadu_si128(&((__m128i*)in)[i]));
+        _mm_storeu_si128(&((__m128i*)out)[i], tmp);
+    }
+    return EXIT_SUCCESS;
+}
+
+#else
+
+void aes_CBC_encrypt(const unsigned char *in,
+    unsigned char *out,
+    unsigned char ivec[16],
+    unsigned long length,
+    unsigned char *key,
+    int number_of_rounds)
+{
+    __m128i feedback, data;
+    unsigned long i;
+    int j;
+    if(length % 16)
+        length = length / 16 + 1;
+    else length /= 16;
+    feedback = _mm_loadu_si128((__m128i*)ivec);
+    for(i = 0; i < length; i++)
+    {
+        data = _mm_loadu_si128(&((__m128i*)in)[i]);
+        feedback = _mm_xor_si128(data, feedback);
+        feedback = _mm_xor_si128(feedback, ((__m128i*)key)[0]);
+        for(j = 1; j <number_of_rounds; j++)
+            feedback = _mm_aesenc_si128(feedback, ((__m128i*)key)[j]);
+        feedback = _mm_aesenclast_si128(feedback, ((__m128i*)key)[j]);
+        _mm_storeu_si128(&((__m128i*)out)[i], feedback);
+    }
+}
+
+void aes_CBC_decrypt(const unsigned char *in,
+	unsigned char *out,
+	unsigned char ivec[16],
+	unsigned long length,
+	unsigned char *key,
+	int number_of_rounds)
+{
+	__m128i data, feedback, last_in;
+	unsigned long i;
+	int j;
+	if(length % 16)
+		length = length / 16 + 1;
+	else length /= 16;
+	feedback = _mm_loadu_si128((__m128i*)ivec);
+	for(i = 0; i < length; i++)
+	{
+		last_in = _mm_loadu_si128(&((__m128i*)in)[i]);
+		data = _mm_xor_si128(last_in, ((__m128i*)key)[0]);
+		for(j = 1; j <number_of_rounds; j++)
+		{
+			data = _mm_aesdec_si128(data, ((__m128i*)key)[j]);
+		}
+		data = _mm_aesdeclast_si128(data, ((__m128i*)key)[j]);
+		data = _mm_xor_si128(data, feedback);
+		_mm_storeu_si128(&((__m128i*)out)[i], data);
+		feedback = last_in;
+	}
+}
+
+void AES_CTR_encrypt(const unsigned char *in,
+	unsigned char *out,
+	const unsigned char ivec[8],
+	const unsigned char nonce[4],
+	unsigned long length,
+	const unsigned char *key,
+	int number_of_rounds)
+{
+	__m128i ctr_block = { 0 }, tmp, ONE, BSWAP_EPI64;
+	unsigned long i;
+	int j;
+	if(length % 16)
+		length = length / 16 + 1;
+	else length /= 16;
+	ONE = _mm_set_epi32(0, 1, 0, 0);
+	BSWAP_EPI64 = _mm_setr_epi8(7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8);
+#ifdef _MSC_VER
+	ctr_block = _mm_insert_epi64(ctr_block, *(long long*)ivec, 1);
+#else
+	ctr_block = _mm_set_epi64(*(__m64*)ivec, *(__m64*)&ctr_block);
+#endif
+	ctr_block = _mm_insert_epi32(ctr_block, *(long*)nonce, 1);
+	ctr_block = _mm_srli_si128(ctr_block, 4);
+	ctr_block = _mm_shuffle_epi8(ctr_block, BSWAP_EPI64);
+	ctr_block = _mm_add_epi64(ctr_block, ONE);
+	for(i = 0; i < length; i++)
+	{
+		tmp = _mm_shuffle_epi8(ctr_block, BSWAP_EPI64);
+		ctr_block = _mm_add_epi64(ctr_block, ONE);
+		tmp = _mm_xor_si128(tmp, ((__m128i*)key)[0]);
+		for(j = 1; j <number_of_rounds; j++)
+		{
+			tmp = _mm_aesenc_si128(tmp, ((__m128i*)key)[j]);
+		};
+		tmp = _mm_aesenclast_si128(tmp, ((__m128i*)key)[j]);
+		tmp = _mm_xor_si128(tmp, _mm_loadu_si128(&((__m128i*)in)[i]));
+		_mm_storeu_si128(&((__m128i*)out)[i], tmp);
+	}
+}
+#endif
+#endif
+
+#endif

+ 59 - 0
ios/Classes/SSZipArchive/minizip/aes/aes_ni.h

@@ -0,0 +1,59 @@
+/*
+Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 13/11/2013
+*/
+
+#ifndef AES_NI_H
+#define AES_NI_H
+
+#define USE_AES_CONTEXT
+
+#include "aesopt.h"
+
+#if defined( USE_INTEL_AES_IF_PRESENT )
+
+/* map names in C code to make them internal ('name' -> 'aes_name_i') */
+#define aes_xi(x) aes_ ## x ## _i
+
+/* map names here to provide the external API ('name' -> 'aes_name') */
+#define aes_ni(x) aes_ ## x
+
+AES_RETURN aes_ni(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1]);
+AES_RETURN aes_ni(encrypt_key192)(const unsigned char *key, aes_encrypt_ctx cx[1]);
+AES_RETURN aes_ni(encrypt_key256)(const unsigned char *key, aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_ni(decrypt_key128)(const unsigned char *key, aes_decrypt_ctx cx[1]);
+AES_RETURN aes_ni(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1]);
+AES_RETURN aes_ni(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1]);
+
+AES_RETURN aes_ni(encrypt)(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]);
+AES_RETURN aes_ni(decrypt)(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]);
+
+AES_RETURN aes_xi(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1]);
+AES_RETURN aes_xi(encrypt_key192)(const unsigned char *key, aes_encrypt_ctx cx[1]);
+AES_RETURN aes_xi(encrypt_key256)(const unsigned char *key, aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_xi(decrypt_key128)(const unsigned char *key, aes_decrypt_ctx cx[1]);
+AES_RETURN aes_xi(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1]);
+AES_RETURN aes_xi(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1]);
+
+AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]);
+AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]);
+
+#endif
+
+#endif

+ 301 - 0
ios/Classes/SSZipArchive/minizip/aes/aescrypt.c

@@ -0,0 +1,301 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+*/
+
+#include "aesopt.h"
+#include "aestab.h"
+
+#if defined( USE_INTEL_AES_IF_PRESENT )
+#  include "aes_ni.h"
+#else
+/* map names here to provide the external API ('name' -> 'aes_name') */
+#  define aes_xi(x) aes_ ## x
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c])
+#define so(y,x,c)   word_out(y, c, s(x,c))
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[4],y[4]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
+#endif
+
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
+
+#if ( FUNCS_IN_C & ENCRYPTION_IN_C )
+
+/* Visual C++ .Net v7.1 provides the fastest encryption code when using
+   Pentium optimiation with small code but this is poor for decryption
+   so we need to control this with the following VC++ pragmas
+*/
+
+#if defined( _MSC_VER ) && !defined( _WIN64 )
+#pragma optimize( "s", on )
+#endif
+
+/* Given the column (c) of the output state variable, the following
+   macros give the input state variables which are needed in its
+   computation for each row (r) of the state. All the alternative
+   macros give the same end values but expand into different ways
+   of calculating these values.  In particular the complex macro
+   used for dynamically variable block sizes is designed to expand
+   to a compile time constant whenever possible but will expand to
+   conditional clauses on some branches (I am grateful to Frank
+   Yellin for this construction)
+*/
+
+#define fwd_var(x,r,c)\
+ ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
+ : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
+ : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
+ :          ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
+
+#if defined(FT4_SET)
+#undef  dec_fmvars
+#define fwd_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
+#elif defined(FT1_SET)
+#undef  dec_fmvars
+#define fwd_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c))
+#else
+#define fwd_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c)))
+#endif
+
+#if defined(FL4_SET)
+#define fwd_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c))
+#elif defined(FL1_SET)
+#define fwd_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c))
+#else
+#define fwd_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c))
+#endif
+
+AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1])
+{   uint32_t         locals(b0, b1);
+    const uint32_t   *kp;
+#if defined( dec_fmvars )
+    dec_fmvars; /* declare variables for fwd_mcol() if needed */
+#endif
+
+	if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16)
+		return EXIT_FAILURE;
+
+	kp = cx->ks;
+    state_in(b0, in, kp);
+
+#if (ENC_UNROLL == FULL)
+
+    switch(cx->inf.b[0])
+    {
+    case 14 * 16:
+        round(fwd_rnd,  b1, b0, kp + 1 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 2 * N_COLS);
+        kp += 2 * N_COLS;
+    case 12 * 16:
+        round(fwd_rnd,  b1, b0, kp + 1 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 2 * N_COLS);
+        kp += 2 * N_COLS;
+    case 10 * 16:
+        round(fwd_rnd,  b1, b0, kp + 1 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 2 * N_COLS);
+        round(fwd_rnd,  b1, b0, kp + 3 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 4 * N_COLS);
+        round(fwd_rnd,  b1, b0, kp + 5 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 6 * N_COLS);
+        round(fwd_rnd,  b1, b0, kp + 7 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 8 * N_COLS);
+        round(fwd_rnd,  b1, b0, kp + 9 * N_COLS);
+        round(fwd_lrnd, b0, b1, kp +10 * N_COLS);
+    }
+
+#else
+
+#if (ENC_UNROLL == PARTIAL)
+    {   uint32_t    rnd;
+        for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd)
+        {
+            kp += N_COLS;
+            round(fwd_rnd, b1, b0, kp);
+            kp += N_COLS;
+            round(fwd_rnd, b0, b1, kp);
+        }
+        kp += N_COLS;
+        round(fwd_rnd,  b1, b0, kp);
+#else
+    {   uint32_t    rnd;
+        for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd)
+        {
+            kp += N_COLS;
+            round(fwd_rnd, b1, b0, kp);
+            l_copy(b0, b1);
+        }
+#endif
+        kp += N_COLS;
+        round(fwd_lrnd, b0, b1, kp);
+    }
+#endif
+
+    state_out(out, b0);
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if ( FUNCS_IN_C & DECRYPTION_IN_C)
+
+/* Visual C++ .Net v7.1 provides the fastest encryption code when using
+   Pentium optimiation with small code but this is poor for decryption
+   so we need to control this with the following VC++ pragmas
+*/
+
+#if defined( _MSC_VER ) && !defined( _WIN64 )
+#pragma optimize( "t", on )
+#endif
+
+/* Given the column (c) of the output state variable, the following
+   macros give the input state variables which are needed in its
+   computation for each row (r) of the state. All the alternative
+   macros give the same end values but expand into different ways
+   of calculating these values.  In particular the complex macro
+   used for dynamically variable block sizes is designed to expand
+   to a compile time constant whenever possible but will expand to
+   conditional clauses on some branches (I am grateful to Frank
+   Yellin for this construction)
+*/
+
+#define inv_var(x,r,c)\
+ ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
+ : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\
+ : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
+ :          ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0)))
+
+#if defined(IT4_SET)
+#undef  dec_imvars
+#define inv_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c))
+#elif defined(IT1_SET)
+#undef  dec_imvars
+#define inv_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c))
+#else
+#define inv_rnd(y,x,k,c)    (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)))
+#endif
+
+#if defined(IL4_SET)
+#define inv_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c))
+#elif defined(IL1_SET)
+#define inv_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c))
+#else
+#define inv_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))
+#endif
+
+/* This code can work with the decryption key schedule in the   */
+/* order that is used for encrytpion (where the 1st decryption  */
+/* round key is at the high end ot the schedule) or with a key  */
+/* schedule that has been reversed to put the 1st decryption    */
+/* round key at the low end of the schedule in memory (when     */
+/* AES_REV_DKS is defined)                                      */
+
+#ifdef AES_REV_DKS
+#define key_ofs     0
+#define rnd_key(n)  (kp + n * N_COLS)
+#else
+#define key_ofs     1
+#define rnd_key(n)  (kp - n * N_COLS)
+#endif
+
+AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1])
+{   uint32_t        locals(b0, b1);
+#if defined( dec_imvars )
+    dec_imvars; /* declare variables for inv_mcol() if needed */
+#endif
+    const uint32_t *kp;
+
+    if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16)
+        return EXIT_FAILURE;
+
+    kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0);
+    state_in(b0, in, kp);
+
+#if (DEC_UNROLL == FULL)
+
+    kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2));
+    switch(cx->inf.b[0])
+    {
+    case 14 * 16:
+        round(inv_rnd,  b1, b0, rnd_key(-13));
+        round(inv_rnd,  b0, b1, rnd_key(-12));
+    case 12 * 16:
+        round(inv_rnd,  b1, b0, rnd_key(-11));
+        round(inv_rnd,  b0, b1, rnd_key(-10));
+    case 10 * 16:
+        round(inv_rnd,  b1, b0, rnd_key(-9));
+        round(inv_rnd,  b0, b1, rnd_key(-8));
+        round(inv_rnd,  b1, b0, rnd_key(-7));
+        round(inv_rnd,  b0, b1, rnd_key(-6));
+        round(inv_rnd,  b1, b0, rnd_key(-5));
+        round(inv_rnd,  b0, b1, rnd_key(-4));
+        round(inv_rnd,  b1, b0, rnd_key(-3));
+        round(inv_rnd,  b0, b1, rnd_key(-2));
+        round(inv_rnd,  b1, b0, rnd_key(-1));
+        round(inv_lrnd, b0, b1, rnd_key( 0));
+    }
+
+#else
+
+#if (DEC_UNROLL == PARTIAL)
+    {   uint32_t    rnd;
+        for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd)
+        {
+            kp = rnd_key(1);
+            round(inv_rnd, b1, b0, kp);
+            kp = rnd_key(1);
+            round(inv_rnd, b0, b1, kp);
+        }
+        kp = rnd_key(1);
+        round(inv_rnd, b1, b0, kp);
+#else
+    {   uint32_t    rnd;
+        for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd)
+        {
+            kp = rnd_key(1);
+            round(inv_rnd, b1, b0, kp);
+            l_copy(b0, b1);
+        }
+#endif
+        kp = rnd_key(1);
+        round(inv_lrnd, b0, b1, kp);
+        }
+#endif
+
+    state_out(out, b0);
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(__cplusplus)
+}
+#endif

+ 554 - 0
ios/Classes/SSZipArchive/minizip/aes/aeskey.c

@@ -0,0 +1,554 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+*/
+
+#include "aesopt.h"
+#include "aestab.h"
+
+#if defined( USE_INTEL_AES_IF_PRESENT )
+#  include "aes_ni.h"
+#else
+/* map names here to provide the external API ('name' -> 'aes_name') */
+#  define aes_xi(x) aes_ ## x
+#endif
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+#  include "aes_via_ace.h"
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* Initialise the key schedule from the user supplied key. The key
+   length can be specified in bytes, with legal values of 16, 24
+   and 32, or in bits, with legal values of 128, 192 and 256. These
+   values correspond with Nk values of 4, 6 and 8 respectively.
+
+   The following macros implement a single cycle in the key
+   schedule generation process. The number of cycles needed
+   for each cx->n_col and nk value is:
+
+    nk =             4  5  6  7  8
+    ------------------------------
+    cx->n_col = 4   10  9  8  7  7
+    cx->n_col = 5   14 11 10  9  9
+    cx->n_col = 6   19 15 12 11 11
+    cx->n_col = 7   21 19 16 13 14
+    cx->n_col = 8   29 23 19 17 14
+*/
+
+#if defined( REDUCE_CODE_SIZE )
+#  define ls_box ls_sub
+   uint32_t ls_sub(const uint32_t t, const uint32_t n);
+#  define inv_mcol im_sub
+   uint32_t im_sub(const uint32_t x);
+#  ifdef ENC_KS_UNROLL
+#    undef ENC_KS_UNROLL
+#  endif
+#  ifdef DEC_KS_UNROLL
+#    undef DEC_KS_UNROLL
+#  endif
+#endif
+
+#if (FUNCS_IN_C & ENC_KEYING_IN_C)
+
+#if defined(AES_128) || defined( AES_VAR )
+
+#define ke4(k,i) \
+{   k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
+    k[4*(i)+5] = ss[1] ^= ss[0]; \
+    k[4*(i)+6] = ss[2] ^= ss[1]; \
+    k[4*(i)+7] = ss[3] ^= ss[2]; \
+}
+
+AES_RETURN aes_xi(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1])
+{   uint32_t    ss[4];
+
+    cx->ks[0] = ss[0] = word_in(key, 0);
+    cx->ks[1] = ss[1] = word_in(key, 1);
+    cx->ks[2] = ss[2] = word_in(key, 2);
+    cx->ks[3] = ss[3] = word_in(key, 3);
+
+#ifdef ENC_KS_UNROLL
+    ke4(cx->ks, 0);  ke4(cx->ks, 1);
+    ke4(cx->ks, 2);  ke4(cx->ks, 3);
+    ke4(cx->ks, 4);  ke4(cx->ks, 5);
+    ke4(cx->ks, 6);  ke4(cx->ks, 7);
+    ke4(cx->ks, 8);
+#else
+    {   uint32_t i;
+        for(i = 0; i < 9; ++i)
+            ke4(cx->ks, i);
+    }
+#endif
+    ke4(cx->ks, 9);
+    cx->inf.l = 0;
+    cx->inf.b[0] = 10 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_192) || defined( AES_VAR )
+
+#define kef6(k,i) \
+{   k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
+    k[6*(i)+ 7] = ss[1] ^= ss[0]; \
+    k[6*(i)+ 8] = ss[2] ^= ss[1]; \
+    k[6*(i)+ 9] = ss[3] ^= ss[2]; \
+}
+
+#define ke6(k,i) \
+{   kef6(k,i); \
+    k[6*(i)+10] = ss[4] ^= ss[3]; \
+    k[6*(i)+11] = ss[5] ^= ss[4]; \
+}
+
+AES_RETURN aes_xi(encrypt_key192)(const unsigned char *key, aes_encrypt_ctx cx[1])
+{   uint32_t    ss[6];
+
+	cx->ks[0] = ss[0] = word_in(key, 0);
+    cx->ks[1] = ss[1] = word_in(key, 1);
+    cx->ks[2] = ss[2] = word_in(key, 2);
+    cx->ks[3] = ss[3] = word_in(key, 3);
+    cx->ks[4] = ss[4] = word_in(key, 4);
+    cx->ks[5] = ss[5] = word_in(key, 5);
+
+#ifdef ENC_KS_UNROLL
+    ke6(cx->ks, 0);  ke6(cx->ks, 1);
+    ke6(cx->ks, 2);  ke6(cx->ks, 3);
+    ke6(cx->ks, 4);  ke6(cx->ks, 5);
+    ke6(cx->ks, 6);
+#else
+    {   uint32_t i;
+        for(i = 0; i < 7; ++i)
+            ke6(cx->ks, i);
+    }
+#endif
+    kef6(cx->ks, 7);
+    cx->inf.l = 0;
+    cx->inf.b[0] = 12 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_256) || defined( AES_VAR )
+
+#define kef8(k,i) \
+{   k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
+    k[8*(i)+ 9] = ss[1] ^= ss[0]; \
+    k[8*(i)+10] = ss[2] ^= ss[1]; \
+    k[8*(i)+11] = ss[3] ^= ss[2]; \
+}
+
+#define ke8(k,i) \
+{   kef8(k,i); \
+    k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \
+    k[8*(i)+13] = ss[5] ^= ss[4]; \
+    k[8*(i)+14] = ss[6] ^= ss[5]; \
+    k[8*(i)+15] = ss[7] ^= ss[6]; \
+}
+
+AES_RETURN aes_xi(encrypt_key256)(const unsigned char *key, aes_encrypt_ctx cx[1])
+{   uint32_t    ss[8];
+
+    cx->ks[0] = ss[0] = word_in(key, 0);
+    cx->ks[1] = ss[1] = word_in(key, 1);
+    cx->ks[2] = ss[2] = word_in(key, 2);
+    cx->ks[3] = ss[3] = word_in(key, 3);
+    cx->ks[4] = ss[4] = word_in(key, 4);
+    cx->ks[5] = ss[5] = word_in(key, 5);
+    cx->ks[6] = ss[6] = word_in(key, 6);
+    cx->ks[7] = ss[7] = word_in(key, 7);
+
+#ifdef ENC_KS_UNROLL
+    ke8(cx->ks, 0); ke8(cx->ks, 1);
+    ke8(cx->ks, 2); ke8(cx->ks, 3);
+    ke8(cx->ks, 4); ke8(cx->ks, 5);
+#else
+    {   uint32_t i;
+        for(i = 0; i < 6; ++i)
+            ke8(cx->ks,  i);
+    }
+#endif
+    kef8(cx->ks, 6);
+    cx->inf.l = 0;
+    cx->inf.b[0] = 14 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#endif
+
+#if (FUNCS_IN_C & DEC_KEYING_IN_C)
+
+/* this is used to store the decryption round keys  */
+/* in forward or reverse order                      */
+
+#ifdef AES_REV_DKS
+#define v(n,i)  ((n) - (i) + 2 * ((i) & 3))
+#else
+#define v(n,i)  (i)
+#endif
+
+#if DEC_ROUND == NO_TABLES
+#define ff(x)   (x)
+#else
+#define ff(x)   inv_mcol(x)
+#if defined( dec_imvars )
+#define d_vars  dec_imvars
+#endif
+#endif
+
+#if defined(AES_128) || defined( AES_VAR )
+
+#define k4e(k,i) \
+{   k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
+    k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \
+    k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \
+    k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \
+}
+
+#if 1
+
+#define kdf4(k,i) \
+{   ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \
+    ss[1] = ss[1] ^ ss[3]; \
+    ss[2] = ss[2] ^ ss[3]; \
+    ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
+    ss[i % 4] ^= ss[4]; \
+    ss[4] ^= k[v(40,(4*(i)))];   k[v(40,(4*(i))+4)] = ff(ss[4]); \
+    ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \
+    ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \
+    ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \
+}
+
+#define kd4(k,i) \
+{   ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
+    ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \
+    k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \
+    k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \
+    k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \
+    k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \
+}
+
+#define kdl4(k,i) \
+{   ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \
+    k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \
+    k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \
+    k[v(40,(4*(i))+6)] = ss[0]; \
+    k[v(40,(4*(i))+7)] = ss[1]; \
+}
+
+#else
+
+#define kdf4(k,i) \
+{   ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \
+    ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \
+    ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \
+    ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \
+}
+
+#define kd4(k,i) \
+{   ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \
+    ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \
+    ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \
+    ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \
+    ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \
+}
+
+#define kdl4(k,i) \
+{   ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \
+    ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \
+    ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \
+    ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \
+}
+
+#endif
+
+AES_RETURN aes_xi(decrypt_key128)(const unsigned char *key, aes_decrypt_ctx cx[1])
+{   uint32_t    ss[5];
+#if defined( d_vars )
+        d_vars;
+#endif
+
+	cx->ks[v(40,(0))] = ss[0] = word_in(key, 0);
+    cx->ks[v(40,(1))] = ss[1] = word_in(key, 1);
+    cx->ks[v(40,(2))] = ss[2] = word_in(key, 2);
+    cx->ks[v(40,(3))] = ss[3] = word_in(key, 3);
+
+#ifdef DEC_KS_UNROLL
+     kdf4(cx->ks, 0); kd4(cx->ks, 1);
+     kd4(cx->ks, 2);  kd4(cx->ks, 3);
+     kd4(cx->ks, 4);  kd4(cx->ks, 5);
+     kd4(cx->ks, 6);  kd4(cx->ks, 7);
+     kd4(cx->ks, 8);  kdl4(cx->ks, 9);
+#else
+    {   uint32_t i;
+        for(i = 0; i < 10; ++i)
+            k4e(cx->ks, i);
+#if !(DEC_ROUND == NO_TABLES)
+        for(i = N_COLS; i < 10 * N_COLS; ++i)
+            cx->ks[i] = inv_mcol(cx->ks[i]);
+#endif
+    }
+#endif
+    cx->inf.l = 0;
+    cx->inf.b[0] = 10 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_192) || defined( AES_VAR )
+
+#define k6ef(k,i) \
+{   k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
+    k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \
+    k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \
+    k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \
+}
+
+#define k6e(k,i) \
+{   k6ef(k,i); \
+    k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \
+    k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \
+}
+
+#define kdf6(k,i) \
+{   ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \
+    ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \
+    ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \
+    ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \
+    ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \
+    ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \
+}
+
+#define kd6(k,i) \
+{   ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \
+    ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \
+    ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \
+    ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \
+    ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \
+    ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \
+    ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \
+}
+
+#define kdl6(k,i) \
+{   ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \
+    ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \
+    ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \
+    ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \
+}
+
+AES_RETURN aes_xi(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1])
+{   uint32_t    ss[7];
+#if defined( d_vars )
+        d_vars;
+#endif
+
+    cx->ks[v(48,(0))] = ss[0] = word_in(key, 0);
+    cx->ks[v(48,(1))] = ss[1] = word_in(key, 1);
+    cx->ks[v(48,(2))] = ss[2] = word_in(key, 2);
+    cx->ks[v(48,(3))] = ss[3] = word_in(key, 3);
+
+#ifdef DEC_KS_UNROLL
+    cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4));
+    cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5));
+    kdf6(cx->ks, 0); kd6(cx->ks, 1);
+    kd6(cx->ks, 2);  kd6(cx->ks, 3);
+    kd6(cx->ks, 4);  kd6(cx->ks, 5);
+    kd6(cx->ks, 6);  kdl6(cx->ks, 7);
+#else
+    cx->ks[v(48,(4))] = ss[4] = word_in(key, 4);
+    cx->ks[v(48,(5))] = ss[5] = word_in(key, 5);
+    {   uint32_t i;
+
+        for(i = 0; i < 7; ++i)
+            k6e(cx->ks, i);
+        k6ef(cx->ks, 7);
+#if !(DEC_ROUND == NO_TABLES)
+        for(i = N_COLS; i < 12 * N_COLS; ++i)
+            cx->ks[i] = inv_mcol(cx->ks[i]);
+#endif
+    }
+#endif
+    cx->inf.l = 0;
+    cx->inf.b[0] = 12 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_256) || defined( AES_VAR )
+
+#define k8ef(k,i) \
+{   k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
+    k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \
+    k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \
+    k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \
+}
+
+#define k8e(k,i) \
+{   k8ef(k,i); \
+    k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \
+    k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \
+    k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \
+    k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \
+}
+
+#define kdf8(k,i) \
+{   ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \
+    ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \
+    ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \
+    ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \
+    ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \
+    ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \
+    ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \
+    ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \
+}
+
+#define kd8(k,i) \
+{   ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \
+    ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \
+    ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \
+    ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \
+    ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \
+    ss[8] = ls_box(ss[3],0); \
+    ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \
+    ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \
+    ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \
+    ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \
+}
+
+#define kdl8(k,i) \
+{   ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \
+    ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \
+    ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \
+    ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \
+}
+
+AES_RETURN aes_xi(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1])
+{   uint32_t    ss[9];
+#if defined( d_vars )
+        d_vars;
+#endif
+
+    cx->ks[v(56,(0))] = ss[0] = word_in(key, 0);
+    cx->ks[v(56,(1))] = ss[1] = word_in(key, 1);
+    cx->ks[v(56,(2))] = ss[2] = word_in(key, 2);
+    cx->ks[v(56,(3))] = ss[3] = word_in(key, 3);
+
+#ifdef DEC_KS_UNROLL
+    cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4));
+    cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5));
+    cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6));
+    cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7));
+    kdf8(cx->ks, 0); kd8(cx->ks, 1);
+    kd8(cx->ks, 2);  kd8(cx->ks, 3);
+    kd8(cx->ks, 4);  kd8(cx->ks, 5);
+    kdl8(cx->ks, 6);
+#else
+    cx->ks[v(56,(4))] = ss[4] = word_in(key, 4);
+    cx->ks[v(56,(5))] = ss[5] = word_in(key, 5);
+    cx->ks[v(56,(6))] = ss[6] = word_in(key, 6);
+    cx->ks[v(56,(7))] = ss[7] = word_in(key, 7);
+    {   uint32_t i;
+
+        for(i = 0; i < 6; ++i)
+            k8e(cx->ks,  i);
+        k8ef(cx->ks,  6);
+#if !(DEC_ROUND == NO_TABLES)
+        for(i = N_COLS; i < 14 * N_COLS; ++i)
+            cx->ks[i] = inv_mcol(cx->ks[i]);
+#endif
+    }
+#endif
+    cx->inf.l = 0;
+    cx->inf.b[0] = 14 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#endif
+
+#if defined( AES_VAR )
+
+AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1])
+{
+	switch(key_len)
+	{
+	case 16: case 128: return aes_encrypt_key128(key, cx);
+	case 24: case 192: return aes_encrypt_key192(key, cx);
+	case 32: case 256: return aes_encrypt_key256(key, cx);
+	default: return EXIT_FAILURE;
+	}
+}
+
+AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1])
+{
+	switch(key_len)
+	{
+	case 16: case 128: return aes_decrypt_key128(key, cx);
+	case 24: case 192: return aes_decrypt_key192(key, cx);
+	case 32: case 256: return aes_decrypt_key256(key, cx);
+	default: return EXIT_FAILURE;
+	}
+}
+
+#endif
+
+#if defined(__cplusplus)
+}
+#endif

+ 776 - 0
ios/Classes/SSZipArchive/minizip/aes/aesopt.h

@@ -0,0 +1,776 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+
+ This file contains the compilation options for AES (Rijndael) and code
+ that is common across encryption, key scheduling and table generation.
+
+ OPERATION
+
+ These source code files implement the AES algorithm Rijndael designed by
+ Joan Daemen and Vincent Rijmen. This version is designed for the standard
+ block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24
+ and 32 bytes).
+
+ This version is designed for flexibility and speed using operations on
+ 32-bit words rather than operations on bytes.  It can be compiled with
+ either big or little endian internal byte order but is faster when the
+ native byte order for the processor is used.
+
+ THE CIPHER INTERFACE
+
+ The cipher interface is implemented as an array of bytes in which lower
+ AES bit sequence indexes map to higher numeric significance within bytes.
+
+  uint8_t                 (an unsigned  8-bit type)
+  uint32_t                (an unsigned 32-bit type)
+  struct aes_encrypt_ctx  (structure for the cipher encryption context)
+  struct aes_decrypt_ctx  (structure for the cipher decryption context)
+  AES_RETURN                the function return type
+
+  C subroutine calls:
+
+  AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
+  AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
+  AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
+  AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out,
+                                                  const aes_encrypt_ctx cx[1]);
+
+  AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
+  AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
+  AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
+  AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out,
+                                                  const aes_decrypt_ctx cx[1]);
+
+ IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that
+ you call aes_init() before AES is used so that the tables are initialised.
+
+ C++ aes class subroutines:
+
+     Class AESencrypt  for encryption
+
+      Construtors:
+          AESencrypt(void)
+          AESencrypt(const unsigned char *key) - 128 bit key
+      Members:
+          AES_RETURN key128(const unsigned char *key)
+          AES_RETURN key192(const unsigned char *key)
+          AES_RETURN key256(const unsigned char *key)
+          AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const
+
+      Class AESdecrypt  for encryption
+      Construtors:
+          AESdecrypt(void)
+          AESdecrypt(const unsigned char *key) - 128 bit key
+      Members:
+          AES_RETURN key128(const unsigned char *key)
+          AES_RETURN key192(const unsigned char *key)
+          AES_RETURN key256(const unsigned char *key)
+          AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const
+*/
+
+#if !defined( _AESOPT_H )
+#define _AESOPT_H
+
+#if defined( __cplusplus )
+#include "aescpp.h"
+#else
+#include "aes.h"
+#endif
+
+/*  PLATFORM SPECIFIC INCLUDES */
+
+#include "brg_endian.h"
+
+/*  CONFIGURATION - THE USE OF DEFINES
+
+    Later in this section there are a number of defines that control the
+    operation of the code.  In each section, the purpose of each define is
+    explained so that the relevant form can be included or excluded by
+    setting either 1's or 0's respectively on the branches of the related
+    #if clauses.  The following local defines should not be changed.
+*/
+
+#define ENCRYPTION_IN_C     1
+#define DECRYPTION_IN_C     2
+#define ENC_KEYING_IN_C     4
+#define DEC_KEYING_IN_C     8
+
+#define NO_TABLES           0
+#define ONE_TABLE           1
+#define FOUR_TABLES         4
+#define NONE                0
+#define PARTIAL             1
+#define FULL                2
+
+/*  --- START OF USER CONFIGURED OPTIONS --- */
+
+/*  1. BYTE ORDER WITHIN 32 BIT WORDS
+
+    The fundamental data processing units in Rijndael are 8-bit bytes. The
+    input, output and key input are all enumerated arrays of bytes in which
+    bytes are numbered starting at zero and increasing to one less than the
+    number of bytes in the array in question. This enumeration is only used
+    for naming bytes and does not imply any adjacency or order relationship
+    from one byte to another. When these inputs and outputs are considered
+    as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to
+    byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte.
+    In this implementation bits are numbered from 0 to 7 starting at the
+    numerically least significant end of each byte (bit n represents 2^n).
+
+    However, Rijndael can be implemented more efficiently using 32-bit
+    words by packing bytes into words so that bytes 4*n to 4*n+3 are placed
+    into word[n]. While in principle these bytes can be assembled into words
+    in any positions, this implementation only supports the two formats in
+    which bytes in adjacent positions within words also have adjacent byte
+    numbers. This order is called big-endian if the lowest numbered bytes
+    in words have the highest numeric significance and little-endian if the
+    opposite applies.
+
+    This code can work in either order irrespective of the order used by the
+    machine on which it runs. Normally the internal byte order will be set
+    to the order of the processor on which the code is to be run but this
+    define can be used to reverse this in special situations
+
+    WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set.
+    This define will hence be redefined later (in section 4) if necessary
+*/
+
+#if 1
+#  define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
+#elif 0
+#  define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN
+#elif 0
+#  define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN
+#else
+#  error The algorithm byte order is not defined
+#endif
+
+/*  2. Intel AES AND VIA ACE SUPPORT */
+
+#if defined( __GNUC__ ) && defined( __i386__ ) \
+ || defined( _WIN32 ) && defined( _M_IX86 ) && !(defined( _WIN64 ) \
+ || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 ))
+#  define VIA_ACE_POSSIBLE
+#endif
+
+#if (defined( _WIN64 ) && defined( _MSC_VER )) \
+ || (defined( __GNUC__ ) && defined( __x86_64__ )) && !(defined( __APPLE__ ))\
+ && !(defined( INTEL_AES_POSSIBLE ))
+#  define INTEL_AES_POSSIBLE
+#endif
+
+/*  Define this option if support for the Intel AESNI is required
+    If USE_INTEL_AES_IF_PRESENT is defined then AESNI will be used
+    if it is detected (both present and enabled).
+
+	AESNI uses a decryption key schedule with the first decryption
+	round key at the high end of the key scedule with the following
+	round keys at lower positions in memory.  So AES_REV_DKS must NOT
+	be defined when AESNI will be used.  ALthough it is unlikely that
+	assembler code will be used with an AESNI build, if it is then
+	AES_REV_DKS must NOT be defined when the assembler files are
+	built
+*/
+
+#if 1 && defined( INTEL_AES_POSSIBLE ) && !defined( USE_INTEL_AES_IF_PRESENT )
+#  define USE_INTEL_AES_IF_PRESENT
+#endif
+
+/*  Define this option if support for the VIA ACE is required. This uses
+    inline assembler instructions and is only implemented for the Microsoft,
+    Intel and GCC compilers.  If VIA ACE is known to be present, then defining
+    ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption
+    code.  If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if
+    it is detected (both present and enabled) but the normal AES code will
+    also be present.
+
+    When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte
+    aligned; other input/output buffers do not need to be 16 byte aligned
+    but there are very large performance gains if this can be arranged.
+    VIA ACE also requires the decryption key schedule to be in reverse
+    order (which later checks below ensure).
+
+	AES_REV_DKS must be set for assembler code used with a VIA ACE build
+*/
+
+#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT )
+#  define USE_VIA_ACE_IF_PRESENT
+#endif
+
+#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT )
+#  define ASSUME_VIA_ACE_PRESENT
+#  endif
+
+/*  3. ASSEMBLER SUPPORT
+
+    This define (which can be on the command line) enables the use of the
+    assembler code routines for encryption, decryption and key scheduling
+    as follows:
+
+    ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for
+                encryption and decryption and but with key scheduling in C
+    ASM_X86_V2  uses assembler (aes_x86_v2.asm) with compressed tables for
+                encryption, decryption and key scheduling
+    ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for
+                encryption and decryption and but with key scheduling in C
+    ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for
+                encryption and decryption and but with key scheduling in C
+
+    Change one 'if 0' below to 'if 1' to select the version or define
+    as a compilation option.
+*/
+
+#if 0 && !defined( ASM_X86_V1C )
+#  define ASM_X86_V1C
+#elif 0 && !defined( ASM_X86_V2  )
+#  define ASM_X86_V2
+#elif 0 && !defined( ASM_X86_V2C )
+#  define ASM_X86_V2C
+#elif 0 && !defined( ASM_AMD64_C )
+#  define ASM_AMD64_C
+#endif
+
+#if defined( __i386 ) || defined( _M_IX86 )
+#  define A32_
+#elif defined( __x86_64__ ) || defined( _M_X64 )
+#  define A64_
+#endif
+
+#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \
+       && !defined( A32_ )  || defined( ASM_AMD64_C ) && !defined( A64_ )
+#  error Assembler code is only available for x86 and AMD64 systems
+#endif
+
+/*  4. FAST INPUT/OUTPUT OPERATIONS.
+
+    On some machines it is possible to improve speed by transferring the
+    bytes in the input and output arrays to and from the internal 32-bit
+    variables by addressing these arrays as if they are arrays of 32-bit
+    words.  On some machines this will always be possible but there may
+    be a large performance penalty if the byte arrays are not aligned on
+    the normal word boundaries. On other machines this technique will
+    lead to memory access errors when such 32-bit word accesses are not
+    properly aligned. The option SAFE_IO avoids such problems but will
+    often be slower on those machines that support misaligned access
+    (especially so if care is taken to align the input  and output byte
+    arrays on 32-bit word boundaries). If SAFE_IO is not defined it is
+    assumed that access to byte arrays as if they are arrays of 32-bit
+    words will not cause problems when such accesses are misaligned.
+*/
+#if 1 && !defined( _MSC_VER )
+#  define SAFE_IO
+#endif
+
+/*  5. LOOP UNROLLING
+
+    The code for encryption and decrytpion cycles through a number of rounds
+    that can be implemented either in a loop or by expanding the code into a
+    long sequence of instructions, the latter producing a larger program but
+    one that will often be much faster. The latter is called loop unrolling.
+    There are also potential speed advantages in expanding two iterations in
+    a loop with half the number of iterations, which is called partial loop
+    unrolling.  The following options allow partial or full loop unrolling
+    to be set independently for encryption and decryption
+*/
+#if 1
+#  define ENC_UNROLL  FULL
+#elif 0
+#  define ENC_UNROLL  PARTIAL
+#else
+#  define ENC_UNROLL  NONE
+#endif
+
+#if 1
+#  define DEC_UNROLL  FULL
+#elif 0
+#  define DEC_UNROLL  PARTIAL
+#else
+#  define DEC_UNROLL  NONE
+#endif
+
+#if 1
+#  define ENC_KS_UNROLL
+#endif
+
+#if 1
+#  define DEC_KS_UNROLL
+#endif
+
+/*  6. FAST FINITE FIELD OPERATIONS
+
+    If this section is included, tables are used to provide faster finite
+    field arithmetic (this has no effect if STATIC_TABLES is defined).
+*/
+#if 1
+#  define FF_TABLES
+#endif
+
+/*  7. INTERNAL STATE VARIABLE FORMAT
+
+    The internal state of Rijndael is stored in a number of local 32-bit
+    word varaibles which can be defined either as an array or as individual
+    names variables. Include this section if you want to store these local
+    varaibles in arrays. Otherwise individual local variables will be used.
+*/
+#if 1
+#  define ARRAYS
+#endif
+
+/*  8. FIXED OR DYNAMIC TABLES
+
+    When this section is included the tables used by the code are compiled
+    statically into the binary file.  Otherwise the subroutine aes_init()
+    must be called to compute them before the code is first used.
+*/
+#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 ))
+#  define STATIC_TABLES
+#endif
+
+/*  9. MASKING OR CASTING FROM LONGER VALUES TO BYTES
+
+    In some systems it is better to mask longer values to extract bytes
+    rather than using a cast. This option allows this choice.
+*/
+#if 0
+#  define to_byte(x)  ((uint8_t)(x))
+#else
+#  define to_byte(x)  ((x) & 0xff)
+#endif
+
+/*  10. TABLE ALIGNMENT
+
+    On some sytsems speed will be improved by aligning the AES large lookup
+    tables on particular boundaries. This define should be set to a power of
+    two giving the desired alignment. It can be left undefined if alignment
+    is not needed.  This option is specific to the Microsft VC++ compiler -
+    it seems to sometimes cause trouble for the VC++ version 6 compiler.
+*/
+
+#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
+#  define TABLE_ALIGN 32
+#endif
+
+/*  11.  REDUCE CODE AND TABLE SIZE
+
+    This replaces some expanded macros with function calls if AES_ASM_V2 or
+    AES_ASM_V2C are defined
+*/
+
+#if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))
+#  define REDUCE_CODE_SIZE
+#endif
+
+/*  12. TABLE OPTIONS
+
+    This cipher proceeds by repeating in a number of cycles known as 'rounds'
+    which are implemented by a round function which can optionally be speeded
+    up using tables.  The basic tables are each 256 32-bit words, with either
+    one or four tables being required for each round function depending on
+    how much speed is required. The encryption and decryption round functions
+    are different and the last encryption and decrytpion round functions are
+    different again making four different round functions in all.
+
+    This means that:
+      1. Normal encryption and decryption rounds can each use either 0, 1
+         or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
+      2. The last encryption and decryption rounds can also use either 0, 1
+         or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
+
+    Include or exclude the appropriate definitions below to set the number
+    of tables used by this implementation.
+*/
+
+#if 1   /* set tables for the normal encryption round */
+#  define ENC_ROUND   FOUR_TABLES
+#elif 0
+#  define ENC_ROUND   ONE_TABLE
+#else
+#  define ENC_ROUND   NO_TABLES
+#endif
+
+#if 1   /* set tables for the last encryption round */
+#  define LAST_ENC_ROUND  FOUR_TABLES
+#elif 0
+#  define LAST_ENC_ROUND  ONE_TABLE
+#else
+#  define LAST_ENC_ROUND  NO_TABLES
+#endif
+
+#if 1   /* set tables for the normal decryption round */
+#  define DEC_ROUND   FOUR_TABLES
+#elif 0
+#  define DEC_ROUND   ONE_TABLE
+#else
+#  define DEC_ROUND   NO_TABLES
+#endif
+
+#if 1   /* set tables for the last decryption round */
+#  define LAST_DEC_ROUND  FOUR_TABLES
+#elif 0
+#  define LAST_DEC_ROUND  ONE_TABLE
+#else
+#  define LAST_DEC_ROUND  NO_TABLES
+#endif
+
+/*  The decryption key schedule can be speeded up with tables in the same
+    way that the round functions can.  Include or exclude the following
+    defines to set this requirement.
+*/
+#if 1
+#  define KEY_SCHED   FOUR_TABLES
+#elif 0
+#  define KEY_SCHED   ONE_TABLE
+#else
+#  define KEY_SCHED   NO_TABLES
+#endif
+
+/*  ---- END OF USER CONFIGURED OPTIONS ---- */
+
+/* VIA ACE support is only available for VC++ and GCC */
+
+#if !defined( _MSC_VER ) && !defined( __GNUC__ )
+#  if defined( ASSUME_VIA_ACE_PRESENT )
+#    undef ASSUME_VIA_ACE_PRESENT
+#  endif
+#  if defined( USE_VIA_ACE_IF_PRESENT )
+#    undef USE_VIA_ACE_IF_PRESENT
+#  endif
+#endif
+
+#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT )
+#  define USE_VIA_ACE_IF_PRESENT
+#endif
+
+/* define to reverse decryption key schedule    */
+#if 1 || defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS )
+#  define AES_REV_DKS
+#endif
+
+/* Intel AESNI uses a decryption key schedule in the encryption order */
+#if defined( USE_INTEL_AES_IF_PRESENT ) && defined ( AES_REV_DKS )
+#  undef AES_REV_DKS
+#endif
+
+/* Assembler support requires the use of platform byte order */
+
+#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \
+    && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER)
+#  undef  ALGORITHM_BYTE_ORDER
+#  define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
+#endif
+
+/* In this implementation the columns of the state array are each held in
+   32-bit words. The state array can be held in various ways: in an array
+   of words, in a number of individual word variables or in a number of
+   processor registers. The following define maps a variable name x and
+   a column number c to the way the state array variable is to be held.
+   The first define below maps the state into an array x[c] whereas the
+   second form maps the state into a number of individual variables x0,
+   x1, etc.  Another form could map individual state colums to machine
+   register names.
+*/
+
+#if defined( ARRAYS )
+#  define s(x,c) x[c]
+#else
+#  define s(x,c) x##c
+#endif
+
+/*  This implementation provides subroutines for encryption, decryption
+    and for setting the three key lengths (separately) for encryption
+    and decryption. Since not all functions are needed, masks are set
+    up here to determine which will be implemented in C
+*/
+
+#if !defined( AES_ENCRYPT )
+#  define EFUNCS_IN_C   0
+#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \
+    || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C )
+#  define EFUNCS_IN_C   ENC_KEYING_IN_C
+#elif !defined( ASM_X86_V2 )
+#  define EFUNCS_IN_C   ( ENCRYPTION_IN_C | ENC_KEYING_IN_C )
+#else
+#  define EFUNCS_IN_C   0
+#endif
+
+#if !defined( AES_DECRYPT )
+#  define DFUNCS_IN_C   0
+#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \
+    || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C )
+#  define DFUNCS_IN_C   DEC_KEYING_IN_C
+#elif !defined( ASM_X86_V2 )
+#  define DFUNCS_IN_C   ( DECRYPTION_IN_C | DEC_KEYING_IN_C )
+#else
+#  define DFUNCS_IN_C   0
+#endif
+
+#define FUNCS_IN_C  ( EFUNCS_IN_C | DFUNCS_IN_C )
+
+/* END OF CONFIGURATION OPTIONS */
+
+#define RC_LENGTH   (5 * (AES_BLOCK_SIZE / 4 - 2))
+
+/* Disable or report errors on some combinations of options */
+
+#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES
+#  undef  LAST_ENC_ROUND
+#  define LAST_ENC_ROUND  NO_TABLES
+#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES
+#  undef  LAST_ENC_ROUND
+#  define LAST_ENC_ROUND  ONE_TABLE
+#endif
+
+#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE
+#  undef  ENC_UNROLL
+#  define ENC_UNROLL  NONE
+#endif
+
+#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES
+#  undef  LAST_DEC_ROUND
+#  define LAST_DEC_ROUND  NO_TABLES
+#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES
+#  undef  LAST_DEC_ROUND
+#  define LAST_DEC_ROUND  ONE_TABLE
+#endif
+
+#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE
+#  undef  DEC_UNROLL
+#  define DEC_UNROLL  NONE
+#endif
+
+#if defined( bswap32 )
+#  define aes_sw32    bswap32
+#elif defined( bswap_32 )
+#  define aes_sw32    bswap_32
+#else
+#  define brot(x,n)   (((uint32_t)(x) <<  n) | ((uint32_t)(x) >> (32 - n)))
+#  define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00))
+#endif
+
+/*  upr(x,n):  rotates bytes within words by n positions, moving bytes to
+               higher index positions with wrap around into low positions
+    ups(x,n):  moves bytes by n positions to higher index positions in
+               words but without wrap around
+    bval(x,n): extracts a byte from a word
+
+    WARNING:   The definitions given here are intended only for use with
+               unsigned variables and with shift counts that are compile
+               time constants
+*/
+
+#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN )
+#  define upr(x,n)      (((uint32_t)(x) << (8 * (n))) | ((uint32_t)(x) >> (32 - 8 * (n))))
+#  define ups(x,n)      ((uint32_t) (x) << (8 * (n)))
+#  define bval(x,n)     to_byte((x) >> (8 * (n)))
+#  define bytes2word(b0, b1, b2, b3)  \
+        (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0))
+#endif
+
+#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN )
+#  define upr(x,n)      (((uint32_t)(x) >> (8 * (n))) | ((uint32_t)(x) << (32 - 8 * (n))))
+#  define ups(x,n)      ((uint32_t) (x) >> (8 * (n)))
+#  define bval(x,n)     to_byte((x) >> (24 - 8 * (n)))
+#  define bytes2word(b0, b1, b2, b3)  \
+        (((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | ((uint32_t)(b2) << 8) | (b3))
+#endif
+
+#if defined( SAFE_IO )
+#  define word_in(x,c)    bytes2word(((const uint8_t*)(x)+4*c)[0], ((const uint8_t*)(x)+4*c)[1], \
+                                   ((const uint8_t*)(x)+4*c)[2], ((const uint8_t*)(x)+4*c)[3])
+#  define word_out(x,c,v) { ((uint8_t*)(x)+4*c)[0] = bval(v,0); ((uint8_t*)(x)+4*c)[1] = bval(v,1); \
+                          ((uint8_t*)(x)+4*c)[2] = bval(v,2); ((uint8_t*)(x)+4*c)[3] = bval(v,3); }
+#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER )
+#  define word_in(x,c)    (*((uint32_t*)(x)+(c)))
+#  define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v))
+#else
+#  define word_in(x,c)    aes_sw32(*((uint32_t*)(x)+(c)))
+#  define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = aes_sw32(v))
+#endif
+
+/* the finite field modular polynomial and elements */
+
+#define WPOLY   0x011b
+#define BPOLY     0x1b
+
+/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+#define gf_c1  0x80808080
+#define gf_c2  0x7f7f7f7f
+#define gf_mulx(x)  ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY))
+
+/* The following defines provide alternative definitions of gf_mulx that might
+   give improved performance if a fast 32-bit multiply is not available. Note
+   that a temporary variable u needs to be defined where gf_mulx is used.
+
+#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6))
+#define gf_c4  (0x01010101 * BPOLY)
+#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4)
+*/
+
+/* Work out which tables are needed for the different options   */
+
+#if defined( ASM_X86_V1C )
+#  if defined( ENC_ROUND )
+#    undef  ENC_ROUND
+#  endif
+#  define ENC_ROUND   FOUR_TABLES
+#  if defined( LAST_ENC_ROUND )
+#    undef  LAST_ENC_ROUND
+#  endif
+#  define LAST_ENC_ROUND  FOUR_TABLES
+#  if defined( DEC_ROUND )
+#    undef  DEC_ROUND
+#  endif
+#  define DEC_ROUND   FOUR_TABLES
+#  if defined( LAST_DEC_ROUND )
+#    undef  LAST_DEC_ROUND
+#  endif
+#  define LAST_DEC_ROUND  FOUR_TABLES
+#  if defined( KEY_SCHED )
+#    undef  KEY_SCHED
+#    define KEY_SCHED   FOUR_TABLES
+#  endif
+#endif
+
+#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C )
+#  if ENC_ROUND == ONE_TABLE
+#    define FT1_SET
+#  elif ENC_ROUND == FOUR_TABLES
+#    define FT4_SET
+#  else
+#    define SBX_SET
+#  endif
+#  if LAST_ENC_ROUND == ONE_TABLE
+#    define FL1_SET
+#  elif LAST_ENC_ROUND == FOUR_TABLES
+#    define FL4_SET
+#  elif !defined( SBX_SET )
+#    define SBX_SET
+#  endif
+#endif
+
+#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C )
+#  if DEC_ROUND == ONE_TABLE
+#    define IT1_SET
+#  elif DEC_ROUND == FOUR_TABLES
+#    define IT4_SET
+#  else
+#    define ISB_SET
+#  endif
+#  if LAST_DEC_ROUND == ONE_TABLE
+#    define IL1_SET
+#  elif LAST_DEC_ROUND == FOUR_TABLES
+#    define IL4_SET
+#  elif !defined(ISB_SET)
+#    define ISB_SET
+#  endif
+#endif
+
+#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )))
+#  if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C))
+#    if KEY_SCHED == ONE_TABLE
+#      if !defined( FL1_SET )  && !defined( FL4_SET )
+#        define LS1_SET
+#      endif
+#    elif KEY_SCHED == FOUR_TABLES
+#      if !defined( FL4_SET )
+#        define LS4_SET
+#      endif
+#    elif !defined( SBX_SET )
+#      define SBX_SET
+#    endif
+#  endif
+#  if (FUNCS_IN_C & DEC_KEYING_IN_C)
+#    if KEY_SCHED == ONE_TABLE
+#      define IM1_SET
+#    elif KEY_SCHED == FOUR_TABLES
+#      define IM4_SET
+#    elif !defined( SBX_SET )
+#      define SBX_SET
+#    endif
+#  endif
+#endif
+
+/* generic definitions of Rijndael macros that use tables    */
+
+#define no_table(x,box,vf,rf,c) bytes2word( \
+    box[bval(vf(x,0,c),rf(0,c))], \
+    box[bval(vf(x,1,c),rf(1,c))], \
+    box[bval(vf(x,2,c),rf(2,c))], \
+    box[bval(vf(x,3,c),rf(3,c))])
+
+#define one_table(x,op,tab,vf,rf,c) \
+ (     tab[bval(vf(x,0,c),rf(0,c))] \
+  ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
+  ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
+  ^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
+
+#define four_tables(x,tab,vf,rf,c) \
+ (  tab[0][bval(vf(x,0,c),rf(0,c))] \
+  ^ tab[1][bval(vf(x,1,c),rf(1,c))] \
+  ^ tab[2][bval(vf(x,2,c),rf(2,c))] \
+  ^ tab[3][bval(vf(x,3,c),rf(3,c))])
+
+#define vf1(x,r,c)  (x)
+#define rf1(r,c)    (r)
+#define rf2(r,c)    ((8+r-c)&3)
+
+/* perform forward and inverse column mix operation on four bytes in long word x in */
+/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros.  */
+
+#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )))
+
+#if defined( FM4_SET )      /* not currently used */
+#  define fwd_mcol(x)       four_tables(x,t_use(f,m),vf1,rf1,0)
+#elif defined( FM1_SET )    /* not currently used */
+#  define fwd_mcol(x)       one_table(x,upr,t_use(f,m),vf1,rf1,0)
+#else
+#  define dec_fmvars        uint32_t g2
+#  define fwd_mcol(x)       (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1))
+#endif
+
+#if defined( IM4_SET )
+#  define inv_mcol(x)       four_tables(x,t_use(i,m),vf1,rf1,0)
+#elif defined( IM1_SET )
+#  define inv_mcol(x)       one_table(x,upr,t_use(i,m),vf1,rf1,0)
+#else
+#  define dec_imvars        uint32_t g2, g4, g9
+#  define inv_mcol(x)       (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \
+                            (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1))
+#endif
+
+#if defined( FL4_SET )
+#  define ls_box(x,c)       four_tables(x,t_use(f,l),vf1,rf2,c)
+#elif defined( LS4_SET )
+#  define ls_box(x,c)       four_tables(x,t_use(l,s),vf1,rf2,c)
+#elif defined( FL1_SET )
+#  define ls_box(x,c)       one_table(x,upr,t_use(f,l),vf1,rf2,c)
+#elif defined( LS1_SET )
+#  define ls_box(x,c)       one_table(x,upr,t_use(l,s),vf1,rf2,c)
+#else
+#  define ls_box(x,c)       no_table(x,t_use(s,box),vf1,rf2,c)
+#endif
+
+#endif
+
+#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET )
+#  define ISB_SET
+#endif
+
+#endif

+ 418 - 0
ios/Classes/SSZipArchive/minizip/aes/aestab.c

@@ -0,0 +1,418 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+*/
+
+#define DO_TABLES
+
+#include "aes.h"
+#include "aesopt.h"
+
+#if defined(STATIC_TABLES)
+
+#define sb_data(w) {\
+    w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
+    w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
+    w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
+    w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
+    w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
+    w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
+    w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
+    w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
+    w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
+    w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
+    w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
+    w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
+    w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
+    w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
+    w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
+    w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
+    w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
+    w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
+    w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
+    w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
+    w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
+    w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
+    w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
+    w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
+    w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
+    w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
+    w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
+    w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
+    w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
+    w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
+    w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
+    w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
+
+#define isb_data(w) {\
+    w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
+    w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
+    w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
+    w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
+    w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
+    w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
+    w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
+    w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
+    w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
+    w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
+    w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
+    w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
+    w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
+    w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
+    w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
+    w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
+    w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
+    w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
+    w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
+    w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
+    w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
+    w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
+    w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
+    w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
+    w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
+    w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
+    w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
+    w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
+    w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
+    w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
+    w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
+    w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) }
+
+#define mm_data(w) {\
+    w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
+    w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
+    w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
+    w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
+    w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
+    w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
+    w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
+    w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
+    w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
+    w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
+    w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
+    w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
+    w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
+    w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
+    w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
+    w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
+    w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
+    w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
+    w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
+    w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
+    w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
+    w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
+    w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
+    w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
+    w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
+    w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
+    w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
+    w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
+    w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
+    w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
+    w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
+    w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) }
+
+#define rc_data(w) {\
+    w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
+    w(0x1b), w(0x36) }
+
+#define h0(x)   (x)
+
+#define w0(p)   bytes2word(p, 0, 0, 0)
+#define w1(p)   bytes2word(0, p, 0, 0)
+#define w2(p)   bytes2word(0, 0, p, 0)
+#define w3(p)   bytes2word(0, 0, 0, p)
+
+#define u0(p)   bytes2word(f2(p), p, p, f3(p))
+#define u1(p)   bytes2word(f3(p), f2(p), p, p)
+#define u2(p)   bytes2word(p, f3(p), f2(p), p)
+#define u3(p)   bytes2word(p, p, f3(p), f2(p))
+
+#define v0(p)   bytes2word(fe(p), f9(p), fd(p), fb(p))
+#define v1(p)   bytes2word(fb(p), fe(p), f9(p), fd(p))
+#define v2(p)   bytes2word(fd(p), fb(p), fe(p), f9(p))
+#define v3(p)   bytes2word(f9(p), fd(p), fb(p), fe(p))
+
+#endif
+
+#if defined(STATIC_TABLES) || !defined(FF_TABLES)
+
+#define f2(x)   ((x<<1) ^ (((x>>7) & 1) * WPOLY))
+#define f4(x)   ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
+#define f8(x)   ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \
+                        ^ (((x>>5) & 4) * WPOLY))
+#define f3(x)   (f2(x) ^ x)
+#define f9(x)   (f8(x) ^ x)
+#define fb(x)   (f8(x) ^ f2(x) ^ x)
+#define fd(x)   (f8(x) ^ f4(x) ^ x)
+#define fe(x)   (f8(x) ^ f4(x) ^ f2(x))
+
+#else
+
+#define f2(x) ((x) ? pow[log[x] + 0x19] : 0)
+#define f3(x) ((x) ? pow[log[x] + 0x01] : 0)
+#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0)
+#define fb(x) ((x) ? pow[log[x] + 0x68] : 0)
+#define fd(x) ((x) ? pow[log[x] + 0xee] : 0)
+#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0)
+
+#endif
+
+#include "aestab.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#if defined(STATIC_TABLES)
+
+/* implemented in case of wrong call for fixed tables */
+
+AES_RETURN aes_init(void)
+{
+    return EXIT_SUCCESS;
+}
+
+#else   /*  Generate the tables for the dynamic table option */
+
+#if defined(FF_TABLES)
+
+#define gf_inv(x)   ((x) ? pow[ 255 - log[x]] : 0)
+
+#else
+
+/*  It will generally be sensible to use tables to compute finite
+    field multiplies and inverses but where memory is scarse this
+    code might sometimes be better. But it only has effect during
+    initialisation so its pretty unimportant in overall terms.
+*/
+
+/*  return 2 ^ (n - 1) where n is the bit number of the highest bit
+    set in x with x in the range 1 < x < 0x00000200.   This form is
+    used so that locals within fi can be bytes rather than words
+*/
+
+static uint8_t hibit(const uint32_t x)
+{   uint8_t r = (uint8_t)((x >> 1) | (x >> 2));
+
+    r |= (r >> 2);
+    r |= (r >> 4);
+    return (r + 1) >> 1;
+}
+
+/* return the inverse of the finite field element x */
+
+static uint8_t gf_inv(const uint8_t x)
+{   uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+    if(x < 2)
+        return x;
+
+    for( ; ; )
+    {
+        if(n1)
+            while(n2 >= n1)             /* divide polynomial p2 by p1    */
+            {
+                n2 /= n1;               /* shift smaller polynomial left */
+                p2 ^= (p1 * n2) & 0xff; /* and remove from larger one    */
+                v2 ^= v1 * n2;          /* shift accumulated value and   */
+                n2 = hibit(p2);         /* add into result               */
+            }
+        else
+            return v1;
+
+        if(n2)                          /* repeat with values swapped    */
+            while(n1 >= n2)
+            {
+                n1 /= n2;
+                p1 ^= p2 * n1;
+                v1 ^= v2 * n1;
+                n1 = hibit(p1);
+            }
+        else
+            return v2;
+    }
+}
+
+#endif
+
+/* The forward and inverse affine transformations used in the S-box */
+uint8_t fwd_affine(const uint8_t x)
+{   uint32_t w = x;
+    w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
+    return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
+}
+
+uint8_t inv_affine(const uint8_t x)
+{   uint32_t w = x;
+    w = (w << 1) ^ (w << 3) ^ (w << 6);
+    return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
+}
+
+static int init = 0;
+
+AES_RETURN aes_init(void)
+{   uint32_t  i, w;
+
+#if defined(FF_TABLES)
+
+    uint8_t  pow[512], log[256];
+
+    if(init)
+        return EXIT_SUCCESS;
+    /*  log and power tables for GF(2^8) finite field with
+        WPOLY as modular polynomial - the simplest primitive
+        root is 0x03, used here to generate the tables
+    */
+
+    i = 0; w = 1;
+    do
+    {
+        pow[i] = (uint8_t)w;
+        pow[i + 255] = (uint8_t)w;
+        log[w] = (uint8_t)i++;
+        w ^=  (w << 1) ^ (w & 0x80 ? WPOLY : 0);
+    }
+    while (w != 1);
+
+#else
+    if(init)
+        return EXIT_SUCCESS;
+#endif
+
+    for(i = 0, w = 1; i < RC_LENGTH; ++i)
+    {
+        t_set(r,c)[i] = bytes2word(w, 0, 0, 0);
+        w = f2(w);
+    }
+
+    for(i = 0; i < 256; ++i)
+    {   uint8_t    b;
+
+        b = fwd_affine(gf_inv((uint8_t)i));
+        w = bytes2word(f2(b), b, b, f3(b));
+
+#if defined( SBX_SET )
+        t_set(s,box)[i] = b;
+#endif
+
+#if defined( FT1_SET )                 /* tables for a normal encryption round */
+        t_set(f,n)[i] = w;
+#endif
+#if defined( FT4_SET )
+        t_set(f,n)[0][i] = w;
+        t_set(f,n)[1][i] = upr(w,1);
+        t_set(f,n)[2][i] = upr(w,2);
+        t_set(f,n)[3][i] = upr(w,3);
+#endif
+        w = bytes2word(b, 0, 0, 0);
+
+#if defined( FL1_SET )            /* tables for last encryption round (may also   */
+        t_set(f,l)[i] = w;        /* be used in the key schedule)                 */
+#endif
+#if defined( FL4_SET )
+        t_set(f,l)[0][i] = w;
+        t_set(f,l)[1][i] = upr(w,1);
+        t_set(f,l)[2][i] = upr(w,2);
+        t_set(f,l)[3][i] = upr(w,3);
+#endif
+
+#if defined( LS1_SET )			/* table for key schedule if t_set(f,l) above is*/
+        t_set(l,s)[i] = w;      /* not of the required form                     */
+#endif
+#if defined( LS4_SET )
+        t_set(l,s)[0][i] = w;
+        t_set(l,s)[1][i] = upr(w,1);
+        t_set(l,s)[2][i] = upr(w,2);
+        t_set(l,s)[3][i] = upr(w,3);
+#endif
+
+        b = gf_inv(inv_affine((uint8_t)i));
+        w = bytes2word(fe(b), f9(b), fd(b), fb(b));
+
+#if defined( IM1_SET )			/* tables for the inverse mix column operation  */
+        t_set(i,m)[b] = w;
+#endif
+#if defined( IM4_SET )
+        t_set(i,m)[0][b] = w;
+        t_set(i,m)[1][b] = upr(w,1);
+        t_set(i,m)[2][b] = upr(w,2);
+        t_set(i,m)[3][b] = upr(w,3);
+#endif
+
+#if defined( ISB_SET )
+        t_set(i,box)[i] = b;
+#endif
+#if defined( IT1_SET )			/* tables for a normal decryption round */
+        t_set(i,n)[i] = w;
+#endif
+#if defined( IT4_SET )
+        t_set(i,n)[0][i] = w;
+        t_set(i,n)[1][i] = upr(w,1);
+        t_set(i,n)[2][i] = upr(w,2);
+        t_set(i,n)[3][i] = upr(w,3);
+#endif
+        w = bytes2word(b, 0, 0, 0);
+#if defined( IL1_SET )			/* tables for last decryption round */
+        t_set(i,l)[i] = w;
+#endif
+#if defined( IL4_SET )
+        t_set(i,l)[0][i] = w;
+        t_set(i,l)[1][i] = upr(w,1);
+        t_set(i,l)[2][i] = upr(w,2);
+        t_set(i,l)[3][i] = upr(w,3);
+#endif
+    }
+    init = 1;
+    return EXIT_SUCCESS;
+}
+
+/* 
+   Automatic code initialisation (suggested by by Henrik S. Gaßmann)
+   based on code provided by Joe Lowe and placed in the public domain at:
+   http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
+*/
+
+#ifdef _MSC_VER
+
+#pragma section(".CRT$XCU", read)
+
+__declspec(allocate(".CRT$XCU")) void (__cdecl *aes_startup)(void) = aes_init;
+
+#elif defined(__GNUC__)
+
+static void aes_startup(void) __attribute__((constructor));
+
+static void aes_startup(void)
+{
+    aes_init();
+}
+
+#else
+
+#pragma message( "dynamic tables must be initialised manually on your system" )
+
+#endif
+
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+

+ 173 - 0
ios/Classes/SSZipArchive/minizip/aes/aestab.h

@@ -0,0 +1,173 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+
+ This file contains the code for declaring the tables needed to implement
+ AES. The file aesopt.h is assumed to be included before this header file.
+ If there are no global variables, the definitions here can be used to put
+ the AES tables in a structure so that a pointer can then be added to the
+ AES context to pass them to the AES routines that need them.   If this
+ facility is used, the calling program has to ensure that this pointer is
+ managed appropriately.  In particular, the value of the t_dec(in,it) item
+ in the table structure must be set to zero in order to ensure that the
+ tables are initialised. In practice the three code sequences in aeskey.c
+ that control the calls to aes_init() and the aes_init() routine itself will
+ have to be changed for a specific implementation. If global variables are
+ available it will generally be preferable to use them with the precomputed
+ STATIC_TABLES option that uses static global tables.
+
+ The following defines can be used to control the way the tables
+ are defined, initialised and used in embedded environments that
+ require special features for these purposes
+
+    the 't_dec' construction is used to declare fixed table arrays
+    the 't_set' construction is used to set fixed table values
+    the 't_use' construction is used to access fixed table values
+
+    256 byte tables:
+
+        t_xxx(s,box)    => forward S box
+        t_xxx(i,box)    => inverse S box
+
+    256 32-bit word OR 4 x 256 32-bit word tables:
+
+        t_xxx(f,n)      => forward normal round
+        t_xxx(f,l)      => forward last round
+        t_xxx(i,n)      => inverse normal round
+        t_xxx(i,l)      => inverse last round
+        t_xxx(l,s)      => key schedule table
+        t_xxx(i,m)      => key schedule table
+
+    Other variables and tables:
+
+        t_xxx(r,c)      => the rcon table
+*/
+
+#if !defined( _AESTAB_H )
+#define _AESTAB_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define t_dec(m,n) t_##m##n
+#define t_set(m,n) t_##m##n
+#define t_use(m,n) t_##m##n
+
+#if defined(STATIC_TABLES)
+#  if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ ))
+/*   make tables far data to avoid using too much DGROUP space (PG) */
+#    define CONST const far
+#  else
+#    define CONST const
+#  endif
+#else
+#  define CONST
+#endif
+
+#if defined(DO_TABLES)
+#  define EXTERN
+#else
+#  define EXTERN extern
+#endif
+
+#if defined(_MSC_VER) && defined(TABLE_ALIGN)
+#define ALIGN __declspec(align(TABLE_ALIGN))
+#else
+#define ALIGN
+#endif
+
+#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 )
+#  define XP_DIR __cdecl
+#else
+#  define XP_DIR
+#endif
+
+#if defined(DO_TABLES) && defined(STATIC_TABLES)
+#define d_1(t,n,b,e)       EXTERN ALIGN CONST XP_DIR t n[256]    =   b(e)
+#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) }
+EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH] = rc_data(w0);
+#else
+#define d_1(t,n,b,e)       EXTERN ALIGN CONST XP_DIR t n[256]
+#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256]
+EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH];
+#endif
+
+#if defined( SBX_SET )
+    d_1(uint8_t, t_dec(s,box), sb_data, h0);
+#endif
+#if defined( ISB_SET )
+    d_1(uint8_t, t_dec(i,box), isb_data, h0);
+#endif
+
+#if defined( FT1_SET )
+    d_1(uint32_t, t_dec(f,n), sb_data, u0);
+#endif
+#if defined( FT4_SET )
+    d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3);
+#endif
+
+#if defined( FL1_SET )
+    d_1(uint32_t, t_dec(f,l), sb_data, w0);
+#endif
+#if defined( FL4_SET )
+    d_4(uint32_t, t_dec(f,l), sb_data, w0, w1, w2, w3);
+#endif
+
+#if defined( IT1_SET )
+    d_1(uint32_t, t_dec(i,n), isb_data, v0);
+#endif
+#if defined( IT4_SET )
+    d_4(uint32_t, t_dec(i,n), isb_data, v0, v1, v2, v3);
+#endif
+
+#if defined( IL1_SET )
+    d_1(uint32_t, t_dec(i,l), isb_data, w0);
+#endif
+#if defined( IL4_SET )
+    d_4(uint32_t, t_dec(i,l), isb_data, w0, w1, w2, w3);
+#endif
+
+#if defined( LS1_SET )
+#if defined( FL1_SET )
+#undef  LS1_SET
+#else
+    d_1(uint32_t, t_dec(l,s), sb_data, w0);
+#endif
+#endif
+
+#if defined( LS4_SET )
+#if defined( FL4_SET )
+#undef  LS4_SET
+#else
+    d_4(uint32_t, t_dec(l,s), sb_data, w0, w1, w2, w3);
+#endif
+#endif
+
+#if defined( IM1_SET )
+    d_1(uint32_t, t_dec(i,m), mm_data, v0);
+#endif
+#if defined( IM4_SET )
+    d_4(uint32_t, t_dec(i,m), mm_data, v0, v1, v2, v3);
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

+ 127 - 0
ios/Classes/SSZipArchive/minizip/aes/brg_endian.h

@@ -0,0 +1,127 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+*/
+
+#ifndef _BRG_ENDIAN_H
+#define _BRG_ENDIAN_H
+
+#define IS_BIG_ENDIAN      4321 /* byte 0 is most significant (mc68k) */
+#define IS_LITTLE_ENDIAN   1234 /* byte 0 is least significant (i386) */
+
+/* Include files where endian defines and byteswap functions may reside */
+#if defined( __sun )
+#  include <sys/isa_defs.h>
+#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ )
+#  include <sys/endian.h>
+#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \
+      defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) || \
+      defined(__pnacl__)
+#  include <machine/endian.h>
+#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
+#  if !defined( __MINGW32__ ) && !defined( _AIX )
+#    include <endian.h>
+#    if !defined( __BEOS__ )
+#      include <byteswap.h>
+#    endif
+#  endif
+#endif
+
+/* Now attempt to set the define for platform byte order using any  */
+/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which  */
+/* seem to encompass most endian symbol definitions                 */
+
+#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN )
+#  if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#  elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#  endif
+#elif defined( BIG_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#elif defined( LITTLE_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#endif
+
+#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN )
+#  if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#  elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#  endif
+#elif defined( _BIG_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#elif defined( _LITTLE_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#endif
+
+#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN )
+#  if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#  elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#  endif
+#elif defined( __BIG_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#elif defined( __LITTLE_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#endif
+
+#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ )
+#  if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__
+#    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#  elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__
+#    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#  endif
+#elif defined( __BIG_ENDIAN__ )
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#elif defined( __LITTLE_ENDIAN__ )
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#endif
+
+/*  if the platform byte order could not be determined, then try to */
+/*  set this define using common machine defines                    */
+#if !defined(PLATFORM_BYTE_ORDER)
+
+#if   defined( __alpha__ ) || defined( __alpha ) || defined( i386 )       || \
+      defined( __i386__ )  || defined( _M_I86 )  || defined( _M_IX86 )    || \
+      defined( __OS2__ )   || defined( sun386 )  || defined( __TURBOC__ ) || \
+      defined( vax )       || defined( vms )     || defined( VMS )        || \
+      defined( __VMS )     || defined( _M_X64 )
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+
+#elif defined( AMIGA )   || defined( applec )    || defined( __AS400__ )  || \
+      defined( _CRAY )   || defined( __hppa )    || defined( __hp9000 )   || \
+      defined( ibm370 )  || defined( mc68000 )   || defined( m68k )       || \
+      defined( __MRC__ ) || defined( __MVS__ )   || defined( __MWERKS__ ) || \
+      defined( sparc )   || defined( __sparc)    || defined( SYMANTEC_C ) || \
+      defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM )   || \
+      defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX )
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+
+#elif 0     /* **** EDIT HERE IF NECESSARY **** */
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#elif 0     /* **** EDIT HERE IF NECESSARY **** */
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#else
+#  error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order
+#endif
+
+#endif
+
+#endif

+ 191 - 0
ios/Classes/SSZipArchive/minizip/aes/brg_types.h

@@ -0,0 +1,191 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+
+ The unsigned integer types defined here are of the form uint_<nn>t where
+ <nn> is the length of the type; for example, the unsigned 32-bit type is
+ 'uint32_t'.  These are NOT the same as the 'C99 integer types' that are
+ defined in the inttypes.h and stdint.h headers since attempts to use these
+ types have shown that support for them is still highly variable.  However,
+ since the latter are of the form uint<nn>_t, a regular expression search
+ and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t')
+ can be used to convert the types used here to the C99 standard types.
+*/
+
+#ifndef _BRG_TYPES_H
+#define _BRG_TYPES_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+
+#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
+#  include <stddef.h>
+#  define ptrint_t intptr_t
+#elif defined( __ECOS__ )
+#  define intptr_t unsigned int
+#  define ptrint_t intptr_t
+#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 )
+#  define ptrint_t intptr_t
+#else
+#  define ptrint_t int
+#endif
+
+#ifndef BRG_UI32
+#  define BRG_UI32
+#  if UINT_MAX == 4294967295u
+#    define li_32(h) 0x##h##u
+#  elif ULONG_MAX == 4294967295u
+#    define li_32(h) 0x##h##ul
+#  elif defined( _CRAY )
+#    error This code needs 32-bit data types, which Cray machines do not provide
+#  else
+#    error Please define uint32_t as a 32-bit unsigned integer type in brg_types.h
+#  endif
+#endif
+
+#ifndef BRG_UI64
+#  if defined( __BORLANDC__ ) && !defined( __MSDOS__ )
+#    define BRG_UI64
+#    define li_64(h) 0x##h##ui64
+#  elif defined( _MSC_VER ) && ( _MSC_VER < 1300 )    /* 1300 == VC++ 7.0 */
+#    define BRG_UI64
+#    define li_64(h) 0x##h##ui64
+#  elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful
+#    define BRG_UI64
+#    define li_64(h) 0x##h##ull
+#  elif defined( __MVS__ )
+#    define BRG_UI64
+#    define li_64(h) 0x##h##ull
+#  elif defined( UINT_MAX ) && UINT_MAX > 4294967295u
+#    if UINT_MAX == 18446744073709551615u
+#      define BRG_UI64
+#      define li_64(h) 0x##h##u
+#    endif
+#  elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u
+#    if ULONG_MAX == 18446744073709551615ul
+#      define BRG_UI64
+#      define li_64(h) 0x##h##ul
+#    endif
+#  elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u
+#    if ULLONG_MAX == 18446744073709551615ull
+#      define BRG_UI64
+#      define li_64(h) 0x##h##ull
+#    endif
+#  elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u
+#    if ULONG_LONG_MAX == 18446744073709551615ull
+#      define BRG_UI64
+#      define li_64(h) 0x##h##ull
+#    endif
+#  endif
+#endif
+
+#if !defined( BRG_UI64 )
+#  if defined( NEED_UINT_64T )
+#    error Please define uint64_t as an unsigned 64 bit type in brg_types.h
+#  endif
+#endif
+
+#ifndef RETURN_VALUES
+#  define RETURN_VALUES
+#  if defined( DLL_EXPORT )
+#    if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
+#      define VOID_RETURN    __declspec( dllexport ) void __stdcall
+#      define INT_RETURN     __declspec( dllexport ) int  __stdcall
+#    elif defined( __GNUC__ )
+#      define VOID_RETURN    __declspec( __dllexport__ ) void
+#      define INT_RETURN     __declspec( __dllexport__ ) int
+#    else
+#      error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
+#    endif
+#  elif defined( DLL_IMPORT )
+#    if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
+#      define VOID_RETURN    __declspec( dllimport ) void __stdcall
+#      define INT_RETURN     __declspec( dllimport ) int  __stdcall
+#    elif defined( __GNUC__ )
+#      define VOID_RETURN    __declspec( __dllimport__ ) void
+#      define INT_RETURN     __declspec( __dllimport__ ) int
+#    else
+#      error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
+#    endif
+#  elif defined( __WATCOMC__ )
+#    define VOID_RETURN  void __cdecl
+#    define INT_RETURN   int  __cdecl
+#  else
+#    define VOID_RETURN  void
+#    define INT_RETURN   int
+#  endif
+#endif
+
+/*	These defines are used to detect and set the memory alignment of pointers.
+    Note that offsets are in bytes.
+
+    ALIGN_OFFSET(x,n)			return the positive or zero offset of 
+                                the memory addressed by the pointer 'x' 
+                                from an address that is aligned on an 
+                                'n' byte boundary ('n' is a power of 2)
+
+    ALIGN_FLOOR(x,n)			return a pointer that points to memory
+                                that is aligned on an 'n' byte boundary 
+                                and is not higher than the memory address
+                                pointed to by 'x' ('n' is a power of 2)
+
+    ALIGN_CEIL(x,n)				return a pointer that points to memory
+                                that is aligned on an 'n' byte boundary 
+                                and is not lower than the memory address
+                                pointed to by 'x' ('n' is a power of 2)
+*/
+
+#define ALIGN_OFFSET(x,n)	(((ptrint_t)(x)) & ((n) - 1))
+#define ALIGN_FLOOR(x,n)	((uint8_t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1)))
+#define ALIGN_CEIL(x,n)		((uint8_t*)(x) + (-((ptrint_t)(x)) & ((n) - 1)))
+
+/*  These defines are used to declare buffers in a way that allows
+    faster operations on longer variables to be used.  In all these
+    defines 'size' must be a power of 2 and >= 8. NOTE that the 
+    buffer size is in bytes but the type length is in bits
+
+    UNIT_TYPEDEF(x,size)        declares a variable 'x' of length 
+                                'size' bits
+
+    BUFR_TYPEDEF(x,size,bsize)  declares a buffer 'x' of length 'bsize' 
+                                bytes defined as an array of variables
+                                each of 'size' bits (bsize must be a 
+                                multiple of size / 8)
+
+    UNIT_CAST(x,size)           casts a variable to a type of 
+                                length 'size' bits
+
+    UPTR_CAST(x,size)           casts a pointer to a pointer to a 
+                                varaiable of length 'size' bits
+*/
+
+#define UI_TYPE(size)               uint##size##_t
+#define UNIT_TYPEDEF(x,size)        typedef UI_TYPE(size) x
+#define BUFR_TYPEDEF(x,size,bsize)  typedef UI_TYPE(size) x[bsize / (size >> 3)]
+#define UNIT_CAST(x,size)           ((UI_TYPE(size) )(x))  
+#define UPTR_CAST(x,size)           ((UI_TYPE(size)*)(x))
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

+ 145 - 0
ios/Classes/SSZipArchive/minizip/aes/fileenc.c

@@ -0,0 +1,145 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 2002, Dr Brian Gladman <                 >, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products
+      built using this software without specific written permission.
+
+ ALTERNATIVELY, provided that this notice is retained in full, this product
+ may be distributed under the terms of the GNU General Public License (GPL),
+ in which case the provisions of the GPL apply INSTEAD OF those given above.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ -------------------------------------------------------------------------
+ Issue Date: 24/01/2003
+
+ This file implements password based file encryption and authentication 
+ using AES in CTR mode, HMAC-SHA1 authentication and RFC2898 password 
+ based key derivation.
+
+*/
+
+#include <string.h>
+
+#include "fileenc.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* subroutine for data encryption/decryption    */
+/* this could be speeded up a lot by aligning   */
+/* buffers and using 32 bit operations          */
+
+static void encr_data(unsigned char data[], unsigned long d_len, fcrypt_ctx cx[1])
+{
+    unsigned int i = 0, pos = cx->encr_pos;
+
+    while (i < d_len)
+    {
+        if (pos == AES_BLOCK_SIZE)
+        {
+            unsigned int j = 0;
+            /* increment encryption nonce   */
+            while (j < 8 && !++cx->nonce[j])
+                ++j;
+            /* encrypt the nonce to form next xor buffer    */
+            aes_encrypt(cx->nonce, cx->encr_bfr, cx->encr_ctx);
+            pos = 0;
+        }
+
+        data[i++] ^= cx->encr_bfr[pos++];
+    }
+
+    cx->encr_pos = pos;
+}
+
+int fcrypt_init(
+    int mode,                               /* the mode to be used (input)          */
+    const unsigned char pwd[],              /* the user specified password (input)  */
+    unsigned int pwd_len,                   /* the length of the password (input)   */
+    const unsigned char salt[],             /* the salt (input)                     */
+#ifdef PASSWORD_VERIFIER
+    unsigned char pwd_ver[PWD_VER_LENGTH],  /* 2 byte password verifier (output)    */
+#endif
+    fcrypt_ctx      cx[1])                  /* the file encryption context (output) */
+{   unsigned char kbuf[2 * MAX_KEY_LENGTH + PWD_VER_LENGTH];
+
+    if (pwd_len > MAX_PWD_LENGTH)
+        return PASSWORD_TOO_LONG;
+
+    if (mode < 1 || mode > 3)
+        return BAD_MODE;
+
+    cx->mode = mode;
+    cx->pwd_len = pwd_len;
+
+    /* derive the encryption and authentication keys and the password verifier   */
+    derive_key(pwd, pwd_len, salt, SALT_LENGTH(mode), KEYING_ITERATIONS,
+                        kbuf, 2 * KEY_LENGTH(mode) + PWD_VER_LENGTH);
+
+    /* initialise the encryption nonce and buffer pos   */
+    cx->encr_pos = AES_BLOCK_SIZE;
+    /* if we need a random component in the encryption  */
+    /* nonce, this is where it would have to be set     */
+    memset(cx->nonce, 0, AES_BLOCK_SIZE * sizeof(unsigned char));
+
+    /* initialise for encryption using key 1            */
+    aes_encrypt_key(kbuf, KEY_LENGTH(mode), cx->encr_ctx);
+
+    /* initialise for authentication using key 2        */
+    hmac_sha_begin(HMAC_SHA1, cx->auth_ctx);
+    hmac_sha_key(kbuf + KEY_LENGTH(mode), KEY_LENGTH(mode), cx->auth_ctx);
+
+#ifdef PASSWORD_VERIFIER
+    memcpy(pwd_ver, kbuf + 2 * KEY_LENGTH(mode), PWD_VER_LENGTH);
+#endif
+
+    return GOOD_RETURN;
+}
+
+/* perform 'in place' encryption and authentication */
+
+void fcrypt_encrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1])
+{
+    encr_data(data, data_len, cx);
+    hmac_sha_data(data, data_len, cx->auth_ctx);
+}
+
+/* perform 'in place' authentication and decryption */
+
+void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1])
+{
+    hmac_sha_data(data, data_len, cx->auth_ctx);
+    encr_data(data, data_len, cx);
+}
+
+/* close encryption/decryption and return the MAC value */
+
+int fcrypt_end(unsigned char mac[], fcrypt_ctx cx[1])
+{
+    hmac_sha_end(mac, MAC_LENGTH(cx->mode), cx->auth_ctx);
+    return MAC_LENGTH(cx->mode);    /* return MAC length in bytes   */
+}
+
+#if defined(__cplusplus)
+}
+#endif

+ 121 - 0
ios/Classes/SSZipArchive/minizip/aes/fileenc.h

@@ -0,0 +1,121 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 2002, Dr Brian Gladman <                 >, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products
+      built using this software without specific written permission.
+
+ ALTERNATIVELY, provided that this notice is retained in full, this product
+ may be distributed under the terms of the GNU General Public License (GPL),
+ in which case the provisions of the GPL apply INSTEAD OF those given above.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 24/01/2003
+
+ This file contains the header file for fileenc.c, which implements password
+ based file encryption and authentication using AES in CTR mode, HMAC-SHA1 
+ authentication and RFC2898 password based key derivation.
+*/
+
+#ifndef _FENC_H
+#define _FENC_H
+
+#include "aes.h"
+#include "hmac.h"
+#include "pwd2key.h"
+
+#define PASSWORD_VERIFIER
+
+#define MAX_KEY_LENGTH        32
+#define MAX_PWD_LENGTH       128
+#define MAX_SALT_LENGTH       16
+#define KEYING_ITERATIONS   1000
+
+#ifdef  PASSWORD_VERIFIER
+#define PWD_VER_LENGTH         2
+#else
+#define PWD_VER_LENGTH         0
+#endif
+
+#define GOOD_RETURN            0
+#define PASSWORD_TOO_LONG   -100
+#define BAD_MODE            -101
+
+/*
+    Field lengths (in bytes) versus File Encryption Mode (0 < mode < 4)
+
+    Mode Key Salt  MAC Overhead
+       1  16    8   10       18
+       2  24   12   10       22
+       3  32   16   10       26
+
+   The following macros assume that the mode value is correct.
+*/
+
+#define KEY_LENGTH(mode)        (8 * (mode & 3) + 8)
+#define SALT_LENGTH(mode)       (4 * (mode & 3) + 4)
+#define MAC_LENGTH(mode)        (10)
+
+/* the context for file encryption   */
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+typedef struct
+{   unsigned char   nonce[AES_BLOCK_SIZE];      /* the CTR nonce          */
+    unsigned char   encr_bfr[AES_BLOCK_SIZE];   /* encrypt buffer         */
+    aes_encrypt_ctx encr_ctx[1];                /* encryption context     */
+    hmac_ctx        auth_ctx[1];                /* authentication context */
+    unsigned int    encr_pos;                   /* block position (enc)   */
+    unsigned int    pwd_len;                    /* password length        */
+    unsigned int    mode;                       /* File encryption mode   */
+} fcrypt_ctx;
+
+/* initialise file encryption or decryption */
+
+int fcrypt_init(
+    int mode,                               /* the mode to be used (input)          */
+    const unsigned char pwd[],              /* the user specified password (input)  */
+    unsigned int pwd_len,                   /* the length of the password (input)   */
+    const unsigned char salt[],             /* the salt (input)                     */
+#ifdef PASSWORD_VERIFIER
+    unsigned char pwd_ver[PWD_VER_LENGTH],  /* 2 byte password verifier (output)    */
+#endif
+    fcrypt_ctx      cx[1]);                 /* the file encryption context (output) */
+
+/* perform 'in place' encryption or decryption and authentication               */
+
+void fcrypt_encrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]);
+void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]);
+
+/* close encryption/decryption and return the MAC value */
+/* the return value is the length of the MAC            */
+
+int fcrypt_end(unsigned char mac[],     /* the MAC value (output)   */
+               fcrypt_ctx cx[1]);       /* the context (input)      */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

+ 209 - 0
ios/Classes/SSZipArchive/minizip/aes/hmac.c

@@ -0,0 +1,209 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+
+This is an implementation of HMAC, the FIPS standard keyed hash function
+*/
+
+#include "hmac.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* initialise the HMAC context to zero */
+int hmac_sha_begin(enum hmac_hash hash, hmac_ctx cx[1])
+{
+    memset(cx, 0, sizeof(hmac_ctx));
+    switch(hash)
+    {
+#ifdef SHA_1
+    case HMAC_SHA1:
+        cx->f_begin = (hf_begin *)sha1_begin;
+        cx->f_hash  = (hf_hash *)sha1_hash;
+        cx->f_end   = (hf_end *)sha1_end;
+        cx->input_len = SHA1_BLOCK_SIZE;
+        cx->output_len = SHA1_DIGEST_SIZE;
+        break;
+#endif
+#ifdef SHA_224
+    case HMAC_SHA224:
+        cx->f_begin = (hf_begin *)sha224_begin;
+        cx->f_hash  = (hf_hash *)sha224_hash;
+        cx->f_end   = (hf_end *)sha224_end;
+        cx->input_len = SHA224_BLOCK_SIZE;
+        cx->output_len = SHA224_DIGEST_SIZE;
+        break;
+#endif
+#ifdef SHA_256
+    case HMAC_SHA256:
+        cx->f_begin = (hf_begin *)sha256_begin;
+        cx->f_hash  = (hf_hash *)sha256_hash;
+        cx->f_end   = (hf_end *)sha256_end;
+        cx->input_len = SHA256_BLOCK_SIZE;
+        cx->output_len = SHA256_DIGEST_SIZE;
+        break;
+#endif
+#ifdef SHA_384
+    case HMAC_SHA384:
+        cx->f_begin = (hf_begin *)sha384_begin;
+        cx->f_hash  = (hf_hash *)sha384_hash;
+        cx->f_end   = (hf_end *)sha384_end;
+        cx->input_len = SHA384_BLOCK_SIZE;
+        cx->output_len = SHA384_DIGEST_SIZE;
+        break;
+#endif
+#ifdef SHA_512
+    case HMAC_SHA512:
+        cx->f_begin = (hf_begin *)sha512_begin;
+        cx->f_hash  = (hf_hash *)sha512_hash;
+        cx->f_end   = (hf_end *)sha512_end;
+        cx->input_len = SHA512_BLOCK_SIZE;
+        cx->output_len = SHA512_DIGEST_SIZE;
+        break;
+    case HMAC_SHA512_256:
+        cx->f_begin = (hf_begin *)sha512_256_begin;
+        cx->f_hash  = (hf_hash *)sha512_256_hash;
+        cx->f_end   = (hf_end *)sha512_256_end;
+        cx->input_len = SHA512_256_BLOCK_SIZE;
+        cx->output_len = SHA512_256_DIGEST_SIZE;
+        break;
+    case HMAC_SHA512_224:
+        cx->f_begin = (hf_begin *)sha512_224_begin;
+        cx->f_hash  = (hf_hash *)sha512_224_hash;
+        cx->f_end   = (hf_end *)sha512_224_end;
+        cx->input_len = SHA512_224_BLOCK_SIZE;
+        cx->output_len = SHA512_224_DIGEST_SIZE;
+        break;
+    case HMAC_SHA512_192:
+        cx->f_begin = (hf_begin *)sha512_192_begin;
+        cx->f_hash  = (hf_hash *)sha512_192_hash;
+        cx->f_end   = (hf_end *)sha512_192_end;
+        cx->input_len = SHA512_192_BLOCK_SIZE;
+        cx->output_len = SHA512_192_DIGEST_SIZE;
+        break;
+    case HMAC_SHA512_128:
+        cx->f_begin = (hf_begin *)sha512_128_begin;
+        cx->f_hash  = (hf_hash *)sha512_128_hash;
+        cx->f_end   = (hf_begin *)sha512_128_end;
+        cx->input_len = SHA512_128_BLOCK_SIZE;
+        cx->output_len = SHA512_128_DIGEST_SIZE;
+        break;
+#endif
+    }
+    return (int)cx->output_len;
+}
+
+/* input the HMAC key (can be called multiple times)    */
+int hmac_sha_key(const unsigned char key[], unsigned long key_len, hmac_ctx cx[1])
+{
+    if(cx->klen == HMAC_IN_DATA)                /* error if further key input   */
+        return EXIT_FAILURE;                    /* is attempted in data mode    */
+
+    if(cx->klen + key_len > cx->input_len)      /* if the key has to be hashed  */
+    {
+        if(cx->klen <= cx->input_len)           /* if the hash has not yet been */
+        {                                       /* started, initialise it and   */
+            cx->f_begin(cx->sha_ctx);           /* hash stored key characters   */
+            cx->f_hash(cx->key, cx->klen, cx->sha_ctx);
+        }
+
+        cx->f_hash(key, key_len, cx->sha_ctx);  /* hash long key data into hash */
+    }
+    else                                        /* otherwise store key data     */
+        memcpy(cx->key + cx->klen, key, key_len);
+
+    cx->klen += key_len;                        /* update the key length count  */
+    return EXIT_SUCCESS;
+}
+
+/* input the HMAC data (can be called multiple times) - */
+/* note that this call terminates the key input phase   */
+void hmac_sha_data(const unsigned char data[], unsigned long data_len, hmac_ctx cx[1])
+{   unsigned int i;
+
+    if(cx->klen != HMAC_IN_DATA)                /* if not yet in data phase */
+    {
+        if(cx->klen > cx->input_len)            /* if key is being hashed   */
+        {                                       /* complete the hash and    */
+            cx->f_end(cx->key, cx->sha_ctx);    /* store the result as the  */
+            cx->klen = cx->output_len;          /* key and set new length   */
+        }
+
+        /* pad the key if necessary */
+        memset(cx->key + cx->klen, 0, cx->input_len - cx->klen);
+
+        /* xor ipad into key value  */
+        for(i = 0; i < (cx->input_len >> 2); ++i)
+            ((uint32_t*)cx->key)[i] ^= 0x36363636;
+
+        /* and start hash operation */
+        cx->f_begin(cx->sha_ctx);
+        cx->f_hash(cx->key, cx->input_len, cx->sha_ctx);
+
+        /* mark as now in data mode */
+        cx->klen = HMAC_IN_DATA;
+    }
+
+    /* hash the data (if any)       */
+    if(data_len)
+        cx->f_hash(data, data_len, cx->sha_ctx);
+}
+
+/* compute and output the MAC value */
+void hmac_sha_end(unsigned char mac[], unsigned long mac_len, hmac_ctx cx[1])
+{   unsigned char dig[HMAC_MAX_OUTPUT_SIZE];
+    unsigned int i;
+
+    /* if no data has been entered perform a null data phase        */
+    if(cx->klen != HMAC_IN_DATA)
+        hmac_sha_data((const unsigned char*)0, 0, cx);
+
+    cx->f_end(dig, cx->sha_ctx);        /* complete the inner hash       */
+
+    /* set outer key value using opad and removing ipad */
+    for(i = 0; i < (cx->input_len >> 2); ++i)
+        ((uint32_t*)cx->key)[i] ^= 0x36363636 ^ 0x5c5c5c5c;
+
+    /* perform the outer hash operation */
+    cx->f_begin(cx->sha_ctx);
+    cx->f_hash(cx->key, cx->input_len, cx->sha_ctx);
+    cx->f_hash(dig, cx->output_len, cx->sha_ctx);
+    cx->f_end(dig, cx->sha_ctx);
+
+    /* output the hash value            */
+    for(i = 0; i < mac_len; ++i)
+        mac[i] = dig[i];
+}
+
+/* 'do it all in one go' subroutine     */
+void hmac_sha(enum hmac_hash hash, const unsigned char key[], unsigned long key_len,
+          const unsigned char data[], unsigned long data_len,
+          unsigned char mac[], unsigned long mac_len)
+{   hmac_ctx    cx[1];
+
+    hmac_sha_begin(hash, cx);
+    hmac_sha_key(key, key_len, cx);
+    hmac_sha_data(data, data_len, cx);
+    hmac_sha_end(mac, mac_len, cx);
+}
+
+#if defined(__cplusplus)
+}
+#endif

+ 119 - 0
ios/Classes/SSZipArchive/minizip/aes/hmac.h

@@ -0,0 +1,119 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+
+This is an implementation of HMAC, the FIPS standard keyed hash function
+*/
+
+#ifndef _HMAC2_H
+#define _HMAC2_H
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#include "sha1.h"
+
+#if defined(SHA_224) || defined(SHA_256) || defined(SHA_384) || defined(SHA_512)
+#define HMAC_MAX_OUTPUT_SIZE SHA2_MAX_DIGEST_SIZE
+#define HMAC_MAX_BLOCK_SIZE SHA2_MAX_BLOCK_SIZE
+#else 
+#define HMAC_MAX_OUTPUT_SIZE SHA1_DIGEST_SIZE
+#define HMAC_MAX_BLOCK_SIZE SHA1_BLOCK_SIZE
+#endif
+
+#define HMAC_IN_DATA  0xffffffff
+
+enum hmac_hash  
+{ 
+#ifdef SHA_1
+    HMAC_SHA1, 
+#endif
+#ifdef SHA_224 
+    HMAC_SHA224, 
+#endif
+#ifdef SHA_256
+    HMAC_SHA256, 
+#endif
+#ifdef SHA_384
+    HMAC_SHA384, 
+#endif
+#ifdef SHA_512
+    HMAC_SHA512, 
+    HMAC_SHA512_256,
+    HMAC_SHA512_224,
+    HMAC_SHA512_192,
+    HMAC_SHA512_128
+#endif
+};
+
+typedef VOID_RETURN hf_begin(void*);
+typedef VOID_RETURN hf_hash(const void*, unsigned long len, void*);
+typedef VOID_RETURN hf_end(void*, void*);
+
+typedef struct
+{   hf_begin        *f_begin;
+    hf_hash         *f_hash;
+    hf_end          *f_end;
+    unsigned char   key[HMAC_MAX_BLOCK_SIZE];
+    union
+    {
+#ifdef SHA_1
+       sha1_ctx    u_sha1;
+#endif
+#ifdef SHA_224
+        sha224_ctx  u_sha224;
+#endif
+#ifdef SHA_256
+        sha256_ctx  u_sha256;
+#endif
+#ifdef SHA_384
+        sha384_ctx  u_sha384;
+#endif
+#ifdef SHA_512
+        sha512_ctx  u_sha512;
+#endif
+    } sha_ctx[1];
+    unsigned long   input_len;
+    unsigned long   output_len;
+    unsigned long   klen;
+} hmac_ctx;
+
+/* returns the length of hash digest for the hash used  */
+/* mac_len must not be greater than this                */
+int hmac_sha_begin(enum hmac_hash hash, hmac_ctx cx[1]);
+
+int  hmac_sha_key(const unsigned char key[], unsigned long key_len, hmac_ctx cx[1]);
+
+void hmac_sha_data(const unsigned char data[], unsigned long data_len, hmac_ctx cx[1]);
+
+void hmac_sha_end(unsigned char mac[], unsigned long mac_len, hmac_ctx cx[1]);
+
+void hmac_sha(enum hmac_hash hash, const unsigned char key[], unsigned long key_len,
+          const unsigned char data[], unsigned long data_len,
+          unsigned char mac[], unsigned long mac_len);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

+ 155 - 0
ios/Classes/SSZipArchive/minizip/aes/prng.c

@@ -0,0 +1,155 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 2002, Dr Brian Gladman <                 >, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products
+      built using this software without specific written permission.
+
+ ALTERNATIVELY, provided that this notice is retained in full, this product
+ may be distributed under the terms of the GNU General Public License (GPL),
+ in which case the provisions of the GPL apply INSTEAD OF those given above.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 24/01/2003
+
+ This file implements a random data pool based on the use of an external
+ entropy function.  It is based on the ideas advocated by Peter Gutmann in
+ his work on pseudo random sequence generators.  It is not a 'paranoid'
+ random sequence generator and no attempt is made to protect the pool
+ from prying eyes either by memory locking or by techniques to obscure
+ its location in memory.
+*/
+
+#include <string.h>
+#include "prng.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* mix a random data pool using the SHA1 compression function (as   */
+/* suggested by Peter Gutmann in his paper on random pools)         */
+
+static void prng_mix(unsigned char buf[])
+{   unsigned int    i, len;
+    sha1_ctx        ctx[1];
+
+    /*lint -e{663}  unusual array to pointer conversion */
+    for(i = 0; i < PRNG_POOL_SIZE; i += SHA1_DIGEST_SIZE)
+    {
+        /* copy digest size pool block into SHA1 hash block */
+        memcpy(ctx->hash, buf + (i ? i : PRNG_POOL_SIZE)
+                            - SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE);
+
+        /* copy data from pool into the SHA1 data buffer    */
+        len = PRNG_POOL_SIZE - i;
+        memcpy(ctx->wbuf, buf + i, (len > SHA1_BLOCK_SIZE ? SHA1_BLOCK_SIZE : len));
+
+        if(len < SHA1_BLOCK_SIZE)
+            memcpy(((char*)ctx->wbuf) + len, buf, SHA1_BLOCK_SIZE - len);
+
+        /* compress using the SHA1 compression function     */
+        sha1_compile(ctx);
+
+        /* put digest size block back into the random pool  */
+        memcpy(buf + i, ctx->hash, SHA1_DIGEST_SIZE);
+    }
+}
+
+/* refresh the output buffer and update the random pool by adding   */
+/* entropy and remixing                                             */
+
+static void update_pool(prng_ctx ctx[1])
+{   unsigned int    i = 0;
+
+    /* transfer random pool data to the output buffer   */
+    memcpy(ctx->obuf, ctx->rbuf, PRNG_POOL_SIZE);
+
+    /* enter entropy data into the pool */
+    while(i < PRNG_POOL_SIZE)
+        i += ctx->entropy(ctx->rbuf + i, PRNG_POOL_SIZE - i);
+
+    /* invert and xor the original pool data into the pool  */
+    for(i = 0; i < PRNG_POOL_SIZE; ++i)
+        ctx->rbuf[i] ^= ~ctx->obuf[i];
+
+    /* mix the pool and the output buffer   */
+    prng_mix(ctx->rbuf);
+    prng_mix(ctx->obuf);
+}
+
+void prng_init(prng_entropy_fn fun, prng_ctx ctx[1])
+{   int i;
+
+    /* clear the buffers and the counter in the context     */
+    memset(ctx, 0, sizeof(prng_ctx));
+
+    /* set the pointer to the entropy collection function   */
+    ctx->entropy = fun;
+
+    /* initialise the random data pool                      */
+    update_pool(ctx);
+
+    /* mix the pool a minimum number of times               */
+    for(i = 0; i < PRNG_MIN_MIX; ++i)
+        prng_mix(ctx->rbuf);
+
+    /* update the pool to prime the pool output buffer      */
+    update_pool(ctx);
+}
+
+/* provide random bytes from the random data pool   */
+
+void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1])
+{   unsigned char   *rp = data;
+    unsigned int    len, pos = ctx->pos;
+
+    while(data_len)
+    {
+        /* transfer 'data_len' bytes (or the number of bytes remaining  */
+        /* the pool output buffer if less) into the output              */
+        len = (data_len < PRNG_POOL_SIZE - pos ? data_len : PRNG_POOL_SIZE - pos);
+        memcpy(rp, ctx->obuf + pos, len);
+        rp += len;          /* update ouput buffer position pointer     */
+        pos += len;         /* update pool output buffer pointer        */
+        data_len -= len;    /* update the remaining data count          */
+
+        /* refresh the random pool if necessary */
+        if(pos == PRNG_POOL_SIZE)
+        {
+            update_pool(ctx); pos = 0;
+        }
+    }
+
+    ctx->pos = pos;
+}
+
+void prng_end(prng_ctx ctx[1])
+{
+    /* ensure the data in the context is destroyed  */
+    memset(ctx, 0, sizeof(prng_ctx));
+}
+
+#if defined(__cplusplus)
+}
+#endif
+

+ 82 - 0
ios/Classes/SSZipArchive/minizip/aes/prng.h

@@ -0,0 +1,82 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 2002, Dr Brian Gladman <                 >, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products
+      built using this software without specific written permission.
+
+ ALTERNATIVELY, provided that this notice is retained in full, this product
+ may be distributed under the terms of the GNU General Public License (GPL),
+ in which case the provisions of the GPL apply INSTEAD OF those given above.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 24/01/2003
+
+ This is the header file for an implementation of a random data pool based on
+ the use of an external entropy function (inspired by Peter Gutmann's work).
+*/
+
+#ifndef _PRNG_H
+#define _PRNG_H
+
+#include "sha1.h"
+
+#define PRNG_POOL_LEN    256    /* minimum random pool size             */
+#define PRNG_MIN_MIX      20    /* min initial pool mixing iterations   */
+
+/* ensure that pool length is a multiple of the SHA1 digest size        */
+
+#define PRNG_POOL_SIZE  (SHA1_DIGEST_SIZE * (1 + (PRNG_POOL_LEN - 1) / SHA1_DIGEST_SIZE))
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* A function for providing entropy is a parameter in the prng_init()   */
+/* call.  This function has the following form and returns a maximum    */
+/* of 'len' bytes of pseudo random data in the buffer 'buf'.  It can    */
+/* return less than 'len' bytes but will be repeatedly called for more  */
+/* data in this case.                                                   */
+
+typedef int (*prng_entropy_fn)(unsigned char buf[], unsigned int len);
+
+typedef struct
+{   unsigned char   rbuf[PRNG_POOL_SIZE];   /* the random pool          */
+    unsigned char   obuf[PRNG_POOL_SIZE];   /* pool output buffer       */
+    unsigned int    pos;                    /* output buffer position   */
+    prng_entropy_fn entropy;                /* entropy function pointer */
+} prng_ctx;
+
+/* initialise the random stream generator   */
+void prng_init(prng_entropy_fn fun, prng_ctx ctx[1]);
+
+/* obtain random bytes from the generator   */
+void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1]);
+
+/* close the random stream generator        */
+void prng_end(prng_ctx ctx[1]);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

+ 181 - 0
ios/Classes/SSZipArchive/minizip/aes/pwd2key.c

@@ -0,0 +1,181 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+
+This is an implementation of RFC2898, which specifies key derivation from
+a password and a salt value.
+*/
+
+#include <string.h>
+#include "hmac.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+void derive_key(const unsigned char pwd[],  /* the PASSWORD     */
+               unsigned int pwd_len,        /* and its length   */
+               const unsigned char salt[],  /* the SALT and its */
+               unsigned int salt_len,       /* length           */
+               unsigned int iter,   /* the number of iterations */
+               unsigned char key[], /* space for the output key */
+               unsigned int key_len)/* and its required length  */
+{
+    unsigned int    i, j, k, n_blk, h_size;
+    unsigned char uu[HMAC_MAX_OUTPUT_SIZE], ux[HMAC_MAX_OUTPUT_SIZE];
+    hmac_ctx c1[1], c2[1], c3[1];
+
+    /* set HMAC context (c1) for password               */
+    h_size = hmac_sha_begin(HMAC_SHA1, c1);
+    hmac_sha_key(pwd, pwd_len, c1);
+
+    /* set HMAC context (c2) for password and salt      */
+    memcpy(c2, c1, sizeof(hmac_ctx));
+    hmac_sha_data(salt, salt_len, c2);
+
+    /* find the number of SHA blocks in the key         */
+    n_blk = 1 + (key_len - 1) / h_size;
+
+    for(i = 0; i < n_blk; ++i) /* for each block in key */
+    {
+        /* ux[] holds the running xor value             */
+        memset(ux, 0, h_size);
+
+        /* set HMAC context (c3) for password and salt  */
+        memcpy(c3, c2, sizeof(hmac_ctx));
+
+        /* enter additional data for 1st block into uu  */
+        uu[0] = (unsigned char)((i + 1) >> 24);
+        uu[1] = (unsigned char)((i + 1) >> 16);
+        uu[2] = (unsigned char)((i + 1) >> 8);
+        uu[3] = (unsigned char)(i + 1);
+
+        /* this is the key mixing iteration         */
+        for(j = 0, k = 4; j < iter; ++j)
+        {
+            /* add previous round data to HMAC      */
+            hmac_sha_data(uu, k, c3);
+
+            /* obtain HMAC for uu[]                 */
+            hmac_sha_end(uu, h_size, c3);
+
+            /* xor into the running xor block       */
+            for(k = 0; k < h_size; ++k)
+                ux[k] ^= uu[k];
+
+            /* set HMAC context (c3) for password   */
+            memcpy(c3, c1, sizeof(hmac_ctx));
+        }
+
+        /* compile key blocks into the key output   */
+        j = 0; k = i * h_size;
+        while(j < h_size && k < key_len)
+            key[k++] = ux[j++];
+    }
+}
+
+#ifdef TEST
+
+#include <stdio.h>
+
+struct
+{   unsigned int    pwd_len;
+    unsigned int    salt_len;
+    unsigned int    it_count;
+    unsigned char   *pwd;
+    unsigned char   salt[32];
+    unsigned char   key[32];
+} tests[] =
+{
+    {   8, 4, 5, (unsigned char*)"password",
+        {   
+            0x12, 0x34, 0x56, 0x78 
+        },
+        {   
+            0x5c, 0x75, 0xce, 0xf0, 0x1a, 0x96, 0x0d, 0xf7,
+            0x4c, 0xb6, 0xb4, 0x9b, 0x9e, 0x38, 0xe6, 0xb5 
+        }
+    },
+    {   8, 8, 5, (unsigned char*)"password",
+        {   
+            0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12 
+        },
+        {   
+            0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6,
+            0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49 
+        }
+    },
+    {   8, 21, 1, (unsigned char*)"password",
+        {
+            "ATHENA.MIT.EDUraeburn"
+        },
+        {
+            0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01,
+            0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15
+        }
+    },
+    {   8, 21, 2, (unsigned char*)"password",
+        {
+            "ATHENA.MIT.EDUraeburn"
+        },
+        {
+            0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e, 
+            0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d
+        }
+    },
+    {   8, 21, 1200, (unsigned char*)"password",
+        {
+            "ATHENA.MIT.EDUraeburn"
+        },
+        {
+            0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e, 
+            0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b
+        }
+    }
+};
+
+int main()
+{   unsigned int    i, j, key_len = 256;
+    unsigned char   key[256];
+
+    printf("\nTest of RFC2898 Password Based Key Derivation");
+    for(i = 0; i < 5; ++i)
+    {
+        derive_key(tests[i].pwd, tests[i].pwd_len, tests[i].salt,
+                    tests[i].salt_len, tests[i].it_count, key, key_len);
+
+        printf("\ntest %i: ", i + 1);
+        printf("key %s", memcmp(tests[i].key, key, 16) ? "is bad" : "is good");
+        for(j = 0; j < key_len && j < 64; j += 4)
+        {
+            if(j % 16 == 0)
+                printf("\n");
+            printf("0x%02x%02x%02x%02x ", key[j], key[j + 1], key[j + 2], key[j + 3]);
+        }
+        printf(j < key_len ? " ... \n" : "\n");
+    }
+    printf("\n");
+    return 0;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

+ 45 - 0
ios/Classes/SSZipArchive/minizip/aes/pwd2key.h

@@ -0,0 +1,45 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+
+This is an implementation of RFC2898, which specifies key derivation from
+a password and a salt value.
+*/
+
+#ifndef PWD2KEY_H
+#define PWD2KEY_H
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+void derive_key(
+        const unsigned char pwd[],   /* the PASSWORD, and   */
+        unsigned int pwd_len,        /*    its length       */ 
+        const unsigned char salt[],  /* the SALT and its    */
+        unsigned int salt_len,       /*    length           */
+        unsigned int iter,      /* the number of iterations */
+        unsigned char key[],    /* space for the output key */
+        unsigned int key_len);  /* and its required length  */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

+ 283 - 0
ios/Classes/SSZipArchive/minizip/aes/sha1.c

@@ -0,0 +1,283 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+*/
+
+#include <string.h>     /* for memcpy() etc.        */
+
+#include "sha1.h"
+#include "brg_endian.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#if defined( _MSC_VER ) && ( _MSC_VER > 800 )
+#pragma intrinsic(memcpy)
+#pragma intrinsic(memset)
+#endif
+
+#if 0 && defined(_MSC_VER)
+#define rotl32  _lrotl
+#define rotr32  _lrotr
+#else
+#define rotl32(x,n)   (((x) << n) | ((x) >> (32 - n)))
+#define rotr32(x,n)   (((x) >> n) | ((x) << (32 - n)))
+#endif
+
+#if !defined(bswap_32)
+#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00))
+#endif
+
+#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
+#define SWAP_BYTES
+#else
+#undef  SWAP_BYTES
+#endif
+
+#if defined(SWAP_BYTES)
+#define bsw_32(p,n) \
+    { int _i = (n); while(_i--) ((uint32_t*)p)[_i] = bswap_32(((uint32_t*)p)[_i]); }
+#else
+#define bsw_32(p,n)
+#endif
+
+#define SHA1_MASK   (SHA1_BLOCK_SIZE - 1)
+
+#if 0
+
+#define ch(x,y,z)       (((x) & (y)) ^ (~(x) & (z)))
+#define parity(x,y,z)   ((x) ^ (y) ^ (z))
+#define maj(x,y,z)      (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+#else   /* Discovered by Rich Schroeppel and Colin Plumb   */
+
+#define ch(x,y,z)       ((z) ^ ((x) & ((y) ^ (z))))
+#define parity(x,y,z)   ((x) ^ (y) ^ (z))
+#define maj(x,y,z)      (((x) & (y)) | ((z) & ((x) ^ (y))))
+
+#endif
+
+/* Compile 64 bytes of hash data into SHA1 context. Note    */
+/* that this routine assumes that the byte order in the     */
+/* ctx->wbuf[] at this point is in such an order that low   */
+/* address bytes in the ORIGINAL byte stream will go in     */
+/* this buffer to the high end of 32-bit words on BOTH big  */
+/* and little endian systems                                */
+
+#ifdef ARRAY
+#define q(v,n)  v[n]
+#else
+#define q(v,n)  v##n
+#endif
+
+#ifdef SHA_1
+
+#define one_cycle(v,a,b,c,d,e,f,k,h)            \
+    q(v,e) += rotr32(q(v,a),27) +               \
+              f(q(v,b),q(v,c),q(v,d)) + k + h;  \
+    q(v,b)  = rotr32(q(v,b), 2)
+
+#define five_cycle(v,f,k,i)                 \
+    one_cycle(v, 0,1,2,3,4, f,k,hf(i  ));   \
+    one_cycle(v, 4,0,1,2,3, f,k,hf(i+1));   \
+    one_cycle(v, 3,4,0,1,2, f,k,hf(i+2));   \
+    one_cycle(v, 2,3,4,0,1, f,k,hf(i+3));   \
+    one_cycle(v, 1,2,3,4,0, f,k,hf(i+4))
+
+VOID_RETURN sha1_compile(sha1_ctx ctx[1])
+{   uint32_t    *w = ctx->wbuf;
+
+#ifdef ARRAY
+    uint32_t    v[5];
+    memcpy(v, ctx->hash, sizeof(ctx->hash));
+#else
+    uint32_t    v0, v1, v2, v3, v4;
+    v0 = ctx->hash[0]; v1 = ctx->hash[1];
+    v2 = ctx->hash[2]; v3 = ctx->hash[3];
+    v4 = ctx->hash[4];
+#endif
+
+#define hf(i)   w[i]
+
+    five_cycle(v, ch, 0x5a827999,  0);
+    five_cycle(v, ch, 0x5a827999,  5);
+    five_cycle(v, ch, 0x5a827999, 10);
+    one_cycle(v,0,1,2,3,4, ch, 0x5a827999, hf(15)); \
+
+#undef  hf
+#define hf(i) (w[(i) & 15] = rotl32(                    \
+                 w[((i) + 13) & 15] ^ w[((i) + 8) & 15] \
+               ^ w[((i) +  2) & 15] ^ w[(i) & 15], 1))
+
+    one_cycle(v,4,0,1,2,3, ch, 0x5a827999, hf(16));
+    one_cycle(v,3,4,0,1,2, ch, 0x5a827999, hf(17));
+    one_cycle(v,2,3,4,0,1, ch, 0x5a827999, hf(18));
+    one_cycle(v,1,2,3,4,0, ch, 0x5a827999, hf(19));
+
+    five_cycle(v, parity, 0x6ed9eba1,  20);
+    five_cycle(v, parity, 0x6ed9eba1,  25);
+    five_cycle(v, parity, 0x6ed9eba1,  30);
+    five_cycle(v, parity, 0x6ed9eba1,  35);
+
+    five_cycle(v, maj, 0x8f1bbcdc,  40);
+    five_cycle(v, maj, 0x8f1bbcdc,  45);
+    five_cycle(v, maj, 0x8f1bbcdc,  50);
+    five_cycle(v, maj, 0x8f1bbcdc,  55);
+
+    five_cycle(v, parity, 0xca62c1d6,  60);
+    five_cycle(v, parity, 0xca62c1d6,  65);
+    five_cycle(v, parity, 0xca62c1d6,  70);
+    five_cycle(v, parity, 0xca62c1d6,  75);
+
+#ifdef ARRAY
+    ctx->hash[0] += v[0]; ctx->hash[1] += v[1];
+    ctx->hash[2] += v[2]; ctx->hash[3] += v[3];
+    ctx->hash[4] += v[4];
+#else
+    ctx->hash[0] += v0; ctx->hash[1] += v1;
+    ctx->hash[2] += v2; ctx->hash[3] += v3;
+    ctx->hash[4] += v4;
+#endif
+}
+
+VOID_RETURN sha1_begin(sha1_ctx ctx[1])
+{
+    memset(ctx, 0, sizeof(sha1_ctx));
+    ctx->hash[0] = 0x67452301;
+    ctx->hash[1] = 0xefcdab89;
+    ctx->hash[2] = 0x98badcfe;
+    ctx->hash[3] = 0x10325476;
+    ctx->hash[4] = 0xc3d2e1f0;
+}
+
+/* SHA1 hash data in an array of bytes into hash buffer and */
+/* call the hash_compile function as required. For both the */
+/* bit and byte orientated versions, the block length 'len' */
+/* must not be greater than 2^32 - 1 bits (2^29 - 1 bytes)  */ 
+
+VOID_RETURN sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1])
+{   uint32_t pos = (uint32_t)((ctx->count[0] >> 3) & SHA1_MASK);
+    const unsigned char *sp = data;
+    unsigned char *w = (unsigned char*)ctx->wbuf;
+#if SHA1_BITS == 1
+    uint32_t ofs = (ctx->count[0] & 7);
+#else
+    len <<= 3;
+#endif
+    if((ctx->count[0] += len) < len)
+        ++(ctx->count[1]);
+#if SHA1_BITS == 1
+    if(ofs)                 /* if not on a byte boundary    */
+    {
+        if(ofs + len < 8)   /* if no added bytes are needed */
+        {
+            w[pos] |= (*sp >> ofs);
+        }
+        else                /* otherwise and add bytes      */
+        {   unsigned char part = w[pos];
+
+            while((int)(ofs + (len -= 8)) >= 0)
+            {
+                w[pos++] = part | (*sp >> ofs);
+                part = *sp++ << (8 - ofs);
+                if(pos == SHA1_BLOCK_SIZE)
+                {
+                    bsw_32(w, SHA1_BLOCK_SIZE >> 2);
+                    sha1_compile(ctx); pos = 0;
+                }
+            }
+
+            w[pos] = part;
+        }
+    }
+    else    /* data is byte aligned */
+#endif
+    {   uint32_t space = SHA1_BLOCK_SIZE - pos;
+
+        while(len >= (space << 3))
+        {
+            memcpy(w + pos, sp, space);
+            bsw_32(w, SHA1_BLOCK_SIZE >> 2);
+            sha1_compile(ctx); 
+            sp += space; len -= (space << 3); 
+            space = SHA1_BLOCK_SIZE; pos = 0;
+        }
+        memcpy(w + pos, sp, (len + 7 * SHA1_BITS) >> 3);
+    }
+}
+
+/* SHA1 final padding and digest calculation  */
+
+VOID_RETURN sha1_end(unsigned char hval[], sha1_ctx ctx[1])
+{   uint32_t    i = (uint32_t)((ctx->count[0] >> 3) & SHA1_MASK), m1;
+
+    /* put bytes in the buffer in an order in which references to   */
+    /* 32-bit words will put bytes with lower addresses into the    */
+    /* top of 32 bit words on BOTH big and little endian machines   */
+    bsw_32(ctx->wbuf, (i + 3 + SHA1_BITS) >> 2);
+
+    /* we now need to mask valid bytes and add the padding which is */
+    /* a single 1 bit and as many zero bits as necessary. Note that */
+    /* we can always add the first padding byte here because the    */
+    /* buffer always has at least one empty slot                    */
+    m1 = (unsigned char)0x80 >> (ctx->count[0] & 7);
+    ctx->wbuf[i >> 2] &= ((0xffffff00 | (~m1 + 1)) << 8 * (~i & 3));
+    ctx->wbuf[i >> 2] |= (m1 << 8 * (~i & 3));
+
+    /* we need 9 or more empty positions, one for the padding byte  */
+    /* (above) and eight for the length count. If there is not      */
+    /* enough space, pad and empty the buffer                       */
+    if(i > SHA1_BLOCK_SIZE - 9)
+    {
+        if(i < 60) ctx->wbuf[15] = 0;
+        sha1_compile(ctx);
+        i = 0;
+    }
+    else    /* compute a word index for the empty buffer positions  */
+        i = (i >> 2) + 1;
+
+    while(i < 14) /* and zero pad all but last two positions        */
+        ctx->wbuf[i++] = 0;
+
+    /* the following 32-bit length fields are assembled in the      */
+    /* wrong byte order on little endian machines but this is       */
+    /* corrected later since they are only ever used as 32-bit      */
+    /* word values.                                                 */
+    ctx->wbuf[14] = ctx->count[1];
+    ctx->wbuf[15] = ctx->count[0];
+    sha1_compile(ctx);
+
+    /* extract the hash value as bytes in case the hash buffer is   */
+    /* misaligned for 32-bit words                                  */
+    for(i = 0; i < SHA1_DIGEST_SIZE; ++i)
+        hval[i] = ((ctx->hash[i >> 2] >> (8 * (~i & 3))) & 0xff);
+}
+
+VOID_RETURN sha1(unsigned char hval[], const unsigned char data[], unsigned long len)
+{   sha1_ctx    cx[1];
+
+    sha1_begin(cx); sha1_hash(data, len, cx); sha1_end(hval, cx);
+}
+
+#endif
+
+#if defined(__cplusplus)
+}
+#endif

+ 72 - 0
ios/Classes/SSZipArchive/minizip/aes/sha1.h

@@ -0,0 +1,72 @@
+/*
+---------------------------------------------------------------------------
+Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
+
+The redistribution and use of this software (with or without changes)
+is allowed without the payment of fees or royalties provided that:
+
+  source code distributions include the above copyright notice, this
+  list of conditions and the following disclaimer;
+
+  binary distributions include the above copyright notice, this list
+  of conditions and the following disclaimer in their documentation.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its operation, including, but not limited to, correctness
+and fitness for purpose.
+---------------------------------------------------------------------------
+Issue Date: 20/12/2007
+*/
+
+#ifndef _SHA1_H
+#define _SHA1_H
+
+#define SHA_1
+
+/* define for bit or byte oriented SHA   */
+#if 1
+#  define SHA1_BITS 0   /* byte oriented */
+#else
+#  define SHA1_BITS 1   /* bit oriented  */
+#endif
+
+#include <stdlib.h>
+#include "brg_types.h"
+
+#define SHA1_BLOCK_SIZE  64
+#define SHA1_DIGEST_SIZE 20
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* type to hold the SHA256 context  */
+
+typedef struct
+{   uint32_t count[2];
+    uint32_t hash[SHA1_DIGEST_SIZE >> 2];
+    uint32_t wbuf[SHA1_BLOCK_SIZE >> 2];
+} sha1_ctx;
+
+/* Note that these prototypes are the same for both bit and */
+/* byte oriented implementations. However the length fields */
+/* are in bytes or bits as appropriate for the version used */
+/* and bit sequences are input as arrays of bytes in which  */
+/* bit sequences run from the most to the least significant */
+/* end of each byte. The value 'len' in sha1_hash for the   */
+/* byte oriented version of SHA1 is limited to 2^29 bytes,  */
+/* but multiple calls will handle longer data blocks.       */
+
+VOID_RETURN sha1_compile(sha1_ctx ctx[1]);
+
+VOID_RETURN sha1_begin(sha1_ctx ctx[1]);
+VOID_RETURN sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]);
+VOID_RETURN sha1_end(unsigned char hval[], sha1_ctx ctx[1]);
+VOID_RETURN sha1(unsigned char hval[], const unsigned char data[], unsigned long len);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

+ 161 - 0
ios/Classes/SSZipArchive/minizip/crypt.c

@@ -0,0 +1,161 @@
+/* crypt.c -- base code for traditional PKWARE encryption
+   Version 1.2.0, September 16th, 2017
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 1998-2005 Gilles Vollant
+     Modifications for Info-ZIP crypting
+     http://www.winimage.com/zLibDll/minizip.html
+   Copyright (C) 2003 Terry Thorsen
+
+   This code is a modified version of crypting code in Info-ZIP distribution
+
+   Copyright (C) 1990-2000 Info-ZIP.  All rights reserved.
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+
+   This encryption code is a direct transcription of the algorithm from
+   Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+   file (appnote.txt) is distributed with the PKZIP program (even in the
+   version without encryption capabilities).
+
+   If you don't need crypting in your application, just define symbols
+   NOCRYPT and NOUNCRYPT.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <time.h>
+
+#ifdef _WIN32
+#  include <windows.h>
+#  include <wincrypt.h>
+#else
+#  include <sys/stat.h>
+#  include <fcntl.h>
+#  include <unistd.h>
+#endif
+
+#include "zlib.h"
+
+#include "crypt.h"
+
+/***************************************************************************/
+
+#define CRC32(c, b) ((*(pcrc_32_tab+(((uint32_t)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
+
+#ifndef ZCR_SEED2
+#  define ZCR_SEED2 3141592654UL     /* use PI as default pattern */
+#endif
+
+/***************************************************************************/
+
+uint8_t decrypt_byte(uint32_t *pkeys)
+{
+    unsigned temp;  /* POTENTIAL BUG:  temp*(temp^1) may overflow in an
+                     * unpredictable manner on 16-bit systems; not a problem
+                     * with any known compiler so far, though */
+
+    temp = ((uint32_t)(*(pkeys+2)) & 0xffff) | 2;
+    return (uint8_t)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+uint8_t update_keys(uint32_t *pkeys, const z_crc_t *pcrc_32_tab, int32_t c)
+{
+    (*(pkeys+0)) = (uint32_t)CRC32((*(pkeys+0)), c);
+    (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
+    (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
+    {
+        register int32_t keyshift = (int32_t)((*(pkeys + 1)) >> 24);
+        (*(pkeys+2)) = (uint32_t)CRC32((*(pkeys+2)), keyshift);
+    }
+    return c;
+}
+
+void init_keys(const char *passwd, uint32_t *pkeys, const z_crc_t *pcrc_32_tab)
+{
+    *(pkeys+0) = 305419896L;
+    *(pkeys+1) = 591751049L;
+    *(pkeys+2) = 878082192L;
+    while (*passwd != 0)
+    {
+        update_keys(pkeys, pcrc_32_tab, *passwd);
+        passwd += 1;
+    }
+}
+
+/***************************************************************************/
+
+int cryptrand(unsigned char *buf, unsigned int len)
+{
+    static unsigned calls = 0;
+    int rlen = 0;
+#ifdef _WIN32
+    HCRYPTPROV provider;
+    unsigned __int64 pentium_tsc[1];
+    int result = 0;
+
+
+    if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    {
+        result = CryptGenRandom(provider, len, buf);
+        CryptReleaseContext(provider, 0);
+        if (result)
+            return len;
+    }
+
+    for (rlen = 0; rlen < (int)len; ++rlen)
+    {
+        if (rlen % 8 == 0)
+            QueryPerformanceCounter((LARGE_INTEGER *)pentium_tsc);
+        buf[rlen] = ((unsigned char*)pentium_tsc)[rlen % 8];
+    }
+#else
+    int frand = open("/dev/urandom", O_RDONLY);
+    if (frand != -1)
+    {
+        rlen = (int)read(frand, buf, len);
+        close(frand);
+    }
+#endif
+    if (rlen < (int)len)
+    {
+        /* Ensure different random header each time */
+        if (++calls == 1)
+            srand((unsigned)(time(NULL) ^ ZCR_SEED2));
+
+        while (rlen < (int)len)
+            buf[rlen++] = (rand() >> 7) & 0xff;
+    }
+    return rlen;
+}
+
+int crypthead(const char *passwd, uint8_t *buf, int buf_size, uint32_t *pkeys,
+              const z_crc_t *pcrc_32_tab, uint8_t verify1, uint8_t verify2)
+{
+    uint8_t n = 0;                      /* index in random header */
+    uint8_t header[RAND_HEAD_LEN-2];    /* random header */
+    uint16_t t = 0;                     /* temporary */
+
+    if (buf_size < RAND_HEAD_LEN)
+        return 0;
+
+    init_keys(passwd, pkeys, pcrc_32_tab);
+
+    /* First generate RAND_HEAD_LEN-2 random bytes. */
+    cryptrand(header, RAND_HEAD_LEN-2);
+
+    /* Encrypt random header (last two bytes is high word of crc) */
+    init_keys(passwd, pkeys, pcrc_32_tab);
+
+    for (n = 0; n < RAND_HEAD_LEN-2; n++)
+        buf[n] = (uint8_t)zencode(pkeys, pcrc_32_tab, header[n], t);
+
+    buf[n++] = (uint8_t)zencode(pkeys, pcrc_32_tab, verify1, t);
+    buf[n++] = (uint8_t)zencode(pkeys, pcrc_32_tab, verify2, t);
+    return n;
+}
+
+/***************************************************************************/

+ 64 - 0
ios/Classes/SSZipArchive/minizip/crypt.h

@@ -0,0 +1,64 @@
+/* crypt.h -- base code for traditional PKWARE encryption
+   Version 1.2.0, September 16th, 2017
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 1998-2005 Gilles Vollant
+     Modifications for Info-ZIP crypting
+     http://www.winimage.com/zLibDll/minizip.html
+   Copyright (C) 2003 Terry Thorsen
+
+   This code is a modified version of crypting code in Info-ZIP distribution
+
+   Copyright (C) 1990-2000 Info-ZIP.  All rights reserved.
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef _MINICRYPT_H
+#define _MINICRYPT_H
+
+#if ZLIB_VERNUM < 0x1270
+typedef unsigned long z_crc_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RAND_HEAD_LEN  12
+
+/***************************************************************************/
+
+#define zdecode(pkeys,pcrc_32_tab,c) \
+    (update_keys(pkeys,pcrc_32_tab, c ^= decrypt_byte(pkeys)))
+
+#define zencode(pkeys,pcrc_32_tab,c,t) \
+    (t = decrypt_byte(pkeys), update_keys(pkeys,pcrc_32_tab,c), t^(c))
+
+/***************************************************************************/
+
+/* Return the next byte in the pseudo-random sequence */
+uint8_t decrypt_byte(uint32_t *pkeys);
+
+/* Update the encryption keys with the next byte of plain text */
+uint8_t update_keys(uint32_t *pkeys, const z_crc_t *pcrc_32_tab, int32_t c);
+
+/* Initialize the encryption keys and the random header according to the given password. */
+void init_keys(const char *passwd, uint32_t *pkeys, const z_crc_t *pcrc_32_tab);
+
+/* Generate cryptographically secure random numbers */
+int cryptrand(unsigned char *buf, unsigned int len);
+
+/* Create encryption header */
+int crypthead(const char *passwd, uint8_t *buf, int buf_size, uint32_t *pkeys,
+    const z_crc_t *pcrc_32_tab, uint8_t verify1, uint8_t verify2);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 353 - 0
ios/Classes/SSZipArchive/minizip/ioapi.c

@@ -0,0 +1,353 @@
+/* ioapi.c -- IO base function header for compress/uncompress .zip
+   part of the MiniZip project
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Modifications for Zip64 support
+     Copyright (C) 2009-2010 Mathias Svensson
+     http://result42.com
+   Copyright (C) 1998-2010 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined unix || defined __APPLE__
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include "ioapi.h"
+
+#if defined(_WIN32)
+#  define snprintf _snprintf
+#endif
+
+voidpf call_zopen64(const zlib_filefunc64_32_def *pfilefunc, const void *filename, int mode)
+{
+    if (pfilefunc->zfile_func64.zopen64_file != NULL)
+        return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque, filename, mode);
+    return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque, (const char*)filename, mode);
+}
+
+voidpf call_zopendisk64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint32_t number_disk, int mode)
+{
+    if (pfilefunc->zfile_func64.zopendisk64_file != NULL)
+        return (*(pfilefunc->zfile_func64.zopendisk64_file)) (pfilefunc->zfile_func64.opaque, filestream, number_disk, mode);
+    return (*(pfilefunc->zopendisk32_file))(pfilefunc->zfile_func64.opaque, filestream, number_disk, mode);
+}
+
+long call_zseek64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint64_t offset, int origin)
+{
+    uint32_t offset_truncated = 0;
+    if (pfilefunc->zfile_func64.zseek64_file != NULL)
+        return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
+    offset_truncated = (uint32_t)offset;
+    if (offset_truncated != offset)
+        return -1;
+    return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream, offset_truncated, origin);
+}
+
+uint64_t call_ztell64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream)
+{
+    uint64_t position;
+    if (pfilefunc->zfile_func64.zseek64_file != NULL)
+        return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque, filestream);
+    position = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque, filestream);
+    if ((position) == UINT32_MAX)
+        return (uint64_t)-1;
+    return position;
+}
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filefunc64_32, const zlib_filefunc_def *p_filefunc32)
+{
+    p_filefunc64_32->zfile_func64.zopen64_file = NULL;
+    p_filefunc64_32->zfile_func64.zopendisk64_file = NULL;
+    p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
+    p_filefunc64_32->zopendisk32_file = p_filefunc32->zopendisk_file;
+    p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+    p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
+    p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
+    p_filefunc64_32->zfile_func64.ztell64_file = NULL;
+    p_filefunc64_32->zfile_func64.zseek64_file = NULL;
+    p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
+    p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+    p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
+    p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
+    p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+}
+
+static voidpf   ZCALLBACK fopen_file_func(voidpf opaque, const char *filename, int mode);
+static uint32_t ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size);
+static uint32_t ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void *buf, uint32_t size);
+static uint64_t ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream);
+static long     ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, uint64_t offset, int origin);
+static int      ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream);
+static int      ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream);
+
+typedef struct 
+{
+    FILE *file;
+    int filenameLength;
+    void *filename;
+} FILE_IOPOSIX;
+
+static voidpf file_build_ioposix(FILE *file, const char *filename)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    if (file == NULL)
+        return NULL;
+    ioposix = (FILE_IOPOSIX*)malloc(sizeof(FILE_IOPOSIX));
+    ioposix->file = file;
+    ioposix->filenameLength = (int)strlen(filename) + 1;
+    ioposix->filename = (char*)malloc(ioposix->filenameLength * sizeof(char));
+    strncpy((char*)ioposix->filename, filename, ioposix->filenameLength);
+    return (voidpf)ioposix;
+}
+
+static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char *filename, int mode)
+{
+    FILE* file = NULL;
+    const char *mode_fopen = NULL;
+    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
+        mode_fopen = "rb";
+    else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+        mode_fopen = "r+b";
+    else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+        mode_fopen = "wb";
+
+    if ((filename != NULL) && (mode_fopen != NULL))
+    {
+        file = fopen(filename, mode_fopen);
+        return file_build_ioposix(file, filename);
+    }
+    return file;
+}
+
+static voidpf ZCALLBACK fopen64_file_func(voidpf opaque, const void *filename, int mode)
+{
+    FILE* file = NULL;
+    const char *mode_fopen = NULL;
+    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
+        mode_fopen = "rb";
+    else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+        mode_fopen = "r+b";
+    else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+        mode_fopen = "wb";
+
+    if ((filename != NULL) && (mode_fopen != NULL))
+    {
+        file = fopen64((const char*)filename, mode_fopen);
+        return file_build_ioposix(file, (const char*)filename);
+    }
+    return file;
+}
+
+static voidpf ZCALLBACK fopendisk64_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    char *diskFilename = NULL;
+    voidpf ret = NULL;
+    int i = 0;
+
+    if (stream == NULL)
+        return NULL;
+    ioposix = (FILE_IOPOSIX*)stream;
+    diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
+    strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
+    for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
+    {
+        if (diskFilename[i] != '.')
+            continue;
+        snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02u", number_disk + 1);
+        break;
+    }
+    if (i >= 0)
+        ret = fopen64_file_func(opaque, diskFilename, mode);
+    free(diskFilename);
+    return ret;
+}
+
+static voidpf ZCALLBACK fopendisk_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    char *diskFilename = NULL;
+    voidpf ret = NULL;
+    int i = 0;
+
+    if (stream == NULL)
+        return NULL;
+    ioposix = (FILE_IOPOSIX*)stream;
+    diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
+    strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
+    for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
+    {
+        if (diskFilename[i] != '.')
+            continue;
+        snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02u", number_disk + 1);
+        break;
+    }
+    if (i >= 0)
+        ret = fopen_file_func(opaque, diskFilename, mode);
+    free(diskFilename);
+    return ret;
+}
+
+static uint32_t ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    uint32_t read = (uint32_t)-1;
+    if (stream == NULL)
+        return read;
+    ioposix = (FILE_IOPOSIX*)stream;
+    read = (uint32_t)fread(buf, 1, (size_t)size, ioposix->file);
+    return read;
+}
+
+static uint32_t ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void *buf, uint32_t size)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    uint32_t written = (uint32_t)-1;
+    if (stream == NULL)
+        return written;
+    ioposix = (FILE_IOPOSIX*)stream;
+    written = (uint32_t)fwrite(buf, 1, (size_t)size, ioposix->file);
+    return written;
+}
+
+static long ZCALLBACK ftell_file_func(voidpf opaque, voidpf stream)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    long ret = -1;
+    if (stream == NULL)
+        return ret;
+    ioposix = (FILE_IOPOSIX*)stream;
+    ret = ftell(ioposix->file);
+    return ret;
+}
+
+static uint64_t ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    uint64_t ret = (uint64_t)-1;
+    if (stream == NULL)
+        return ret;
+    ioposix = (FILE_IOPOSIX*)stream;
+    ret = ftello64(ioposix->file);
+    return ret;
+}
+
+static long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uint32_t offset, int origin)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    int fseek_origin = 0;
+    long ret = 0;
+
+    if (stream == NULL)
+        return -1;
+    ioposix = (FILE_IOPOSIX*)stream;
+
+    switch (origin)
+    {
+        case ZLIB_FILEFUNC_SEEK_CUR:
+            fseek_origin = SEEK_CUR;
+            break;
+        case ZLIB_FILEFUNC_SEEK_END:
+            fseek_origin = SEEK_END;
+            break;
+        case ZLIB_FILEFUNC_SEEK_SET:
+            fseek_origin = SEEK_SET;
+            break;
+        default:
+            return -1;
+    }
+    if (fseek(ioposix->file, offset, fseek_origin) != 0)
+        ret = -1;
+    return ret;
+}
+
+static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, uint64_t offset, int origin)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    int fseek_origin = 0;
+    long ret = 0;
+
+    if (stream == NULL)
+        return -1;
+    ioposix = (FILE_IOPOSIX*)stream;
+
+    switch (origin)
+    {
+        case ZLIB_FILEFUNC_SEEK_CUR:
+            fseek_origin = SEEK_CUR;
+            break;
+        case ZLIB_FILEFUNC_SEEK_END:
+            fseek_origin = SEEK_END;
+            break;
+        case ZLIB_FILEFUNC_SEEK_SET:
+            fseek_origin = SEEK_SET;
+            break;
+        default:
+            return -1;
+    }
+
+    if (fseeko64(ioposix->file, offset, fseek_origin) != 0)
+        ret = -1;
+
+    return ret;
+}
+
+static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    int ret = -1;
+    if (stream == NULL)
+        return ret;
+    ioposix = (FILE_IOPOSIX*)stream;
+    if (ioposix->filename != NULL)
+        free(ioposix->filename);
+    ret = fclose(ioposix->file);
+    free(ioposix);
+    return ret;
+}
+
+static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    int ret = -1;
+    if (stream == NULL)
+        return ret;
+    ioposix = (FILE_IOPOSIX*)stream;
+    ret = ferror(ioposix->file);
+    return ret;
+}
+
+void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def)
+{
+    pzlib_filefunc_def->zopen_file = fopen_file_func;
+    pzlib_filefunc_def->zopendisk_file = fopendisk_file_func;
+    pzlib_filefunc_def->zread_file = fread_file_func;
+    pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+    pzlib_filefunc_def->ztell_file = ftell_file_func;
+    pzlib_filefunc_def->zseek_file = fseek_file_func;
+    pzlib_filefunc_def->zclose_file = fclose_file_func;
+    pzlib_filefunc_def->zerror_file = ferror_file_func;
+    pzlib_filefunc_def->opaque = NULL;
+}
+
+void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def)
+{
+    pzlib_filefunc_def->zopen64_file = fopen64_file_func;
+    pzlib_filefunc_def->zopendisk64_file = fopendisk64_file_func;
+    pzlib_filefunc_def->zread_file = fread_file_func;
+    pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+    pzlib_filefunc_def->ztell64_file = ftell64_file_func;
+    pzlib_filefunc_def->zseek64_file = fseek64_file_func;
+    pzlib_filefunc_def->zclose_file = fclose_file_func;
+    pzlib_filefunc_def->zerror_file = ferror_file_func;
+    pzlib_filefunc_def->opaque = NULL;
+}

+ 148 - 0
ios/Classes/SSZipArchive/minizip/ioapi.h

@@ -0,0 +1,148 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+   part of the MiniZip project
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 2009-2010 Mathias Svensson
+     Modifications for Zip64 support
+     http://result42.com
+   Copyright (C) 1998-2010 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef _ZLIBIOAPI64_H
+#define _ZLIBIOAPI64_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "zlib.h"
+
+#if defined(USE_FILE32API)
+#  define fopen64 fopen
+#  define ftello64 ftell
+#  define fseeko64 fseek
+#else
+#  if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__ANDROID__)
+#    define fopen64 fopen
+#    define ftello64 ftello
+#    define fseeko64 fseeko
+#  endif
+#  ifdef _MSC_VER
+#    define fopen64 fopen
+#    if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
+#      define ftello64 _ftelli64
+#      define fseeko64 _fseeki64
+#    else /* old MSC */
+#      define ftello64 ftell
+#      define fseeko64 fseek
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ             (1)
+#define ZLIB_FILEFUNC_MODE_WRITE            (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER  (3)
+#define ZLIB_FILEFUNC_MODE_EXISTING         (4)
+#define ZLIB_FILEFUNC_MODE_CREATE           (8)
+
+#ifndef ZCALLBACK
+#  if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || \
+       defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+#    define ZCALLBACK CALLBACK
+#  else
+#    define ZCALLBACK
+#  endif
+#endif
+
+typedef voidpf   (ZCALLBACK *open_file_func)     (voidpf opaque, const char *filename, int mode);
+typedef voidpf   (ZCALLBACK *opendisk_file_func) (voidpf opaque, voidpf stream, uint32_t number_disk, int mode);
+typedef uint32_t (ZCALLBACK *read_file_func)     (voidpf opaque, voidpf stream, void* buf, uint32_t size);
+typedef uint32_t (ZCALLBACK *write_file_func)    (voidpf opaque, voidpf stream, const void *buf, uint32_t size);
+typedef int      (ZCALLBACK *close_file_func)    (voidpf opaque, voidpf stream);
+typedef int      (ZCALLBACK *error_file_func)    (voidpf opaque, voidpf stream);
+
+typedef long     (ZCALLBACK *tell_file_func)     (voidpf opaque, voidpf stream);
+typedef long     (ZCALLBACK *seek_file_func)     (voidpf opaque, voidpf stream, uint32_t offset, int origin);
+
+/* here is the "old" 32 bits structure structure */
+typedef struct zlib_filefunc_def_s
+{
+    open_file_func      zopen_file;
+    opendisk_file_func  zopendisk_file;
+    read_file_func      zread_file;
+    write_file_func     zwrite_file;
+    tell_file_func      ztell_file;
+    seek_file_func      zseek_file;
+    close_file_func     zclose_file;
+    error_file_func     zerror_file;
+    voidpf              opaque;
+} zlib_filefunc_def;
+
+typedef uint64_t (ZCALLBACK *tell64_file_func)    (voidpf opaque, voidpf stream);
+typedef long     (ZCALLBACK *seek64_file_func)    (voidpf opaque, voidpf stream, uint64_t offset, int origin);
+typedef voidpf   (ZCALLBACK *open64_file_func)    (voidpf opaque, const void *filename, int mode);
+typedef voidpf   (ZCALLBACK *opendisk64_file_func)(voidpf opaque, voidpf stream, uint32_t number_disk, int mode);
+
+typedef struct zlib_filefunc64_def_s
+{
+    open64_file_func     zopen64_file;
+    opendisk64_file_func zopendisk64_file;
+    read_file_func       zread_file;
+    write_file_func      zwrite_file;
+    tell64_file_func     ztell64_file;
+    seek64_file_func     zseek64_file;
+    close_file_func      zclose_file;
+    error_file_func      zerror_file;
+    voidpf               opaque;
+} zlib_filefunc64_def;
+
+void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
+void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def);
+
+/* now internal definition, only for zip.c and unzip.h */
+typedef struct zlib_filefunc64_32_def_s
+{
+    zlib_filefunc64_def zfile_func64;
+    open_file_func      zopen32_file;
+    opendisk_file_func  zopendisk32_file;
+    tell_file_func      ztell32_file;
+    seek_file_func      zseek32_file;
+} zlib_filefunc64_32_def;
+
+#define ZREAD64(filefunc,filestream,buf,size)       ((*((filefunc).zfile_func64.zread_file))        ((filefunc).zfile_func64.opaque,filestream,buf,size))
+#define ZWRITE64(filefunc,filestream,buf,size)      ((*((filefunc).zfile_func64.zwrite_file))       ((filefunc).zfile_func64.opaque,filestream,buf,size))
+/*#define ZTELL64(filefunc,filestream)                ((*((filefunc).ztell64_file))                   ((filefunc).opaque,filestream))*/
+/*#define ZSEEK64(filefunc,filestream,pos,mode)       ((*((filefunc).zseek64_file))                   ((filefunc).opaque,filestream,pos,mode))*/
+#define ZCLOSE64(filefunc,filestream)               ((*((filefunc).zfile_func64.zclose_file))       ((filefunc).zfile_func64.opaque,filestream))
+#define ZERROR64(filefunc,filestream)               ((*((filefunc).zfile_func64.zerror_file))       ((filefunc).zfile_func64.opaque,filestream))
+
+voidpf   call_zopen64(const zlib_filefunc64_32_def *pfilefunc,const void*filename, int mode);
+voidpf   call_zopendisk64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint32_t number_disk, int mode);
+long     call_zseek64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint64_t offset, int origin);
+uint64_t call_ztell64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream);
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filefunc64_32, const zlib_filefunc_def *p_filefunc32);
+
+#define ZOPEN64(filefunc,filename,mode)             (call_zopen64((&(filefunc)),(filename),(mode)))
+#define ZOPENDISK64(filefunc,filestream,diskn,mode) (call_zopendisk64((&(filefunc)),(filestream),(diskn),(mode)))
+#define ZTELL64(filefunc,filestream)                (call_ztell64((&(filefunc)),(filestream)))
+#define ZSEEK64(filefunc,filestream,pos,mode)       (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 461 - 0
ios/Classes/SSZipArchive/minizip/ioapi_buf.c

@@ -0,0 +1,461 @@
+/* ioapi_buf.c -- IO base function header for compress/uncompress .zip
+   files using zlib + zip or unzip API
+
+   This version of ioapi is designed to buffer IO.
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+      https://github.com/nmoinvaz/minizip
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "zlib.h"
+#include "ioapi.h"
+
+#include "ioapi_buf.h"
+
+#ifndef IOBUF_BUFFERSIZE
+#  define IOBUF_BUFFERSIZE (UINT16_MAX)
+#endif
+
+#if defined(_WIN32)
+#  include <conio.h>
+#  define PRINTF  _cprintf
+#  define VPRINTF _vcprintf
+#else
+#  define PRINTF  printf
+#  define VPRINTF vprintf
+#endif
+
+//#define IOBUF_VERBOSE
+
+#ifdef __GNUC__
+#ifndef max
+#define max(x,y) ({ \
+const typeof(x) _x = (x);	\
+const typeof(y) _y = (y);	\
+(void) (&_x == &_y);		\
+_x > _y ? _x : _y; })
+#endif /* __GNUC__ */
+
+#ifndef min
+#define min(x,y) ({ \
+const typeof(x) _x = (x);	\
+const typeof(y) _y = (y);	\
+(void) (&_x == &_y);		\
+_x < _y ? _x : _y; })
+#endif
+#endif
+
+typedef struct ourstream_s {
+  char      readbuf[IOBUF_BUFFERSIZE];
+  uint32_t  readbuf_len;
+  uint32_t  readbuf_pos;
+  uint32_t  readbuf_hits;
+  uint32_t  readbuf_misses;
+  char      writebuf[IOBUF_BUFFERSIZE];
+  uint32_t  writebuf_len;
+  uint32_t  writebuf_pos;
+  uint32_t  writebuf_hits;
+  uint32_t  writebuf_misses;
+  uint64_t  position;
+  voidpf    stream;
+} ourstream_t;
+
+#if defined(IOBUF_VERBOSE)
+#  define print_buf(o,s,f,...) print_buf_internal(o,s,f,__VA_ARGS__);
+#else
+#  define print_buf(o,s,f,...)
+#endif
+
+void print_buf_internal(voidpf opaque, voidpf stream, char *format, ...)
+{
+    ourstream_t *streamio = (ourstream_t *)stream;
+    va_list arglist;
+    PRINTF("Buf stream %p - ", streamio);
+    va_start(arglist, format);
+    VPRINTF(format, arglist);
+    va_end(arglist);
+}
+
+voidpf fopen_buf_internal_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
+{
+    ourstream_t *streamio = NULL;
+    if (stream == NULL)
+        return NULL;
+    streamio = (ourstream_t *)malloc(sizeof(ourstream_t));
+    if (streamio == NULL)
+        return NULL;
+    memset(streamio, 0, sizeof(ourstream_t));
+    streamio->stream = stream;
+    print_buf(opaque, streamio, "open [num %d mode %d]\n", number_disk, mode);
+    return streamio;
+}
+
+voidpf ZCALLBACK fopen_buf_func(voidpf opaque, const char *filename, int mode)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    voidpf stream = bufio->filefunc.zopen_file(bufio->filefunc.opaque, filename, mode);
+    return fopen_buf_internal_func(opaque, stream, 0, mode);
+}
+
+voidpf ZCALLBACK fopen64_buf_func(voidpf opaque, const void *filename, int mode)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    voidpf stream = bufio->filefunc64.zopen64_file(bufio->filefunc64.opaque, filename, mode);
+    return fopen_buf_internal_func(opaque, stream, 0, mode);
+}
+
+voidpf ZCALLBACK fopendisk_buf_func(voidpf opaque, voidpf stream_cd, uint32_t number_disk, int mode)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream_cd;
+    voidpf *stream = bufio->filefunc.zopendisk_file(bufio->filefunc.opaque, streamio->stream, number_disk, mode);
+    return fopen_buf_internal_func(opaque, stream, number_disk, mode);
+}
+
+voidpf ZCALLBACK fopendisk64_buf_func(voidpf opaque, voidpf stream_cd, uint32_t number_disk, int mode)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream_cd;
+    voidpf stream = bufio->filefunc64.zopendisk64_file(bufio->filefunc64.opaque, streamio->stream, number_disk, mode);
+    return fopen_buf_internal_func(opaque, stream, number_disk, mode);
+}
+
+long fflush_buf(voidpf opaque, voidpf stream)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream;
+    uint32_t total_bytes_to_write = 0;
+    uint32_t bytes_to_write = streamio->writebuf_len;
+    uint32_t bytes_left_to_write = streamio->writebuf_len;
+    long bytes_written = 0;
+
+    while (bytes_left_to_write > 0)
+    {
+        if (bufio->filefunc64.zwrite_file != NULL)
+            bytes_written = bufio->filefunc64.zwrite_file(bufio->filefunc64.opaque, streamio->stream, streamio->writebuf + (bytes_to_write - bytes_left_to_write), bytes_left_to_write);
+        else
+            bytes_written = bufio->filefunc.zwrite_file(bufio->filefunc.opaque, streamio->stream, streamio->writebuf + (bytes_to_write - bytes_left_to_write), bytes_left_to_write);
+
+        streamio->writebuf_misses += 1;
+
+        print_buf(opaque, stream, "write flush [%d:%d len %d]\n", bytes_to_write, bytes_left_to_write, streamio->writebuf_len);
+
+        if (bytes_written < 0)
+            return bytes_written;
+
+        total_bytes_to_write += bytes_written;
+        bytes_left_to_write -= bytes_written;
+        streamio->position += bytes_written;
+    }
+    streamio->writebuf_len = 0;
+    streamio->writebuf_pos = 0;
+    return total_bytes_to_write;
+}
+
+uint32_t ZCALLBACK fread_buf_func(voidpf opaque, voidpf stream, void *buf, uint32_t size)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream;
+    uint32_t buf_len = 0;
+    uint32_t bytes_to_read = 0;
+    uint32_t bytes_to_copy = 0;
+    uint32_t bytes_left_to_read = size;
+    uint32_t bytes_read = 0;
+
+    print_buf(opaque, stream, "read [size %ld pos %lld]\n", size, streamio->position);
+
+    if (streamio->writebuf_len > 0)
+    {
+        print_buf(opaque, stream, "switch from write to read, not yet supported [%lld]\n", streamio->position);
+    }
+
+    while (bytes_left_to_read > 0)
+    {
+        if ((streamio->readbuf_len == 0) || (streamio->readbuf_pos == streamio->readbuf_len))
+        {
+            if (streamio->readbuf_len == IOBUF_BUFFERSIZE)
+            {
+                streamio->readbuf_pos = 0;
+                streamio->readbuf_len = 0;
+            }
+
+            bytes_to_read = IOBUF_BUFFERSIZE - (streamio->readbuf_len - streamio->readbuf_pos);
+
+            if (bufio->filefunc64.zread_file != NULL)
+                bytes_read = bufio->filefunc64.zread_file(bufio->filefunc64.opaque, streamio->stream, streamio->readbuf + streamio->readbuf_pos, bytes_to_read);
+            else
+                bytes_read = bufio->filefunc.zread_file(bufio->filefunc.opaque, streamio->stream, streamio->readbuf + streamio->readbuf_pos, bytes_to_read);
+
+            streamio->readbuf_misses += 1;
+            streamio->readbuf_len += bytes_read;
+            streamio->position += bytes_read;
+
+            print_buf(opaque, stream, "filled [read %d/%d buf %d:%d pos %lld]\n", bytes_read, bytes_to_read, streamio->readbuf_pos, streamio->readbuf_len, streamio->position);
+
+            if (bytes_read == 0)
+                break;
+        }
+
+        if ((streamio->readbuf_len - streamio->readbuf_pos) > 0)
+        {
+            bytes_to_copy = min(bytes_left_to_read, (uint32_t)(streamio->readbuf_len - streamio->readbuf_pos));
+            memcpy((char *)buf + buf_len, streamio->readbuf + streamio->readbuf_pos, bytes_to_copy);
+
+            buf_len += bytes_to_copy;
+            bytes_left_to_read -= bytes_to_copy;
+
+            streamio->readbuf_hits += 1;
+            streamio->readbuf_pos += bytes_to_copy;
+
+            print_buf(opaque, stream, "emptied [copied %d remaining %d buf %d:%d pos %lld]\n", bytes_to_copy, bytes_left_to_read, streamio->readbuf_pos, streamio->readbuf_len, streamio->position);
+        }
+    }
+
+    return size - bytes_left_to_read;
+}
+
+uint32_t ZCALLBACK fwrite_buf_func(voidpf opaque, voidpf stream, const void *buf, uint32_t size)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream;
+    uint32_t bytes_to_write = size;
+    uint32_t bytes_left_to_write = size;
+    uint32_t bytes_to_copy = 0;
+    int64_t ret = 0;
+
+    print_buf(opaque, stream, "write [size %ld len %d pos %lld]\n", size, streamio->writebuf_len, streamio->position);
+
+    if (streamio->readbuf_len > 0)
+    {
+        streamio->position -= streamio->readbuf_len;
+        streamio->position += streamio->readbuf_pos;
+
+        streamio->readbuf_len = 0;
+        streamio->readbuf_pos = 0;
+
+        print_buf(opaque, stream, "switch from read to write [%lld]\n", streamio->position);
+
+        if (bufio->filefunc64.zseek64_file != NULL)
+            ret = bufio->filefunc64.zseek64_file(bufio->filefunc64.opaque, streamio->stream, streamio->position, ZLIB_FILEFUNC_SEEK_SET);
+        else
+            ret = bufio->filefunc.zseek_file(bufio->filefunc.opaque, streamio->stream, (uint32_t)streamio->position, ZLIB_FILEFUNC_SEEK_SET);
+
+        if (ret != 0)
+            return (uint32_t)-1;
+    }
+
+    while (bytes_left_to_write > 0)
+    {
+        bytes_to_copy = min(bytes_left_to_write, (uint32_t)(IOBUF_BUFFERSIZE - min(streamio->writebuf_len, streamio->writebuf_pos)));
+
+        if (bytes_to_copy == 0)
+        {
+            if (fflush_buf(opaque, stream) <= 0)
+                return 0;
+
+            continue;
+        }
+
+        memcpy(streamio->writebuf + streamio->writebuf_pos, (char *)buf + (bytes_to_write - bytes_left_to_write), bytes_to_copy);
+
+        print_buf(opaque, stream, "write copy [remaining %d write %d:%d len %d]\n", bytes_to_copy, bytes_to_write, bytes_left_to_write, streamio->writebuf_len);
+
+        bytes_left_to_write -= bytes_to_copy;
+
+        streamio->writebuf_pos += bytes_to_copy;
+        streamio->writebuf_hits += 1;
+        if (streamio->writebuf_pos > streamio->writebuf_len)
+            streamio->writebuf_len += streamio->writebuf_pos - streamio->writebuf_len;
+    }
+
+    return size - bytes_left_to_write;
+}
+
+uint64_t ftell_buf_internal_func(voidpf opaque, voidpf stream, uint64_t position)
+{
+    ourstream_t *streamio = (ourstream_t *)stream;
+    streamio->position = position;
+    print_buf(opaque, stream, "tell [pos %llu readpos %d writepos %d err %d]\n", streamio->position, streamio->readbuf_pos, streamio->writebuf_pos, errno);
+    if (streamio->readbuf_len > 0)
+        position -= (streamio->readbuf_len - streamio->readbuf_pos);
+    if (streamio->writebuf_len > 0)
+        position += streamio->writebuf_pos;
+    return position;
+}
+
+long ZCALLBACK ftell_buf_func(voidpf opaque, voidpf stream)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream;
+    uint64_t position = bufio->filefunc.ztell_file(bufio->filefunc.opaque, streamio->stream);
+    return (long)ftell_buf_internal_func(opaque, stream, position);
+}
+
+uint64_t ZCALLBACK ftell64_buf_func(voidpf opaque, voidpf stream)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream;
+    uint64_t position = bufio->filefunc64.ztell64_file(bufio->filefunc64.opaque, streamio->stream);
+    return ftell_buf_internal_func(opaque, stream, position);
+}
+
+int fseek_buf_internal_func(voidpf opaque, voidpf stream, uint64_t offset, int origin)
+{
+    ourstream_t *streamio = (ourstream_t *)stream;
+
+    print_buf(opaque, stream, "seek [origin %d offset %llu pos %lld]\n", origin, offset, streamio->position);
+
+    switch (origin)
+    {
+        case ZLIB_FILEFUNC_SEEK_SET:
+
+            if (streamio->writebuf_len > 0)
+            {
+                if ((offset >= streamio->position) && (offset <= streamio->position + streamio->writebuf_len))
+                {
+                    streamio->writebuf_pos = (uint32_t)(offset - streamio->position);
+                    return 0;
+                }
+            }
+            if ((streamio->readbuf_len > 0) && (offset < streamio->position) && (offset >= streamio->position - streamio->readbuf_len))
+            {
+                streamio->readbuf_pos = (uint32_t)(offset - (streamio->position - streamio->readbuf_len));
+                return 0;
+            }
+            if (fflush_buf(opaque, stream) < 0)
+                return -1;
+            streamio->position = offset;
+            break;
+
+        case ZLIB_FILEFUNC_SEEK_CUR:
+
+            if (streamio->readbuf_len > 0)
+            {
+                if (offset <= (streamio->readbuf_len - streamio->readbuf_pos))
+                {
+                    streamio->readbuf_pos += (uint32_t)offset;
+                    return 0;
+                }
+                offset -= (streamio->readbuf_len - streamio->readbuf_pos);
+                streamio->position += offset;
+            }
+            if (streamio->writebuf_len > 0)
+            {
+                if (offset <= (streamio->writebuf_len - streamio->writebuf_pos))
+                {
+                    streamio->writebuf_pos += (uint32_t)offset;
+                    return 0;
+                }
+                //offset -= (streamio->writebuf_len - streamio->writebuf_pos);
+            }
+
+            if (fflush_buf(opaque, stream) < 0)
+                return -1;
+
+            break;
+
+        case ZLIB_FILEFUNC_SEEK_END:
+
+            if (streamio->writebuf_len > 0)
+            {
+                streamio->writebuf_pos = streamio->writebuf_len;
+                return 0;
+            }
+            break;
+    }
+
+    streamio->readbuf_len = 0;
+    streamio->readbuf_pos = 0;
+    streamio->writebuf_len = 0;
+    streamio->writebuf_pos = 0;
+    return 1;
+}
+
+long ZCALLBACK fseek_buf_func(voidpf opaque, voidpf stream, uint32_t offset, int origin)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream;
+    long ret = -1;
+    if (bufio->filefunc.zseek_file == NULL)
+        return ret;
+    ret = fseek_buf_internal_func(opaque, stream, offset, origin);
+    if (ret == 1)
+        ret = bufio->filefunc.zseek_file(bufio->filefunc.opaque, streamio->stream, offset, origin);
+    return ret;
+}
+
+long ZCALLBACK fseek64_buf_func(voidpf opaque, voidpf stream, uint64_t offset, int origin)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream;
+    long ret = -1;
+    if (bufio->filefunc64.zseek64_file == NULL)
+        return ret;
+    ret = fseek_buf_internal_func(opaque, stream, offset, origin);
+    if (ret == 1)
+        ret = bufio->filefunc64.zseek64_file(bufio->filefunc64.opaque, streamio->stream, offset, origin);
+    return ret;
+}
+
+int ZCALLBACK fclose_buf_func(voidpf opaque, voidpf stream)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream;
+    int ret = 0;
+    fflush_buf(opaque, stream);
+    print_buf(opaque, stream, "close\n");
+    if (streamio->readbuf_hits + streamio->readbuf_misses > 0)
+        print_buf(opaque, stream, "read efficency %.02f%%\n", (streamio->readbuf_hits / ((float)streamio->readbuf_hits + streamio->readbuf_misses)) * 100);
+    if (streamio->writebuf_hits + streamio->writebuf_misses > 0)
+        print_buf(opaque, stream, "write efficency %.02f%%\n", (streamio->writebuf_hits / ((float)streamio->writebuf_hits + streamio->writebuf_misses)) * 100);
+    if (bufio->filefunc64.zclose_file != NULL)
+        ret = bufio->filefunc64.zclose_file(bufio->filefunc64.opaque, streamio->stream);
+    else
+        ret = bufio->filefunc.zclose_file(bufio->filefunc.opaque, streamio->stream);
+    free(streamio);
+    return ret;
+}
+
+int ZCALLBACK ferror_buf_func(voidpf opaque, voidpf stream)
+{
+    ourbuffer_t *bufio = (ourbuffer_t *)opaque;
+    ourstream_t *streamio = (ourstream_t *)stream;
+    if (bufio->filefunc64.zerror_file != NULL)
+        return bufio->filefunc64.zerror_file(bufio->filefunc64.opaque, streamio->stream);
+    return bufio->filefunc.zerror_file(bufio->filefunc.opaque, streamio->stream);
+}
+
+void fill_buffer_filefunc(zlib_filefunc_def *pzlib_filefunc_def, ourbuffer_t *ourbuf)
+{
+    pzlib_filefunc_def->zopen_file = fopen_buf_func;
+    pzlib_filefunc_def->zopendisk_file = fopendisk_buf_func;
+    pzlib_filefunc_def->zread_file = fread_buf_func;
+    pzlib_filefunc_def->zwrite_file = fwrite_buf_func;
+    pzlib_filefunc_def->ztell_file = ftell_buf_func;
+    pzlib_filefunc_def->zseek_file = fseek_buf_func;
+    pzlib_filefunc_def->zclose_file = fclose_buf_func;
+    pzlib_filefunc_def->zerror_file = ferror_buf_func;
+    pzlib_filefunc_def->opaque = ourbuf;
+}
+
+void fill_buffer_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def, ourbuffer_t *ourbuf)
+{
+    pzlib_filefunc_def->zopen64_file = fopen64_buf_func;
+    pzlib_filefunc_def->zopendisk64_file = fopendisk64_buf_func;
+    pzlib_filefunc_def->zread_file = fread_buf_func;
+    pzlib_filefunc_def->zwrite_file = fwrite_buf_func;
+    pzlib_filefunc_def->ztell64_file = ftell64_buf_func;
+    pzlib_filefunc_def->zseek64_file = fseek64_buf_func;
+    pzlib_filefunc_def->zclose_file = fclose_buf_func;
+    pzlib_filefunc_def->zerror_file = ferror_buf_func;
+    pzlib_filefunc_def->opaque = ourbuf;
+}

+ 52 - 0
ios/Classes/SSZipArchive/minizip/ioapi_buf.h

@@ -0,0 +1,52 @@
+/* ioapi_buf.h -- IO base function header for compress/uncompress .zip
+   files using zlib + zip or unzip API
+
+   This version of ioapi is designed to buffer IO.
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+      https://github.com/nmoinvaz/minizip
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef _IOAPI_BUF_H
+#define _IOAPI_BUF_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zlib.h"
+#include "ioapi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+voidpf   ZCALLBACK fopen_buf_func(voidpf opaque, const char* filename, int mode);
+voidpf   ZCALLBACK fopen64_buf_func(voidpf opaque, const void* filename, int mode);
+voidpf   ZCALLBACK fopendisk_buf_func(voidpf opaque, voidpf stream_cd, uint32_t number_disk, int mode);
+voidpf   ZCALLBACK fopendisk64_buf_func(voidpf opaque, voidpf stream_cd, uint32_t number_disk, int mode);
+uint32_t ZCALLBACK fread_buf_func(voidpf opaque, voidpf stream, void* buf, uint32_t size);
+uint32_t ZCALLBACK fwrite_buf_func(voidpf opaque, voidpf stream, const void* buf, uint32_t size);
+long     ZCALLBACK ftell_buf_func(voidpf opaque, voidpf stream);
+uint64_t ZCALLBACK ftell64_buf_func(voidpf opaque, voidpf stream);
+long     ZCALLBACK fseek_buf_func(voidpf opaque, voidpf stream, uint32_t offset, int origin);
+long     ZCALLBACK fseek64_buf_func(voidpf opaque, voidpf stream, uint64_t offset, int origin);
+int      ZCALLBACK fclose_buf_func(voidpf opaque,voidpf stream);
+int      ZCALLBACK ferror_buf_func(voidpf opaque,voidpf stream);
+
+typedef struct ourbuffer_s {
+  zlib_filefunc_def   filefunc;
+  zlib_filefunc64_def filefunc64;
+} ourbuffer_t;
+
+void fill_buffer_filefunc(zlib_filefunc_def* pzlib_filefunc_def, ourbuffer_t *ourbuf);
+void fill_buffer_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def, ourbuffer_t *ourbuf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 167 - 0
ios/Classes/SSZipArchive/minizip/ioapi_mem.c

@@ -0,0 +1,167 @@
+/* ioapi_mem.c -- IO base function header for compress/uncompress .zip
+   files using zlib + zip or unzip API
+
+   This version of ioapi is designed to access memory rather than files.
+   We do use a region of memory to put data in to and take it out of. We do
+   not have auto-extending buffers and do not inform anyone else that the
+   data has been written. It is really intended for accessing a zip archive
+   embedded in an application such that I can write an installer with no
+   external files. Creation of archives has not been attempted, although
+   parts of the framework are present.
+
+   Based on Unzip ioapi.c version 0.22, May 19th, 2003
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 2003 Justin Fletcher
+   Copyright (C) 1998-2003 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This file is under the same license as the Unzip tool it is distributed
+   with.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zlib.h"
+#include "ioapi.h"
+
+#include "ioapi_mem.h"
+
+#ifndef IOMEM_BUFFERSIZE
+#  define IOMEM_BUFFERSIZE (UINT16_MAX)
+#endif
+
+voidpf ZCALLBACK fopen_mem_func(voidpf opaque, const char *filename, int mode)
+{
+    ourmemory_t *mem = (ourmemory_t *)opaque;
+    if (mem == NULL)
+        return NULL; /* Mem structure passed in was null */
+
+    if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+    {
+        if (mem->grow)
+        {
+            mem->size = IOMEM_BUFFERSIZE;
+            mem->base = (char *)malloc(mem->size);
+        }
+
+        mem->limit = 0; /* When writing we start with 0 bytes written */
+    }
+    else
+        mem->limit = mem->size;
+
+    mem->cur_offset = 0;
+
+    return mem;
+}
+
+voidpf ZCALLBACK fopendisk_mem_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
+{
+    /* Not used */
+    return NULL;
+}
+
+uint32_t ZCALLBACK fread_mem_func(voidpf opaque, voidpf stream, void *buf, uint32_t size)
+{
+    ourmemory_t *mem = (ourmemory_t *)stream;
+
+    if (size > mem->size - mem->cur_offset)
+        size = mem->size - mem->cur_offset;
+
+    memcpy(buf, mem->base + mem->cur_offset, size);
+    mem->cur_offset += size;
+
+    return size;
+}
+
+uint32_t ZCALLBACK fwrite_mem_func(voidpf opaque, voidpf stream, const void *buf, uint32_t size)
+{
+    ourmemory_t *mem = (ourmemory_t *)stream;
+    uint32_t newmemsize = 0;
+    char *newbase = NULL;
+
+    if (size > mem->size - mem->cur_offset)
+    {
+        if (mem->grow)
+        {
+            newmemsize = mem->size;
+            if (size < IOMEM_BUFFERSIZE)
+                newmemsize += IOMEM_BUFFERSIZE;
+            else
+                newmemsize += size;
+            newbase = (char *)malloc(newmemsize);
+            memcpy(newbase, mem->base, mem->size);
+            free(mem->base);
+            mem->base = newbase;
+            mem->size = newmemsize;
+        }
+        else
+            size = mem->size - mem->cur_offset;
+    }
+    memcpy(mem->base + mem->cur_offset, buf, size);
+    mem->cur_offset += size;
+    if (mem->cur_offset > mem->limit)
+        mem->limit = mem->cur_offset;
+
+    return size;
+}
+
+long ZCALLBACK ftell_mem_func(voidpf opaque, voidpf stream)
+{
+    ourmemory_t *mem = (ourmemory_t *)stream;
+    return mem->cur_offset;
+}
+
+long ZCALLBACK fseek_mem_func(voidpf opaque, voidpf stream, uint32_t offset, int origin)
+{
+    ourmemory_t *mem = (ourmemory_t *)stream;
+    uint32_t new_pos = 0;
+    switch (origin)
+    {
+        case ZLIB_FILEFUNC_SEEK_CUR:
+            new_pos = mem->cur_offset + offset;
+            break;
+        case ZLIB_FILEFUNC_SEEK_END:
+            new_pos = mem->limit + offset;
+            break;
+        case ZLIB_FILEFUNC_SEEK_SET:
+            new_pos = offset;
+            break;
+        default:
+            return -1;
+    }
+
+    if (new_pos > mem->size)
+        return 1; /* Failed to seek that far */
+    mem->cur_offset = new_pos;
+    return 0;
+}
+
+int ZCALLBACK fclose_mem_func(voidpf opaque, voidpf stream)
+{
+    /* Even with grow = 1, caller must always free() memory */
+    return 0;
+}
+
+int ZCALLBACK ferror_mem_func(voidpf opaque, voidpf stream)
+{
+    /* We never return errors */
+    return 0;
+}
+
+void fill_memory_filefunc(zlib_filefunc_def *pzlib_filefunc_def, ourmemory_t *ourmem)
+{
+    pzlib_filefunc_def->zopen_file = fopen_mem_func;
+    pzlib_filefunc_def->zopendisk_file = fopendisk_mem_func;
+    pzlib_filefunc_def->zread_file = fread_mem_func;
+    pzlib_filefunc_def->zwrite_file = fwrite_mem_func;
+    pzlib_filefunc_def->ztell_file = ftell_mem_func;
+    pzlib_filefunc_def->zseek_file = fseek_mem_func;
+    pzlib_filefunc_def->zclose_file = fclose_mem_func;
+    pzlib_filefunc_def->zerror_file = ferror_mem_func;
+    pzlib_filefunc_def->opaque = ourmem;
+}

+ 52 - 0
ios/Classes/SSZipArchive/minizip/ioapi_mem.h

@@ -0,0 +1,52 @@
+/* ioapi_mem.h -- IO base function header for compress/uncompress .zip
+   files using zlib + zip or unzip API
+
+   This version of ioapi is designed to access memory rather than files.
+   We do use a region of memory to put data in to and take it out of.
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri (https://github.com/nmoinvaz/minizip)
+             (C) 2003 Justin Fletcher
+             (C) 1998-2003 Gilles Vollant
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef _IOAPI_MEM_H
+#define _IOAPI_MEM_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zlib.h"
+#include "ioapi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+voidpf   ZCALLBACK fopen_mem_func(voidpf opaque, const char* filename, int mode);
+voidpf   ZCALLBACK fopendisk_mem_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode);
+uint32_t ZCALLBACK fread_mem_func(voidpf opaque, voidpf stream, void* buf, uint32_t size);
+uint32_t ZCALLBACK fwrite_mem_func(voidpf opaque, voidpf stream, const void* buf, uint32_t size);
+long     ZCALLBACK ftell_mem_func(voidpf opaque, voidpf stream);
+long     ZCALLBACK fseek_mem_func(voidpf opaque, voidpf stream, uint32_t offset, int origin);
+int      ZCALLBACK fclose_mem_func(voidpf opaque, voidpf stream);
+int      ZCALLBACK ferror_mem_func(voidpf opaque, voidpf stream);
+
+typedef struct ourmemory_s {
+    char *base;          /* Base of the region of memory we're using */
+    uint32_t size;       /* Size of the region of memory we're using */
+    uint32_t limit;      /* Furthest we've written */
+    uint32_t cur_offset; /* Current offset in the area */
+    int grow;            /* Growable memory buffer */
+} ourmemory_t;
+
+void fill_memory_filefunc(zlib_filefunc_def* pzlib_filefunc_def, ourmemory_t *ourmem);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 292 - 0
ios/Classes/SSZipArchive/minizip/minishared.c

@@ -0,0 +1,292 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "zlib.h"
+#include "ioapi.h"
+
+#ifdef _WIN32
+#  include <direct.h>
+#  include <io.h>
+#else
+#  include <unistd.h>
+#  include <utime.h>
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#endif
+
+#include "minishared.h"
+
+#ifdef _WIN32
+#  define USEWIN32IOAPI
+#  include "iowin32.h"
+#endif
+
+uint32_t get_file_date(const char *path, uint32_t *dos_date)
+{
+    int ret = 0;
+#ifdef _WIN32
+    FILETIME ftm_local;
+    HANDLE find = NULL;
+    WIN32_FIND_DATAA ff32;
+
+    find = FindFirstFileA(path, &ff32);
+    if (find != INVALID_HANDLE_VALUE)
+    {
+        FileTimeToLocalFileTime(&(ff32.ftLastWriteTime), &ftm_local);
+        FileTimeToDosDateTime(&ftm_local, ((LPWORD)dos_date) + 1, ((LPWORD)dos_date) + 0);
+        FindClose(find);
+        ret = 1;
+    }
+#else
+    struct stat s;
+    struct tm *filedate = NULL;
+    time_t tm_t = 0;
+
+    memset(&s, 0, sizeof(s));
+
+    if (strcmp(path, "-") != 0)
+    {
+        size_t len = strlen(path);
+        char *name = (char *)malloc(len + 1);
+        strncpy(name, path, len + 1);
+        name[len] = 0;
+        if (name[len - 1] == '/')
+            name[len - 1] = 0;
+
+        /* Not all systems allow stat'ing a file with / appended */
+        if (stat(name, &s) == 0)
+        {
+            tm_t = s.st_mtime;
+            ret = 1;
+        }
+        free(name);
+    }
+
+    filedate = localtime(&tm_t);
+    *dos_date = tm_to_dosdate(filedate);
+#endif
+    return ret;
+}
+
+void change_file_date(const char *path, uint32_t dos_date)
+{
+#ifdef _WIN32
+    HANDLE handle = NULL;
+    FILETIME ftm, ftm_local, ftm_create, ftm_access, ftm_modified;
+
+    handle = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+    if (handle != INVALID_HANDLE_VALUE)
+    {
+        GetFileTime(handle, &ftm_create, &ftm_access, &ftm_modified);
+        DosDateTimeToFileTime((WORD)(dos_date >> 16), (WORD)dos_date, &ftm_local);
+        LocalFileTimeToFileTime(&ftm_local, &ftm);
+        SetFileTime(handle, &ftm, &ftm_access, &ftm);
+        CloseHandle(handle);
+    }
+#else
+    struct utimbuf ut;
+    ut.actime = ut.modtime = dosdate_to_time_t(dos_date);
+    utime(path, &ut);
+#endif
+}
+
+int invalid_date(const struct tm *ptm)
+{
+#define datevalue_in_range(min, max, value) ((min) <= (value) && (value) <= (max))
+    return (!datevalue_in_range(0, 207, ptm->tm_year) ||
+            !datevalue_in_range(0, 11, ptm->tm_mon) ||
+            !datevalue_in_range(1, 31, ptm->tm_mday) ||
+            !datevalue_in_range(0, 23, ptm->tm_hour) ||
+            !datevalue_in_range(0, 59, ptm->tm_min) ||
+            !datevalue_in_range(0, 59, ptm->tm_sec));
+#undef datevalue_in_range
+}
+
+// Conversion without validation
+void dosdate_to_raw_tm(uint64_t dos_date, struct tm *ptm)
+{
+    uint64_t date = (uint64_t)(dos_date >> 16);
+
+    ptm->tm_mday = (uint16_t)(date & 0x1f);
+    ptm->tm_mon = (uint16_t)(((date & 0x1E0) / 0x20) - 1);
+    ptm->tm_year = (uint16_t)(((date & 0x0FE00) / 0x0200) + 80);
+    ptm->tm_hour = (uint16_t)((dos_date & 0xF800) / 0x800);
+    ptm->tm_min = (uint16_t)((dos_date & 0x7E0) / 0x20);
+    ptm->tm_sec = (uint16_t)(2 * (dos_date & 0x1f));
+    ptm->tm_isdst = -1;
+}
+
+int dosdate_to_tm(uint64_t dos_date, struct tm *ptm)
+{
+    dosdate_to_raw_tm(dos_date, ptm);
+
+    if (invalid_date(ptm))
+    {
+        // Invalid date stored, so don't return it.
+        memset(ptm, 0, sizeof(struct tm));
+        return -1;
+    }
+    return 0;
+}
+
+time_t dosdate_to_time_t(uint64_t dos_date)
+{
+    struct tm ptm;
+    dosdate_to_raw_tm(dos_date, &ptm);
+    return mktime(&ptm);
+}
+
+uint32_t tm_to_dosdate(const struct tm *ptm)
+{
+    struct tm fixed_tm;
+
+    /* Years supported:
+    * [00, 79]      (assumed to be between 2000 and 2079)
+    * [80, 207]     (assumed to be between 1980 and 2107, typical output of old
+                     software that does 'year-1900' to get a double digit year)
+    * [1980, 2107]  (due to the date format limitations, only years between 1980 and 2107 can be stored.)
+    */
+
+    memcpy(&fixed_tm, ptm, sizeof(struct tm));
+    if (fixed_tm.tm_year >= 1980) /* range [1980, 2107] */
+        fixed_tm.tm_year -= 1980;
+    else if (fixed_tm.tm_year >= 80) /* range [80, 99] */
+        fixed_tm.tm_year -= 80;
+    else /* range [00, 79] */
+        fixed_tm.tm_year += 20;
+
+    if (invalid_date(ptm))
+        return 0;
+
+    return (uint32_t)(((fixed_tm.tm_mday) + (32 * (fixed_tm.tm_mon + 1)) + (512 * fixed_tm.tm_year)) << 16) |
+        ((fixed_tm.tm_sec / 2) + (32 * fixed_tm.tm_min) + (2048 * (uint32_t)fixed_tm.tm_hour));
+}
+
+int makedir(const char *newdir)
+{
+    char *buffer = NULL;
+    char *p = NULL;
+    int len = (int)strlen(newdir);
+
+    if (len <= 0)
+        return 0;
+
+    buffer = (char*)malloc(len + 1);
+    if (buffer == NULL)
+    {
+        printf("Error allocating memory\n");
+        return -1;
+    }
+
+    strcpy(buffer, newdir);
+
+    if (buffer[len - 1] == '/')
+        buffer[len - 1] = 0;
+
+    if (MKDIR(buffer) == 0)
+    {
+        free(buffer);
+        return 1;
+    }
+
+    p = buffer + 1;
+    while (1)
+    {
+        char hold;
+        while (*p && *p != '\\' && *p != '/')
+            p++;
+        hold = *p;
+        *p = 0;
+
+        if ((MKDIR(buffer) == -1) && (errno == ENOENT))
+        {
+            printf("couldn't create directory %s (%d)\n", buffer, errno);
+            free(buffer);
+            return 0;
+        }
+
+        if (hold == 0)
+            break;
+
+        *p++ = hold;
+    }
+
+    free(buffer);
+    return 1;
+}
+
+FILE *get_file_handle(const char *path)
+{
+    FILE *handle = NULL;
+#if defined(WIN32)
+    wchar_t *pathWide = NULL;
+    int pathLength = 0;
+
+    pathLength = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) + 1;
+    pathWide = (wchar_t*)calloc(pathLength, sizeof(wchar_t));
+    MultiByteToWideChar(CP_UTF8, 0, path, -1, pathWide, pathLength);
+    handle = _wfopen((const wchar_t*)pathWide, L"rb");
+    free(pathWide);
+#else
+    handle = fopen64(path, "rb");
+#endif
+
+    return handle;
+}
+
+int check_file_exists(const char *path)
+{
+    FILE *handle = get_file_handle(path);
+    if (handle == NULL)
+        return 0;
+    fclose(handle);
+    return 1;
+}
+
+int is_large_file(const char *path)
+{
+    FILE* handle = NULL;
+    uint64_t pos = 0;
+
+    handle = get_file_handle(path);
+    if (handle == NULL)
+        return 0;
+
+    fseeko64(handle, 0, SEEK_END);
+    pos = ftello64(handle);
+    fclose(handle);
+
+    printf("file : %s is %lld bytes\n", path, pos);
+
+    return (pos >= UINT32_MAX);
+}
+
+void display_zpos64(uint64_t n, int size_char)
+{
+    /* To avoid compatibility problem we do here the conversion */
+    char number[21] = { 0 };
+    int offset = 19;
+    int pos_string = 19;
+    int size_display_string = 19;
+
+    while (1)
+    {
+        number[offset] = (char)((n % 10) + '0');
+        if (number[offset] != '0')
+            pos_string = offset;
+        n /= 10;
+        if (offset == 0)
+            break;
+        offset--;
+    }
+
+    size_display_string -= pos_string;
+    while (size_char-- > size_display_string)
+        printf(" ");
+    printf("%s", &number[pos_string]);
+}

+ 51 - 0
ios/Classes/SSZipArchive/minizip/minishared.h

@@ -0,0 +1,51 @@
+#ifndef _MINISHARED_H
+#define _MINISHARED_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _WIN32
+#  define MKDIR(d) _mkdir(d)
+#  define CHDIR(d) _chdir(d)
+#else
+#  define MKDIR(d) mkdir(d, 0775)
+#  define CHDIR(d) chdir(d)
+#endif
+
+/***************************************************************************/
+
+/* Get a file's date and time in dos format */
+uint32_t get_file_date(const char *path, uint32_t *dos_date);
+
+/* Sets a file's date and time in dos format */
+void change_file_date(const char *path, uint32_t dos_date);
+
+/* Convert dos date/time format to struct tm */
+int dosdate_to_tm(uint64_t dos_date, struct tm *ptm);
+
+/* Convert dos date/time format to time_t */
+time_t dosdate_to_time_t(uint64_t dos_date);
+
+/* Convert struct tm to dos date/time format */
+uint32_t tm_to_dosdate(const struct tm *ptm);
+
+/* Create a directory and all subdirectories */
+int makedir(const char *newdir);
+
+/* Check to see if a file exists */
+int check_file_exists(const char *path);
+
+/* Check to see if a file is over 4GB and needs ZIP64 extension */
+int is_large_file(const char *path);
+
+/* Print a 64-bit number for compatibility */
+void display_zpos64(uint64_t n, int size_char);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MINISHARED_H */

+ 1978 - 0
ios/Classes/SSZipArchive/minizip/unzip.c

@@ -0,0 +1,1978 @@
+/* unzip.c -- IO for uncompress .zip files using zlib
+   Version 1.2.0, September 16th, 2017
+   part of the MiniZip project
+
+   Copyright (C) 2010-2017 Nathan Moinvaziri
+     Modifications for AES, PKWARE disk spanning
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 2009-2010 Mathias Svensson
+     Modifications for Zip64 support on both zip and unzip
+     http://result42.com
+   Copyright (C) 2007-2008 Even Rouault
+     Modifications of Unzip for Zip64
+   Copyright (C) 1998-2010 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include "zlib.h"
+#include "unzip.h"
+
+#ifdef HAVE_AES
+#  define AES_METHOD          (99)
+#  define AES_PWVERIFYSIZE    (2)
+#  define AES_MAXSALTLENGTH   (16)
+#  define AES_AUTHCODESIZE    (10)
+#  define AES_HEADERSIZE      (11)
+#  define AES_KEYSIZE(mode)   (64 + (mode * 64))
+
+#  include "aes/aes.h"
+#  include "aes/fileenc.h"
+#endif
+#ifdef HAVE_APPLE_COMPRESSION
+#  include <compression.h>
+#endif
+
+#ifndef NOUNCRYPT
+#  include "crypt.h"
+#endif
+
+#define DISKHEADERMAGIC             (0x08074b50)
+#define LOCALHEADERMAGIC            (0x04034b50)
+#define CENTRALHEADERMAGIC          (0x02014b50)
+#define ENDHEADERMAGIC              (0x06054b50)
+#define ZIP64ENDHEADERMAGIC         (0x06064b50)
+#define ZIP64ENDLOCHEADERMAGIC      (0x07064b50)
+
+#define SIZECENTRALDIRITEM          (0x2e)
+#define SIZECENTRALHEADERLOCATOR    (0x14)
+#define SIZEZIPLOCALHEADER          (0x1e)
+
+#ifndef BUFREADCOMMENT
+#  define BUFREADCOMMENT            (0x400)
+#endif
+
+#ifndef UNZ_BUFSIZE
+#  define UNZ_BUFSIZE               (UINT16_MAX)
+#endif
+#ifndef UNZ_MAXFILENAMEINZIP
+#  define UNZ_MAXFILENAMEINZIP      (256)
+#endif
+
+#ifndef ALLOC
+#  define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+#  define TRYFREE(p) {if (p) free(p);}
+#endif
+
+const char unz_copyright[] = " unzip 1.2.0 Copyright 1998-2017 - https://github.com/nmoinvaz/minizip";
+
+/* unz_file_info_internal contain internal info about a file in zipfile*/
+typedef struct unz_file_info64_internal_s
+{
+    uint64_t offset_curfile;            /* relative offset of local header 8 bytes */
+    uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (>0 for sfx) */
+#ifdef HAVE_AES
+    uint8_t  aes_encryption_mode;
+    uint16_t aes_compression_method;
+    uint16_t aes_version;
+#endif
+} unz_file_info64_internal;
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile */
+typedef struct
+{
+    uint8_t *read_buffer;               /* internal buffer for compressed data */
+    z_stream stream;                    /* zLib stream structure for inflate */
+#ifdef HAVE_BZIP2
+    bz_stream bstream;                  /* bzLib stream structure for bziped */
+#endif
+#ifdef HAVE_APPLE_COMPRESSION
+    compression_stream astream;         /* libcompression stream structure */
+#endif
+#ifdef HAVE_AES
+    fcrypt_ctx aes_ctx;
+#endif
+    uint64_t pos_in_zipfile;            /* position in byte on the zipfile, for fseek */
+    uint8_t  stream_initialised;        /* flag set if stream structure is initialised */
+
+    uint64_t offset_local_extrafield;   /* offset of the local extra field */
+    uint16_t size_local_extrafield;     /* size of the local extra field */
+    uint64_t pos_local_extrafield;      /* position in the local extra field in read */
+    uint64_t total_out_64;
+
+    uint32_t crc32;                     /* crc32 of all data uncompressed */
+    uint32_t crc32_expected;            /* crc32 we must obtain after decompress all */
+    uint64_t rest_read_compressed;      /* number of byte to be decompressed */
+    uint64_t rest_read_uncompressed;    /* number of byte to be obtained after decomp */
+
+    zlib_filefunc64_32_def z_filefunc;
+
+    voidpf   filestream;                /* io structore of the zipfile */
+    uint16_t compression_method;        /* compression method (0==store) */
+    uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (>0 for sfx) */
+    int      raw;
+} file_in_zip64_read_info_s;
+
+/* unz64_s contain internal information about the zipfile */
+typedef struct
+{
+    zlib_filefunc64_32_def z_filefunc;
+
+    voidpf filestream;                  /* io structure of the current zipfile */
+    voidpf filestream_with_CD;          /* io structure of the disk with the central directory */
+
+    unz_global_info64 gi;               /* public global information */
+
+    uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (>0 for sfx) */
+    uint64_t num_file;                  /* number of the current file in the zipfile */
+    uint64_t pos_in_central_dir;        /* pos of the current file in the central dir */
+    uint64_t current_file_ok;           /* flag about the usability of the current file */
+    uint64_t central_pos;               /* position of the beginning of the central dir */
+    uint32_t number_disk;               /* number of the current disk, used for spanning ZIP */
+    uint64_t size_central_dir;          /* size of the central directory */
+    uint64_t offset_central_dir;        /* offset of start of central directory with
+                                           respect to the starting disk number */
+
+    unz_file_info64 cur_file_info;      /* public info about the current file in zip*/
+    unz_file_info64_internal cur_file_info_internal;
+                                        /* private info about it*/
+    file_in_zip64_read_info_s *pfile_in_zip_read;
+                                        /* structure about the current file if we are decompressing it */
+    int is_zip64;                       /* is the current file zip64 */
+#ifndef NOUNCRYPT
+    uint32_t keys[3];                   /* keys defining the pseudo-random sequence */
+    const z_crc_t *pcrc_32_tab;
+#endif
+} unz64_internal;
+
+/* Read a byte from a gz_stream; Return EOF for end of file. */
+static int unzReadUInt8(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint8_t *value)
+{
+    uint8_t c = 0;
+    if (ZREAD64(*pzlib_filefunc_def, filestream, &c, 1) == 1)
+    {
+        *value = (uint8_t)c;
+        return UNZ_OK;
+    }
+    *value = 0;
+    if (ZERROR64(*pzlib_filefunc_def, filestream))
+        return UNZ_ERRNO;
+    return UNZ_EOF;
+}
+
+static int unzReadUInt16(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint16_t *value)
+{
+    uint16_t x;
+    uint8_t c = 0;
+    int err = UNZ_OK;
+
+    err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x = (uint16_t)c;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x |= ((uint16_t)c) << 8;
+
+    if (err == UNZ_OK)
+        *value = x;
+    else
+        *value = 0;
+    return err;
+}
+
+static int unzReadUInt32(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint32_t *value)
+{
+    uint32_t x = 0;
+    uint8_t c = 0;
+    int err = UNZ_OK;
+
+    err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x = (uint32_t)c;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x |= ((uint32_t)c) << 8;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x |= ((uint32_t)c) << 16;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint32_t)c) << 24;
+
+    if (err == UNZ_OK)
+        *value = x;
+    else
+        *value = 0;
+    return err;
+}
+
+static int unzReadUInt64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint64_t *value)
+{
+    uint64_t x = 0;
+    uint8_t i = 0;
+    int err = UNZ_OK;
+
+    err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x = (uint64_t)i;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 8;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 16;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 24;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 32;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 40;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 48;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 56;
+
+    if (err == UNZ_OK)
+        *value = x;
+    else
+        *value = 0;
+    return err;
+}
+
+/* Locate the Central directory of a zip file (at the end, just before the global comment) */
+static uint64_t unzSearchCentralDir(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream)
+{
+    uint8_t buf[BUFREADCOMMENT + 4];
+    uint64_t file_size = 0;
+    uint64_t back_read = 4;
+    uint64_t max_back = UINT16_MAX; /* maximum size of global comment */
+    uint64_t pos_found = 0;
+    uint32_t read_size = 0;
+    uint64_t read_pos = 0;
+    uint32_t i = 0;
+
+    if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0)
+        return 0;
+
+    file_size = ZTELL64(*pzlib_filefunc_def, filestream);
+
+    if (max_back > file_size)
+        max_back = file_size;
+
+    while (back_read < max_back)
+    {
+        if (back_read + BUFREADCOMMENT > max_back)
+            back_read = max_back;
+        else
+            back_read += BUFREADCOMMENT;
+
+        read_pos = file_size - back_read;
+        read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ?
+                     (BUFREADCOMMENT + 4) : (uint32_t)(file_size - read_pos);
+
+        if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+            break;
+        if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size)
+            break;
+
+        for (i = read_size - 3; (i--) > 0;)
+            if (((*(buf+i)) == (ENDHEADERMAGIC & 0xff)) &&
+                ((*(buf+i+1)) == (ENDHEADERMAGIC >> 8 & 0xff)) &&
+                ((*(buf+i+2)) == (ENDHEADERMAGIC >> 16 & 0xff)) &&
+                ((*(buf+i+3)) == (ENDHEADERMAGIC >> 24 & 0xff)))
+            {
+                pos_found = read_pos+i;
+                break;
+            }
+
+        if (pos_found != 0)
+            break;
+    }
+
+    return pos_found;
+}
+
+/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */
+static uint64_t unzSearchCentralDir64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream,
+    const uint64_t endcentraloffset)
+{
+    uint64_t offset = 0;
+    uint32_t value32 = 0;
+
+    /* Zip64 end of central directory locator */
+    if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return 0;
+
+    /* Read locator signature */
+    if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+        return 0;
+    if (value32 != ZIP64ENDLOCHEADERMAGIC)
+        return 0;
+    /* Number of the disk with the start of the zip64 end of  central directory */
+    if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+        return 0;
+    /* Relative offset of the zip64 end of central directory record */
+    if (unzReadUInt64(pzlib_filefunc_def, filestream, &offset) != UNZ_OK)
+        return 0;
+    /* Total number of disks */
+    if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+        return 0;
+    /* Goto end of central directory record */
+    if (ZSEEK64(*pzlib_filefunc_def, filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return 0;
+     /* The signature */
+    if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+        return 0;
+    if (value32 != ZIP64ENDHEADERMAGIC)
+        return 0;
+
+    return offset;
+}
+
+static unzFile unzOpenInternal(const void *path, zlib_filefunc64_32_def *pzlib_filefunc64_32_def)
+{
+    unz64_internal us;
+    unz64_internal *s = NULL;
+    uint64_t central_pos = 0;
+    uint64_t central_pos64 = 0;
+    uint64_t number_entry_CD = 0;
+    uint16_t value16 = 0;
+    uint32_t value32 = 0;
+    uint64_t value64 = 0;
+    voidpf filestream = NULL;
+    int err = UNZ_OK;
+
+    us.filestream = NULL;
+    us.filestream_with_CD = NULL;
+    us.z_filefunc.zseek32_file = NULL;
+    us.z_filefunc.ztell32_file = NULL;
+
+    if (pzlib_filefunc64_32_def == NULL)
+        fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);
+    else
+        us.z_filefunc = *pzlib_filefunc64_32_def;
+
+    us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
+
+    if (us.filestream == NULL)
+        return NULL;
+
+    us.filestream_with_CD = us.filestream;
+    us.is_zip64 = 0;
+
+    /* Search for end of central directory header */
+    central_pos = unzSearchCentralDir(&us.z_filefunc, us.filestream);
+    if (central_pos)
+    {
+        if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+            err = UNZ_ERRNO;
+
+        /* The signature, already checked */
+        if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
+            err = UNZ_ERRNO;
+        /* Number of this disk */
+        if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+            err = UNZ_ERRNO;
+        us.number_disk = value16;
+        /* Number of the disk with the start of the central directory */
+        if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+            err = UNZ_ERRNO;
+        us.gi.number_disk_with_CD = value16;
+        /* Total number of entries in the central directory on this disk */
+        if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+            err = UNZ_ERRNO;
+        us.gi.number_entry = value16;
+        /* Total number of entries in the central directory */
+        if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+            err = UNZ_ERRNO;
+        number_entry_CD = value16;
+        if (number_entry_CD != us.gi.number_entry)
+            err = UNZ_BADZIPFILE;
+        /* Size of the central directory */
+        if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
+            err = UNZ_ERRNO;
+        us.size_central_dir = value32;
+        /* Offset of start of central directory with respect to the starting disk number */
+        if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
+            err = UNZ_ERRNO;
+        us.offset_central_dir = value32;
+        /* Zipfile comment length */
+        if (unzReadUInt16(&us.z_filefunc, us.filestream, &us.gi.size_comment) != UNZ_OK)
+            err = UNZ_ERRNO;
+
+        if (err == UNZ_OK)
+        {
+            /* Search for Zip64 end of central directory header */
+            central_pos64 = unzSearchCentralDir64(&us.z_filefunc, us.filestream, central_pos);
+            if (central_pos64)
+            {
+                central_pos = central_pos64;
+                us.is_zip64 = 1;
+
+                if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+                    err = UNZ_ERRNO;
+
+                /* the signature, already checked */
+                if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* size of zip64 end of central directory record */
+                if (unzReadUInt64(&us.z_filefunc, us.filestream, &value64) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* version made by */
+                if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* version needed to extract */
+                if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* number of this disk */
+                if (unzReadUInt32(&us.z_filefunc, us.filestream, &us.number_disk) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* number of the disk with the start of the central directory */
+                if (unzReadUInt32(&us.z_filefunc, us.filestream, &us.gi.number_disk_with_CD) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* total number of entries in the central directory on this disk */
+                if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* total number of entries in the central directory */
+                if (unzReadUInt64(&us.z_filefunc, us.filestream, &number_entry_CD) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                if (number_entry_CD != us.gi.number_entry)
+                    err = UNZ_BADZIPFILE;
+                /* size of the central directory */
+                if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.size_central_dir) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* offset of start of central directory with respect to the starting disk number */
+                if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK)
+                    err = UNZ_ERRNO;
+            }
+            else if ((us.gi.number_entry == UINT16_MAX) || (us.size_central_dir == UINT16_MAX) || (us.offset_central_dir == UINT32_MAX))
+                err = UNZ_BADZIPFILE;
+        }
+    }
+    else
+        err = UNZ_ERRNO;
+
+    if ((err == UNZ_OK) && (central_pos < us.offset_central_dir + us.size_central_dir))
+        err = UNZ_BADZIPFILE;
+
+    if (err != UNZ_OK)
+    {
+        ZCLOSE64(us.z_filefunc, us.filestream);
+        return NULL;
+    }
+
+    if (us.gi.number_disk_with_CD == 0)
+    {
+        /* If there is only one disk open another stream so we don't have to seek between the CD
+           and the file headers constantly */
+        filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
+        if (filestream != NULL)
+            us.filestream = filestream;
+    }
+
+    /* Hack for zip files that have no respect for zip64
+    if ((central_pos > 0xffffffff) && (us.offset_central_dir < 0xffffffff))
+        us.offset_central_dir = central_pos - us.size_central_dir;*/
+
+    us.byte_before_the_zipfile = central_pos - (us.offset_central_dir + us.size_central_dir);
+    us.central_pos = central_pos;
+    us.pfile_in_zip_read = NULL;
+
+    s = (unz64_internal*)ALLOC(sizeof(unz64_internal));
+    if (s != NULL)
+    {
+        *s = us;
+        unzGoToFirstFile((unzFile)s);
+    }
+    return (unzFile)s;
+}
+
+extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc32_def)
+{
+    if (pzlib_filefunc32_def != NULL)
+    {
+        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+        fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def);
+        return unzOpenInternal(path, &zlib_filefunc64_32_def_fill);
+    }
+    return unzOpenInternal(path, NULL);
+}
+
+extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def)
+{
+    if (pzlib_filefunc_def != NULL)
+    {
+        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+        zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+        zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+        zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+        return unzOpenInternal(path, &zlib_filefunc64_32_def_fill);
+    }
+    return unzOpenInternal(path, NULL);
+}
+
+extern unzFile ZEXPORT unzOpen(const char *path)
+{
+    return unzOpenInternal(path, NULL);
+}
+
+extern unzFile ZEXPORT unzOpen64(const void *path)
+{
+    return unzOpenInternal(path, NULL);
+}
+
+extern int ZEXPORT unzClose(unzFile file)
+{
+    unz64_internal *s;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (s->pfile_in_zip_read != NULL)
+        unzCloseCurrentFile(file);
+
+    if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD))
+        ZCLOSE64(s->z_filefunc, s->filestream);
+    if (s->filestream_with_CD != NULL)
+        ZCLOSE64(s->z_filefunc, s->filestream_with_CD);
+
+    s->filestream = NULL;
+    s->filestream_with_CD = NULL;
+    TRYFREE(s);
+    return UNZ_OK;
+}
+
+/* Goto to the next available disk for spanned archives */
+static int unzGoToNextDisk(unzFile file)
+{
+    unz64_internal *s;
+    uint32_t number_disk_next = 0;
+
+    s = (unz64_internal*)file;
+    if (s == NULL)
+        return UNZ_PARAMERROR;
+    number_disk_next = s->number_disk;
+
+    if ((s->pfile_in_zip_read != NULL) && (s->pfile_in_zip_read->rest_read_uncompressed > 0))
+        /* We are currently reading a file and we need the next sequential disk */
+        number_disk_next += 1;
+    else
+        /* Goto the disk for the current file */
+        number_disk_next = s->cur_file_info.disk_num_start;
+
+    if (number_disk_next != s->number_disk)
+    {
+        /* Switch disks */
+        if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD))
+            ZCLOSE64(s->z_filefunc, s->filestream);
+
+        if (number_disk_next == s->gi.number_disk_with_CD)
+        {
+            s->filestream = s->filestream_with_CD;
+        }
+        else
+        {
+            s->filestream = ZOPENDISK64(s->z_filefunc, s->filestream_with_CD, number_disk_next,
+                ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
+        }
+
+        if (s->filestream == NULL)
+            return UNZ_ERRNO;
+
+        s->number_disk = number_disk_next;
+    }
+
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32)
+{
+    unz64_internal *s = NULL;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    pglobal_info32->number_entry = (uint32_t)s->gi.number_entry;
+    pglobal_info32->size_comment = s->gi.size_comment;
+    pglobal_info32->number_disk_with_CD = s->gi.number_disk_with_CD;
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info)
+{
+    unz64_internal *s = NULL;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    *pglobal_info = s->gi;
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size)
+{
+    unz64_internal *s = NULL;
+    uint16_t bytes_to_read = comment_size;
+    if (file == NULL)
+        return (int)UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (bytes_to_read > s->gi.size_comment)
+        bytes_to_read = s->gi.size_comment;
+
+    if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, s->central_pos + 22, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return UNZ_ERRNO;
+
+    if (bytes_to_read > 0)
+    {
+        *comment = 0;
+        if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, bytes_to_read) != bytes_to_read)
+            return UNZ_ERRNO;
+    }
+
+    if ((comment != NULL) && (comment_size > s->gi.size_comment))
+        *(comment + s->gi.size_comment) = 0;
+
+    return (int)bytes_to_read;
+}
+
+static int unzGetCurrentFileInfoField(unzFile file, uint32_t *seek, void *field, uint16_t field_size, uint16_t size_file_field, int null_terminated_field)
+{
+    unz64_internal *s = NULL;
+    uint32_t bytes_to_read = 0;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return (int)UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    /* Read field */
+    if (field != NULL)
+    {
+        if (size_file_field < field_size)
+        {
+            if (null_terminated_field)
+                *((char *)field+size_file_field) = 0;
+
+            bytes_to_read = size_file_field;
+        }
+        else
+            bytes_to_read = field_size;
+        
+        if (*seek != 0)
+        {
+            if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, *seek, ZLIB_FILEFUNC_SEEK_CUR) == 0)
+                *seek = 0;
+            else
+                err = UNZ_ERRNO;
+        }
+        
+        if ((size_file_field > 0) && (field_size > 0))
+        {
+            if (ZREAD64(s->z_filefunc, s->filestream_with_CD, field, bytes_to_read) != bytes_to_read)
+                err = UNZ_ERRNO;
+        }
+        *seek += size_file_field - bytes_to_read;
+    }
+    else
+    {
+        *seek += size_file_field;
+    }
+
+    return err;
+}
+
+/* Get info about the current file in the zipfile, with internal only info */
+static int unzGetCurrentFileInfoInternal(unzFile file, unz_file_info64 *pfile_info,
+    unz_file_info64_internal *pfile_info_internal, char *filename, uint16_t filename_size, void *extrafield,
+    uint16_t extrafield_size, char *comment, uint16_t comment_size)
+{
+    unz64_internal *s = NULL;
+    unz_file_info64 file_info;
+    unz_file_info64_internal file_info_internal;
+    uint32_t magic = 0;
+    uint64_t current_pos = 0;
+    uint32_t seek = 0;
+    uint32_t extra_pos = 0;
+    uint16_t extra_header_id = 0;
+    uint16_t extra_data_size = 0;
+    uint16_t value16 = 0;
+    uint32_t value32 = 0;
+    uint64_t value64 = 0;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,
+            s->pos_in_central_dir + s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        err = UNZ_ERRNO;
+
+    /* Check the magic */
+    if (err == UNZ_OK)
+    {
+        if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &magic) != UNZ_OK)
+            err = UNZ_ERRNO;
+        else if (magic != CENTRALHEADERMAGIC)
+            err = UNZ_BADZIPFILE;
+    }
+
+    /* Read central directory header */
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.version) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.version_needed) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.flag) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.compression_method) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.dos_date) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.crc) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
+        err = UNZ_ERRNO;
+    file_info.compressed_size = value32;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
+        err = UNZ_ERRNO;
+    file_info.uncompressed_size = value32;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_filename) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_extra) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_comment) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
+        err = UNZ_ERRNO;
+    file_info.disk_num_start = value16;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.internal_fa) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.external_fa) != UNZ_OK)
+        err = UNZ_ERRNO;
+    /* Relative offset of local header */
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
+        err = UNZ_ERRNO;
+
+    file_info.size_file_extra_internal = 0;
+    file_info.disk_offset = value32;
+    file_info_internal.offset_curfile = value32;
+#ifdef HAVE_AES
+    file_info_internal.aes_compression_method = 0;
+    file_info_internal.aes_encryption_mode = 0;
+    file_info_internal.aes_version = 0;
+#endif
+
+    if (err == UNZ_OK)
+        err = unzGetCurrentFileInfoField(file, &seek, filename, filename_size, file_info.size_filename, 1);
+
+    /* Read extrafield */
+    if (err == UNZ_OK)
+        err = unzGetCurrentFileInfoField(file, &seek, extrafield, extrafield_size, file_info.size_file_extra, 0);
+
+    if ((err == UNZ_OK) && (file_info.size_file_extra != 0))
+    {
+        if (seek != 0)
+        {
+            if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, seek, ZLIB_FILEFUNC_SEEK_CUR) == 0)
+                seek = 0;
+            else
+                err = UNZ_ERRNO;
+        }
+
+        /* We are going to parse the extra field so we need to move back */
+        current_pos = ZTELL64(s->z_filefunc, s->filestream_with_CD);
+        if (current_pos < file_info.size_file_extra)
+            err = UNZ_ERRNO;
+        current_pos -= file_info.size_file_extra;
+        if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, current_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+            err = UNZ_ERRNO;
+
+        while ((err != UNZ_ERRNO) && (extra_pos < file_info.size_file_extra))
+        {
+            if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &extra_header_id) != UNZ_OK)
+                err = UNZ_ERRNO;
+            if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &extra_data_size) != UNZ_OK)
+                err = UNZ_ERRNO;
+
+            /* ZIP64 extra fields */
+            if (extra_header_id == 0x0001)
+            {
+                /* Subtract size of ZIP64 field, since ZIP64 is handled internally */
+                file_info.size_file_extra_internal += 2 + 2 + extra_data_size;
+
+                if (file_info.uncompressed_size == UINT32_MAX)
+                {
+                    if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &file_info.uncompressed_size) != UNZ_OK)
+                        err = UNZ_ERRNO;
+                }
+                if (file_info.compressed_size == UINT32_MAX)
+                {
+                    if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &file_info.compressed_size) != UNZ_OK)
+                        err = UNZ_ERRNO;
+                }
+                if (file_info_internal.offset_curfile == UINT32_MAX)
+                {
+                    /* Relative Header offset */
+                    if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &value64) != UNZ_OK)
+                        err = UNZ_ERRNO;
+                    file_info_internal.offset_curfile = value64;
+                    file_info.disk_offset = value64;
+                }
+                if (file_info.disk_num_start == UINT32_MAX)
+                {
+                    /* Disk Start Number */
+                    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK)
+                        err = UNZ_ERRNO;
+                }
+            }
+#ifdef HAVE_AES
+            /* AES header */
+            else if (extra_header_id == 0x9901)
+            {
+                uint8_t value8 = 0;
+
+                /* Subtract size of AES field, since AES is handled internally */
+                file_info.size_file_extra_internal += 2 + 2 + extra_data_size;
+
+                /* Verify version info */
+                if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* Support AE-1 and AE-2 */
+                if (value16 != 1 && value16 != 2)
+                    err = UNZ_ERRNO;
+                file_info_internal.aes_version = value16;
+                if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                if ((char)value8 != 'A')
+                    err = UNZ_ERRNO;
+                if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                if ((char)value8 != 'E')
+                    err = UNZ_ERRNO;
+                /* Get AES encryption strength and actual compression method */
+                if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                file_info_internal.aes_encryption_mode = value8;
+                if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                file_info_internal.aes_compression_method = value16;
+            }
+#endif
+            else
+            {
+                if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,extra_data_size, ZLIB_FILEFUNC_SEEK_CUR) != 0)
+                    err = UNZ_ERRNO;
+            }
+
+            extra_pos += 2 + 2 + extra_data_size;
+        }
+    }
+
+    if (file_info.disk_num_start == s->gi.number_disk_with_CD)
+        file_info_internal.byte_before_the_zipfile = s->byte_before_the_zipfile;
+    else
+        file_info_internal.byte_before_the_zipfile = 0;
+
+    if (err == UNZ_OK)
+        err = unzGetCurrentFileInfoField(file, &seek, comment, comment_size, file_info.size_file_comment, 1);
+
+    if ((err == UNZ_OK) && (pfile_info != NULL))
+        *pfile_info = file_info;
+    if ((err == UNZ_OK) && (pfile_info_internal != NULL))
+        *pfile_info_internal = file_info_internal;
+
+    return err;
+}
+
+extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
+{
+    unz_file_info64 file_info64;
+    int err = UNZ_OK;
+
+    err = unzGetCurrentFileInfoInternal(file, &file_info64, NULL, filename, filename_size,
+                extrafield, extrafield_size, comment, comment_size);
+
+    if ((err == UNZ_OK) && (pfile_info != NULL))
+    {
+        pfile_info->version = file_info64.version;
+        pfile_info->version_needed = file_info64.version_needed;
+        pfile_info->flag = file_info64.flag;
+        pfile_info->compression_method = file_info64.compression_method;
+        pfile_info->dos_date = file_info64.dos_date;
+        pfile_info->crc = file_info64.crc;
+
+        pfile_info->size_filename = file_info64.size_filename;
+        pfile_info->size_file_extra = file_info64.size_file_extra - file_info64.size_file_extra_internal;
+        pfile_info->size_file_comment = file_info64.size_file_comment;
+
+        pfile_info->disk_num_start = (uint16_t)file_info64.disk_num_start;
+        pfile_info->internal_fa = file_info64.internal_fa;
+        pfile_info->external_fa = file_info64.external_fa;
+
+        pfile_info->compressed_size = (uint32_t)file_info64.compressed_size;
+        pfile_info->uncompressed_size = (uint32_t)file_info64.uncompressed_size;
+    }
+    return err;
+}
+
+extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
+{
+    return unzGetCurrentFileInfoInternal(file, pfile_info, NULL, filename, filename_size,
+        extrafield, extrafield_size, comment,comment_size);
+}
+
+/* Read the local header of the current zipfile. Check the coherency of the local header and info in the
+   end of central directory about this file store in *piSizeVar the size of extra info in local header
+   (filename and size of extra field data) */
+static int unzCheckCurrentFileCoherencyHeader(unz64_internal *s, uint32_t *psize_variable, uint64_t *poffset_local_extrafield,
+    uint16_t *psize_local_extrafield)
+{
+    uint32_t magic = 0;
+    uint16_t value16 = 0;
+    uint32_t value32 = 0;
+    uint32_t flags = 0;
+    uint16_t size_filename = 0;
+    uint16_t size_extra_field = 0;
+    uint16_t compression_method = 0;
+    int err = UNZ_OK;
+
+    if (psize_variable == NULL)
+        return UNZ_PARAMERROR;
+    *psize_variable = 0;
+    if (poffset_local_extrafield == NULL)
+        return UNZ_PARAMERROR;
+    *poffset_local_extrafield = 0;
+    if (psize_local_extrafield == NULL)
+        return UNZ_PARAMERROR;
+    *psize_local_extrafield = 0;
+
+    err = unzGoToNextDisk((unzFile)s);
+    if (err != UNZ_OK)
+        return err;
+
+    if (ZSEEK64(s->z_filefunc, s->filestream, s->cur_file_info_internal.offset_curfile +
+        s->cur_file_info_internal.byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return UNZ_ERRNO;
+
+    if (err == UNZ_OK)
+    {
+        if (unzReadUInt32(&s->z_filefunc, s->filestream, &magic) != UNZ_OK)
+            err = UNZ_ERRNO;
+        else if (magic != LOCALHEADERMAGIC)
+            err = UNZ_BADZIPFILE;
+    }
+
+    if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
+        err = UNZ_ERRNO;
+    flags = value16;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
+        err = UNZ_ERRNO;
+    else if ((err == UNZ_OK) && (value16 != s->cur_file_info.compression_method))
+        err = UNZ_BADZIPFILE;
+
+    compression_method = s->cur_file_info.compression_method;
+#ifdef HAVE_AES
+    if (compression_method == AES_METHOD)
+        compression_method = s->cur_file_info_internal.aes_compression_method;
+#endif
+
+    if ((err == UNZ_OK) && (compression_method != 0) && (compression_method != Z_DEFLATED))
+    {
+#ifdef HAVE_BZIP2
+        if (compression_method != Z_BZIP2ED)
+#endif
+            err = UNZ_BADZIPFILE;
+    }
+
+    if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* date/time */
+        err = UNZ_ERRNO;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* crc */
+        err = UNZ_ERRNO;
+    else if ((err == UNZ_OK) && (value32 != s->cur_file_info.crc) && ((flags & 8) == 0))
+        err = UNZ_BADZIPFILE;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* size compr */
+        err = UNZ_ERRNO;
+    else if ((value32 != UINT32_MAX) && (err == UNZ_OK) && (value32 != s->cur_file_info.compressed_size) && ((flags & 8) == 0))
+        err = UNZ_BADZIPFILE;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* size uncompr */
+        err = UNZ_ERRNO;
+    else if ((value32 != UINT32_MAX) && (err == UNZ_OK) && (value32 != s->cur_file_info.uncompressed_size) && ((flags & 8) == 0))
+        err = UNZ_BADZIPFILE;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream, &size_filename) != UNZ_OK)
+        err = UNZ_ERRNO;
+
+    *psize_variable += size_filename;
+
+    if (unzReadUInt16(&s->z_filefunc, s->filestream, &size_extra_field) != UNZ_OK)
+        err = UNZ_ERRNO;
+
+    *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename;
+    *psize_local_extrafield = size_extra_field;
+    *psize_variable += size_extra_field;
+
+    return err;
+}
+
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password)
+{
+    unz64_internal *s = NULL;
+    file_in_zip64_read_info_s *pfile_in_zip_read_info = NULL;
+    uint16_t compression_method = 0;
+    uint64_t offset_local_extrafield = 0;
+    uint16_t size_local_extrafield = 0;
+    uint32_t size_variable = 0;
+    int err = UNZ_OK;
+#ifndef NOUNCRYPT
+    char source[12];
+#else
+    if (password != NULL)
+        return UNZ_PARAMERROR;
+#endif
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (!s->current_file_ok)
+        return UNZ_PARAMERROR;
+
+    if (s->pfile_in_zip_read != NULL)
+        unzCloseCurrentFile(file);
+
+    if (unzCheckCurrentFileCoherencyHeader(s, &size_variable, &offset_local_extrafield, &size_local_extrafield) != UNZ_OK)
+        return UNZ_BADZIPFILE;
+    
+    compression_method = s->cur_file_info.compression_method;
+#ifdef HAVE_AES
+    if (compression_method == AES_METHOD)
+    {
+        compression_method = s->cur_file_info_internal.aes_compression_method;
+        if (password == NULL)
+        {
+            return UNZ_PARAMERROR;
+        }
+    }
+#endif
+
+    if (method != NULL)
+        *method = compression_method;
+
+    if (level != NULL)
+    {
+        *level = 6;
+        switch (s->cur_file_info.flag & 0x06)
+        {
+          case 6 : *level = 1; break;
+          case 4 : *level = 2; break;
+          case 2 : *level = 9; break;
+        }
+    }
+
+    if ((compression_method != 0) && (compression_method != Z_DEFLATED))
+    {
+#ifdef HAVE_BZIP2
+        if (compression_method != Z_BZIP2ED)
+#endif
+        {
+            return UNZ_BADZIPFILE;
+        }
+    }
+    
+    pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
+    if (pfile_in_zip_read_info == NULL)
+        return UNZ_INTERNALERROR;
+
+    pfile_in_zip_read_info->read_buffer = (uint8_t*)ALLOC(UNZ_BUFSIZE);
+    if (pfile_in_zip_read_info->read_buffer == NULL)
+    {
+        TRYFREE(pfile_in_zip_read_info);
+        return UNZ_INTERNALERROR;
+    }
+    
+    pfile_in_zip_read_info->stream_initialised = 0;
+
+    pfile_in_zip_read_info->filestream = s->filestream;
+    pfile_in_zip_read_info->z_filefunc = s->z_filefunc;
+
+    pfile_in_zip_read_info->raw = raw;
+    pfile_in_zip_read_info->crc32 = 0;
+    pfile_in_zip_read_info->crc32_expected = s->cur_file_info.crc;
+    pfile_in_zip_read_info->total_out_64 = 0;
+    pfile_in_zip_read_info->compression_method = compression_method;
+    
+    pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+    pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+    pfile_in_zip_read_info->pos_local_extrafield = 0;
+
+    pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size;
+    pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size;
+    pfile_in_zip_read_info->byte_before_the_zipfile = 0;
+
+    if (s->number_disk == s->gi.number_disk_with_CD)
+        pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile;
+        
+    pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_variable;
+
+    pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+    pfile_in_zip_read_info->stream.zfree = (free_func)0;
+    pfile_in_zip_read_info->stream.opaque = (voidpf)s;
+    pfile_in_zip_read_info->stream.total_out = 0;
+    pfile_in_zip_read_info->stream.total_in = 0;
+    pfile_in_zip_read_info->stream.next_in = NULL;
+    pfile_in_zip_read_info->stream.avail_in = 0;
+
+    if (!raw)
+    {
+        if (compression_method == Z_BZIP2ED)
+        {
+#ifdef HAVE_BZIP2
+            pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
+            pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
+            pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
+            pfile_in_zip_read_info->bstream.state = (voidpf)0;
+
+            err = BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
+            if (err == Z_OK)
+            {
+                pfile_in_zip_read_info->stream_initialised = Z_BZIP2ED;
+            }
+            else
+            {
+                TRYFREE(pfile_in_zip_read_info);
+                return err;
+            }
+#else
+            pfile_in_zip_read_info->raw = 1;
+#endif
+        }
+        else if (compression_method == Z_DEFLATED)
+        {
+#ifdef HAVE_APPLE_COMPRESSION
+            err = compression_stream_init(&pfile_in_zip_read_info->astream, COMPRESSION_STREAM_DECODE, COMPRESSION_ZLIB);
+            if (err == COMPRESSION_STATUS_ERROR)
+                err = UNZ_INTERNALERROR;
+            else
+                err = Z_OK;
+#else
+            err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+#endif
+            if (err == Z_OK)
+            {
+                pfile_in_zip_read_info->stream_initialised = Z_DEFLATED;
+            }
+            else
+            {
+                TRYFREE(pfile_in_zip_read_info);
+                return err;
+            }
+            /* windowBits is passed < 0 to tell that there is no zlib header.
+             * Note that in this case inflate *requires* an extra "dummy" byte
+             * after the compressed stream in order to complete decompression and
+             * return Z_STREAM_END.
+             * In unzip, i don't wait absolutely Z_STREAM_END because I known the
+             * size of both compressed and uncompressed data
+             */
+        }
+    }
+
+    s->pfile_in_zip_read = pfile_in_zip_read_info;
+
+#ifndef NOUNCRYPT
+    s->pcrc_32_tab = NULL;
+
+    if ((password != NULL) && ((s->cur_file_info.flag & 1) != 0))
+    {
+        if (ZSEEK64(s->z_filefunc, s->filestream,
+                  s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile,
+                  ZLIB_FILEFUNC_SEEK_SET) != 0)
+            return UNZ_INTERNALERROR;
+#ifdef HAVE_AES
+        if (s->cur_file_info.compression_method == AES_METHOD)
+        {
+            unsigned char passverify_archive[AES_PWVERIFYSIZE];
+            unsigned char passverify_password[AES_PWVERIFYSIZE];
+            unsigned char salt_value[AES_MAXSALTLENGTH];
+            uint32_t salt_length = 0;
+
+            if ((s->cur_file_info_internal.aes_encryption_mode < 1) ||
+                (s->cur_file_info_internal.aes_encryption_mode > 3))
+                return UNZ_INTERNALERROR;
+
+            salt_length = SALT_LENGTH(s->cur_file_info_internal.aes_encryption_mode);
+
+            if (ZREAD64(s->z_filefunc, s->filestream, salt_value, salt_length) != salt_length)
+                return UNZ_INTERNALERROR;
+            if (ZREAD64(s->z_filefunc, s->filestream, passverify_archive, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE)
+                return UNZ_INTERNALERROR;
+
+            fcrypt_init(s->cur_file_info_internal.aes_encryption_mode, (uint8_t *)password,
+                (uint32_t)strlen(password), salt_value, passverify_password, &s->pfile_in_zip_read->aes_ctx);
+
+            if (memcmp(passverify_archive, passverify_password, AES_PWVERIFYSIZE) != 0)
+                return UNZ_BADPASSWORD;
+
+            s->pfile_in_zip_read->rest_read_compressed -= salt_length + AES_PWVERIFYSIZE;
+            s->pfile_in_zip_read->rest_read_compressed -= AES_AUTHCODESIZE;
+
+            s->pfile_in_zip_read->pos_in_zipfile += salt_length + AES_PWVERIFYSIZE;
+        }
+        else
+#endif
+        {
+            int i;
+            s->pcrc_32_tab = (const z_crc_t*)get_crc_table();
+            init_keys(password, s->keys, s->pcrc_32_tab);
+
+            if (ZREAD64(s->z_filefunc, s->filestream, source, 12) < 12)
+                return UNZ_INTERNALERROR;
+
+            for (i = 0; i < 12; i++)
+                zdecode(s->keys, s->pcrc_32_tab, source[i]);
+
+            s->pfile_in_zip_read->rest_read_compressed -= 12;
+            s->pfile_in_zip_read->pos_in_zipfile += 12;
+        }
+    }
+#endif
+
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzOpenCurrentFile(unzFile file)
+{
+    return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
+}
+
+extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password)
+{
+    return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
+}
+
+extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw)
+{
+    return unzOpenCurrentFile3(file, method, level, raw, NULL);
+}
+
+/* Read bytes from the current file.
+   buf contain buffer where data must be copied
+   len the size of buf.
+
+   return the number of byte copied if some bytes are copied
+   return 0 if the end of file was reached
+   return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */
+extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, uint32_t len)
+{
+    unz64_internal *s = NULL;
+    uint32_t read = 0;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_PARAMERROR;
+    if (s->pfile_in_zip_read->read_buffer == NULL)
+        return UNZ_END_OF_LIST_OF_FILE;
+    if (len == 0)
+        return 0;
+    if (len > UINT16_MAX)
+        return UNZ_PARAMERROR;
+
+    s->pfile_in_zip_read->stream.next_out = (uint8_t*)buf;
+    s->pfile_in_zip_read->stream.avail_out = (uint16_t)len;
+
+    if (s->pfile_in_zip_read->raw)
+    {
+        if (len > s->pfile_in_zip_read->rest_read_compressed + s->pfile_in_zip_read->stream.avail_in)
+            s->pfile_in_zip_read->stream.avail_out = (uint16_t)s->pfile_in_zip_read->rest_read_compressed +
+                s->pfile_in_zip_read->stream.avail_in;
+    }
+    else
+    {
+        if (len > s->pfile_in_zip_read->rest_read_uncompressed)
+            s->pfile_in_zip_read->stream.avail_out = (uint16_t)s->pfile_in_zip_read->rest_read_uncompressed;
+    }
+
+    do
+    {
+        if (s->pfile_in_zip_read->stream.avail_in == 0)
+        {
+            uint32_t bytes_to_read = UNZ_BUFSIZE;
+            uint32_t bytes_not_read = 0;
+            uint32_t bytes_read = 0;
+            uint32_t total_bytes_read = 0;
+
+            if (s->pfile_in_zip_read->stream.next_in != NULL)
+                bytes_not_read = (uint32_t)(s->pfile_in_zip_read->read_buffer + UNZ_BUFSIZE -
+                    s->pfile_in_zip_read->stream.next_in);
+            bytes_to_read -= bytes_not_read;
+            if (bytes_not_read > 0)
+                memcpy(s->pfile_in_zip_read->read_buffer, s->pfile_in_zip_read->stream.next_in, bytes_not_read);
+            if (s->pfile_in_zip_read->rest_read_compressed < bytes_to_read)
+                bytes_to_read = (uint16_t)s->pfile_in_zip_read->rest_read_compressed;
+
+            while (total_bytes_read != bytes_to_read)
+            {
+                if (ZSEEK64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
+                        s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile,
+                        ZLIB_FILEFUNC_SEEK_SET) != 0)
+                    return UNZ_ERRNO;
+
+                bytes_read = ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
+                          s->pfile_in_zip_read->read_buffer + bytes_not_read + total_bytes_read,
+                          bytes_to_read - total_bytes_read);
+
+                total_bytes_read += bytes_read;
+                s->pfile_in_zip_read->pos_in_zipfile += bytes_read;
+
+                if (bytes_read == 0)
+                {
+                    if (ZERROR64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream))
+                        return UNZ_ERRNO;
+
+                    err = unzGoToNextDisk(file);
+                    if (err != UNZ_OK)
+                        return err;
+
+                    s->pfile_in_zip_read->pos_in_zipfile = 0;
+                    s->pfile_in_zip_read->filestream = s->filestream;
+                }
+            }
+
+#ifndef NOUNCRYPT
+            if ((s->cur_file_info.flag & 1) != 0)
+            {
+#ifdef HAVE_AES
+                if (s->cur_file_info.compression_method == AES_METHOD)
+                {
+                    fcrypt_decrypt(s->pfile_in_zip_read->read_buffer, bytes_to_read, &s->pfile_in_zip_read->aes_ctx);
+                }
+                else
+#endif
+                if (s->pcrc_32_tab != NULL)
+                {
+                    uint32_t i = 0;
+
+                    for (i = 0; i < total_bytes_read; i++)
+                      s->pfile_in_zip_read->read_buffer[i] =
+                          zdecode(s->keys, s->pcrc_32_tab, s->pfile_in_zip_read->read_buffer[i]);
+                }
+            }
+#endif
+
+            s->pfile_in_zip_read->rest_read_compressed -= total_bytes_read;
+            s->pfile_in_zip_read->stream.next_in = (uint8_t*)s->pfile_in_zip_read->read_buffer;
+            s->pfile_in_zip_read->stream.avail_in = (uint16_t)(bytes_not_read + total_bytes_read);
+        }
+
+        if ((s->pfile_in_zip_read->compression_method == 0) || (s->pfile_in_zip_read->raw))
+        {
+            uint32_t i = 0;
+            uint32_t copy = 0;
+
+            if ((s->pfile_in_zip_read->stream.avail_in == 0) &&
+                (s->pfile_in_zip_read->rest_read_compressed == 0))
+                return (read == 0) ? UNZ_EOF : read;
+
+            if (s->pfile_in_zip_read->stream.avail_out < s->pfile_in_zip_read->stream.avail_in)
+                copy = s->pfile_in_zip_read->stream.avail_out;
+            else
+                copy = s->pfile_in_zip_read->stream.avail_in;
+
+            for (i = 0; i < copy; i++)
+                *(s->pfile_in_zip_read->stream.next_out + i) =
+                        *(s->pfile_in_zip_read->stream.next_in + i);
+
+            s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + copy;
+            s->pfile_in_zip_read->rest_read_uncompressed -= copy;
+            s->pfile_in_zip_read->crc32 = (uint32_t)crc32(s->pfile_in_zip_read->crc32,
+                                s->pfile_in_zip_read->stream.next_out, copy);
+
+            s->pfile_in_zip_read->stream.avail_in -= copy;
+            s->pfile_in_zip_read->stream.avail_out -= copy;
+            s->pfile_in_zip_read->stream.next_out += copy;
+            s->pfile_in_zip_read->stream.next_in += copy;
+            s->pfile_in_zip_read->stream.total_out += copy;
+
+            read += copy;
+        }
+        else if (s->pfile_in_zip_read->compression_method == Z_BZIP2ED)
+        {
+#ifdef HAVE_BZIP2
+            uint64_t total_out_before = 0;
+            uint64_t total_out_after = 0;
+            uint64_t out_bytes = 0;
+            const uint8_t *buf_before = NULL;
+
+            s->pfile_in_zip_read->bstream.next_in        = (char*)s->pfile_in_zip_read->stream.next_in;
+            s->pfile_in_zip_read->bstream.avail_in       = s->pfile_in_zip_read->stream.avail_in;
+            s->pfile_in_zip_read->bstream.total_in_lo32  = (uint32_t)s->pfile_in_zip_read->stream.total_in;
+            s->pfile_in_zip_read->bstream.total_in_hi32  = s->pfile_in_zip_read->stream.total_in >> 32;
+            
+            s->pfile_in_zip_read->bstream.next_out       = (char*)s->pfile_in_zip_read->stream.next_out;
+            s->pfile_in_zip_read->bstream.avail_out      = s->pfile_in_zip_read->stream.avail_out;
+            s->pfile_in_zip_read->bstream.total_out_lo32 = (uint32_t)s->pfile_in_zip_read->stream.total_out;
+            s->pfile_in_zip_read->bstream.total_out_hi32 = s->pfile_in_zip_read->stream.total_out >> 32;
+
+            total_out_before = s->pfile_in_zip_read->bstream.total_out_lo32 + 
+                (((uint32_t)s->pfile_in_zip_read->bstream.total_out_hi32) << 32);
+            buf_before = (const uint8_t*)s->pfile_in_zip_read->bstream.next_out;
+
+            err = BZ2_bzDecompress(&s->pfile_in_zip_read->bstream);
+
+            total_out_after = s->pfile_in_zip_read->bstream.total_out_lo32 + 
+                (((uint32_t)s->pfile_in_zip_read->bstream.total_out_hi32) << 32);
+
+            out_bytes = total_out_after - total_out_before;
+
+            s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + out_bytes;
+            s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
+            s->pfile_in_zip_read->crc32 = crc32(s->pfile_in_zip_read->crc32, buf_before, (uint32_t)out_bytes);
+
+            read += (uint32_t)out_bytes;
+
+            s->pfile_in_zip_read->stream.next_in   = (uint8_t*)s->pfile_in_zip_read->bstream.next_in;
+            s->pfile_in_zip_read->stream.avail_in  = s->pfile_in_zip_read->bstream.avail_in;
+            s->pfile_in_zip_read->stream.total_in  = s->pfile_in_zip_read->bstream.total_in_lo32;
+            s->pfile_in_zip_read->stream.next_out  = (uint8_t*)s->pfile_in_zip_read->bstream.next_out;
+            s->pfile_in_zip_read->stream.avail_out = s->pfile_in_zip_read->bstream.avail_out;
+            s->pfile_in_zip_read->stream.total_out = s->pfile_in_zip_read->bstream.total_out_lo32;
+
+            if (err == BZ_STREAM_END)
+                return (read == 0) ? UNZ_EOF : read;
+            if (err != BZ_OK)
+                break;
+#endif
+        }
+#ifdef HAVE_APPLE_COMPRESSION
+        else
+        {
+            uint64_t total_out_before = 0;
+            uint64_t total_out_after = 0;
+            uint64_t out_bytes = 0;
+            const uint8_t *buf_before = NULL;
+
+            s->pfile_in_zip_read->astream.src_ptr = s->pfile_in_zip_read->stream.next_in;
+            s->pfile_in_zip_read->astream.src_size = s->pfile_in_zip_read->stream.avail_in;
+            s->pfile_in_zip_read->astream.dst_ptr = s->pfile_in_zip_read->stream.next_out;
+            s->pfile_in_zip_read->astream.dst_size = len;
+
+            total_out_before = s->pfile_in_zip_read->stream.total_out;
+            buf_before = s->pfile_in_zip_read->stream.next_out;
+
+            compression_status status;
+            compression_stream_flags flags;
+
+            if (s->pfile_in_zip_read->stream.avail_in == 0)
+            {
+                flags = COMPRESSION_STREAM_FINALIZE;
+            }
+
+            status = compression_stream_process(&s->pfile_in_zip_read->astream, flags);
+
+            total_out_after = len - s->pfile_in_zip_read->astream.dst_size;
+            out_bytes = total_out_after - total_out_before;
+
+            s->pfile_in_zip_read->total_out_64 += out_bytes;
+            s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
+            s->pfile_in_zip_read->crc32 =
+                crc32(s->pfile_in_zip_read->crc32, buf_before, (uint32_t)out_bytes);
+
+            read += (uint32_t)out_bytes;
+
+            s->pfile_in_zip_read->stream.next_in = s->pfile_in_zip_read->astream.src_ptr;
+            s->pfile_in_zip_read->stream.avail_in = s->pfile_in_zip_read->astream.src_size;
+            s->pfile_in_zip_read->stream.next_out = s->pfile_in_zip_read->astream.dst_ptr;
+            s->pfile_in_zip_read->stream.avail_out = s->pfile_in_zip_read->astream.dst_size;
+
+            if (status == COMPRESSION_STATUS_END)
+                return (read == 0) ? UNZ_EOF : read;
+            if (status == COMPRESSION_STATUS_ERROR)
+                return Z_DATA_ERROR;
+            return read;
+        }
+#else
+        else
+        {
+            uint64_t total_out_before = 0;
+            uint64_t total_out_after = 0;
+            uint64_t out_bytes = 0;
+            const uint8_t *buf_before = NULL;
+            int flush = Z_SYNC_FLUSH;
+
+            total_out_before = s->pfile_in_zip_read->stream.total_out;
+            buf_before = s->pfile_in_zip_read->stream.next_out;
+
+            /*
+            if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+                     pfile_in_zip_read_info->stream.avail_out) &&
+                (pfile_in_zip_read_info->rest_read_compressed == 0))
+                flush = Z_FINISH;
+            */
+            err = inflate(&s->pfile_in_zip_read->stream, flush);
+
+            if ((err >= 0) && (s->pfile_in_zip_read->stream.msg != NULL))
+                err = Z_DATA_ERROR;
+
+            total_out_after = s->pfile_in_zip_read->stream.total_out;
+            out_bytes = total_out_after - total_out_before;
+
+            s->pfile_in_zip_read->total_out_64 += out_bytes;
+            s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
+            s->pfile_in_zip_read->crc32 =
+                (uint32_t)crc32(s->pfile_in_zip_read->crc32,buf_before, (uint32_t)out_bytes);
+
+            read += (uint32_t)out_bytes;
+
+            if (err == Z_STREAM_END)
+                return (read == 0) ? UNZ_EOF : read;
+            if (err != Z_OK)
+                break;
+        }
+#endif
+    }
+    while (s->pfile_in_zip_read->stream.avail_out > 0);
+
+    if (err == Z_OK)
+        return read;
+    return err;
+}
+
+extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, uint32_t len)
+{
+    unz64_internal *s = NULL;
+    uint64_t size_to_read = 0;
+    uint32_t read_now = 0;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_PARAMERROR;
+
+    size_to_read = s->pfile_in_zip_read->size_local_extrafield - s->pfile_in_zip_read->pos_local_extrafield;
+
+    if (buf == NULL)
+        return (int)size_to_read;
+
+    if (len > size_to_read)
+        read_now = (uint32_t)size_to_read;
+    else
+        read_now = len;
+
+    if (read_now == 0)
+        return 0;
+
+    if (ZSEEK64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
+        s->pfile_in_zip_read->offset_local_extrafield + s->pfile_in_zip_read->pos_local_extrafield,
+        ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return UNZ_ERRNO;
+
+    if (ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream, buf, read_now) != read_now)
+        return UNZ_ERRNO;
+
+    return (int)read_now;
+}
+
+extern int ZEXPORT unzCloseCurrentFile(unzFile file)
+{
+    unz64_internal *s = NULL;
+    file_in_zip64_read_info_s *pfile_in_zip_read_info = NULL;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    pfile_in_zip_read_info = s->pfile_in_zip_read;
+    if (pfile_in_zip_read_info == NULL)
+        return UNZ_PARAMERROR;
+
+#ifdef HAVE_AES
+    if (s->cur_file_info.compression_method == AES_METHOD)
+    {
+        unsigned char authcode[AES_AUTHCODESIZE];
+        unsigned char rauthcode[AES_AUTHCODESIZE];
+
+        if (ZREAD64(s->z_filefunc, s->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE)
+            return UNZ_ERRNO;
+
+        if (fcrypt_end(rauthcode, &s->pfile_in_zip_read->aes_ctx) != AES_AUTHCODESIZE)
+            err = UNZ_CRCERROR;
+        if (memcmp(authcode, rauthcode, AES_AUTHCODESIZE) != 0)
+            err = UNZ_CRCERROR;
+    }
+    /* AES zip version AE-1 will expect a valid crc as well */
+    if ((s->cur_file_info.compression_method != AES_METHOD) ||
+        (s->cur_file_info_internal.aes_version == 0x0001))
+#endif
+    {
+        if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
+            (!pfile_in_zip_read_info->raw))
+        {
+            if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_expected)
+                err = UNZ_CRCERROR;
+        }
+    }
+
+    TRYFREE(pfile_in_zip_read_info->read_buffer);
+    pfile_in_zip_read_info->read_buffer = NULL;
+    if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
+    {
+#ifdef HAVE_APPLE_COMPRESSION
+        if (compression_stream_destroy)
+            compression_stream_destroy(&pfile_in_zip_read_info->astream);
+#else
+        inflateEnd(&pfile_in_zip_read_info->stream);
+#endif
+        
+    }
+#ifdef HAVE_BZIP2
+    else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
+        BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
+#endif
+
+    pfile_in_zip_read_info->stream_initialised = 0;
+    TRYFREE(pfile_in_zip_read_info);
+
+    s->pfile_in_zip_read = NULL;
+
+    return err;
+}
+
+extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
+{
+    unz64_internal *s = NULL;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    s->pos_in_central_dir = s->offset_central_dir;
+    s->num_file = 0;
+
+    err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal,
+            filename, filename_size, extrafield, extrafield_size, comment,comment_size);
+
+    s->current_file_ok = (err == UNZ_OK);
+    if ((err == UNZ_OK) && (pfile_info != NULL))
+        memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64));
+
+    return err;
+}
+
+extern int ZEXPORT unzGoToFirstFile(unzFile file)
+{
+    return unzGoToFirstFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0);
+}
+
+extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
+{
+    unz64_internal *s = NULL;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (!s->current_file_ok)
+        return UNZ_END_OF_LIST_OF_FILE;
+    if (s->gi.number_entry != UINT16_MAX)    /* 2^16 files overflow hack */
+    {
+        if (s->num_file+1 == s->gi.number_entry)
+            return UNZ_END_OF_LIST_OF_FILE;
+    }
+
+    s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+            s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment;
+    s->num_file += 1;
+
+    err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal,
+            filename, filename_size, extrafield,extrafield_size, comment, comment_size);
+
+    s->current_file_ok = (err == UNZ_OK);
+    if ((err == UNZ_OK) && (pfile_info != NULL))
+        memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64));
+
+    return err;
+}
+
+extern int ZEXPORT unzGoToNextFile(unzFile file)
+{
+    return unzGoToNextFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0);
+}
+
+extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func)
+{
+    unz64_internal *s = NULL;
+    unz_file_info64 cur_file_info_saved;
+    unz_file_info64_internal cur_file_info_internal_saved;
+    uint64_t num_file_saved = 0;
+    uint64_t pos_in_central_dir_saved = 0;
+    char current_filename[UNZ_MAXFILENAMEINZIP+1];
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    if (strlen(filename) >= UNZ_MAXFILENAMEINZIP)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (!s->current_file_ok)
+        return UNZ_END_OF_LIST_OF_FILE;
+
+    /* Save the current state */
+    num_file_saved = s->num_file;
+    pos_in_central_dir_saved = s->pos_in_central_dir;
+    cur_file_info_saved = s->cur_file_info;
+    cur_file_info_internal_saved = s->cur_file_info_internal;
+
+    err = unzGoToFirstFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0);
+
+    while (err == UNZ_OK)
+    {
+        if (filename_compare_func != NULL)
+            err = filename_compare_func(file, current_filename, filename);
+        else
+            err = strcmp(current_filename, filename);
+        if (err == 0)
+            return UNZ_OK;
+        err = unzGoToNextFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0);
+    }
+
+    /* We failed, so restore the state of the 'current file' to where we were. */
+    s->num_file = num_file_saved;
+    s->pos_in_central_dir = pos_in_central_dir_saved;
+    s->cur_file_info = cur_file_info_saved;
+    s->cur_file_info_internal = cur_file_info_internal_saved;
+    return err;
+}
+
+extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos *file_pos)
+{
+    unz64_file_pos file_pos64;
+    int err = unzGetFilePos64(file, &file_pos64);
+    if (err == UNZ_OK)
+    {
+        file_pos->pos_in_zip_directory = (uint32_t)file_pos64.pos_in_zip_directory;
+        file_pos->num_of_file = (uint32_t)file_pos64.num_of_file;
+    }
+    return err;
+}
+
+extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos *file_pos)
+{
+    unz64_file_pos file_pos64;
+    if (file_pos == NULL)
+        return UNZ_PARAMERROR;
+    file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
+    file_pos64.num_of_file = file_pos->num_of_file;
+    return unzGoToFilePos64(file, &file_pos64);
+}
+
+extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos *file_pos)
+{
+    unz64_internal *s = NULL;
+
+    if (file == NULL || file_pos == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (!s->current_file_ok)
+        return UNZ_END_OF_LIST_OF_FILE;
+
+    file_pos->pos_in_zip_directory  = s->pos_in_central_dir;
+    file_pos->num_of_file = s->num_file;
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos)
+{
+    unz64_internal *s = NULL;
+    int err = UNZ_OK;
+
+    if (file == NULL || file_pos == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    /* Jump to the right spot */
+    s->pos_in_central_dir = file_pos->pos_in_zip_directory;
+    s->num_file = file_pos->num_of_file;
+
+    /* Set the current file */
+    err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0);
+    /* Return results */
+    s->current_file_ok = (err == UNZ_OK);
+    return err;
+}
+
+extern int32_t ZEXPORT unzGetOffset(unzFile file)
+{
+    uint64_t offset64 = 0;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    offset64 = unzGetOffset64(file);
+    return (int32_t)offset64;
+}
+
+extern int64_t ZEXPORT unzGetOffset64(unzFile file)
+{
+    unz64_internal *s = NULL;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (!s->current_file_ok)
+        return 0;
+    if (s->gi.number_entry != 0 && s->gi.number_entry != UINT16_MAX)
+    {
+        if (s->num_file == s->gi.number_entry)
+            return 0;
+    }
+    return s->pos_in_central_dir;
+}
+
+extern int ZEXPORT unzSetOffset(unzFile file, uint32_t pos)
+{
+    return unzSetOffset64(file, pos);
+}
+
+extern int ZEXPORT unzSetOffset64(unzFile file, uint64_t pos)
+{
+    unz64_internal *s = NULL;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    s->pos_in_central_dir = pos;
+    s->num_file = s->gi.number_entry; /* hack */
+
+    err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0);
+
+    s->current_file_ok = (err == UNZ_OK);
+    return err;
+}
+
+extern int32_t ZEXPORT unzTell(unzFile file)
+{
+    unz64_internal *s = NULL;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_PARAMERROR;
+    return (int32_t)s->pfile_in_zip_read->stream.total_out;
+}
+
+extern int64_t ZEXPORT unzTell64(unzFile file)
+{
+    unz64_internal *s = NULL;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_PARAMERROR;
+    return s->pfile_in_zip_read->total_out_64;
+}
+
+extern int ZEXPORT unzSeek(unzFile file, uint32_t offset, int origin)
+{
+    return unzSeek64(file, offset, origin);
+}
+
+extern int ZEXPORT unzSeek64(unzFile file, uint64_t offset, int origin)
+{
+    unz64_internal *s = NULL;
+    uint64_t stream_pos_begin = 0;
+    uint64_t stream_pos_end = 0;
+    uint64_t position = 0;
+    int is_within_buffer = 0;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_ERRNO;
+    if (s->pfile_in_zip_read->compression_method != 0)
+        return UNZ_ERRNO;
+
+    if (origin == SEEK_SET)
+        position = offset;
+    else if (origin == SEEK_CUR)
+        position = s->pfile_in_zip_read->total_out_64 + offset;
+    else if (origin == SEEK_END)
+        position = s->cur_file_info.compressed_size + offset;
+    else
+        return UNZ_PARAMERROR;
+
+    if (position > s->cur_file_info.compressed_size)
+        return UNZ_PARAMERROR;
+
+    stream_pos_end = s->pfile_in_zip_read->pos_in_zipfile;
+    stream_pos_begin = stream_pos_end;
+
+    if (stream_pos_begin > UNZ_BUFSIZE)
+        stream_pos_begin -= UNZ_BUFSIZE;
+    else
+        stream_pos_begin = 0;
+
+    is_within_buffer = 
+        (s->pfile_in_zip_read->stream.avail_in != 0) &&
+        (s->pfile_in_zip_read->rest_read_compressed != 0 || s->cur_file_info.compressed_size < UNZ_BUFSIZE) &&
+        (position >= stream_pos_begin && position < stream_pos_end);
+
+    if (is_within_buffer)
+    {
+        s->pfile_in_zip_read->stream.next_in += position - s->pfile_in_zip_read->total_out_64;
+        s->pfile_in_zip_read->stream.avail_in = (uInt)(stream_pos_end - position);
+    }
+    else
+    {
+        s->pfile_in_zip_read->stream.avail_in = 0;
+        s->pfile_in_zip_read->stream.next_in = 0;
+
+        s->pfile_in_zip_read->pos_in_zipfile = s->pfile_in_zip_read->offset_local_extrafield + position;
+        s->pfile_in_zip_read->rest_read_compressed = s->cur_file_info.compressed_size - position;
+    }
+
+    s->pfile_in_zip_read->rest_read_uncompressed -= (position - s->pfile_in_zip_read->total_out_64);
+    s->pfile_in_zip_read->stream.total_out = (uint32_t)position;
+    s->pfile_in_zip_read->total_out_64 = position;
+
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzEndOfFile(unzFile file)
+{
+    unz64_internal *s = NULL;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_PARAMERROR;
+    if (s->pfile_in_zip_read->rest_read_uncompressed == 0)
+        return 1;
+    return 0;
+}

+ 252 - 0
ios/Classes/SSZipArchive/minizip/unzip.h

@@ -0,0 +1,252 @@
+/* unzip.h -- IO for uncompress .zip files using zlib
+   Version 1.2.0, September 16th, 2017
+   part of the MiniZip project
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 2009-2010 Mathias Svensson
+     Modifications for Zip64 support on both zip and unzip
+     http://result42.com
+   Copyright (C) 2007-2008 Even Rouault
+     Modifications of Unzip for Zip64
+   Copyright (C) 1998-2010 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef _UNZ_H
+#define _UNZ_H
+
+#include "SSZipCommon.h"
+
+#define HAVE_AES
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+    from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unz_file__;
+typedef unz_file__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+#define UNZ_OK                          (0)
+#define UNZ_END_OF_LIST_OF_FILE         (-100)
+#define UNZ_ERRNO                       (Z_ERRNO)
+#define UNZ_EOF                         (0)
+#define UNZ_PARAMERROR                  (-102)
+#define UNZ_BADZIPFILE                  (-103)
+#define UNZ_INTERNALERROR               (-104)
+#define UNZ_CRCERROR                    (-105)
+#define UNZ_BADPASSWORD                 (-106)
+
+
+/***************************************************************************/
+/* Opening and close a zip file */
+
+extern unzFile ZEXPORT unzOpen(const char *path);
+extern unzFile ZEXPORT unzOpen64(const void *path);
+/* Open a Zip file.
+
+   path should contain the full path (by example, on a Windows XP computer 
+      "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". 
+   return NULL if zipfile cannot be opened or doesn't exist
+   return unzFile handle if no error
+
+   NOTE: The "64" function take a const void *pointer, because  the path is just the value passed to the
+   open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path 
+   is a pointer to a wide unicode string  (LPCTSTR is LPCWSTR), so const char *does not describe the reality */
+
+extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def);
+/* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write operations */
+extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def);
+/* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write 64-bit operations */
+
+extern int ZEXPORT unzClose(unzFile file);
+/* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile,
+   these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+
+   return UNZ_OK if there is no error */
+
+extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info);
+extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info);
+/* Write info about the ZipFile in the *pglobal_info structure.
+
+   return UNZ_OK if no error */
+
+extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size);
+/* Get the global comment string of the ZipFile, in the comment buffer.
+
+   uSizeBuf is the size of the szComment buffer.
+   return the number of byte copied or an error code <0 */
+
+/***************************************************************************/
+/* Reading the content of the current zipfile, you can open it, read data from it, and close it
+   (you can close it before reading all the file) */
+
+extern int ZEXPORT unzOpenCurrentFile(unzFile file);
+/* Open for reading data the current file in the zipfile.
+
+   return UNZ_OK if no error */
+
+extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password);
+/* Open for reading data the current file in the zipfile.
+   password is a crypting password
+
+   return UNZ_OK if no error */
+
+extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw);
+/* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress)
+   if raw==1 *method will receive method of compression, *level will receive level of compression
+
+   NOTE: you can set level parameter as NULL (if you did not want known level,
+         but you CANNOT set method parameter as NULL */
+
+extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password);
+/* Same as unzOpenCurrentFile, but takes extra parameter password for encrypted files */
+
+extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, uint32_t len);
+/* Read bytes from the current file (opened by unzOpenCurrentFile)
+   buf contain buffer where data must be copied
+   len the size of buf.
+
+   return the number of byte copied if somes bytes are copied
+   return 0 if the end of file was reached
+   return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */
+
+extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename, 
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
+extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
+/* Get Info about the current file
+
+   pfile_info if != NULL, the *pfile_info structure will contain somes info about the current file
+   filename if != NULL, the file name string will be copied in filename 
+   filename_size is the size of the filename buffer
+   extrafield if != NULL, the extra field information from the central header will be copied in to
+   extrafield_size is the size of the extraField buffer 
+   comment if != NULL, the comment string of the file will be copied in to
+   comment_size is the size of the comment buffer */
+
+extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, uint32_t len);
+/* Read extra field from the current file (opened by unzOpenCurrentFile)
+   This is the local-header version of the extra field (sometimes, there is
+   more info in the local-header version than in the central-header)
+
+   if buf == NULL, it return the size of the local extra field
+   if buf != NULL, len is the size of the buffer, the extra header is copied in buf.
+
+   return number of bytes copied in buf, or (if <0) the error code */
+
+extern int ZEXPORT unzCloseCurrentFile(unzFile file);
+/* Close the file in zip opened with unzOpenCurrentFile
+
+   return UNZ_CRCERROR if all the file was read but the CRC is not good */
+
+/***************************************************************************/
+/* Browse the directory of the zipfile */
+
+typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2);
+typedef int (*unzIteratorFunction)(unzFile file);
+typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
+
+extern int ZEXPORT unzGoToFirstFile(unzFile file);
+/* Set the current file of the zipfile to the first file.
+
+   return UNZ_OK if no error */
+
+extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
+/* Set the current file of the zipfile to the first file and retrieves the current info on success. 
+   Not as seek intensive as unzGoToFirstFile + unzGetCurrentFileInfo.
+
+   return UNZ_OK if no error */
+
+extern int ZEXPORT unzGoToNextFile(unzFile file);
+/* Set the current file of the zipfile to the next file.
+
+   return UNZ_OK if no error
+   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */
+
+extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
+/* Set the current file of the zipfile to the next file and retrieves the current 
+   info on success. Does less seeking around than unzGotoNextFile + unzGetCurrentFileInfo.
+
+   return UNZ_OK if no error
+   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */
+
+extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func);
+/* Try locate the file szFileName in the zipfile. For custom filename comparison pass in comparison function.
+
+   return UNZ_OK if the file is found (it becomes the current file)
+   return UNZ_END_OF_LIST_OF_FILE if the file is not found */
+
+/***************************************************************************/
+/* Raw access to zip file */
+
+typedef struct unz_file_pos_s
+{
+    uint32_t pos_in_zip_directory;  /* offset in zip file directory */
+    uint32_t num_of_file;           /* # of file */
+} unz_file_pos;
+
+extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos *file_pos);
+extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos *file_pos);
+
+typedef struct unz64_file_pos_s
+{
+    uint64_t pos_in_zip_directory;   /* offset in zip file directory */
+    uint64_t num_of_file;            /* # of file */
+} unz64_file_pos;
+
+extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos *file_pos);
+extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos);
+
+extern int32_t ZEXPORT unzGetOffset(unzFile file);
+extern int64_t ZEXPORT unzGetOffset64(unzFile file);
+/* Get the current file offset */
+
+extern int ZEXPORT unzSetOffset(unzFile file, uint32_t pos);
+extern int ZEXPORT unzSetOffset64(unzFile file, uint64_t pos);
+/* Set the current file offset */
+
+extern int32_t ZEXPORT unzTell(unzFile file);
+extern int64_t ZEXPORT unzTell64(unzFile file);
+/* return current position in uncompressed data */
+
+extern int ZEXPORT unzSeek(unzFile file, uint32_t offset, int origin);
+extern int ZEXPORT unzSeek64(unzFile file, uint64_t offset, int origin);
+/* Seek within the uncompressed data if compression method is storage */
+
+extern int ZEXPORT unzEndOfFile(unzFile file);
+/* return 1 if the end of file was reached, 0 elsewhere */
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UNZ_H */

+ 1982 - 0
ios/Classes/SSZipArchive/minizip/zip.c

@@ -0,0 +1,1982 @@
+/* zip.c -- IO on .zip files using zlib
+   Version 1.2.0, September 16th, 2017
+   part of the MiniZip project
+
+   Copyright (C) 2010-2017 Nathan Moinvaziri
+     Modifications for AES, PKWARE disk spanning
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 2009-2010 Mathias Svensson
+     Modifications for Zip64 support
+     http://result42.com
+   Copyright (C) 1998-2010 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include "zlib.h"
+#include "zip.h"
+
+#ifdef HAVE_AES
+#  define AES_METHOD          (99)
+#  define AES_PWVERIFYSIZE    (2)
+#  define AES_AUTHCODESIZE    (10)
+#  define AES_MAXSALTLENGTH   (16)
+#  define AES_VERSION         (0x0001)
+#  define AES_ENCRYPTIONMODE  (0x03)
+
+#  include "aes/aes.h"
+#  include "aes/fileenc.h"
+#  include "aes/prng.h"
+#endif
+#ifdef HAVE_APPLE_COMPRESSION
+#  include <compression.h>
+#endif
+
+#ifndef NOCRYPT
+#  include "crypt.h"
+#endif
+
+#define SIZEDATA_INDATABLOCK        (4096-(4*4))
+
+#define DISKHEADERMAGIC             (0x08074b50)
+#define LOCALHEADERMAGIC            (0x04034b50)
+#define CENTRALHEADERMAGIC          (0x02014b50)
+#define ENDHEADERMAGIC              (0x06054b50)
+#define ZIP64ENDHEADERMAGIC         (0x06064b50)
+#define ZIP64ENDLOCHEADERMAGIC      (0x07064b50)
+#define DATADESCRIPTORMAGIC         (0x08074b50)
+
+#define FLAG_LOCALHEADER_OFFSET     (0x06)
+#define CRC_LOCALHEADER_OFFSET      (0x0e)
+
+#define SIZECENTRALHEADER           (0x2e) /* 46 */
+#define SIZECENTRALHEADERLOCATOR    (0x14) /* 20 */
+#define SIZECENTRALDIRITEM          (0x2e)
+#define SIZEZIPLOCALHEADER          (0x1e)
+
+#ifndef BUFREADCOMMENT
+#  define BUFREADCOMMENT            (0x400)
+#endif
+#ifndef VERSIONMADEBY
+#  define VERSIONMADEBY             (0x0) /* platform dependent */
+#endif
+
+#ifndef Z_BUFSIZE
+#  define Z_BUFSIZE                 (UINT16_MAX)
+#endif
+
+#ifndef ALLOC
+#  define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+#  define TRYFREE(p) {if (p) free(p);}
+#endif
+
+/* NOT sure that this work on ALL platform */
+#define MAKEULONG64(a, b) ((uint64_t)(((unsigned long)(a)) | ((uint64_t)((unsigned long)(b))) << 32))
+
+#ifndef DEF_MEM_LEVEL
+#  if MAX_MEM_LEVEL >= 8
+#    define DEF_MEM_LEVEL 8
+#  else
+#    define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#  endif
+#endif
+
+const char zip_copyright[] = " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+typedef struct linkedlist_datablock_internal_s
+{
+    struct linkedlist_datablock_internal_s *next_datablock;
+    uint32_t    avail_in_this_block;
+    uint32_t    filled_in_this_block;
+    uint32_t    unused; /* for future use and alignment */
+    uint8_t     data[SIZEDATA_INDATABLOCK];
+} linkedlist_datablock_internal;
+
+typedef struct linkedlist_data_s
+{
+    linkedlist_datablock_internal *first_block;
+    linkedlist_datablock_internal *last_block;
+} linkedlist_data;
+
+typedef struct
+{
+    z_stream stream;                /* zLib stream structure for inflate */
+#ifdef HAVE_BZIP2
+    bz_stream bstream;              /* bzLib stream structure for bziped */
+#endif
+#ifdef HAVE_APPLE_COMPRESSION
+    compression_stream astream;     /* libcompression stream structure */
+#endif
+#ifdef HAVE_AES
+    fcrypt_ctx aes_ctx;
+    prng_ctx aes_rng[1];
+#endif
+    int      stream_initialised;    /* 1 is stream is initialized */
+    uint32_t pos_in_buffered_data;  /* last written byte in buffered_data */
+
+    uint64_t pos_local_header;      /* offset of the local header of the file currently writing */
+    char    *central_header;        /* central header data for the current file */
+    uint16_t size_centralextra;
+    uint16_t size_centralheader;    /* size of the central header for cur file */
+    uint16_t size_centralextrafree; /* Extra bytes allocated to the central header but that are not used */
+    uint16_t size_comment;
+    uint16_t flag;                  /* flag of the file currently writing */
+
+    uint16_t method;                /* compression method written to file.*/
+    uint16_t compression_method;    /* compression method to use */
+    int      raw;                   /* 1 for directly writing raw data */
+    uint8_t  buffered_data[Z_BUFSIZE];  /* buffer contain compressed data to be writ*/
+    uint32_t dos_date;
+    uint32_t crc32;
+    int      zip64;                 /* add ZIP64 extended information in the extra field */
+    uint32_t number_disk;           /* number of current disk used for spanning ZIP */
+    uint64_t total_compressed;
+    uint64_t total_uncompressed;
+#ifndef NOCRYPT
+    uint32_t keys[3];          /* keys defining the pseudo-random sequence */
+    const z_crc_t *pcrc_32_tab;
+#endif
+} curfile64_info;
+
+typedef struct
+{
+    zlib_filefunc64_32_def z_filefunc;
+    voidpf filestream;              /* io structure of the zipfile */
+    voidpf filestream_with_CD;      /* io structure of the zipfile with the central dir */
+    linkedlist_data central_dir;    /* datablock with central dir in construction*/
+    int in_opened_file_inzip;       /* 1 if a file in the zip is currently writ.*/
+    int append;                     /* append mode */
+    curfile64_info ci;              /* info on the file currently writing */
+
+    uint64_t add_position_when_writting_offset;
+    uint64_t number_entry;
+    uint64_t disk_size;             /* size of each disk */
+    uint32_t number_disk;           /* number of the current disk, used for spanning ZIP */
+    uint32_t number_disk_with_CD;   /* number the the disk with central dir, used for spanning ZIP */
+#ifndef NO_ADDFILEINEXISTINGZIP
+    char *globalcomment;
+#endif
+} zip64_internal;
+
+/* Allocate a new data block */
+static linkedlist_datablock_internal *allocate_new_datablock(void)
+{
+    linkedlist_datablock_internal *ldi = NULL;
+
+    ldi = (linkedlist_datablock_internal*)ALLOC(sizeof(linkedlist_datablock_internal));
+
+    if (ldi != NULL)
+    {
+        ldi->next_datablock = NULL;
+        ldi->filled_in_this_block = 0;
+        ldi->avail_in_this_block = SIZEDATA_INDATABLOCK;
+    }
+    return ldi;
+}
+
+/* Free data block in linked list */
+static void free_datablock(linkedlist_datablock_internal *ldi)
+{
+    while (ldi != NULL)
+    {
+        linkedlist_datablock_internal *ldinext = ldi->next_datablock;
+        TRYFREE(ldi);
+        ldi = ldinext;
+    }
+}
+
+/* Initialize linked list */
+static void init_linkedlist(linkedlist_data *ll)
+{
+    ll->first_block = ll->last_block = NULL;
+}
+
+/* Free entire linked list and all data blocks */
+static void free_linkedlist(linkedlist_data *ll)
+{
+    free_datablock(ll->first_block);
+    ll->first_block = ll->last_block = NULL;
+}
+
+/* Add data to linked list data block */
+static int add_data_in_datablock(linkedlist_data *ll, const void *buf, uint32_t len)
+{
+    linkedlist_datablock_internal *ldi = NULL;
+    const unsigned char *from_copy = NULL;
+
+    if (ll == NULL)
+        return ZIP_INTERNALERROR;
+
+    if (ll->last_block == NULL)
+    {
+        ll->first_block = ll->last_block = allocate_new_datablock();
+        if (ll->first_block == NULL)
+            return ZIP_INTERNALERROR;
+    }
+
+    ldi = ll->last_block;
+    from_copy = (unsigned char*)buf;
+
+    while (len > 0)
+    {
+        uint32_t copy_this = 0;
+        uint32_t i = 0;
+        unsigned char *to_copy = NULL;
+
+        if (ldi->avail_in_this_block == 0)
+        {
+            ldi->next_datablock = allocate_new_datablock();
+            if (ldi->next_datablock == NULL)
+                return ZIP_INTERNALERROR;
+            ldi = ldi->next_datablock ;
+            ll->last_block = ldi;
+        }
+
+        if (ldi->avail_in_this_block < len)
+            copy_this = ldi->avail_in_this_block;
+        else
+            copy_this = len;
+
+        to_copy = &(ldi->data[ldi->filled_in_this_block]);
+
+        for (i = 0; i < copy_this; i++)
+            *(to_copy+i) = *(from_copy+i);
+
+        ldi->filled_in_this_block += copy_this;
+        ldi->avail_in_this_block -= copy_this;
+        from_copy += copy_this;
+        len -= copy_this;
+    }
+    return ZIP_OK;
+}
+
+/* Inputs a long in LSB order to the given file: nbByte == 1, 2 ,4 or 8 (byte, short or long, uint64_t) */
+static int zipWriteValue(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream,
+    uint64_t x, uint32_t len)
+{
+    unsigned char buf[8];
+    uint32_t n = 0;
+
+    for (n = 0; n < len; n++)
+    {
+        buf[n] = (unsigned char)(x & 0xff);
+        x >>= 8;
+    }
+
+    if (x != 0)
+    {
+        /* Data overflow - hack for ZIP64 (X Roche) */
+        for (n = 0; n < len; n++)
+        {
+            buf[n] = 0xff;
+        }
+    }
+
+    if (ZWRITE64(*pzlib_filefunc_def, filestream, buf, len) != len)
+        return ZIP_ERRNO;
+
+    return ZIP_OK;
+}
+
+static void zipWriteValueToMemory(void* dest, uint64_t x, uint32_t len)
+{
+    unsigned char *buf = (unsigned char*)dest;
+    uint32_t n = 0;
+
+    for (n = 0; n < len; n++)
+    {
+        buf[n] = (unsigned char)(x & 0xff);
+        x >>= 8;
+    }
+
+    if (x != 0)
+    {
+       /* data overflow - hack for ZIP64 */
+       for (n = 0; n < len; n++)
+       {
+          buf[n] = 0xff;
+       }
+    }
+}
+
+static void zipWriteValueToMemoryAndMove(unsigned char **dest_ptr, uint64_t x, uint32_t len)
+{
+    zipWriteValueToMemory(*dest_ptr, x, len);
+    *dest_ptr += len;
+}
+
+static int zipReadUInt8(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint8_t *value)
+{
+    uint8_t c = 0;
+    if (ZREAD64(*pzlib_filefunc_def, filestream, &c, 1) == 1)
+    {
+        *value = (uint8_t)c;
+        return ZIP_OK;
+    }
+    if (ZERROR64(*pzlib_filefunc_def, filestream))
+        return ZIP_ERRNO;
+    return ZIP_EOF;
+}
+
+static int zipReadUInt16(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint16_t *value)
+{
+    uint16_t x = 0;
+    uint8_t c = 0;
+    int err = ZIP_OK;
+
+    err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x = (uint16_t)c;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint16_t)c) << 8;
+
+    if (err == ZIP_OK)
+        *value = x;
+    else
+        *value = 0;
+    return err;
+}
+
+static int zipReadUInt32(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint32_t *value)
+{
+    uint32_t x = 0;
+    uint8_t c = 0;
+    int err = ZIP_OK;
+
+    err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x = (uint32_t)c;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint32_t)c) << 8;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint32_t)c) << 16;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint32_t)c) << 24;
+
+    if (err == ZIP_OK)
+        *value = x;
+    else
+        *value = 0;
+    return err;
+}
+
+static int zipReadUInt64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint64_t *value)
+{
+    uint64_t x = 0;
+    uint8_t c = 0;
+    int err = ZIP_OK;
+
+    err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x = (uint64_t)c;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint64_t)c) << 8;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint64_t)c) << 16;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint64_t)c) << 24;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint64_t)c) << 32;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint64_t)c) << 40;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint64_t)c) << 48;
+    if (err == ZIP_OK)
+        err = zipReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint64_t)c) << 56;
+
+    if (err == ZIP_OK)
+        *value = x;
+    else
+        *value = 0;
+
+    return err;
+}
+
+/* Gets the amount of bytes left to write to the current disk for spanning archives */
+static void zipGetDiskSizeAvailable(zipFile file, uint64_t *size_available)
+{
+    zip64_internal *zi = NULL;
+    uint64_t current_disk_size = 0;
+
+    zi = (zip64_internal*)file;
+    ZSEEK64(zi->z_filefunc, zi->filestream, 0, ZLIB_FILEFUNC_SEEK_END);
+    current_disk_size = ZTELL64(zi->z_filefunc, zi->filestream);
+    *size_available = zi->disk_size - current_disk_size;
+}
+
+/* Goes to a specific disk number for spanning archives */
+static int zipGoToSpecificDisk(zipFile file, uint32_t number_disk, int open_existing)
+{
+    zip64_internal *zi = NULL;
+    int err = ZIP_OK;
+
+    zi = (zip64_internal*)file;
+    if (zi->disk_size == 0)
+        return err;
+
+    if ((zi->filestream != NULL) && (zi->filestream != zi->filestream_with_CD))
+        ZCLOSE64(zi->z_filefunc, zi->filestream);
+
+    zi->filestream = ZOPENDISK64(zi->z_filefunc, zi->filestream_with_CD, number_disk, (open_existing == 1) ?
+            (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING) :
+            (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE));
+
+    if (zi->filestream == NULL)
+        err = ZIP_ERRNO;
+
+    return err;
+}
+
+/* Goes to the first disk in a spanned archive */
+static int zipGoToFirstDisk(zipFile file)
+{
+    zip64_internal *zi = NULL;
+    uint32_t number_disk_next = 0;
+    int err = ZIP_OK;
+
+    zi = (zip64_internal*)file;
+
+    if (zi->disk_size == 0)
+        return err;
+    number_disk_next = 0;
+    if (zi->number_disk_with_CD > 0)
+        number_disk_next = zi->number_disk_with_CD - 1;
+    err = zipGoToSpecificDisk(file, number_disk_next, (zi->append == APPEND_STATUS_ADDINZIP));
+    if ((err == ZIP_ERRNO) && (zi->append == APPEND_STATUS_ADDINZIP))
+        err = zipGoToSpecificDisk(file, number_disk_next, 0);
+    if (err == ZIP_OK)
+        zi->number_disk = number_disk_next;
+    ZSEEK64(zi->z_filefunc, zi->filestream, 0, ZLIB_FILEFUNC_SEEK_END);
+    return err;
+}
+
+/* Goes to the next disk in a spanned archive */
+static int zipGoToNextDisk(zipFile file)
+{
+    zip64_internal *zi = NULL;
+    uint64_t size_available_in_disk = 0;
+    uint32_t number_disk_next = 0;
+    int err = ZIP_OK;
+
+    zi = (zip64_internal*)file;
+    if (zi->disk_size == 0)
+        return err;
+
+    number_disk_next = zi->number_disk + 1;
+
+    do
+    {
+        err = zipGoToSpecificDisk(file, number_disk_next, (zi->append == APPEND_STATUS_ADDINZIP));
+        if ((err == ZIP_ERRNO) && (zi->append == APPEND_STATUS_ADDINZIP))
+            err = zipGoToSpecificDisk(file, number_disk_next, 0);
+        if (err != ZIP_OK)
+            break;
+        zipGetDiskSizeAvailable(file, &size_available_in_disk);
+        zi->number_disk = number_disk_next;
+        zi->number_disk_with_CD = zi->number_disk + 1;
+
+        number_disk_next += 1;
+    }
+    while (size_available_in_disk <= 0);
+
+    return err;
+}
+
+/* Locate the Central directory of a zipfile (at the end, just before the global comment) */
+static uint64_t zipSearchCentralDir(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream)
+{
+    unsigned char *buf = NULL;
+    uint64_t file_size = 0;
+    uint64_t back_read = 4;
+    uint64_t max_back = UINT16_MAX; /* maximum size of global comment */
+    uint64_t pos_found = 0;
+    uint32_t read_size = 0;
+    uint64_t read_pos = 0;
+    uint32_t i = 0;
+
+    buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+    if (buf == NULL)
+        return 0;
+
+    if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0)
+    {
+        TRYFREE(buf);
+        return 0;
+    }
+
+    file_size = ZTELL64(*pzlib_filefunc_def, filestream);
+
+    if (max_back > file_size)
+        max_back = file_size;
+
+    while (back_read < max_back)
+    {
+        if (back_read + BUFREADCOMMENT > max_back)
+            back_read = max_back;
+        else
+            back_read += BUFREADCOMMENT;
+
+        read_pos = file_size-back_read;
+        read_size = ((BUFREADCOMMENT+4) < (file_size - read_pos)) ?
+                     (BUFREADCOMMENT+4) : (uint32_t)(file_size - read_pos);
+
+        if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+            break;
+        if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size)
+            break;
+
+        for (i = read_size-3; (i--) > 0;)
+            if ((*(buf+i)) == (ENDHEADERMAGIC & 0xff) &&
+                (*(buf+i+1)) == (ENDHEADERMAGIC >> 8 & 0xff) &&
+                (*(buf+i+2)) == (ENDHEADERMAGIC >> 16 & 0xff) &&
+                (*(buf+i+3)) == (ENDHEADERMAGIC >> 24 & 0xff))
+            {
+                pos_found = read_pos+i;
+                break;
+            }
+
+        if (pos_found != 0)
+            break;
+    }
+    TRYFREE(buf);
+    return pos_found;
+}
+
+/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */
+static uint64_t zipSearchCentralDir64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream,
+    const uint64_t endcentraloffset)
+{
+    uint64_t offset = 0;
+    uint32_t value32 = 0;
+
+    /* Zip64 end of central directory locator */
+    if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return 0;
+
+    /* Read locator signature */
+    if (zipReadUInt32(pzlib_filefunc_def, filestream, &value32) != ZIP_OK)
+        return 0;
+    if (value32 != ZIP64ENDLOCHEADERMAGIC)
+        return 0;
+    /* Number of the disk with the start of the zip64 end of  central directory */
+    if (zipReadUInt32(pzlib_filefunc_def, filestream, &value32) != ZIP_OK)
+        return 0;
+    /* Relative offset of the zip64 end of central directory record */
+    if (zipReadUInt64(pzlib_filefunc_def, filestream, &offset) != ZIP_OK)
+        return 0;
+    /* Total number of disks */
+    if (zipReadUInt32(pzlib_filefunc_def, filestream, &value32) != ZIP_OK)
+        return 0;
+    /* Goto end of central directory record */
+    if (ZSEEK64(*pzlib_filefunc_def,filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return 0;
+    /* The signature */
+    if (zipReadUInt32(pzlib_filefunc_def, filestream, &value32) != ZIP_OK)
+        return 0;
+    if (value32 != ZIP64ENDHEADERMAGIC)
+        return 0;
+
+    return offset;
+}
+
+extern zipFile ZEXPORT zipOpen4(const void *path, int append, uint64_t disk_size, const char **globalcomment,
+    zlib_filefunc64_32_def *pzlib_filefunc64_32_def)
+{
+    zip64_internal ziinit;
+    zip64_internal *zi = NULL;
+#ifndef NO_ADDFILEINEXISTINGZIP
+    uint64_t byte_before_the_zipfile = 0;   /* byte before the zipfile, (>0 for sfx)*/
+    uint64_t size_central_dir = 0;          /* size of the central directory  */
+    uint64_t offset_central_dir = 0;        /* offset of start of central directory */
+    uint64_t number_entry_CD = 0;           /* total number of entries in the central dir */
+    uint64_t number_entry = 0;
+    uint64_t central_pos = 0;
+    uint64_t size_central_dir_to_read = 0;
+    uint16_t value16 = 0;
+    uint32_t value32 = 0;
+    uint16_t size_comment = 0;
+    size_t buf_size = SIZEDATA_INDATABLOCK;
+    void *buf_read = NULL;
+#endif
+    int err = ZIP_OK;
+    int mode = 0;
+
+    ziinit.z_filefunc.zseek32_file = NULL;
+    ziinit.z_filefunc.ztell32_file = NULL;
+
+    if (pzlib_filefunc64_32_def == NULL)
+        fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64);
+    else
+        ziinit.z_filefunc = *pzlib_filefunc64_32_def;
+
+    if (append == APPEND_STATUS_CREATE)
+        mode = (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE);
+    else
+        mode = (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING);
+
+    ziinit.filestream = ZOPEN64(ziinit.z_filefunc, path, mode);
+    if (ziinit.filestream == NULL)
+        return NULL;
+
+    if (append == APPEND_STATUS_CREATEAFTER)
+    {
+        /* Don't support spanning ZIP with APPEND_STATUS_CREATEAFTER */
+        if (disk_size > 0)
+            return NULL;
+
+        ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END);
+    }
+
+    ziinit.filestream_with_CD = ziinit.filestream;
+    ziinit.append = append;
+    ziinit.number_disk = 0;
+    ziinit.number_disk_with_CD = 0;
+    ziinit.disk_size = disk_size;
+    ziinit.in_opened_file_inzip = 0;
+    ziinit.ci.stream_initialised = 0;
+    ziinit.number_entry = 0;
+    ziinit.add_position_when_writting_offset = 0;
+    init_linkedlist(&(ziinit.central_dir));
+
+    zi = (zip64_internal*)ALLOC(sizeof(zip64_internal));
+    if (zi == NULL)
+    {
+        ZCLOSE64(ziinit.z_filefunc,ziinit.filestream);
+        return NULL;
+    }
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+    /* Add file in a zipfile */
+    ziinit.globalcomment = NULL;
+    if (append == APPEND_STATUS_ADDINZIP)
+    {
+        /* Read and Cache Central Directory Records */
+        central_pos = zipSearchCentralDir(&ziinit.z_filefunc,ziinit.filestream);
+        /* Disable to allow appending to empty ZIP archive (must be standard zip, not zip64)
+            if (central_pos == 0)
+                err = ZIP_ERRNO;
+        */
+
+        if (err == ZIP_OK)
+        {
+            /* Read end of central directory info */
+            if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET) != 0)
+                err = ZIP_ERRNO;
+
+            /* The signature, already checked */
+            if (zipReadUInt32(&ziinit.z_filefunc, ziinit.filestream, &value32) != ZIP_OK)
+                err = ZIP_ERRNO;
+            /* Number of this disk */
+            if (zipReadUInt16(&ziinit.z_filefunc, ziinit.filestream, &value16) != ZIP_OK)
+                err = ZIP_ERRNO;
+            ziinit.number_disk = value16;
+            /* Number of the disk with the start of the central directory */
+            if (zipReadUInt16(&ziinit.z_filefunc, ziinit.filestream, &value16) != ZIP_OK)
+                err = ZIP_ERRNO;
+            ziinit.number_disk_with_CD = value16;
+            /* Total number of entries in the central dir on this disk */
+            number_entry = 0;
+            if (zipReadUInt16(&ziinit.z_filefunc, ziinit.filestream, &value16) != ZIP_OK)
+                err = ZIP_ERRNO;
+            else
+                number_entry = value16;
+            /* Total number of entries in the central dir */
+            number_entry_CD = 0;
+            if (zipReadUInt16(&ziinit.z_filefunc, ziinit.filestream, &value16) != ZIP_OK)
+                err = ZIP_ERRNO;
+            else
+                number_entry_CD = value16;
+            if (number_entry_CD!=number_entry)
+                err = ZIP_BADZIPFILE;
+            /* Size of the central directory */
+            size_central_dir = 0;
+            if (zipReadUInt32(&ziinit.z_filefunc, ziinit.filestream, &value32) != ZIP_OK)
+                err = ZIP_ERRNO;
+            else
+                size_central_dir = value32;
+            /* Offset of start of central directory with respect to the starting disk number */
+            offset_central_dir = 0;
+            if (zipReadUInt32(&ziinit.z_filefunc, ziinit.filestream, &value32) != ZIP_OK)
+                err = ZIP_ERRNO;
+            else
+                offset_central_dir = value32;
+            /* Zipfile global comment length */
+            if (zipReadUInt16(&ziinit.z_filefunc, ziinit.filestream, &size_comment) != ZIP_OK)
+                err = ZIP_ERRNO;
+
+            if ((err == ZIP_OK) && ((number_entry_CD == UINT16_MAX) || (offset_central_dir == UINT32_MAX)))
+            {
+                /* Format should be Zip64, as the central directory or file size is too large */
+                central_pos = zipSearchCentralDir64(&ziinit.z_filefunc, ziinit.filestream, central_pos);
+
+                if (central_pos)
+                {
+                    uint64_t sizeEndOfCentralDirectory;
+
+                    if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+                        err = ZIP_ERRNO;
+
+                    /* The signature, already checked */
+                    if (zipReadUInt32(&ziinit.z_filefunc, ziinit.filestream, &value32) != ZIP_OK)
+                        err = ZIP_ERRNO;
+                    /* Size of zip64 end of central directory record */
+                    if (zipReadUInt64(&ziinit.z_filefunc, ziinit.filestream, &sizeEndOfCentralDirectory) != ZIP_OK)
+                        err = ZIP_ERRNO;
+                    /* Version made by */
+                    if (zipReadUInt16(&ziinit.z_filefunc, ziinit.filestream, &value16) != ZIP_OK)
+                        err = ZIP_ERRNO;
+                    /* Version needed to extract */
+                    if (zipReadUInt16(&ziinit.z_filefunc, ziinit.filestream, &value16) != ZIP_OK)
+                        err = ZIP_ERRNO;
+                    /* Number of this disk */
+                    if (zipReadUInt32(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk) != ZIP_OK)
+                        err = ZIP_ERRNO;
+                    /* Number of the disk with the start of the central directory */
+                    if (zipReadUInt32(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk_with_CD) != ZIP_OK)
+                        err = ZIP_ERRNO;
+                    /* Total number of entries in the central directory on this disk */
+                    if (zipReadUInt64(&ziinit.z_filefunc, ziinit.filestream, &number_entry) != ZIP_OK)
+                        err = ZIP_ERRNO;
+                    /* Total number of entries in the central directory */
+                    if (zipReadUInt64(&ziinit.z_filefunc, ziinit.filestream, &number_entry_CD) != ZIP_OK)
+                        err = ZIP_ERRNO;
+                    if (number_entry_CD!=number_entry)
+                        err = ZIP_BADZIPFILE;
+                    /* Size of the central directory */
+                    if (zipReadUInt64(&ziinit.z_filefunc, ziinit.filestream, &size_central_dir) != ZIP_OK)
+                        err = ZIP_ERRNO;
+                    /* Offset of start of central directory with respect to the starting disk number */
+                    if (zipReadUInt64(&ziinit.z_filefunc, ziinit.filestream, &offset_central_dir) != ZIP_OK)
+                        err = ZIP_ERRNO;
+                }
+                else
+                    err = ZIP_BADZIPFILE;
+             }
+        }
+
+        if ((err == ZIP_OK) && (central_pos < offset_central_dir + size_central_dir))
+            err = ZIP_BADZIPFILE;
+
+        if ((err == ZIP_OK) && (size_comment > 0))
+        {
+            ziinit.globalcomment = (char*)ALLOC(size_comment+1);
+            if (ziinit.globalcomment)
+            {
+                if (ZREAD64(ziinit.z_filefunc, ziinit.filestream, ziinit.globalcomment, size_comment) != size_comment)
+                    err = ZIP_ERRNO;
+                else
+                    ziinit.globalcomment[size_comment] = 0;
+            }
+        }
+
+        if (err != ZIP_OK)
+        {
+            ZCLOSE64(ziinit.z_filefunc, ziinit.filestream);
+            TRYFREE(ziinit.globalcomment);
+            TRYFREE(zi);
+            return NULL;
+        }
+
+        byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir);
+        ziinit.add_position_when_writting_offset = byte_before_the_zipfile;
+
+        /* Store central directory in memory */
+        size_central_dir_to_read = size_central_dir;
+        buf_size = SIZEDATA_INDATABLOCK;
+        buf_read = (void*)ALLOC(buf_size);
+
+        if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream,
+                offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+            err = ZIP_ERRNO;
+
+        while ((size_central_dir_to_read > 0) && (err == ZIP_OK))
+        {
+            uint64_t read_this = SIZEDATA_INDATABLOCK;
+            if (read_this > size_central_dir_to_read)
+                read_this = size_central_dir_to_read;
+
+            if (ZREAD64(ziinit.z_filefunc, ziinit.filestream, buf_read, (uint32_t)read_this) != read_this)
+                err = ZIP_ERRNO;
+
+            if (err == ZIP_OK)
+                err = add_data_in_datablock(&ziinit.central_dir, buf_read, (uint32_t)read_this);
+
+            size_central_dir_to_read -= read_this;
+        }
+        TRYFREE(buf_read);
+
+        ziinit.number_entry = number_entry_CD;
+
+        if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream,
+                offset_central_dir+byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+            err = ZIP_ERRNO;
+    }
+
+    if (globalcomment)
+        *globalcomment = ziinit.globalcomment;
+#endif
+
+    if (err != ZIP_OK)
+    {
+#ifndef NO_ADDFILEINEXISTINGZIP
+        TRYFREE(ziinit.globalcomment);
+#endif
+        TRYFREE(zi);
+        return NULL;
+    }
+
+    *zi = ziinit;
+    zipGoToFirstDisk((zipFile)zi);
+    return(zipFile)zi;
+}
+
+extern zipFile ZEXPORT zipOpen2(const char *path, int append, const char **globalcomment,
+    zlib_filefunc_def *pzlib_filefunc32_def)
+{
+    if (pzlib_filefunc32_def != NULL)
+    {
+        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+        fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
+        return zipOpen4(path, append, 0, globalcomment, &zlib_filefunc64_32_def_fill);
+    }
+    return zipOpen4(path, append, 0, globalcomment, NULL);
+}
+
+extern zipFile ZEXPORT zipOpen2_64(const void *path, int append, const char **globalcomment,
+    zlib_filefunc64_def *pzlib_filefunc_def)
+{
+    if (pzlib_filefunc_def != NULL)
+    {
+        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+        zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+        zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+        zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+        return zipOpen4(path, append, 0, globalcomment, &zlib_filefunc64_32_def_fill);
+    }
+    return zipOpen4(path, append, 0, globalcomment, NULL);
+}
+
+extern zipFile ZEXPORT zipOpen3(const char *path, int append, uint64_t disk_size, const char **globalcomment,
+    zlib_filefunc_def *pzlib_filefunc32_def)
+{
+    if (pzlib_filefunc32_def != NULL)
+    {
+        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+        fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
+        return zipOpen4(path, append, disk_size, globalcomment, &zlib_filefunc64_32_def_fill);
+    }
+    return zipOpen4(path, append, disk_size, globalcomment, NULL);
+}
+
+extern zipFile ZEXPORT zipOpen3_64(const void *path, int append, uint64_t disk_size, const char **globalcomment,
+    zlib_filefunc64_def *pzlib_filefunc_def)
+{
+    if (pzlib_filefunc_def != NULL)
+    {
+        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+        zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+        zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+        zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+        return zipOpen4(path, append, disk_size, globalcomment, &zlib_filefunc64_32_def_fill);
+    }
+    return zipOpen4(path, append, disk_size, globalcomment, NULL);
+}
+
+extern zipFile ZEXPORT zipOpen(const char *path, int append)
+{
+    return zipOpen3((const void*)path, append, 0, NULL, NULL);
+}
+
+extern zipFile ZEXPORT zipOpen64(const void *path, int append)
+{
+    return zipOpen3(path, append, 0, NULL, NULL);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw, int windowBits, int memLevel,
+    int strategy, const char *password, ZIP_UNUSED uint32_t crc_for_crypting, uint16_t version_madeby, uint16_t flag_base, int zip64)
+{
+    zip64_internal *zi = NULL;
+    uint64_t size_available = 0;
+    uint64_t size_needed = 0;
+    uint16_t size_filename = 0;
+    uint16_t size_comment = 0;
+    uint16_t i = 0;
+    unsigned char *central_dir = NULL;
+    int err = ZIP_OK;
+
+#ifdef NOCRYPT
+    if (password != NULL)
+        return ZIP_PARAMERROR;
+#endif
+
+    if (file == NULL)
+        return ZIP_PARAMERROR;
+
+    if ((method != 0) &&
+#ifdef HAVE_BZIP2
+        (method != Z_BZIP2ED) &&
+#endif
+        (method != Z_DEFLATED))
+        return ZIP_PARAMERROR;
+
+    zi = (zip64_internal*)file;
+
+    if (zi->in_opened_file_inzip == 1)
+    {
+        err = zipCloseFileInZip (file);
+        if (err != ZIP_OK)
+            return err;
+    }
+
+    if (filename == NULL)
+        filename = "-";
+    if (comment != NULL)
+        size_comment = (uint16_t)strlen(comment);
+
+    size_filename = (uint16_t)strlen(filename);
+
+    if (zipfi == NULL)
+        zi->ci.dos_date = 0;
+    else
+    {
+        if (zipfi->dos_date != 0)
+            zi->ci.dos_date = zipfi->dos_date;
+    }
+
+    zi->ci.method = method;
+    zi->ci.compression_method = method;
+    zi->ci.raw = raw;
+    zi->ci.flag = flag_base | 8;
+    if ((level == 8) || (level == 9))
+        zi->ci.flag |= 2;
+    if (level == 2)
+        zi->ci.flag |= 4;
+    if (level == 1)
+        zi->ci.flag |= 6;
+
+    if (password != NULL)
+    {
+        zi->ci.flag |= 1;
+#ifdef HAVE_AES
+        zi->ci.method = AES_METHOD;
+#endif
+    }
+    else
+    {
+        zi->ci.flag &= ~1;
+    }
+
+    if (zi->disk_size > 0)
+    {
+        if ((zi->number_disk == 0) && (zi->number_entry == 0))
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)DISKHEADERMAGIC, 4);
+
+        /* Make sure enough space available on current disk for local header */
+        zipGetDiskSizeAvailable((zipFile)zi, &size_available);
+        size_needed = 30 + size_filename + size_extrafield_local;
+#ifdef HAVE_AES
+        if (zi->ci.method == AES_METHOD)
+            size_needed += 11;
+#endif
+        if (size_available < size_needed)
+            zipGoToNextDisk((zipFile)zi);
+    }
+
+    zi->ci.zip64 = zip64;
+
+    zi->ci.pos_local_header = ZTELL64(zi->z_filefunc, zi->filestream);
+    if (zi->ci.pos_local_header >= UINT32_MAX)
+        zi->ci.zip64 = 1;
+
+    zi->ci.size_comment = size_comment;
+    zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global;
+    zi->ci.size_centralextra = size_extrafield_global;
+    zi->ci.size_centralextrafree = 32; /* Extra space reserved for ZIP64 extra info */
+#ifdef HAVE_AES
+    if (zi->ci.method == AES_METHOD)
+        zi->ci.size_centralextrafree += 11; /* Extra space reserved for AES extra info */
+#endif
+    zi->ci.central_header = (char*)ALLOC((uint32_t)zi->ci.size_centralheader + zi->ci.size_centralextrafree + size_comment);
+    zi->ci.number_disk = zi->number_disk;
+
+    /* Write central directory header */
+    central_dir = (unsigned char*)zi->ci.central_header;
+    zipWriteValueToMemoryAndMove(&central_dir, (uint32_t)CENTRALHEADERMAGIC, 4);
+    zipWriteValueToMemoryAndMove(&central_dir, version_madeby, 2);
+    if (zi->ci.zip64)
+        zipWriteValueToMemoryAndMove(&central_dir, (uint16_t)45, 2);
+    else
+        zipWriteValueToMemoryAndMove(&central_dir, (uint16_t)20, 2);
+    zipWriteValueToMemoryAndMove(&central_dir, zi->ci.flag, 2);
+    zipWriteValueToMemoryAndMove(&central_dir, zi->ci.method, 2);
+    zipWriteValueToMemoryAndMove(&central_dir, zi->ci.dos_date, 4);
+    zipWriteValueToMemoryAndMove(&central_dir, (uint32_t)0, 4); /*crc*/
+    zipWriteValueToMemoryAndMove(&central_dir, (uint32_t)0, 4); /*compr size*/
+    zipWriteValueToMemoryAndMove(&central_dir, (uint32_t)0, 4); /*uncompr size*/
+    zipWriteValueToMemoryAndMove(&central_dir, size_filename, 2);
+    zipWriteValueToMemoryAndMove(&central_dir, size_extrafield_global, 2);
+    zipWriteValueToMemoryAndMove(&central_dir, size_comment, 2);
+    zipWriteValueToMemoryAndMove(&central_dir, (uint16_t)zi->ci.number_disk, 2); /*disk nm start*/
+
+    if (zipfi == NULL)
+        zipWriteValueToMemoryAndMove(&central_dir, (uint16_t)0, 2);
+    else
+        zipWriteValueToMemoryAndMove(&central_dir, zipfi->internal_fa, 2);
+    if (zipfi == NULL)
+        zipWriteValueToMemoryAndMove(&central_dir, (uint32_t)0, 4);
+    else
+        zipWriteValueToMemoryAndMove(&central_dir, zipfi->external_fa, 4);
+    if (zi->ci.pos_local_header >= UINT32_MAX)
+        zipWriteValueToMemoryAndMove(&central_dir, UINT32_MAX, 4);
+    else
+        zipWriteValueToMemoryAndMove(&central_dir,
+            (uint32_t)(zi->ci.pos_local_header - zi->add_position_when_writting_offset), 4);
+
+    for (i = 0; i < size_filename; i++)
+        zi->ci.central_header[SIZECENTRALHEADER+i] = filename[i];
+    for (i = 0; i < size_extrafield_global; i++)
+        zi->ci.central_header[SIZECENTRALHEADER+size_filename+i] =
+            ((const char*)extrafield_global)[i];
+
+    /* Store comment at the end for later repositioning */
+    for (i = 0; i < size_comment; i++)
+        zi->ci.central_header[zi->ci.size_centralheader+
+            zi->ci.size_centralextrafree+i] = comment[i];
+
+    if (zi->ci.central_header == NULL)
+        return ZIP_INTERNALERROR;
+
+    /* Write the local header */
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)LOCALHEADERMAGIC, 4);
+
+    if (err == ZIP_OK)
+    {
+        if (zi->ci.zip64)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint16_t)45, 2); /* version needed to extract */
+        else
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint16_t)20, 2); /* version needed to extract */
+    }
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->ci.flag, 2);
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->ci.method, 2);
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->ci.dos_date, 4);
+
+    /* CRC & compressed size & uncompressed size is in data descriptor */
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)0, 4); /* crc 32, unknown */
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)0, 4); /* compressed size, unknown */
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)0, 4); /* uncompressed size, unknown */
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, size_filename, 2);
+    if (err == ZIP_OK)
+    {
+        uint64_t size_extrafield = size_extrafield_local;
+#ifdef HAVE_AES
+        if (zi->ci.method == AES_METHOD)
+            size_extrafield += 11;
+#endif
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint16_t)size_extrafield, 2);
+    }
+    if ((err == ZIP_OK) && (size_filename > 0))
+    {
+        if (ZWRITE64(zi->z_filefunc, zi->filestream, filename, size_filename) != size_filename)
+            err = ZIP_ERRNO;
+    }
+    if ((err == ZIP_OK) && (size_extrafield_local > 0))
+    {
+        if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local)
+            err = ZIP_ERRNO;
+    }
+
+#ifdef HAVE_AES
+    /* Write the AES extended info */
+    if ((err == ZIP_OK) && (zi->ci.method == AES_METHOD))
+    {
+        int headerid = 0x9901;
+        short datasize = 7;
+
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, headerid, 2);
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, datasize, 2);
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, AES_VERSION, 2);
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, 'A', 1);
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, 'E', 1);
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, AES_ENCRYPTIONMODE, 1);
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->ci.compression_method, 2);
+    }
+#endif
+
+    zi->ci.crc32 = 0;
+    zi->ci.stream_initialised = 0;
+    zi->ci.pos_in_buffered_data = 0;
+    zi->ci.total_compressed = 0;
+    zi->ci.total_uncompressed = 0;
+
+#ifdef HAVE_BZIP2
+    zi->ci.bstream.avail_in = (uint16_t)0;
+    zi->ci.bstream.avail_out = (uint16_t)Z_BUFSIZE;
+    zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+    zi->ci.bstream.total_in_hi32 = 0;
+    zi->ci.bstream.total_in_lo32 = 0;
+    zi->ci.bstream.total_out_hi32 = 0;
+    zi->ci.bstream.total_out_lo32 = 0;
+#endif
+
+    zi->ci.stream.avail_in = (uint16_t)0;
+    zi->ci.stream.avail_out = Z_BUFSIZE;
+    zi->ci.stream.next_out = zi->ci.buffered_data;
+    zi->ci.stream.total_in = 0;
+    zi->ci.stream.total_out = 0;
+    zi->ci.stream.data_type = Z_BINARY;
+
+    if ((err == ZIP_OK) && (!zi->ci.raw))
+    {
+        if (method == Z_DEFLATED)
+        {
+            zi->ci.stream.zalloc = (alloc_func)0;
+            zi->ci.stream.zfree = (free_func)0;
+            zi->ci.stream.opaque = (voidpf)zi;
+
+            if (windowBits > 0)
+                windowBits = -windowBits;
+
+#ifdef HAVE_APPLE_COMPRESSION
+            err = compression_stream_init(&zi->ci.astream, COMPRESSION_STREAM_ENCODE, COMPRESSION_ZLIB);
+            if (err == COMPRESSION_STATUS_ERROR)
+                err = Z_ERRNO;
+            else
+                err = Z_OK;
+#else
+            err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
+#endif
+            if (err == Z_OK)
+                zi->ci.stream_initialised = Z_DEFLATED;
+        }
+        else if (method == Z_BZIP2ED)
+        {
+#ifdef HAVE_BZIP2
+            zi->ci.bstream.bzalloc = 0;
+            zi->ci.bstream.bzfree = 0;
+            zi->ci.bstream.opaque = (voidpf)0;
+
+            err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0, 35);
+            if (err == BZ_OK)
+                zi->ci.stream_initialised = Z_BZIP2ED;
+#endif
+        }
+    }
+
+#ifndef NOCRYPT
+    if ((err == Z_OK) && (password != NULL))
+    {
+#ifdef HAVE_AES
+        if (zi->ci.method == AES_METHOD)
+        {
+            unsigned char passverify[AES_PWVERIFYSIZE];
+            unsigned char saltvalue[AES_MAXSALTLENGTH];
+            uint16_t saltlength = 0;
+
+            if ((AES_ENCRYPTIONMODE < 1) || (AES_ENCRYPTIONMODE > 3))
+                return Z_ERRNO;
+
+            saltlength = SALT_LENGTH(AES_ENCRYPTIONMODE);
+
+            prng_init(cryptrand, zi->ci.aes_rng);
+            prng_rand(saltvalue, saltlength, zi->ci.aes_rng);
+            prng_end(zi->ci.aes_rng);
+
+            fcrypt_init(AES_ENCRYPTIONMODE, (uint8_t *)password, (uint32_t)strlen(password), saltvalue, passverify, &zi->ci.aes_ctx);
+
+            if (ZWRITE64(zi->z_filefunc, zi->filestream, saltvalue, saltlength) != saltlength)
+                err = ZIP_ERRNO;
+            if (ZWRITE64(zi->z_filefunc, zi->filestream, passverify, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE)
+                err = ZIP_ERRNO;
+
+            zi->ci.total_compressed += saltlength + AES_PWVERIFYSIZE + AES_AUTHCODESIZE;
+        }
+        else
+#endif
+        {
+            unsigned char buf_head[RAND_HEAD_LEN];
+            uint32_t size_head = 0;
+            uint8_t verify1 = 0;
+            uint8_t verify2 = 0;
+
+            zi->ci.pcrc_32_tab = get_crc_table();
+
+            /*
+            Info-ZIP modification to ZipCrypto format:
+            If bit 3 of the general purpose bit flag is set, it uses high byte of 16-bit File Time. 
+            */
+            verify1 = (uint8_t)((zi->ci.dos_date >> 16) & 0xff);
+            verify2 = (uint8_t)((zi->ci.dos_date >> 8) & 0xff);
+
+            size_head = crypthead(password, buf_head, RAND_HEAD_LEN, zi->ci.keys, zi->ci.pcrc_32_tab, verify1, verify2);
+            zi->ci.total_compressed += size_head;
+
+            if (ZWRITE64(zi->z_filefunc, zi->filestream, buf_head, size_head) != size_head)
+                err = ZIP_ERRNO;
+        }
+    }
+#endif
+
+    if (err == Z_OK)
+        zi->in_opened_file_inzip = 1;
+    return err;
+}
+
+extern int ZEXPORT zipOpenNewFileInZip4(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw, int windowBits,
+    int memLevel, int strategy, const char *password, ZIP_UNUSED uint32_t crc_for_crypting, uint16_t version_madeby, uint16_t flag_base)
+{
+    return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+        extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel,
+        strategy, password, crc_for_crypting, version_madeby, flag_base, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip3(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw, int windowBits,
+    int memLevel, int strategy, const char *password, ZIP_UNUSED uint32_t crc_for_crypting)
+{
+    return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+        extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel,
+        strategy, password, crc_for_crypting, VERSIONMADEBY, 0, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw, int windowBits,
+    int memLevel, int strategy, const char *password, ZIP_UNUSED uint32_t crc_for_crypting, int zip64)
+{
+    return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+        extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy,
+        password, crc_for_crypting, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw)
+{
+    return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+        extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL,
+        Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw, int zip64)
+{
+    return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+        extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL,
+        Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int zip64)
+{
+    return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+        extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL,
+        Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level)
+{
+    return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+        extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL,
+        Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0);
+}
+
+/* Flushes the write buffer to disk */
+static int zipFlushWriteBuffer(zip64_internal *zi)
+{
+    uint64_t size_available = 0;
+    uint32_t written = 0;
+    uint32_t total_written = 0;
+    uint32_t write = 0;
+    uint32_t max_write = 0;
+    int err = ZIP_OK;
+
+    if ((zi->ci.flag & 1) != 0)
+    {
+#ifndef NOCRYPT
+#ifdef HAVE_AES
+        if (zi->ci.method == AES_METHOD)
+        {
+            fcrypt_encrypt(zi->ci.buffered_data, zi->ci.pos_in_buffered_data, &zi->ci.aes_ctx);
+        }
+        else
+#endif
+        {
+            uint32_t i = 0;
+            uint8_t t = 0;
+
+            for (i = 0; i < zi->ci.pos_in_buffered_data; i++)
+                zi->ci.buffered_data[i] = (uint8_t)zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i], t);
+        }
+#endif
+    }
+
+    write = zi->ci.pos_in_buffered_data;
+
+    do
+    {
+        max_write = write;
+
+        if (zi->disk_size > 0)
+        {
+            zipGetDiskSizeAvailable((zipFile)zi, &size_available);
+
+            if (size_available == 0)
+            {
+                err = zipGoToNextDisk((zipFile)zi);
+                if (err != ZIP_OK)
+                    return err;
+            }
+
+            if (size_available < (uint64_t)max_write)
+                max_write = (uint32_t)size_available;
+        }
+
+        written = ZWRITE64(zi->z_filefunc, zi->filestream, zi->ci.buffered_data + total_written, max_write);
+        if (written != max_write)
+        {
+            err = ZIP_ERRNO;
+            break;
+        }
+
+        total_written += written;
+        write -= written;
+    }
+    while (write > 0);
+
+    zi->ci.total_compressed += zi->ci.pos_in_buffered_data;
+
+#ifdef HAVE_BZIP2
+    if (zi->ci.compression_method == Z_BZIP2ED)
+    {
+        zi->ci.total_uncompressed += zi->ci.bstream.total_in_lo32;
+        zi->ci.bstream.total_in_lo32 = 0;
+        zi->ci.bstream.total_in_hi32 = 0;
+    }
+    else
+#endif
+    {
+        zi->ci.total_uncompressed += zi->ci.stream.total_in;
+        zi->ci.stream.total_in = 0;
+    }
+
+    zi->ci.pos_in_buffered_data = 0;
+
+    return err;
+}
+
+extern int ZEXPORT zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len)
+{
+    zip64_internal *zi = NULL;
+    int err = ZIP_OK;
+
+    if (file == NULL)
+        return ZIP_PARAMERROR;
+    zi = (zip64_internal*)file;
+
+    if (zi->in_opened_file_inzip == 0)
+        return ZIP_PARAMERROR;
+
+    zi->ci.crc32 = (uint32_t)crc32(zi->ci.crc32, buf, len);
+
+#ifdef HAVE_BZIP2
+    if ((zi->ci.compression_method == Z_BZIP2ED) && (!zi->ci.raw))
+    {
+        zi->ci.bstream.next_in = (void*)buf;
+        zi->ci.bstream.avail_in = len;
+        err = BZ_RUN_OK;
+
+        while ((err == BZ_RUN_OK) && (zi->ci.bstream.avail_in > 0))
+        {
+            if (zi->ci.bstream.avail_out == 0)
+            {
+                err = zipFlushWriteBuffer(zi);
+                
+                zi->ci.bstream.avail_out = (uint16_t)Z_BUFSIZE;
+                zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+            }
+            else
+            {
+                uint32_t total_out_before_lo = zi->ci.bstream.total_out_lo32;
+                uint32_t total_out_before_hi = zi->ci.bstream.total_out_hi32;
+
+                err = BZ2_bzCompress(&zi->ci.bstream, BZ_RUN);
+
+                zi->ci.pos_in_buffered_data += (uint16_t)(zi->ci.bstream.total_out_lo32 - total_out_before_lo);
+            }
+        }
+
+        if (err == BZ_RUN_OK)
+            err = ZIP_OK;
+    }
+    else
+#endif
+    {
+        zi->ci.stream.next_in = (uint8_t*)buf;
+        zi->ci.stream.avail_in = len;
+
+        while ((err == ZIP_OK) && (zi->ci.stream.avail_in > 0))
+        {
+            if (zi->ci.stream.avail_out == 0)
+            {
+                err = zipFlushWriteBuffer(zi);
+                
+                zi->ci.stream.avail_out = Z_BUFSIZE;
+                zi->ci.stream.next_out = zi->ci.buffered_data;
+            }
+
+            if (err != ZIP_OK)
+                break;
+
+            if ((zi->ci.compression_method == Z_DEFLATED) && (!zi->ci.raw))
+            {
+#ifdef HAVE_APPLE_COMPRESSION
+                uLong total_out_before = zi->ci.stream.total_out;
+
+                zi->ci.astream.src_ptr = zi->ci.stream.next_in;
+                zi->ci.astream.src_size = zi->ci.stream.avail_in;
+                zi->ci.astream.dst_ptr = zi->ci.stream.next_out;
+                zi->ci.astream.dst_size = zi->ci.stream.avail_out;
+
+                compression_status status = 0;
+                compression_stream_flags flags = 0;
+
+                status = compression_stream_process(&zi->ci.astream, flags);
+
+                uLong total_out_after = len - zi->ci.astream.src_size;
+
+                zi->ci.stream.next_in = zi->ci.astream.src_ptr;
+                zi->ci.stream.avail_in = zi->ci.astream.src_size;
+                zi->ci.stream.next_out = zi->ci.astream.dst_ptr;
+                zi->ci.stream.avail_out = zi->ci.astream.dst_size;
+                zi->ci.stream.total_in += total_out_after;
+                //zi->ci.stream.total_out += copy_this;
+                zi->ci.pos_in_buffered_data += total_out_after;
+
+                if (status == COMPRESSION_STATUS_ERROR)
+                    err = ZIP_INTERNALERROR;
+#else
+                uint32_t total_out_before = (uint32_t)zi->ci.stream.total_out;
+                err = deflate(&zi->ci.stream, Z_NO_FLUSH);
+                zi->ci.pos_in_buffered_data += (uint32_t)(zi->ci.stream.total_out - total_out_before);
+#endif
+            }
+            else
+            {
+                uint32_t copy_this = 0;
+                uint32_t i = 0;
+                if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
+                    copy_this = zi->ci.stream.avail_in;
+                else
+                    copy_this = zi->ci.stream.avail_out;
+
+                for (i = 0; i < copy_this; i++)
+                    *(((char*)zi->ci.stream.next_out)+i) =
+                        *(((const char*)zi->ci.stream.next_in)+i);
+
+                zi->ci.stream.avail_in -= copy_this;
+                zi->ci.stream.avail_out -= copy_this;
+                zi->ci.stream.next_in += copy_this;
+                zi->ci.stream.next_out += copy_this;
+                zi->ci.stream.total_in += copy_this;
+                zi->ci.stream.total_out += copy_this;
+                zi->ci.pos_in_buffered_data += copy_this;
+            }
+        }
+    }
+
+    return err;
+}
+
+extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, uint64_t uncompressed_size, uint32_t crc32)
+{
+    zip64_internal *zi = NULL;
+    uint16_t extra_data_size = 0;
+    uint32_t i = 0;
+    unsigned char *extra_info = NULL;
+    int err = ZIP_OK;
+
+    if (file == NULL)
+        return ZIP_PARAMERROR;
+    zi = (zip64_internal*)file;
+
+    if (zi->in_opened_file_inzip == 0)
+        return ZIP_PARAMERROR;
+    zi->ci.stream.avail_in = 0;
+
+    if (!zi->ci.raw)
+    {
+        if (zi->ci.compression_method == Z_DEFLATED)
+        {
+            while (err == ZIP_OK)
+            {
+                uint32_t total_out_before = 0;
+                
+                if (zi->ci.stream.avail_out == 0)
+                {
+                    err = zipFlushWriteBuffer(zi);
+
+                    zi->ci.stream.avail_out = Z_BUFSIZE;
+                    zi->ci.stream.next_out = zi->ci.buffered_data;
+                }
+                
+                if (err != ZIP_OK)
+                    break;
+                
+#ifdef HAVE_APPLE_COMPRESSION
+                total_out_before = zi->ci.stream.total_out;
+
+                zi->ci.astream.src_ptr = zi->ci.stream.next_in;
+                zi->ci.astream.src_size = zi->ci.stream.avail_in;
+                zi->ci.astream.dst_ptr = zi->ci.stream.next_out;
+                zi->ci.astream.dst_size = zi->ci.stream.avail_out;
+
+                compression_status status = 0;
+                status = compression_stream_process(&zi->ci.astream, COMPRESSION_STREAM_FINALIZE);
+
+                uint32_t total_out_after = Z_BUFSIZE - zi->ci.astream.dst_size;
+
+                zi->ci.stream.next_in = zi->ci.astream.src_ptr;
+                zi->ci.stream.avail_in = zi->ci.astream.src_size;
+                zi->ci.stream.next_out = zi->ci.astream.dst_ptr;
+                zi->ci.stream.avail_out = zi->ci.astream.dst_size;
+                //zi->ci.stream.total_in += total_out_after;
+                //zi->ci.stream.total_out += copy_this;
+                zi->ci.pos_in_buffered_data += total_out_after;
+
+                if (status == COMPRESSION_STATUS_ERROR)
+                {
+                    err = ZIP_INTERNALERROR;
+                }
+                else if (status == COMPRESSION_STATUS_END)
+                {
+                    err = Z_STREAM_END;
+                }
+#else
+                total_out_before = (uint32_t)zi->ci.stream.total_out;
+                err = deflate(&zi->ci.stream, Z_FINISH);
+                zi->ci.pos_in_buffered_data += (uint16_t)(zi->ci.stream.total_out - total_out_before);
+#endif
+            }
+        }
+        else if (zi->ci.compression_method == Z_BZIP2ED)
+        {
+#ifdef HAVE_BZIP2
+            err = BZ_FINISH_OK;
+            while (err == BZ_FINISH_OK)
+            {
+                uint32_t total_out_before = 0;
+                
+                if (zi->ci.bstream.avail_out == 0)
+                {
+                    err = zipFlushWriteBuffer(zi);
+                    
+                    zi->ci.bstream.avail_out = (uint16_t)Z_BUFSIZE;
+                    zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+                }
+                
+                total_out_before = zi->ci.bstream.total_out_lo32;
+                err = BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH);
+                if (err == BZ_STREAM_END)
+                    err = Z_STREAM_END;
+                zi->ci.pos_in_buffered_data += (uint16_t)(zi->ci.bstream.total_out_lo32 - total_out_before);
+            }
+
+            if (err == BZ_FINISH_OK)
+                err = ZIP_OK;
+#endif
+        }
+    }
+
+    if (err == Z_STREAM_END)
+        err = ZIP_OK; /* this is normal */
+
+    if ((zi->ci.pos_in_buffered_data > 0) && (err == ZIP_OK))
+    {
+        err = zipFlushWriteBuffer(zi);
+    }
+
+#ifdef HAVE_AES
+    if (zi->ci.method == AES_METHOD)
+    {
+        unsigned char authcode[AES_AUTHCODESIZE];
+
+        fcrypt_end(authcode, &zi->ci.aes_ctx);
+
+        if (ZWRITE64(zi->z_filefunc, zi->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE)
+            err = ZIP_ERRNO;
+    }
+#endif
+
+    if (!zi->ci.raw)
+    {
+        if (zi->ci.compression_method == Z_DEFLATED)
+        {
+            int tmp_err = 0;
+#ifdef HAVE_APPLE_COMPRESSION
+            tmp_err = compression_stream_destroy(&zi->ci.astream);
+#else
+            tmp_err = deflateEnd(&zi->ci.stream);
+#endif
+            if (err == ZIP_OK)
+                err = tmp_err;
+            zi->ci.stream_initialised = 0;
+        }
+#ifdef HAVE_BZIP2
+        else if (zi->ci.compression_method == Z_BZIP2ED)
+        {
+            int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream);
+            if (err == ZIP_OK)
+                err = tmperr;
+            zi->ci.stream_initialised = 0;
+        }
+#endif
+
+        crc32 = zi->ci.crc32;
+        uncompressed_size = zi->ci.total_uncompressed;
+    }
+
+    /* Write data descriptor */
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)DATADESCRIPTORMAGIC, 4);
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, crc32, 4);
+    if (err == ZIP_OK)
+    {
+        if (zi->ci.zip64)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->ci.total_compressed, 8);
+        else
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)zi->ci.total_compressed, 4);
+    }
+    if (err == ZIP_OK)
+    {
+        if (zi->ci.zip64)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8);
+        else
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)uncompressed_size, 4);
+    }
+
+    /* Update crc and sizes to central directory */
+    zipWriteValueToMemory(zi->ci.central_header + 16, crc32, 4); /* crc */
+    if (zi->ci.total_compressed >= UINT32_MAX)
+        zipWriteValueToMemory(zi->ci.central_header + 20, UINT32_MAX, 4); /* compr size */
+    else
+        zipWriteValueToMemory(zi->ci.central_header + 20, zi->ci.total_compressed, 4); /* compr size */
+    if (uncompressed_size >= UINT32_MAX)
+        zipWriteValueToMemory(zi->ci.central_header + 24, UINT32_MAX, 4); /* uncompr size */
+    else
+        zipWriteValueToMemory(zi->ci.central_header + 24, uncompressed_size, 4); /* uncompr size */
+    if (zi->ci.stream.data_type == Z_ASCII)
+        zipWriteValueToMemory(zi->ci.central_header + 36, (uint16_t)Z_ASCII, 2); /* internal file attrib */
+
+    /* Add ZIP64 extra info field for uncompressed size */
+    if (uncompressed_size >= UINT32_MAX)
+        extra_data_size += 8;
+    /* Add ZIP64 extra info field for compressed size */
+    if (zi->ci.total_compressed >= UINT32_MAX)
+        extra_data_size += 8;
+    /* Add ZIP64 extra info field for relative offset to local file header of current file */
+    if (zi->ci.pos_local_header >= UINT32_MAX)
+        extra_data_size += 8;
+
+    /* Add ZIP64 extra info header to central directory */
+    if (extra_data_size > 0)
+    {
+        if ((uint32_t)(extra_data_size + 4) > zi->ci.size_centralextrafree)
+            return ZIP_BADZIPFILE;
+
+        extra_info = (unsigned char*)zi->ci.central_header + zi->ci.size_centralheader;
+
+        zipWriteValueToMemoryAndMove(&extra_info, 0x0001, 2);
+        zipWriteValueToMemoryAndMove(&extra_info, extra_data_size, 2);
+
+        if (uncompressed_size >= UINT32_MAX)
+            zipWriteValueToMemoryAndMove(&extra_info, uncompressed_size, 8);
+        if (zi->ci.total_compressed >= UINT32_MAX)
+            zipWriteValueToMemoryAndMove(&extra_info, zi->ci.total_compressed, 8);
+        if (zi->ci.pos_local_header >= UINT32_MAX)
+            zipWriteValueToMemoryAndMove(&extra_info, zi->ci.pos_local_header, 8);
+
+        zi->ci.size_centralextrafree -= extra_data_size + 4;
+        zi->ci.size_centralheader += extra_data_size + 4;
+        zi->ci.size_centralextra += extra_data_size + 4;
+
+        zipWriteValueToMemory(zi->ci.central_header + 30, zi->ci.size_centralextra, 2);
+    }
+
+#ifdef HAVE_AES
+    /* Write AES extra info header to central directory */
+    if (zi->ci.method == AES_METHOD)
+    {
+        extra_info = (unsigned char*)zi->ci.central_header + zi->ci.size_centralheader;
+        extra_data_size = 7;
+
+        if ((uint32_t)(extra_data_size + 4) > zi->ci.size_centralextrafree)
+            return ZIP_BADZIPFILE;
+
+        zipWriteValueToMemoryAndMove(&extra_info, 0x9901, 2);
+        zipWriteValueToMemoryAndMove(&extra_info, extra_data_size, 2);
+        zipWriteValueToMemoryAndMove(&extra_info, AES_VERSION, 2);
+        zipWriteValueToMemoryAndMove(&extra_info, 'A', 1);
+        zipWriteValueToMemoryAndMove(&extra_info, 'E', 1);
+        zipWriteValueToMemoryAndMove(&extra_info, AES_ENCRYPTIONMODE, 1);
+        zipWriteValueToMemoryAndMove(&extra_info, zi->ci.compression_method, 2);
+
+        zi->ci.size_centralextrafree -= extra_data_size + 4;
+        zi->ci.size_centralheader += extra_data_size + 4;
+        zi->ci.size_centralextra += extra_data_size + 4;
+
+        zipWriteValueToMemory(zi->ci.central_header + 30, zi->ci.size_centralextra, 2);
+    }
+#endif
+    /* Restore comment to correct position */
+    for (i = 0; i < zi->ci.size_comment; i++)
+        zi->ci.central_header[zi->ci.size_centralheader+i] =
+            zi->ci.central_header[zi->ci.size_centralheader+zi->ci.size_centralextrafree+i];
+    zi->ci.size_centralheader += zi->ci.size_comment;
+
+    if (err == ZIP_OK)
+        err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, zi->ci.size_centralheader);
+
+    free(zi->ci.central_header);
+
+    zi->number_entry++;
+    zi->in_opened_file_inzip = 0;
+
+    return err;
+}
+
+extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uint32_t uncompressed_size, uint32_t crc32)
+{
+    return zipCloseFileInZipRaw64(file, uncompressed_size, crc32);
+}
+
+extern int ZEXPORT zipCloseFileInZip(zipFile file)
+{
+    return zipCloseFileInZipRaw(file, 0, 0);
+}
+
+extern int ZEXPORT zipClose(zipFile file, const char *global_comment)
+{
+    return zipClose_64(file, global_comment);
+}
+
+extern int ZEXPORT zipClose_64(zipFile file, const char *global_comment)
+{
+    return zipClose2_64(file, global_comment, VERSIONMADEBY);
+}
+
+extern int ZEXPORT zipClose2_64(zipFile file, const char *global_comment, uint16_t version_madeby)
+{
+    zip64_internal *zi = NULL;
+    uint32_t size_centraldir = 0;
+    uint16_t size_global_comment = 0;
+    uint64_t centraldir_pos_inzip = 0;
+    uint64_t pos = 0;
+    uint64_t cd_pos = 0;
+    uint32_t write = 0;
+    int err = ZIP_OK;
+
+    if (file == NULL)
+        return ZIP_PARAMERROR;
+    zi = (zip64_internal*)file;
+
+    if (zi->in_opened_file_inzip == 1)
+        err = zipCloseFileInZip(file);
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+    if (global_comment == NULL)
+        global_comment = zi->globalcomment;
+#endif
+
+    if (zi->filestream != zi->filestream_with_CD)
+    {
+        if (ZCLOSE64(zi->z_filefunc, zi->filestream) != 0)
+            if (err == ZIP_OK)
+                err = ZIP_ERRNO;
+        if (zi->disk_size > 0)
+            zi->number_disk_with_CD = zi->number_disk + 1;
+        zi->filestream = zi->filestream_with_CD;
+    }
+
+    centraldir_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream);
+
+    if (err == ZIP_OK)
+    {
+        linkedlist_datablock_internal *ldi = zi->central_dir.first_block;
+        while (ldi != NULL)
+        {
+            if ((err == ZIP_OK) && (ldi->filled_in_this_block > 0))
+            {
+                write = ZWRITE64(zi->z_filefunc, zi->filestream, ldi->data, ldi->filled_in_this_block);
+                if (write != ldi->filled_in_this_block)
+                    err = ZIP_ERRNO;
+            }
+
+            size_centraldir += ldi->filled_in_this_block;
+            ldi = ldi->next_datablock;
+        }
+    }
+
+    free_linkedlist(&(zi->central_dir));
+
+    pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+
+    /* Write the ZIP64 central directory header */
+    if (pos >= UINT32_MAX || zi->number_entry > UINT32_MAX)
+    {
+        uint64_t zip64_eocd_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream);
+        uint32_t zip64_datasize = 44;
+
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)ZIP64ENDHEADERMAGIC, 4);
+
+        /* Size of this 'zip64 end of central directory' */
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint64_t)zip64_datasize, 8);
+        /* Version made by */
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, version_madeby, 2);
+        /* version needed */
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint16_t)45, 2);
+        /* Number of this disk */
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->number_disk_with_CD, 4);
+        /* Number of the disk with the start of the central directory */
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->number_disk_with_CD, 4);
+        /* Total number of entries in the central dir on this disk */
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
+        /* Total number of entries in the central dir */
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
+        /* Size of the central directory */
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint64_t)size_centraldir, 8);
+
+        if (err == ZIP_OK)
+        {
+            /* Offset of start of central directory with respect to the starting disk number */
+            cd_pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, cd_pos, 8);
+        }
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)ZIP64ENDLOCHEADERMAGIC, 4);
+
+        /* Number of the disk with the start of the central directory */
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->number_disk_with_CD, 4);
+        /* Relative offset to the Zip64EndOfCentralDirectory */
+        if (err == ZIP_OK)
+        {
+            cd_pos = zip64_eocd_pos_inzip - zi->add_position_when_writting_offset;
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, cd_pos, 8);
+        }
+        /* Number of the disk with the start of the central directory */
+        if (err == ZIP_OK)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, zi->number_disk_with_CD + 1, 4);
+    }
+
+    /* Write the central directory header */
+
+    /* Signature */
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)ENDHEADERMAGIC, 4);
+    /* Number of this disk */
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint16_t)zi->number_disk_with_CD, 2);
+    /* Number of the disk with the start of the central directory */
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint16_t)zi->number_disk_with_CD, 2);
+    /* Total number of entries in the central dir on this disk */
+    if (err == ZIP_OK)
+    {
+        if (zi->number_entry >= UINT16_MAX)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, UINT16_MAX, 2); /* use value in ZIP64 record */
+        else
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint16_t)zi->number_entry, 2);
+    }
+    /* Total number of entries in the central dir */
+    if (err == ZIP_OK)
+    {
+        if (zi->number_entry >= UINT16_MAX)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, UINT16_MAX, 2); /* use value in ZIP64 record */
+        else
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint16_t)zi->number_entry, 2);
+    }
+    /* Size of the central directory */
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, size_centraldir, 4);
+    /* Offset of start of central directory with respect to the starting disk number */
+    if (err == ZIP_OK)
+    {
+        cd_pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+        if (pos >= UINT32_MAX)
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, UINT32_MAX, 4);
+        else
+            err = zipWriteValue(&zi->z_filefunc, zi->filestream, (uint32_t)cd_pos, 4);
+    }
+
+    /* Write global comment */
+
+    if (global_comment != NULL)
+        size_global_comment = (uint16_t)strlen(global_comment);
+    if (err == ZIP_OK)
+        err = zipWriteValue(&zi->z_filefunc, zi->filestream, size_global_comment, 2);
+    if (err == ZIP_OK && size_global_comment > 0)
+    {
+        if (ZWRITE64(zi->z_filefunc, zi->filestream, global_comment, size_global_comment) != size_global_comment)
+            err = ZIP_ERRNO;
+    }
+
+    if ((ZCLOSE64(zi->z_filefunc, zi->filestream) != 0) && (err == ZIP_OK))
+        err = ZIP_ERRNO;
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+    TRYFREE(zi->globalcomment);
+#endif
+    TRYFREE(zi);
+
+    return err;
+}

+ 200 - 0
ios/Classes/SSZipArchive/minizip/zip.h

@@ -0,0 +1,200 @@
+/* zip.h -- IO on .zip files using zlib
+   Version 1.2.0, September 16th, 2017
+   part of the MiniZip project
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 2009-2010 Mathias Svensson
+     Modifications for Zip64 support
+     http://result42.com
+   Copyright (C) 1998-2010 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef _ZIP_H
+#define _ZIP_H
+
+#define HAVE_AES
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#  include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#  include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#  include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+    from (void*) without cast */
+typedef struct TagzipFile__ { int unused; } zip_file__;
+typedef zip_file__ *zipFile;
+#else
+typedef voidp zipFile;
+#endif
+
+#define ZIP_OK                          (0)
+#define ZIP_EOF                         (0)
+#define ZIP_ERRNO                       (Z_ERRNO)
+#define ZIP_PARAMERROR                  (-102)
+#define ZIP_BADZIPFILE                  (-103)
+#define ZIP_INTERNALERROR               (-104)
+
+#ifdef __GNUC__
+#  define ZIP_UNUSED __attribute__((__unused__))
+#else
+#  define ZIP_UNUSED
+#endif
+
+#ifndef DEF_MEM_LEVEL
+#  if MAX_MEM_LEVEL >= 8
+#    define DEF_MEM_LEVEL 8
+#  else
+#    define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#  endif
+#endif
+
+typedef struct
+{
+    uint32_t    dos_date;
+    uint16_t    internal_fa;        /* internal file attributes        2 bytes */
+    uint32_t    external_fa;        /* external file attributes        4 bytes */
+} zip_fileinfo;
+
+#define APPEND_STATUS_CREATE        (0)
+#define APPEND_STATUS_CREATEAFTER   (1)
+#define APPEND_STATUS_ADDINZIP      (2)
+
+/***************************************************************************/
+/* Writing a zip file */
+
+extern zipFile ZEXPORT zipOpen(const char *path, int append);
+extern zipFile ZEXPORT zipOpen64(const void *path, int append);
+/* Create a zipfile.
+
+   path should contain the full path (by example, on a Windows XP computer 
+      "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". 
+
+   return NULL if zipfile cannot be opened
+   return zipFile handle if no error
+
+   If the file path exist and append == APPEND_STATUS_CREATEAFTER, the zip
+   will be created at the end of the file. (useful if the file contain a self extractor code)
+   If the file path exist and append == APPEND_STATUS_ADDINZIP, we will add files in existing 
+   zip (be sure you don't add file that doesn't exist)
+
+   NOTE: There is no delete function into a zipfile. If you want delete file into a zipfile, 
+   you must open a zipfile, and create another. Of course, you can use RAW reading and writing to copy
+   the file you did not want delete. */
+
+extern zipFile ZEXPORT zipOpen2(const char *path, int append, const char **globalcomment, 
+    zlib_filefunc_def *pzlib_filefunc_def);
+
+extern zipFile ZEXPORT zipOpen2_64(const void *path, int append, const char **globalcomment, 
+    zlib_filefunc64_def *pzlib_filefunc_def);
+
+extern zipFile ZEXPORT zipOpen3(const char *path, int append, uint64_t disk_size, 
+    const char **globalcomment, zlib_filefunc_def *pzlib_filefunc_def);
+/* Same as zipOpen2 but allows specification of spanned zip size */
+
+extern zipFile ZEXPORT zipOpen3_64(const void *path, int append, uint64_t disk_size, 
+    const char **globalcomment, zlib_filefunc64_def *pzlib_filefunc_def);
+
+extern int ZEXPORT zipOpenNewFileInZip(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global, 
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level);
+/* Open a file in the ZIP for writing.
+
+   filename : the filename in zip (if NULL, '-' without quote will be used
+   *zipfi contain supplemental information
+   extrafield_local buffer to store the local header extra field data, can be NULL
+   size_extrafield_local size of extrafield_local buffer
+   extrafield_global buffer to store the global header extra field data, can be NULL
+   size_extrafield_global size of extrafield_local buffer
+   comment buffer for comment string
+   method contain the compression method (0 for store, Z_DEFLATED for deflate)
+   level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
+   zip64 is set to 1 if a zip64 extended information block should be added to the local file header.
+   this MUST be '1' if the uncompressed size is >= 0xffffffff. */
+
+extern int ZEXPORT zipOpenNewFileInZip64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int zip64);
+/* Same as zipOpenNewFileInZip with zip64 support */
+
+extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw);
+/* Same as zipOpenNewFileInZip, except if raw=1, we write raw file */
+
+extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw, int zip64);
+/* Same as zipOpenNewFileInZip3 with zip64 support */
+
+extern int ZEXPORT zipOpenNewFileInZip3(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw, int windowBits, int memLevel,
+    int strategy, const char *password, ZIP_UNUSED uint32_t crc_for_crypting);
+/* Same as zipOpenNewFileInZip2, except
+    windowBits, memLevel, strategy : see parameter strategy in deflateInit2
+    password : crypting password (NULL for no crypting)
+    crc_for_crypting : crc of file to compress (needed for crypting) */
+
+extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw, int windowBits, int memLevel,
+    int strategy, const char *password, ZIP_UNUSED uint32_t crc_for_crypting, int zip64);
+/* Same as zipOpenNewFileInZip3 with zip64 support */
+
+extern int ZEXPORT zipOpenNewFileInZip4(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw, int windowBits, int memLevel,
+    int strategy, const char *password, ZIP_UNUSED uint32_t crc_for_crypting, uint16_t version_madeby, uint16_t flag_base);
+/* Same as zipOpenNewFileInZip3 except versionMadeBy & flag fields */
+
+extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+    uint16_t size_extrafield_global, const char *comment, uint16_t method, int level, int raw, int windowBits, int memLevel,
+    int strategy, const char *password, ZIP_UNUSED uint32_t crc_for_crypting, uint16_t version_madeby, uint16_t flag_base, int zip64);
+/* Same as zipOpenNewFileInZip4 with zip64 support */
+
+extern int ZEXPORT zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len);
+/* Write data in the zipfile */
+
+extern int ZEXPORT zipCloseFileInZip(zipFile file);
+/* Close the current file in the zipfile */
+
+extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uint32_t uncompressed_size, uint32_t crc32);
+extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, uint64_t uncompressed_size, uint32_t crc32);
+/* Close the current file in the zipfile, for file opened with parameter raw=1 in zipOpenNewFileInZip2
+   where raw is compressed data. Parameters uncompressed_size and crc32 are value for the uncompressed data. */
+
+extern int ZEXPORT zipClose(zipFile file, const char *global_comment);
+/* Close the zipfile */
+
+extern int ZEXPORT zipClose_64(zipFile file, const char *global_comment);
+
+extern int ZEXPORT zipClose2_64(zipFile file, const char *global_comment, uint16_t version_madeby);
+/* Same as zipClose_64 except version_madeby field */
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZIP_H */

+ 9 - 7
ios/Classes/SwiftFlutterzipPlugin.swift

@@ -1,8 +1,7 @@
 import Flutter
 import UIKit
 //SSZipArchiveDelegate
-import  SSZipArchive
-public class SwiftFlutterzipPlugin: NSObject, FlutterPlugin ,SSZipArchiveDelegate{
+public class SwiftFlutterzipPlugin: NSObject, FlutterPlugin{
     var channell : FlutterMethodChannel?
     init(channell:FlutterMethodChannel) {
         self.channell = channell;
@@ -25,8 +24,8 @@ public class SwiftFlutterzipPlugin: NSObject, FlutterPlugin ,SSZipArchiveDelegat
    let arguments = call.arguments as! Dictionary<String, AnyObject>
    let outPath = arguments["outPath"] as! String
    let unzipPath = arguments["unzipPath"] as! String
-        SSZipArchive.unzipFile(atPath: unzipPath, toDestination: outPath,delegate: self);
-          
+//        SSZipArchive.unzipFile(atPath: unzipPath, toDestination: outPath,delegate: self);
+//        result("ok");
            
     }
     
@@ -34,9 +33,12 @@ public class SwiftFlutterzipPlugin: NSObject, FlutterPlugin ,SSZipArchiveDelegat
     
     public func zipArchiveProgressEvent(_ loaded: UInt64, total: UInt64) {
         
-        var someDict:[String:UInt64] = ["total":total, "percent":loaded]
-
-        channell?.invokeMethod("process", arguments:someDict)
+//        var someDict:[String:UInt64] = ["total":total, "percent":loaded]
+        if(total==loaded){
+            
+            print("Progress==done");
+        }
+        //channell?.invokeMethod("process", arguments:someDict)
         
     }
     

+ 16 - 0
ios/Classes/flutterzip-Bridging-Header.h

@@ -0,0 +1,16 @@
+//
+//  flutterzip-Bridging-Header.h
+//  Pods
+//
+//  Created by jiajunzhou on 2020/7/9.
+//
+
+//#ifndef flutterzip_Bridging_Header_h
+//#define flutterzip_Bridging_Header_h
+//
+//
+//#endif /* flutterzip_Bridging_Header_h */
+
+#import "ZipArchive.h"
+#import "SSZipArchive.h"
+

+ 1 - 2
ios/flutterzip.podspec

@@ -16,11 +16,10 @@ A new Flutter plugin.
   s.source_files = 'Classes/**/*'
   s.dependency 'Flutter'
   s.platform = :ios, '8.0'
-
+  s.public_header_files = 'Classes/**/*.h'
   # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported.
   s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
   s.swift_version = '5.0'
 
-   s.dependency 'SSZipArchive','~> 2.0.7'
 
 end