commit 7e2c90a5605fecbc51cda8d514eee4d2d6066c80
Author: Donato Fiore <50346119+donato-fiore@users.noreply.github.com>
Date: Thu Nov 30 21:06:53 2023 -0500
Initial Commit
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6c66155
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,25 @@
+TARGET := iphone:clang:latest:14.0
+INSTALL_TARGET_PROCESSES = TrollDecrypt
+
+GO_EASY_ON_ME = 1
+PACKAGE_FORMAT = ipa
+
+include $(THEOS)/makefiles/common.mk
+
+APPLICATION_NAME = TrollDecrypt
+
+TrollDecrypt_FILES = SSZipArchive/minizip/unzip.c SSZipArchive/minizip/crypt.c SSZipArchive/minizip/ioapi_buf.c SSZipArchive/minizip/ioapi_mem.c SSZipArchive/minizip/ioapi.c SSZipArchive/minizip/minishared.c SSZipArchive/minizip/zip.c SSZipArchive/minizip/aes/aes_ni.c SSZipArchive/minizip/aes/aescrypt.c SSZipArchive/minizip/aes/aeskey.c SSZipArchive/minizip/aes/aestab.c SSZipArchive/minizip/aes/fileenc.c SSZipArchive/minizip/aes/hmac.c SSZipArchive/minizip/aes/prng.c SSZipArchive/minizip/aes/pwd2key.c SSZipArchive/minizip/aes/sha1.c SSZipArchive/SSZipArchive.m
+TrollDecrypt_FILES += main.m TDAppDelegate.m TDRootViewController.m TDDumpDecrypted.m TDUtils.m TDFileManagerViewController.m
+TrollDecrypt_FRAMEWORKS = UIKit CoreGraphics MobileCoreServices
+TrollDecrypt_CFLAGS = -fobjc-arc
+TrollDecrypt_CODESIGN_FLAGS = -Sentitlements.plist
+
+include $(THEOS_MAKE_PATH)/application.mk
+
+after-stage::
+ rm -rf Payload
+ mkdir -p $(THEOS_STAGING_DIR)/Payload
+ ldid -Sentitlements.plist $(THEOS_STAGING_DIR)/Applications/TrollDecrypt.app/TrollDecrypt
+ cp -a $(THEOS_STAGING_DIR)/Applications/* $(THEOS_STAGING_DIR)/Payload
+ mv $(THEOS_STAGING_DIR)/Payload .
+ zip -q -r TrollDecrypt.ipa Payload
diff --git a/Payload/TrollDecrypt.app/AppIcon60x60.png b/Payload/TrollDecrypt.app/AppIcon60x60.png
new file mode 100644
index 0000000..9989629
Binary files /dev/null and b/Payload/TrollDecrypt.app/AppIcon60x60.png differ
diff --git a/Payload/TrollDecrypt.app/AppIcon76x76~ipad.png b/Payload/TrollDecrypt.app/AppIcon76x76~ipad.png
new file mode 100644
index 0000000..b2d07fb
Binary files /dev/null and b/Payload/TrollDecrypt.app/AppIcon76x76~ipad.png differ
diff --git a/Payload/TrollDecrypt.app/Info.plist b/Payload/TrollDecrypt.app/Info.plist
new file mode 100644
index 0000000..598a85f
--- /dev/null
+++ b/Payload/TrollDecrypt.app/Info.plist
@@ -0,0 +1,68 @@
+
+
+
+
+ CFBundleExecutable
+ TrollDecrypt
+ CFBundleIcons
+
+ CFBundlePrimaryIcon
+
+ CFBundleIconFiles
+
+ AppIcon60x60
+
+ UIPrerenderedIcon
+
+
+
+ CFBundleIcons~ipad
+
+ CFBundlePrimaryIcon
+
+ CFBundleIconFiles
+
+ AppIcon60x60
+ AppIcon76x76~ipad
+
+ UIPrerenderedIcon
+
+
+
+ CFBundleIdentifier
+ com.fiore.trolldecrypt
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ CFBundleSupportedPlatforms
+
+ iPhoneOS
+
+ CFBundleVersion
+ 1.0
+ LSRequiresIPhoneOS
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+
+
+
diff --git a/Payload/TrollDecrypt.app/TrollDecrypt b/Payload/TrollDecrypt.app/TrollDecrypt
new file mode 100644
index 0000000..33c01bc
Binary files /dev/null and b/Payload/TrollDecrypt.app/TrollDecrypt differ
diff --git a/Resources/AppIcon60x60.png b/Resources/AppIcon60x60.png
new file mode 100644
index 0000000..9989629
Binary files /dev/null and b/Resources/AppIcon60x60.png differ
diff --git a/Resources/AppIcon76x76~ipad.png b/Resources/AppIcon76x76~ipad.png
new file mode 100644
index 0000000..b2d07fb
Binary files /dev/null and b/Resources/AppIcon76x76~ipad.png differ
diff --git a/Resources/Info.plist b/Resources/Info.plist
new file mode 100644
index 0000000..598a85f
--- /dev/null
+++ b/Resources/Info.plist
@@ -0,0 +1,68 @@
+
+
+
+
+ CFBundleExecutable
+ TrollDecrypt
+ CFBundleIcons
+
+ CFBundlePrimaryIcon
+
+ CFBundleIconFiles
+
+ AppIcon60x60
+
+ UIPrerenderedIcon
+
+
+
+ CFBundleIcons~ipad
+
+ CFBundlePrimaryIcon
+
+ CFBundleIconFiles
+
+ AppIcon60x60
+ AppIcon76x76~ipad
+
+ UIPrerenderedIcon
+
+
+
+ CFBundleIdentifier
+ com.fiore.trolldecrypt
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ CFBundleSupportedPlatforms
+
+ iPhoneOS
+
+ CFBundleVersion
+ 1.0
+ LSRequiresIPhoneOS
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+
+
+
diff --git a/SSZipArchive/SSZipArchive.h b/SSZipArchive/SSZipArchive.h
new file mode 100644
index 0000000..e5768b1
--- /dev/null
+++ b/SSZipArchive/SSZipArchive.h
@@ -0,0 +1,146 @@
+//
+// 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
+#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)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)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)delegate;
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+ toDestination:(NSString *)destination
+ progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+ completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+ toDestination:(NSString *)destination
+ overwrite:(BOOL)overwrite
+ password:(nullable NSString *)password
+ progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+ completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+ toDestination:(NSString *)destination
+ preserveAttributes:(BOOL)preserveAttributes
+ overwrite:(BOOL)overwrite
+ nestedZipLevel:(NSInteger)nestedZipLevel
+ password:(nullable NSString *)password
+ error:(NSError **)error
+ delegate:(nullable id)delegate
+ progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+ completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;
+
+// Zip
+// default compression level is Z_DEFAULT_COMPRESSION (from "zlib.h")
+
+// without password
++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths;
++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath;
+
++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory;
+
+// with optional password, default encryption is AES
+// don't use AES if you need compatibility with native macOS unzip and Archive Utility
++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)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;
++ (BOOL)createZipFileAtPath:(NSString *)path
+ withContentsOfDirectory:(NSString *)directoryPath
+ keepParentDirectory:(BOOL)keepParentDirectory
+ compressionLevel:(int)compressionLevel
+ password:(nullable NSString *)password
+ AES:(BOOL)aes
+ progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler;
+
+- (instancetype)init NS_UNAVAILABLE;
+- (instancetype)initWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER;
+- (BOOL)open;
+
+/// write empty folder
+- (BOOL)writeFolderAtPath:(NSString *)path withFolderName:(NSString *)folderName withPassword:(nullable NSString *)password;
+/// write file
+- (BOOL)writeFile:(NSString *)path withPassword:(nullable NSString *)password;
+- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName withPassword:(nullable NSString *)password;
+- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes;
+/// write data
+- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename withPassword:(nullable NSString *)password;
+- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes;
+
+- (BOOL)close;
+
+@end
+
+@protocol SSZipArchiveDelegate
+
+@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;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif /* _SSZIPARCHIVE_H */
diff --git a/SSZipArchive/SSZipArchive.m b/SSZipArchive/SSZipArchive.m
new file mode 100644
index 0000000..79897d4
--- /dev/null
+++ b/SSZipArchive/SSZipArchive.m
@@ -0,0 +1,1069 @@
+//
+// SSZipArchive.m
+// SSZipArchive
+//
+// Created by Sam Soffes on 7/21/10.
+// Copyright (c) Sam Soffes 2010-2015. All rights reserved.
+//
+
+#import "SSZipArchive.h"
+#include "./minizip/unzip.h"
+#include "./minizip/zip.h"
+#include "./minizip/minishared.h"
+
+#include
+
+NSString *const SSZipArchiveErrorDomain = @"SSZipArchiveErrorDomain";
+
+#define CHUNK 16384
+
+int _zipOpenEntry(zipFile entry, NSString *name, const zip_fileinfo *zipfi, int level, NSString *password, BOOL aes);
+BOOL _fileIsSymbolicLink(const unz_file_info *fileInfo);
+
+#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 = {};
+ 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);
+ }
+
+ 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 = {};
+ 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 error Z_DATA_ERROR is caused by an invalid password
+ // Let's assume other errors are caused by Content Not Readable
+ 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);
+ }
+
+ // 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)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)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 (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+ completionHandler:(void (^_Nullable)(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)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:(nullable id)delegate
+ progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+ completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler
+{
+ return [self unzipFileAtPath:path toDestination:destination preserveAttributes:preserveAttributes overwrite:overwrite nestedZipLevel:0 password:password error:error delegate:delegate progressHandler:progressHandler completionHandler:completionHandler];
+}
+
++ (BOOL)unzipFileAtPath:(NSString *)path
+ toDestination:(NSString *)destination
+ preserveAttributes:(BOOL)preserveAttributes
+ overwrite:(BOOL)overwrite
+ nestedZipLevel:(NSInteger)nestedZipLevel
+ password:(nullable NSString *)password
+ error:(NSError **)error
+ delegate:(nullable id)delegate
+ progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
+ completionHandler:(void (^_Nullable)(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 = {};
+ unzGetGlobalInfo(zip, &globalInfo);
+
+ // Begin unzipping
+ int ret = 0;
+ ret = unzGoToFirstFile(zip);
+ if (ret != UNZ_OK && ret != UNZ_END_OF_LIST_OF_FILE)
+ {
+ 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 crc_ret = 0;
+ unsigned char buffer[4096] = {0};
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSMutableArray *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 = -1;
+ NSError *unzippingError;
+ do {
+ currentFileNumber++;
+ if (ret == UNZ_END_OF_LIST_OF_FILE)
+ break;
+ @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';
+
+ BOOL fileIsSymbolicLink = _fileIsSymbolicLink(&fileInfo);
+
+ NSString * strPath = [SSZipArchive _filenameStringWithCString:filename size:fileInfo.size_filename];
+ if ([strPath hasPrefix:@"__MACOSX/"]) {
+ // ignoring resource forks: https://superuser.com/questions/104500/what-is-macosx-folder
+ unzCloseCurrentFile(zip);
+ ret = unzGoToNextFile(zip);
+ free(filename);
+ continue;
+ }
+ 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 (readBytes < 0) {
+ // Let's assume error Z_DATA_ERROR is caused by an invalid password
+ // Let's assume other errors are caused by Content Not Readable
+ success = NO;
+ }
+ }
+
+ if (fp) {
+ fclose(fp);
+
+ if (nestedZipLevel
+ && [fullPath.pathExtension.lowercaseString isEqualToString:@"zip"]
+ && [self unzipFileAtPath:fullPath
+ toDestination:fullPath.stringByDeletingLastPathComponent
+ preserveAttributes:preserveAttributes
+ overwrite:overwrite
+ nestedZipLevel:nestedZipLevel - 1
+ password:password
+ error:nil
+ delegate:nil
+ progressHandler:nil
+ completionHandler:nil]) {
+ [directoriesModificationDates removeLastObject];
+ [[NSFileManager defaultManager] removeItemAtPath:fullPath error:nil];
+ } else 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 {
+ // Let's assume error Z_DATA_ERROR is caused by an invalid password
+ // Let's assume other errors are caused by Content Not Readable
+ 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] = 0;
+ [destinationPath appendString:@((const char *)buffer)];
+ }
+ if (bytesRead < 0) {
+ // Let's assume error Z_DATA_ERROR is caused by an invalid password
+ // Let's assume other errors are caused by Content Not Readable
+ success = NO;
+ break;
+ }
+
+ // 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];
+ }
+
+ 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 *)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 *)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 {
+ return [self createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:keepParentDirectory compressionLevel:Z_DEFAULT_COMPRESSION password:password AES:YES progressHandler:progressHandler];
+}
+
++ (BOOL)createZipFileAtPath:(NSString *)path
+ withContentsOfDirectory:(NSString *)directoryPath
+ keepParentDirectory:(BOOL)keepParentDirectory
+ compressionLevel:(int)compressionLevel
+ password:(nullable NSString *)password
+ AES:(BOOL)aes
+ progressHandler:(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 *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 compressionLevel:compressionLevel password:password AES:aes];
+ }
+ else
+ {
+ if ([[NSFileManager defaultManager] subpathsOfDirectoryAtPath:fullFilePath error:nil].count == 0)
+ {
+ success &= [zipArchive writeFolderAtPath:fullFilePath withFolderName:fileName 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);
+}
+
+- (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 = {};
+
+ [SSZipArchive zipInfo:&zipInfo setAttributesOfItemAtPath:path];
+
+ int error = _zipOpenEntry(_zip, [folderName stringByAppendingString:@"/"], &zipInfo, Z_NO_COMPRESSION, password, 0);
+ const void *buffer = NULL;
+ zipWriteInFileInZip(_zip, buffer, 0);
+ zipCloseFileInZip(_zip);
+ return error == ZIP_OK;
+}
+
+- (BOOL)writeFile:(NSString *)path withPassword:(nullable NSString *)password
+{
+ return [self writeFileAtPath:path withFileName:nil withPassword:password];
+}
+
+- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName withPassword:(nullable NSString *)password
+{
+ return [self writeFileAtPath:path withFileName:fileName compressionLevel:Z_DEFAULT_COMPRESSION password:password AES:YES];
+}
+
+// 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 compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes
+{
+ NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened");
+
+ FILE *input = fopen(path.fileSystemRepresentation, "r");
+ if (NULL == input) {
+ return NO;
+ }
+
+ if (!fileName) {
+ fileName = path.lastPathComponent;
+ }
+
+ zip_fileinfo zipInfo = {};
+
+ [SSZipArchive zipInfo:&zipInfo setAttributesOfItemAtPath:path];
+
+ void *buffer = malloc(CHUNK);
+ if (buffer == NULL)
+ {
+ fclose(input);
+ return NO;
+ }
+
+ int error = _zipOpenEntry(_zip, fileName, &zipInfo, compressionLevel, password, aes);
+
+ while (!feof(input) && !ferror(input))
+ {
+ unsigned int len = (unsigned int) fread(buffer, 1, CHUNK, input);
+ zipWriteInFileInZip(_zip, buffer, len);
+ }
+
+ zipCloseFileInZip(_zip);
+ free(buffer);
+ fclose(input);
+ return error == ZIP_OK;
+}
+
+- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename withPassword:(nullable NSString *)password
+{
+ return [self writeData:data filename:filename compressionLevel:Z_DEFAULT_COMPRESSION password:password AES:YES];
+}
+
+- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes
+{
+ if (!_zip) {
+ return NO;
+ }
+ if (!data) {
+ return NO;
+ }
+ zip_fileinfo zipInfo = {};
+ [SSZipArchive zipInfo:&zipInfo setDate:[NSDate date]];
+
+ int error = _zipOpenEntry(_zip, filename, &zipInfo, compressionLevel, password, aes);
+
+ zipWriteInFileInZip(_zip, data.bytes, (unsigned int)data.length);
+
+ zipCloseFileInZip(_zip);
+ return error == ZIP_OK;
+}
+
+- (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 *)_filenameStringWithCString:(const char *)filename size:(uint16_t)size_filename
+{
+ // attempting unicode encoding
+ NSString * strPath = @(filename);
+ if (strPath) {
+ return strPath;
+ }
+
+ // if filename is non-unicode, detect and transform Encoding
+ NSData *data = [NSData dataWithBytes:(const void *)filename length:sizeof(unsigned char) * size_filename];
+#ifdef __MAC_10_13
+ // Xcode 9+
+ if (@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)) {
+ // supported encodings are in [NSString availableStringEncodings]
+ [NSString stringEncodingForData:data encodingOptions:nil convertedString:&strPath usedLossyConversion:nil];
+ }
+#else
+ // Xcode 8-
+ if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_9_2) {
+ // supported encodings are in [NSString availableStringEncodings]
+ [NSString stringEncodingForData:data encodingOptions:nil convertedString:&strPath usedLossyConversion:nil];
+ }
+#endif
+ else {
+ // fallback to a simple manual detect for macOS 10.9 or older
+ NSArray *encodings = @[@(kCFStringEncodingGB_18030_2000), @(kCFStringEncodingShiftJIS)];
+ for (NSNumber *encoding in encodings) {
+ strPath = [NSString stringWithCString:filename encoding:(NSStringEncoding)CFStringConvertEncodingToNSStringEncoding(encoding.unsignedIntValue)];
+ if (strPath) {
+ break;
+ }
+ }
+ }
+ if (strPath) {
+ return 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];
+ return strPath;
+}
+
++ (void)zipInfo:(zip_fileinfo *)zipInfo setAttributesOfItemAtPath:(NSString *)path
+{
+ 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)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);
+}
+
++ (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
+
+int _zipOpenEntry(zipFile entry, NSString *name, const zip_fileinfo *zipfi, int level, NSString *password, BOOL aes)
+{
+ return zipOpenNewFileInZip5(entry, name.fileSystemRepresentation, zipfi, NULL, 0, NULL, 0, NULL, 0, 0, Z_DEFLATED, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, password.UTF8String, aes, 0);
+}
+
+#pragma mark - Private tools for file info
+
+BOOL _fileIsSymbolicLink(const unz_file_info *fileInfo)
+{
+ //
+ // 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 = ((fileInfo->version >> 8) == ZipUNIXVersion) && BSD_IFLNK == (BSD_SFMT & (fileInfo->external_fa >> 16));
+ return fileIsSymbolicLink;
+}
+
+#pragma mark - Private tools for unreadable encodings
+
+@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);
+ if (chars == NULL) {
+ // we directly raise an exception instead of using NSAssert to make sure assertion is not disabled as this is irrecoverable
+ [NSException raise:@"NSInternalInconsistencyException" format:@"failed malloc" arguments:nil];
+ return nil;
+ }
+ 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
diff --git a/SSZipArchive/SSZipCommon.h b/SSZipArchive/SSZipCommon.h
new file mode 100644
index 0000000..91670e1
--- /dev/null
+++ b/SSZipArchive/SSZipCommon.h
@@ -0,0 +1,66 @@
+#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 */
+/* https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT */
+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
diff --git a/SSZipArchive/ZipArchive.h b/SSZipArchive/ZipArchive.h
new file mode 100644
index 0000000..7a53df8
--- /dev/null
+++ b/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
+
+//! 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
+
+#import "SSZipArchive.h"
diff --git a/SSZipArchive/minizip/aes/aes.h b/SSZipArchive/minizip/aes/aes.h
new file mode 100644
index 0000000..92e23c2
--- /dev/null
+++ b/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
+
+/* 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
diff --git a/SSZipArchive/minizip/aes/aes_ni.c b/SSZipArchive/minizip/aes/aes_ni.c
new file mode 100644
index 0000000..8afae91
--- /dev/null
+++ b/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
+#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
+
+#if !defined(__clang__)
+#pragma GCC target ("ssse3")
+#pragma GCC target ("sse4.1")
+#pragma GCC target ("aes")
+#endif
+
+#include
+#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 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 '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
diff --git a/SSZipArchive/minizip/aes/aescrypt.c b/SSZipArchive/minizip/aes/aescrypt.c
new file mode 100644
index 0000000..bd647e4
--- /dev/null
+++ b/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
diff --git a/SSZipArchive/minizip/aes/aeskey.c b/SSZipArchive/minizip/aes/aeskey.c
new file mode 100644
index 0000000..16e9607
--- /dev/null
+++ b/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
diff --git a/SSZipArchive/minizip/aes/aesopt.h b/SSZipArchive/minizip/aes/aesopt.h
new file mode 100644
index 0000000..3678e74
--- /dev/null
+++ b/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
diff --git a/SSZipArchive/minizip/aes/aestab.c b/SSZipArchive/minizip/aes/aestab.c
new file mode 100644
index 0000000..3d48edf
--- /dev/null
+++ b/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
+
diff --git a/SSZipArchive/minizip/aes/aestab.h b/SSZipArchive/minizip/aes/aestab.h
new file mode 100644
index 0000000..8fe32d1
--- /dev/null
+++ b/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
diff --git a/SSZipArchive/minizip/aes/brg_endian.h b/SSZipArchive/minizip/aes/brg_endian.h
new file mode 100644
index 0000000..9ef4af5
--- /dev/null
+++ b/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
+#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ )
+# include
+#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \
+ defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) || \
+ defined(__pnacl__)
+# include
+#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
+# if !defined( __MINGW32__ ) && !defined( _AIX )
+# include
+# if !defined( __BEOS__ )
+# include
+# 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
diff --git a/SSZipArchive/minizip/aes/brg_types.h b/SSZipArchive/minizip/aes/brg_types.h
new file mode 100644
index 0000000..307319b
--- /dev/null
+++ b/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_t where
+ 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_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
+#include
+
+#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
+# include
+# 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
diff --git a/SSZipArchive/minizip/aes/fileenc.c b/SSZipArchive/minizip/aes/fileenc.c
new file mode 100644
index 0000000..31a8994
--- /dev/null
+++ b/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
+
+#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
diff --git a/SSZipArchive/minizip/aes/fileenc.h b/SSZipArchive/minizip/aes/fileenc.h
new file mode 100644
index 0000000..9c0250e
--- /dev/null
+++ b/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
diff --git a/SSZipArchive/minizip/aes/hmac.c b/SSZipArchive/minizip/aes/hmac.c
new file mode 100644
index 0000000..face1fb
--- /dev/null
+++ b/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
diff --git a/SSZipArchive/minizip/aes/hmac.h b/SSZipArchive/minizip/aes/hmac.h
new file mode 100644
index 0000000..46956c4
--- /dev/null
+++ b/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
+#include
+
+#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
diff --git a/SSZipArchive/minizip/aes/prng.c b/SSZipArchive/minizip/aes/prng.c
new file mode 100644
index 0000000..b90fcae
--- /dev/null
+++ b/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
+#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
+
diff --git a/SSZipArchive/minizip/aes/prng.h b/SSZipArchive/minizip/aes/prng.h
new file mode 100644
index 0000000..9a77426
--- /dev/null
+++ b/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
diff --git a/SSZipArchive/minizip/aes/pwd2key.c b/SSZipArchive/minizip/aes/pwd2key.c
new file mode 100644
index 0000000..86c97c4
--- /dev/null
+++ b/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
+#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
+
+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
diff --git a/SSZipArchive/minizip/aes/pwd2key.h b/SSZipArchive/minizip/aes/pwd2key.h
new file mode 100644
index 0000000..b9ba421
--- /dev/null
+++ b/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
diff --git a/SSZipArchive/minizip/aes/sha1.c b/SSZipArchive/minizip/aes/sha1.c
new file mode 100644
index 0000000..3300363
--- /dev/null
+++ b/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 /* 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
diff --git a/SSZipArchive/minizip/aes/sha1.h b/SSZipArchive/minizip/aes/sha1.h
new file mode 100644
index 0000000..e805ad9
--- /dev/null
+++ b/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
+#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
diff --git a/SSZipArchive/minizip/crypt.c b/SSZipArchive/minizip/crypt.c
new file mode 100644
index 0000000..9c1203b
--- /dev/null
+++ b/SSZipArchive/minizip/crypt.c
@@ -0,0 +1,144 @@
+/* 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
+#include
+#include
+#include
+
+#ifdef _WIN32
+# include
+# include
+#else
+# include
+# include
+# include
+#endif
+
+#include "zlib.h"
+
+#include "crypt.h"
+
+/***************************************************************************/
+
+#define CRC32(c, b) ((*(pcrc_32_tab+(((uint32_t)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
+
+/***************************************************************************/
+
+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)
+{
+#ifdef _WIN32
+ HCRYPTPROV provider;
+ unsigned __int64 pentium_tsc[1];
+ int rlen = 0;
+ 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];
+ }
+
+ return rlen;
+#else
+ arc4random_buf(buf, len);
+ return len;
+#endif
+}
+
+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;
+}
+
+/***************************************************************************/
diff --git a/SSZipArchive/minizip/crypt.h b/SSZipArchive/minizip/crypt.h
new file mode 100644
index 0000000..0ba8260
--- /dev/null
+++ b/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
diff --git a/SSZipArchive/minizip/ioapi.c b/SSZipArchive/minizip/ioapi.c
new file mode 100644
index 0000000..239bb05
--- /dev/null
+++ b/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
+#include
+
+#if defined unix || defined __APPLE__
+#include
+#include
+#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(ZIP_UNUSED 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(ZIP_UNUSED 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(ZIP_UNUSED 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(ZIP_UNUSED 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(ZIP_UNUSED 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(ZIP_UNUSED 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(ZIP_UNUSED 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(ZIP_UNUSED 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(ZIP_UNUSED 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(ZIP_UNUSED 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(ZIP_UNUSED 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;
+}
diff --git a/SSZipArchive/minizip/ioapi.h b/SSZipArchive/minizip/ioapi.h
new file mode 100644
index 0000000..c5698ad
--- /dev/null
+++ b/SSZipArchive/minizip/ioapi.h
@@ -0,0 +1,154 @@
+/* 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
+#include
+#include
+
+#include "zlib.h"
+
+#ifdef __GNUC__
+# define ZIP_UNUSED __attribute__((__unused__))
+#else
+# define ZIP_UNUSED
+#endif
+
+#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
diff --git a/SSZipArchive/minizip/ioapi_buf.c b/SSZipArchive/minizip/ioapi_buf.c
new file mode 100644
index 0000000..074a930
--- /dev/null
+++ b/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
+#include
+#include
+#include
+
+#include "zlib.h"
+#include "ioapi.h"
+
+#include "ioapi_buf.h"
+
+#ifndef IOBUF_BUFFERSIZE
+# define IOBUF_BUFFERSIZE (UINT16_MAX)
+#endif
+
+#if defined(_WIN32)
+# include
+# 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(ZIP_UNUSED 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(ZIP_UNUSED voidpf opaque, voidpf stream, ZIP_UNUSED uint32_t number_disk, ZIP_UNUSED 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(ZIP_UNUSED 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;
+}
diff --git a/SSZipArchive/minizip/ioapi_buf.h b/SSZipArchive/minizip/ioapi_buf.h
new file mode 100644
index 0000000..b0e7698
--- /dev/null
+++ b/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
+#include
+#include
+
+#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
diff --git a/SSZipArchive/minizip/ioapi_mem.c b/SSZipArchive/minizip/ioapi_mem.c
new file mode 100644
index 0000000..ed53345
--- /dev/null
+++ b/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
+#include
+#include
+
+#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, ZIP_UNUSED 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(ZIP_UNUSED voidpf opaque, ZIP_UNUSED voidpf stream, ZIP_UNUSED uint32_t number_disk, ZIP_UNUSED int mode)
+{
+ /* Not used */
+ return NULL;
+}
+
+uint32_t ZCALLBACK fread_mem_func(ZIP_UNUSED 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(ZIP_UNUSED 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(ZIP_UNUSED voidpf opaque, voidpf stream)
+{
+ ourmemory_t *mem = (ourmemory_t *)stream;
+ return mem->cur_offset;
+}
+
+long ZCALLBACK fseek_mem_func(ZIP_UNUSED 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(ZIP_UNUSED voidpf opaque, ZIP_UNUSED voidpf stream)
+{
+ /* Even with grow = 1, caller must always free() memory */
+ return 0;
+}
+
+int ZCALLBACK ferror_mem_func(ZIP_UNUSED voidpf opaque, ZIP_UNUSED 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;
+}
diff --git a/SSZipArchive/minizip/ioapi_mem.h b/SSZipArchive/minizip/ioapi_mem.h
new file mode 100644
index 0000000..7061d6f
--- /dev/null
+++ b/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
+#include
+#include
+
+#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
diff --git a/SSZipArchive/minizip/minishared.c b/SSZipArchive/minizip/minishared.c
new file mode 100644
index 0000000..beabddc
--- /dev/null
+++ b/SSZipArchive/minizip/minishared.c
@@ -0,0 +1,292 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "zlib.h"
+#include "ioapi.h"
+
+#ifdef _WIN32
+# include
+# include
+#else
+# include
+# include
+# include
+# include
+#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]);
+}
diff --git a/SSZipArchive/minizip/minishared.h b/SSZipArchive/minizip/minishared.h
new file mode 100644
index 0000000..32fccb6
--- /dev/null
+++ b/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 */
\ No newline at end of file
diff --git a/SSZipArchive/minizip/unzip.c b/SSZipArchive/minizip/unzip.c
new file mode 100644
index 0000000..90a7310
--- /dev/null
+++ b/SSZipArchive/minizip/unzip.c
@@ -0,0 +1,1999 @@
+/* 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
+#include
+#include
+#include
+#include
+#include
+
+#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
+#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 int unzSearchCentralDir(const zlib_filefunc64_32_def *pzlib_filefunc_def, uint64_t *pos_found, 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 */
+ uint32_t read_size = 0;
+ uint64_t read_pos = 0;
+ uint32_t i = 0;
+ *pos_found = 0;
+
+ if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0)
+ return UNZ_ERRNO;
+
+ 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;
+ return UNZ_OK;
+ }
+ }
+
+ return UNZ_ERRNO;
+}
+
+/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */
+static int unzSearchCentralDir64(const zlib_filefunc64_32_def *pzlib_filefunc_def, uint64_t *offset, voidpf filestream,
+ const uint64_t endcentraloffset)
+{
+ uint32_t value32 = 0;
+ *offset = 0;
+
+ /* Zip64 end of central directory locator */
+ if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ return UNZ_ERRNO;
+
+ /* Read locator signature */
+ if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+ return UNZ_ERRNO;
+ if (value32 != ZIP64ENDLOCHEADERMAGIC)
+ return UNZ_ERRNO;
+ /* Number of the disk with the start of the zip64 end of central directory */
+ if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+ return UNZ_ERRNO;
+ /* Relative offset of the zip64 end of central directory record */
+ if (unzReadUInt64(pzlib_filefunc_def, filestream, offset) != UNZ_OK)
+ return UNZ_ERRNO;
+ /* Total number of disks */
+ if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+ return UNZ_ERRNO;
+ /* Goto end of central directory record */
+ if (ZSEEK64(*pzlib_filefunc_def, filestream, *offset, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ return UNZ_ERRNO;
+ /* The signature */
+ if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+ return UNZ_ERRNO;
+ if (value32 != ZIP64ENDHEADERMAGIC)
+ return UNZ_ERRNO;
+
+ return UNZ_OK;
+}
+
+static unzFile unzOpenInternal(const void *path, zlib_filefunc64_32_def *pzlib_filefunc64_32_def)
+{
+ unz64_internal us = { 0 };
+ 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;
+ int err64 = UNZ_OK;
+
+ if (pzlib_filefunc64_32_def == NULL)
+ fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);
+ else
+ {
+ assert((pzlib_filefunc64_32_def->zopen32_file || pzlib_filefunc64_32_def->zfile_func64.zopen64_file) &&
+ (pzlib_filefunc64_32_def->zopendisk32_file || pzlib_filefunc64_32_def->zfile_func64.zopendisk64_file) &&
+ (pzlib_filefunc64_32_def->ztell32_file || pzlib_filefunc64_32_def->zfile_func64.ztell64_file) &&
+ (pzlib_filefunc64_32_def->zseek32_file || pzlib_filefunc64_32_def->zfile_func64.zseek64_file));
+ 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;
+
+ /* Search for end of central directory header */
+ err = unzSearchCentralDir(&us.z_filefunc, ¢ral_pos, us.filestream);
+ if (err == UNZ_OK)
+ {
+ 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 */
+ err64 = unzSearchCentralDir64(&us.z_filefunc, ¢ral_pos64, us.filestream, central_pos);
+ if (err64 == UNZ_OK)
+ {
+ 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.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;
+
+ s = (unz64_internal*)ALLOC(sizeof(unz64_internal));
+ if (s != NULL)
+ {
+ *s = us;
+ if (err64 != UNZ_OK)
+ // workaround incorrect count #184
+ s->gi.number_entry = unzCountEntries(s);
+
+ 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 = { 0 };
+ 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 = { 0 };
+ zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+ 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;
+}
+
+extern uint64_t ZEXPORT unzCountEntries(const unzFile file)
+{
+ if (file == NULL)
+ return 0;
+
+ unz64_internal s = *(unz64_internal*)file;
+
+ s.pos_in_central_dir = s.offset_central_dir;
+ s.num_file = 0;
+ while (UNZ_OK == unzGetCurrentFileInfoInternal(&s,
+ &s.cur_file_info,
+ &s.cur_file_info_internal,
+ NULL, 0, NULL, 0, NULL, 0))
+ {
+ 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;
+ }
+ return s.num_file;
+}
+
+/*
+ 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->compression_method == 0) || (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;
+ }
+
+ 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;
+
+ if (s->gi.number_entry == 0)
+ return UNZ_END_OF_LIST_OF_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;
+}
diff --git a/SSZipArchive/minizip/unzip.h b/SSZipArchive/minizip/unzip.h
new file mode 100644
index 0000000..059a026
--- /dev/null
+++ b/SSZipArchive/minizip/unzip.h
@@ -0,0 +1,254 @@
+/* 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 */
+
+extern uint64_t ZEXPORT unzCountEntries(const unzFile file);
+
+/***************************************************************************/
+/* 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 */
diff --git a/SSZipArchive/minizip/zip.c b/SSZipArchive/minizip/zip.c
new file mode 100644
index 0000000..f4ff103
--- /dev/null
+++ b/SSZipArchive/minizip/zip.c
@@ -0,0 +1,2009 @@
+/* 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
+#include
+#include
+#include
+#include
+#include
+
+#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
+#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 = { 0 };
+ 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;
+
+
+ if (pzlib_filefunc64_32_def == NULL)
+ fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64);
+ else
+ {
+ assert((pzlib_filefunc64_32_def->zopen32_file || pzlib_filefunc64_32_def->zfile_func64.zopen64_file) &&
+ (pzlib_filefunc64_32_def->zopendisk32_file || pzlib_filefunc64_32_def->zfile_func64.zopendisk64_file) &&
+ (pzlib_filefunc64_32_def->ztell32_file || pzlib_filefunc64_32_def->zfile_func64.ztell64_file) &&
+ (pzlib_filefunc64_32_def->zseek32_file || pzlib_filefunc64_32_def->zfile_func64.zseek64_file));
+ 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.disk_size = disk_size;
+ 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 = { 0 };
+ 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 = { 0 };
+ zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+ 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 = { 0 };
+ 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 = { 0 };
+ zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+ 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 zipOpenNewFileInZip5(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 flag_base,
+ int zip64,
+ uint16_t method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char *password,
+ int aes,
+ uint16_t version_madeby)
+{
+ 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
+ if (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 */
+ /* https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT */
+ central_dir = (unsigned char*)zi->ci.central_header;
+ zipWriteValueToMemoryAndMove(¢ral_dir, (uint32_t)CENTRALHEADERMAGIC, 4);
+ zipWriteValueToMemoryAndMove(¢ral_dir, version_madeby, 2);
+ if (zi->ci.zip64)
+ zipWriteValueToMemoryAndMove(¢ral_dir, (uint16_t)45, 2);
+ else
+ zipWriteValueToMemoryAndMove(¢ral_dir, (uint16_t)20, 2);
+ zipWriteValueToMemoryAndMove(¢ral_dir, zi->ci.flag, 2);
+ zipWriteValueToMemoryAndMove(¢ral_dir, zi->ci.method, 2);
+ zipWriteValueToMemoryAndMove(¢ral_dir, zi->ci.dos_date, 4);
+ zipWriteValueToMemoryAndMove(¢ral_dir, (uint32_t)0, 4); /*crc*/
+ zipWriteValueToMemoryAndMove(¢ral_dir, (uint32_t)0, 4); /*compr size*/
+ zipWriteValueToMemoryAndMove(¢ral_dir, (uint32_t)0, 4); /*uncompr size*/
+ zipWriteValueToMemoryAndMove(¢ral_dir, size_filename, 2);
+ zipWriteValueToMemoryAndMove(¢ral_dir, size_extrafield_global, 2);
+ zipWriteValueToMemoryAndMove(¢ral_dir, size_comment, 2);
+ zipWriteValueToMemoryAndMove(¢ral_dir, (uint16_t)zi->ci.number_disk, 2); /*disk nm start*/
+
+ if (zipfi == NULL)
+ zipWriteValueToMemoryAndMove(¢ral_dir, (uint16_t)0, 2);
+ else
+ zipWriteValueToMemoryAndMove(¢ral_dir, zipfi->internal_fa, 2);
+ if (zipfi == NULL)
+ zipWriteValueToMemoryAndMove(¢ral_dir, (uint32_t)0, 4);
+ else
+ zipWriteValueToMemoryAndMove(¢ral_dir, zipfi->external_fa, 4);
+ if (zi->ci.pos_local_header >= UINT32_MAX)
+ zipWriteValueToMemoryAndMove(¢ral_dir, UINT32_MAX, 4);
+ else
+ zipWriteValueToMemoryAndMove(¢ral_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_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)
+{
+ uint8_t aes = 0;
+#ifdef HAVE_AES
+ aes = 1;
+#endif
+ return zipOpenNewFileInZip5(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global,
+ size_extrafield_global, comment, flag_base, zip64, method, level, raw, windowBits, memLevel, strategy, password, aes,
+ version_madeby);
+}
+
+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;
+}
diff --git a/SSZipArchive/minizip/zip.h b/SSZipArchive/minizip/zip.h
new file mode 100644
index 0000000..38805ad
--- /dev/null
+++ b/SSZipArchive/minizip/zip.h
@@ -0,0 +1,215 @@
+/* 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)
+
+#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 zipOpenNewFileInZip5(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 flag_base,
+ int zip64,
+ uint16_t method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char *password,
+ int aes,
+ uint16_t version_madeby);
+/* Allowing optional aes */
+
+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 */
diff --git a/TDAppDelegate.h b/TDAppDelegate.h
new file mode 100644
index 0000000..bc7e573
--- /dev/null
+++ b/TDAppDelegate.h
@@ -0,0 +1,8 @@
+#import
+
+@interface TDAppDelegate : UIResponder
+
+@property (nonatomic, strong) UIWindow *window;
+@property (nonatomic, strong) UINavigationController *rootViewController;
+
+@end
diff --git a/TDAppDelegate.m b/TDAppDelegate.m
new file mode 100644
index 0000000..993c1b7
--- /dev/null
+++ b/TDAppDelegate.m
@@ -0,0 +1,14 @@
+#import "TDAppDelegate.h"
+#import "TDRootViewController.h"
+
+@implementation TDAppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+ _rootViewController = [[UINavigationController alloc] initWithRootViewController:[[TDRootViewController alloc] init]];
+ _window.rootViewController = _rootViewController;
+ [_window makeKeyAndVisible];
+ return YES;
+}
+
+@end
diff --git a/TDDumpDecrypted.h b/TDDumpDecrypted.h
new file mode 100644
index 0000000..ffe588d
--- /dev/null
+++ b/TDDumpDecrypted.h
@@ -0,0 +1,17 @@
+@interface DumpDecrypted : NSObject {
+ char decryptedAppPathStr[PATH_MAX];
+ char *filename;
+ char *appDirName;
+ char *appDirPath;
+}
+
+@property (assign) NSString *appPath;
+@property (assign) NSString *docPath;
+@property (assign) NSString *appName;
+@property (assign) NSString *appVersion;
+
+- (id)initWithPathToBinary:(NSString *)pathToBinary appName:(NSString *)appName appVersion:(NSString *)appVersion;
+- (void)createIPAFile:(pid_t)pid;
+- (BOOL)dumpDecryptedImage:(const struct mach_header *)image_mh fileName:(const char *)encryptedImageFilenameStr image:(int)imageNum task:(vm_map_t)targetTask;
+- (NSString *)IPAPath;
+@end
\ No newline at end of file
diff --git a/TDDumpDecrypted.m b/TDDumpDecrypted.m
new file mode 100644
index 0000000..36aabda
--- /dev/null
+++ b/TDDumpDecrypted.m
@@ -0,0 +1,615 @@
+/*
+ bfinject - Inject shared libraries into running App Store apps on iOS 11.x < 11.2
+ https://github.com/BishopFox/bfinject
+
+ Carl Livitt @ Bishop Fox
+
+ Based on code originally by 10n1c: https://github.com/stefanesser/dumpdecrypted/blob/master/dumpdecrypted.c
+ Now with the following enhancements:
+ - Dump ALL encrypted images in the target application: the app itself, its frameworks, etc.
+ - Create a valid .ipa containing the decrypted binaries. Save it in ~/Documents/decrypted-app.ipa
+ - The .ipa can be modified and re-signed with a developer cert for redeployment to non-jailbroken devices
+ - Auto detection of all the necessary sandbox paths
+ - Converted into an Objective-C class for ease of use.
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#import "SSZipArchive/SSZipArchive.h"
+#import
+#import
+
+#include
+#include
+#include
+#include
+#include
+
+#include "TDDumpDecrypted.h"
+#import "TDUtils.h"
+
+kern_return_t
+mach_vm_read_overwrite(vm_map_t, mach_vm_address_t, mach_vm_size_t, mach_vm_address_t, mach_vm_size_t *);
+// kern_return_t mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, mach_msg_type_number_t *dataCnt);
+kern_return_t
+mach_vm_region(vm_map_read_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, vm_region_flavor_t flavor, vm_region_info_t info, mach_msg_type_number_t *infoCnt, mach_port_t *object_name);
+
+
+//#define DEBUG(...) NSLog(__VA_ARGS__);
+// #define DEBUG(...) {}
+
+#define swap32(value) (((value & 0xFF000000) >> 24) | ((value & 0x00FF0000) >> 8) | ((value & 0x0000FF00) << 8) | ((value & 0x000000FF) << 24) )
+
+unsigned char *readProcessMemory (mach_port_t proc, mach_vm_address_t addr, mach_msg_type_number_t* size) {
+ mach_msg_type_number_t dataCnt = (mach_msg_type_number_t) *size;
+ vm_offset_t readMem;
+
+ kern_return_t kr = vm_read(proc, addr, *size, &readMem, &dataCnt);
+
+ if (kr) {
+ //fprintf (stderr, "Unable to read target task's memory @%p - kr 0x%x\n", (void *) addr, kr);
+ return NULL;
+ }
+
+ return ((unsigned char *) readMem);
+}
+
+static kern_return_t
+readmem(mach_vm_offset_t *buffer, mach_vm_address_t address, mach_vm_size_t size, vm_map_t targetTask, vm_region_basic_info_data_64_t *info)
+{
+ // get task for pid
+ vm_map_t port = targetTask;
+
+ kern_return_t kr;
+ mach_msg_type_number_t info_cnt = sizeof (vm_region_basic_info_data_64_t);
+ mach_port_t object_name;
+ mach_vm_size_t size_info;
+ mach_vm_address_t address_info = address;
+ kr = mach_vm_region(port, &address_info, &size_info, VM_REGION_BASIC_INFO_64, (vm_region_info_t)info, &info_cnt, &object_name);
+ if (kr)
+ {
+ fprintf(stderr, "[ERROR] mach_vm_region failed with error %d\n", (int)kr);
+ return KERN_FAILURE;
+ }
+
+ /* read memory - vm_read_overwrite because we supply the buffer */
+ mach_vm_size_t nread;
+ kr = mach_vm_read_overwrite(port, address, size, (mach_vm_address_t)buffer, &nread);
+ if (kr)
+ {
+ fprintf(stderr, "[ERROR] vm_read failed! %d\n", kr);
+ return KERN_FAILURE;
+ }
+ else if (nread != size)
+ {
+ fprintf(stderr, "[ERROR] vm_read failed! requested size: 0x%llx read: 0x%llx\n", size, nread);
+ return KERN_FAILURE;
+ }
+ return KERN_SUCCESS;
+}
+
+int64_t
+get_image_size(mach_vm_address_t address, vm_map_t targetTask, uint64_t *vmaddr_slide)
+{
+ vm_region_basic_info_data_64_t region_info = {0};
+ // allocate a buffer to read the header info
+ // NOTE: this is not exactly correct since the 64bit version has an extra 4 bytes
+ // but this will work for this purpose so no need for more complexity!
+ struct mach_header header = {0};
+ if (readmem((mach_vm_offset_t*)&header, address, sizeof(struct mach_header), targetTask, ®ion_info))
+ {
+ printf("Can't read header!\n");
+ return -1;
+ }
+
+ if (header.magic != MH_MAGIC && header.magic != MH_MAGIC_64)
+ {
+ printf("[ERROR] Target is not a mach-o binary!\n");
+ return -1;
+ }
+
+ int64_t imagefilesize = -1;
+ /* read the load commands */
+ uint8_t *loadcmds = (uint8_t*)malloc(header.sizeofcmds);
+ uint16_t mach_header_size = sizeof(struct mach_header);
+ if (header.magic == MH_MAGIC_64)
+ {
+ mach_header_size = sizeof(struct mach_header_64);
+ }
+ if (readmem((mach_vm_offset_t*)loadcmds, address+mach_header_size, header.sizeofcmds, targetTask, ®ion_info))
+ {
+ printf("Can't read load commands\n");
+ free(loadcmds);
+ return -1;
+ }
+
+ /* process and retrieve address and size of linkedit */
+ uint8_t *loadCmdAddress = 0;
+ loadCmdAddress = (uint8_t*)loadcmds;
+ struct load_command *loadCommand = NULL;
+ struct segment_command *segCmd = NULL;
+ struct segment_command_64 *segCmd64 = NULL;
+ for (uint32_t i = 0; i < header.ncmds; i++)
+ {
+ loadCommand = (struct load_command*)loadCmdAddress;
+ if (loadCommand->cmd == LC_SEGMENT)
+ {
+ segCmd = (struct segment_command*)loadCmdAddress;
+ if (strncmp(segCmd->segname, "__PAGEZERO", 16) != 0)
+ {
+ if (strncmp(segCmd->segname, "__TEXT", 16) == 0)
+ {
+ *vmaddr_slide = address - segCmd->vmaddr;
+ }
+ imagefilesize += segCmd->filesize;
+ }
+ }
+ else if (loadCommand->cmd == LC_SEGMENT_64)
+ {
+ segCmd64 = (struct segment_command_64*)loadCmdAddress;
+ if (strncmp(segCmd64->segname, "__PAGEZERO", 16) != 0)
+ {
+ if (strncmp(segCmd64->segname, "__TEXT", 16) == 0)
+ {
+ *vmaddr_slide = address - segCmd64->vmaddr;
+ }
+ imagefilesize += segCmd64->filesize;
+ }
+ }
+ // advance to next command
+ loadCmdAddress += loadCommand->cmdsize;
+ }
+ free(loadcmds);
+ return imagefilesize;
+}
+
+int find_off_cryptid(const char *filePath) {
+ NSLog(@"[trolldecrypt] %s filePath: %s", __FUNCTION__, filePath);
+ int off_cryptid = 0;
+ FILE* file = fopen(filePath, "rb");
+ if (!file) return 1;
+
+ fseek(file, 0, SEEK_END);
+ long fileSize = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ char* buffer = malloc(fileSize);//new char[fileSize];
+ fread(buffer, 1, fileSize, file);
+
+ struct mach_header_64* header = (struct mach_header_64*)buffer;
+ if (header->magic != MH_MAGIC_64) {
+ printf("[-] error: not a valid macho file\n");
+ free(buffer);
+ fclose(file);
+ return 2;
+ }
+
+ struct load_command* lc = (struct load_command*)((mach_vm_address_t)header + sizeof(struct mach_header_64));
+ for (uint32_t i = 0; i < header->ncmds; i++) {
+ if (lc->cmd == LC_ENCRYPTION_INFO || lc->cmd == LC_ENCRYPTION_INFO_64) {
+ struct encryption_info_command *encryption_info = (struct encryption_info_command*) lc;
+
+
+ NSLog(@"[trolldecrypt] cryptid: %d\n", encryption_info->cryptid);
+ NSLog(@"[trolldecrypt] Found cryptid at offset: 0x%llx\n", (mach_vm_address_t)lc + offsetof(struct encryption_info_command, cryptid) - (mach_vm_address_t)header);
+
+ off_cryptid = (mach_vm_address_t)lc + offsetof(struct encryption_info_command, cryptid) - (mach_vm_address_t)header;
+ break;
+ }
+ lc = (struct load_command*)((mach_vm_address_t)lc + lc->cmdsize);
+ }
+ free(buffer);
+ fclose(file);
+
+ return off_cryptid;
+}
+
+@implementation DumpDecrypted
+
+-(id) initWithPathToBinary:(NSString *)pathToBinary appName:(NSString *)appName appVersion:(NSString *)appVersion {
+ if(!self) {
+ self = [super init];
+ }
+
+ self.appName = appName;
+ self.appVersion = appVersion;
+
+ [self setAppPath:[pathToBinary stringByDeletingLastPathComponent]];
+ [self setDocPath:[NSString stringWithFormat:@"%@/Documents", NSHomeDirectory()]];
+
+ char *lastPartOfAppPath = strdup([[self appPath] UTF8String]);
+ lastPartOfAppPath = strrchr(lastPartOfAppPath, '/') + 1;
+ NSLog(@"[trolldecrypt] init: appDirName: %s", lastPartOfAppPath);
+ self->appDirName = strdup(lastPartOfAppPath);
+
+ return self;
+}
+
+
+-(void) makeDirectories:(const char *)encryptedImageFilenameStr {
+ char *appPath = (char *)[[self appPath] UTF8String];
+ char *docPath = (char *)[[self docPath] UTF8String];
+ char *savePtr;
+ char *encryptedImagePathStr = savePtr = strdup(encryptedImageFilenameStr);
+ self->filename = strdup(strrchr(encryptedImagePathStr, '/') + 1);
+
+ // Normalize the filenames
+ if(strstr(encryptedImagePathStr, "/private") == encryptedImagePathStr)
+ encryptedImagePathStr += 8;
+ if(strstr(appPath, "/private") == appPath)
+ appPath += 8;
+
+ // Find start of image path, relative to the base of the app sandbox (ie. /var/mobile/.../FooBar.app/THIS_PART_HERE)
+ encryptedImagePathStr += strlen(appPath) + 1; // skip over the app path
+ char *p = strrchr(encryptedImagePathStr, '/');
+ if(p)
+ *p = '\0';
+
+ NSLog(@"[trolldecrypt] encryptedImagePathStr: %s", encryptedImagePathStr);
+
+ NSFileManager *fm = [[NSFileManager alloc] init];
+ NSError *err;
+ char *lastPartOfAppPath = strdup(appPath); // Must free()
+ lastPartOfAppPath = strrchr(lastPartOfAppPath, '/');
+ lastPartOfAppPath++;
+ NSString *path = [NSString stringWithFormat:@"%s/ipa/Payload/%s", docPath, lastPartOfAppPath];
+ self->appDirPath = strdup([path UTF8String]);
+ if(p)
+ path = [NSString stringWithFormat:@"%@/%s", path, encryptedImagePathStr];
+
+ NSLog(@"[trolldecrypt] make_directories making dir: %@", path);
+ if(! [fm createDirectoryAtPath:path withIntermediateDirectories:true attributes:nil error:&err]) {
+ NSLog(@"[trolldecrypt] WARNING: make_directories failed to make directory %@. Error: %@", path, err);
+ }
+
+ free(savePtr);
+
+ snprintf(self->decryptedAppPathStr, PATH_MAX, "%s/%s", [path UTF8String], self->filename);
+
+ return;
+}
+
+
+-(BOOL) dumpDecryptedImage:(vm_address_t)imageAddress fileName:(const char *)encryptedImageFilenameStr image:(int)imageNum task:(vm_map_t)targetTask{
+ // struct load_command *lc;
+ struct encryption_info_command *eic;
+ struct fat_header *fh;
+ struct fat_arch *arch;
+ // struct mach_header *mh;
+ char buffer[1024];
+ unsigned int fileoffs = 0, off_cryptid = 0, restsize;
+ int i, fd, outfd, r, n;
+
+ struct mach_header header = {0};
+ vm_region_basic_info_data_64_t region_info = {0};
+ if (readmem((mach_vm_offset_t*)&header, imageAddress, sizeof(struct mach_header), targetTask, ®ion_info))
+ {
+ NSLog(@"[trolldecrypt] Can't read header!");
+ exit(1);
+ }
+ //XXX: change all image_mh -> header NOW
+
+ struct load_command *lc = (struct load_command*)malloc(header.sizeofcmds);
+
+ /* detect if this is a arm64 binary */
+ if (header.magic == MH_MAGIC_64) {
+ // lc = (struct load_command *)((unsigned char *)header + sizeof(struct mach_header_64));
+ readmem((mach_vm_offset_t*)lc, imageAddress+sizeof(struct mach_header_64), header.sizeofcmds, targetTask, ®ion_info);
+ NSLog(@"[trolldecrypt] detected 64bit ARM binary in memory.\n");
+ } else if(header.magic == MH_MAGIC) { /* we might want to check for other errors here, too */
+ // lc = (struct load_command *)((unsigned char *)header + sizeof(struct mach_header));
+ readmem((mach_vm_offset_t*)lc, imageAddress+sizeof(struct mach_header), header.sizeofcmds, targetTask, ®ion_info);
+ NSLog(@"[trolldecrypt] detected 32bit ARM binary in memory.\n");
+ } else {
+ NSLog(@"[trolldecrypt] No valid header found!!");
+ return false;
+ }
+
+
+ // sleep(1);exit(1);
+ const struct mach_header *image_mh = &header;
+
+ /* searching all load commands for an LC_ENCRYPTION_INFO load command */
+ for (i=0; incmds; i++) {
+ if (lc->cmd == LC_ENCRYPTION_INFO || lc->cmd == LC_ENCRYPTION_INFO_64) {
+ eic = (struct encryption_info_command *)lc;
+ // struct encryption_info_command *eic = (uint8_t*)malloc(sizeof(struct encryption_info_command););
+ // readmem((mach_vm_offset_t*)eic, imageAddress+sizeof(struct mach_header_64), header.sizeofcmds, targetTask, ®ion_info);
+
+ const char *appFilename = strrchr(encryptedImageFilenameStr, '/');
+ if(appFilename == NULL) {
+ NSLog(@"[trolldecrypt] There are no / in the filename. This is an error.\n");
+ return false;
+ }
+ appFilename++;
+
+ /* If this load command is present, but data is not crypted then exit */
+ if (eic->cryptid == 0) {
+ NSLog(@"[trolldecrypt] CryptID = 0!! ");
+ return false;
+ }
+
+ // Create a dir structure in ~ just like in /path/to/FooApp.app/Whatever
+ [self makeDirectories:encryptedImageFilenameStr];
+
+ //0x1518
+ uint32_t aslr_slide = 0;
+ get_image_size(imageAddress, targetTask, &aslr_slide);
+ NSLog(@"[trolldecrypt] aslr_slide= 0x%x", aslr_slide);
+
+ off_cryptid=find_off_cryptid(encryptedImageFilenameStr);
+
+ NSLog(@"[trolldecrypt] offset to cryptid (%d) found in memory @ %p (from %p). off_cryptid = %u (0x%x)\n", eic->cryptid, &eic->cryptid, image_mh, off_cryptid, off_cryptid);
+ //NSLog(@"[trolldecrypt] Found encrypted data at offset %u 0x%08x. image_mh @ %p. cryptedData @ 0x%x. cryptsize = %u (0x%x) bytes.\n", eic->cryptoff, eic->cryptoff, image_mh, (unsigned int)image_mh + eic->cryptoff, eic->cryptsize, eic->cryptsize);
+
+ NSLog(@"[trolldecrypt] Dumping: %s", encryptedImageFilenameStr);
+ NSLog(@"[trolldecrypt] Into: %s", self->decryptedAppPathStr);
+ fd = open(encryptedImageFilenameStr, O_RDONLY);
+ if (fd == -1) {
+ NSLog(@"[trolldecrypt] Failed to open %s", encryptedImageFilenameStr);
+ return false;
+ }
+
+ NSLog(@"[trolldecrypt] Reading header");
+ n = read(fd, (void *)buffer, sizeof(buffer));
+ if (n != sizeof(buffer)) {
+ NSLog(@"[trolldecrypt] Warning read only %d of %lu bytes from encrypted file.\n", n, sizeof(buffer));
+ return false;
+ }
+
+ NSLog(@"[trolldecrypt] Detecting header type\n");
+ fh = (struct fat_header *)buffer;
+
+ /* Is this a FAT file - we assume the right endianess */
+ if (fh->magic == FAT_CIGAM) {
+ NSLog(@"[trolldecrypt] Executable is a FAT image - searching for right architecture\n");
+ arch = (struct fat_arch *)&fh[1];
+ for (i=0; infat_arch); i++) {
+ if ((image_mh->cputype == swap32(arch->cputype)) && (image_mh->cpusubtype == swap32(arch->cpusubtype))) {
+ fileoffs = swap32(arch->offset);
+ NSLog(@"[trolldecrypt] Correct arch is at offset 0x%x in the file.\n", fileoffs);
+ break;
+ }
+ arch++;
+ }
+ if (fileoffs == 0) {
+ NSLog(@"[trolldecrypt] Could not find correct arch in FAT image\n");
+ return false;
+ }
+ } else if (fh->magic == MH_MAGIC || fh->magic == MH_MAGIC_64) {
+ NSLog(@"[trolldecrypt] Executable is a plain MACH-O image, fileoffs = 0\n");
+ } else {
+ NSLog(@"[trolldecrypt] Executable is of unknown type, fileoffs = 0\n");
+ return false;
+ }
+
+ NSLog(@"[trolldecrypt] Opening %s for writing.\n", decryptedAppPathStr);
+ outfd = open(decryptedAppPathStr, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ if (outfd == -1) {
+ NSLog(@"[trolldecrypt] Failed opening: ");
+ return false;
+ }
+
+ /* calculate address of beginning of crypted data */
+ n = fileoffs + eic->cryptoff;
+
+ restsize = lseek(fd, 0, SEEK_END) - n - eic->cryptsize;
+ //NSLog(@"[trolldecrypt] restsize = %u, n = %u, cryptsize = %u, total = %u", restsize, n, eic->cryptsize, n + eic->cryptsize + restsize);
+ lseek(fd, 0, SEEK_SET);
+
+ NSLog(@"[trolldecrypt] Copying the not encrypted start of the file (%u bytes)\n", n);
+
+ /* first copy all the data before the encrypted data */
+ char *buf = (char *)malloc((size_t)n);
+ r = read(fd, buf, n);
+ if(r != n) {
+ NSLog(@"[trolldecrypt] Error reading start of file\n");
+ return false;
+ }
+ r = write(outfd, buf, n);
+ if(r != n) {
+ NSLog(@"[trolldecrypt] Error writing start of file\n");
+ return false;
+ }
+ free(buf);
+
+ /* now write the previously encrypted data */
+
+ NSLog(@"[trolldecrypt] Dumping the decrypted data into the file (%u bytes)\n", eic->cryptsize);
+ buf = (char *)malloc((size_t)eic->cryptsize);
+ readmem((mach_vm_offset_t*)buf, imageAddress+eic->cryptoff, eic->cryptsize, targetTask, ®ion_info);
+ // r = write(outfd, (unsigned char *)image_mh + eic->cryptoff, eic->cryptsize);
+ r = write(outfd, buf, eic->cryptsize);
+ if (r != eic->cryptsize) {
+ NSLog(@"[trolldecrypt] Error writing encrypted part of file\n");
+ return false;
+ }
+ free(buf);
+
+
+ /* and finish with the remainder of the file */
+ NSLog(@"[trolldecrypt] Copying the not encrypted remainder of the file (%u bytes)\n", restsize);
+ lseek(fd, eic->cryptsize, SEEK_CUR);
+ buf = (char *)malloc((size_t)restsize);
+ r = read(fd, buf, restsize);
+ if (r != restsize) {
+ NSLog(@"[trolldecrypt] Error reading rest of file, got %u bytes\n", r);
+ return false;
+ }
+ r = write(outfd, buf, restsize);
+ if (r != restsize) {
+ NSLog(@"[trolldecrypt] Error writing rest of file\n");
+ return false;
+ }
+ free(buf);
+
+
+ if (off_cryptid) {
+ uint32_t zero=0;
+ NSLog(@"[trolldecrypt] Setting the LC_ENCRYPTION_INFO->cryptid to 0 at offset 0x%x into file\n", off_cryptid);
+ if (lseek(outfd, off_cryptid, SEEK_SET) == off_cryptid) {
+ if(write(outfd, &zero, 4) != 4) {
+ NSLog(@"[trolldecrypt] Error writing cryptid value!!\n");
+ // Not a fatal error, just warn
+ }
+ } else {
+ NSLog(@"[trolldecrypt] Failed to seek to cryptid offset!!");
+ // this error is not treated as fatal
+ }
+ }
+
+ close(fd);
+ close(outfd);
+ sync();
+ // exit(1);
+
+ return true;
+ }
+
+ lc = (struct load_command *)((unsigned char *)lc+lc->cmdsize);
+ // readmem((mach_vm_offset_t*)lc, lc+lc->cmdsize, header.sizeofcmds, targetTask, ®ion_info);
+ }
+ // DEBUG(@"[!] This mach-o file is not encrypted. Nothing was decrypted.\n");
+ return false;
+}
+
+
+-(void) dumpDecrypted:(pid_t)pid {
+
+ vm_map_t targetTask = 0;
+ if (task_for_pid(mach_task_self(), pid, &targetTask))
+ {
+ NSLog(@"[trolldecrypt] Can't execute task_for_pid! Do you have the right permissions/entitlements?\n");
+ exit(1);
+ }
+
+ //numberOfImages
+ struct task_dyld_info dyld_info;
+ mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+
+ if(task_info(targetTask, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count) != KERN_SUCCESS) exit(1);
+
+ mach_msg_type_number_t size = sizeof(struct dyld_all_image_infos);
+ uint8_t* data = readProcessMemory(targetTask, dyld_info.all_image_info_addr, &size);
+ struct dyld_all_image_infos* infos = (struct dyld_all_image_infos *) data;
+
+ mach_msg_type_number_t size2 = sizeof(struct dyld_image_info) * infos->infoArrayCount;
+ uint8_t* info_addr = readProcessMemory(targetTask, (mach_vm_address_t) infos->infoArray, &size2);
+ struct dyld_image_info* info = (struct dyld_image_info*) info_addr;
+
+ uint32_t numberOfImages = infos->infoArrayCount;
+ mach_vm_address_t imageAddress = 0;
+ const char *appPath = [[self appPath] UTF8String];
+
+ NSLog(@"[trolldecrypt] There are %d images mapped.", numberOfImages);
+
+ for (int i = 0; i < numberOfImages; i++) {
+ NSLog(@"[trolldecrypt] image %d", i);
+ mach_msg_type_number_t size3 = PATH_MAX;
+ uint8_t *fpath_addr = readProcessMemory(targetTask, (mach_vm_address_t) info[i].imageFilePath, &size3);
+
+ imageAddress = (struct mach_header *)info[i].imageLoadAddress;
+ const char *imageName = fpath_addr;
+
+ if(!imageName || !imageAddress)
+ continue;
+
+ NSLog(@"[trolldecrypt] Comparing %s to %s", imageName, appPath);
+
+ if(strstr(imageName, appPath) != NULL) {
+ NSLog(@"[trolldecrypt] Dumping image %d: %s", i, imageName);
+ [self dumpDecryptedImage:imageAddress fileName:imageName image:i task: targetTask];
+ }
+ }
+}
+
+
+-(BOOL)fileManager:(NSFileManager *)f shouldProceedAfterError:(BOOL)proceed copyingItemAtPath:(NSString *)path toPath:(NSString *)dest {
+ return true;
+}
+
+-(NSString *)IPAPath {
+ return [NSString stringWithFormat:@"%@/%@_%@_decrypted.ipa", [self docPath], self.appName, self.appVersion];
+}
+
+-(void) createIPAFile:(pid_t)pid {
+ NSString *IPAFile = [self IPAPath];
+ NSString *appDir = [self appPath];
+ NSString *appCopyDir = [NSString stringWithFormat:@"%@/ipa/Payload/%s", [self docPath], self->appDirName];
+ NSString *zipDir = [NSString stringWithFormat:@"%@/ipa", [self docPath]];
+ NSFileManager *fm = [[NSFileManager alloc] init];
+ NSError *err;
+
+ [fm removeItemAtPath:IPAFile error:nil];
+ [fm removeItemAtPath:appCopyDir error:nil];
+ [fm createDirectoryAtPath:appCopyDir withIntermediateDirectories:true attributes:nil error:nil];
+
+ [fm setDelegate:(id)self];
+
+ NSLog(@"[trolldecrypt] ======== START FILE COPY - IGNORE ANY SANDBOX WARNINGS ========");
+ NSLog(@"[trolldecrypt] IPAFile: %@", IPAFile);
+ NSLog(@"[trolldecrypt] appDir: %@", appDir);
+ NSLog(@"[trolldecrypt] appCopyDir: %@", appCopyDir);
+ NSLog(@"[trolldecrypt] zipDir: %@", zipDir);
+
+ [fm copyItemAtPath:appDir toPath:appCopyDir error:&err];
+ NSLog(@"[trolldecrypt] ======== END OF FILE COPY ========");
+ // sleep(1);
+ // exit(1);
+ // Replace encrypted binaries with decrypted versions
+ NSLog(@"[trolldecrypt] ======== START DECRYPTION PROCESS ========");
+ [self dumpDecrypted:pid];
+ NSLog(@"[trolldecrypt] ======== DECRYPTION COMPLETE ========");
+
+ // ZIP it up
+ NSLog(@"[trolldecrypt] ======== STARTING ZIP ========");
+ NSLog(@"[trolldecrypt] IPA file: %@", IPAFile);
+ NSLog(@"[trolldecrypt] ZIP dir: %@", zipDir);
+ unlink([IPAFile UTF8String]);
+ @try {
+ BOOL success = [SSZipArchive createZipFileAtPath:IPAFile
+ withContentsOfDirectory:zipDir
+ keepParentDirectory:NO
+ compressionLevel:1
+ password:nil
+ AES:NO
+ progressHandler:nil
+ ];
+ NSLog(@"[trolldecrypt] ======== ZIP operation complete: %s ========", (success)?"success":"failed");
+ }
+ @catch(NSException *e) {
+ NSLog(@"[trolldecrypt] BAAAAAAAARF during ZIP operation!!! , %@", e);
+ }
+
+
+ // Clean up. Leave only the .ipa file.
+ [fm removeItemAtPath:zipDir error:nil];
+
+ NSLog(@"[trolldecrypt] ======== Wrote %@ ========", [self IPAPath]);
+ return;
+}
+
+@end
\ No newline at end of file
diff --git a/TDFileManagerViewController.h b/TDFileManagerViewController.h
new file mode 100644
index 0000000..cc3aaae
--- /dev/null
+++ b/TDFileManagerViewController.h
@@ -0,0 +1,7 @@
+#import
+
+@interface TDFileManagerViewController : UITableViewController
+
+@property (nonatomic, strong) NSArray *fileList;
+
+@end
\ No newline at end of file
diff --git a/TDFileManagerViewController.m b/TDFileManagerViewController.m
new file mode 100644
index 0000000..46bdac5
--- /dev/null
+++ b/TDFileManagerViewController.m
@@ -0,0 +1,97 @@
+#import "TDFileManagerViewController.h"
+#import "TDUtils.h"
+
+@implementation TDFileManagerViewController
+
+- (void)loadView {
+ [super loadView];
+
+ self.title = @"Decrypted IPAs";
+ self.fileList = decryptedFileList();
+
+ self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(done)];
+}
+
+- (void)refresh {
+ self.fileList = decryptedFileList();
+ [self.tableView reloadData];
+}
+
+- (void)done {
+ [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (NSInteger)numberOfSelectionsInTableView:(UITableView *)tableView {
+ return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+ return self.fileList.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+ static NSString *cellIdentifier = @"FileCell";
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
+
+ if (!cell) {
+ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
+ }
+
+ NSString *path = [docPath() stringByAppendingPathComponent:self.fileList[indexPath.row]];
+ NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
+ NSDate *date = attributes[NSFileModificationDate];
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
+ [dateFormatter setDateFormat:@"MMM d, yyyy h:mm a"];
+
+ NSNumber *fileSize = attributes[NSFileSize];
+
+
+ cell.textLabel.text = self.fileList[indexPath.row];
+ cell.detailTextLabel.text = [dateFormatter stringFromDate:date];
+ cell.detailTextLabel.textColor = [UIColor systemGray2Color];
+ cell.imageView.image = [UIImage systemImageNamed:@"doc.fill"];
+
+ UILabel *label = [[UILabel alloc] init];
+ label.text = [NSString stringWithFormat:@"%.2f MB", [fileSize doubleValue] / 1000000.0f];
+ label.textColor = [UIColor systemGray2Color];
+ label.font = [UIFont systemFontOfSize:12.0f];
+ [label sizeToFit];
+ label.textAlignment = NSTextAlignmentCenter;
+ cell.accessoryView = label;
+
+
+ return cell;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+ return 65.0f;
+}
+
+- (bool)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
+ return YES;
+}
+
+- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
+ UIContextualAction *deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"Delete" handler:^(UIContextualAction *action, UIView *sourceView, void (^completionHandler)(BOOL)) {
+ NSString *file = self.fileList[indexPath.row];
+ NSString *path = [docPath() stringByAppendingPathComponent:file];
+ [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
+ [self refresh];
+ }];
+
+ UISwipeActionsConfiguration *swipeActions = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction]];
+ return swipeActions;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+ NSString *file = self.fileList[indexPath.row];
+ NSString *path = [docPath() stringByAppendingPathComponent:file];
+ NSURL *url = [NSURL fileURLWithPath:path];
+
+ UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[url] applicationActivities:nil];
+ [self presentViewController:activityViewController animated:YES completion:nil];
+
+ [tableView deselectRowAtIndexPath:indexPath animated:YES];
+}
+
+@end
\ No newline at end of file
diff --git a/TDRootViewController.h b/TDRootViewController.h
new file mode 100644
index 0000000..7b50b79
--- /dev/null
+++ b/TDRootViewController.h
@@ -0,0 +1,7 @@
+#import
+
+@interface TDRootViewController : UITableViewController
+
+@property (nonatomic, strong) NSArray *apps;
+
+@end
diff --git a/TDRootViewController.m b/TDRootViewController.m
new file mode 100644
index 0000000..1a5e1d0
--- /dev/null
+++ b/TDRootViewController.m
@@ -0,0 +1,109 @@
+#import "TDRootViewController.h"
+#import "TDFileManagerViewController.h"
+#import "TDUtils.h"
+
+@implementation TDRootViewController
+
+- (void)loadView {
+ [super loadView];
+
+ self.apps = appList();
+ self.title = @"TrollDecrypt";
+ self.navigationController.navigationBar.prefersLargeTitles = YES;
+ self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"info.circle"] style:UIBarButtonItemStylePlain target:self action:@selector(about:)];
+ self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"folder"] style:UIBarButtonItemStylePlain target:self action:@selector(openDocs:)];
+
+ UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
+ [refreshControl addTarget:self action:@selector(refreshApps:) forControlEvents:UIControlEventValueChanged];
+ self.refreshControl = refreshControl;
+}
+
+- (void)openDocs:(id)sender {
+ TDFileManagerViewController *fmVC = [[TDFileManagerViewController alloc] init];
+ UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:fmVC];
+ [self presentViewController:navController animated:YES completion:nil];
+}
+
+- (void)about:(id)sender {
+ UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"TrollDecrypt" message:@"by fiore\nIcon by @super.user\nbfdecrypt by @bishopfox\ndumpdecrypted by @i0n1c\nUpdated for TrollStore by @wh1te4ever" preferredStyle:UIAlertControllerStyleAlert];
+ [alert addAction:[UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleCancel handler:nil]];
+ [self presentViewController:alert animated:YES completion:nil];
+}
+
+- (void)refreshApps:(UIRefreshControl *)refreshControl {
+ self.apps = appList();
+ [self.tableView reloadData];
+ [refreshControl endRefreshing];
+}
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+ return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+ return self.apps.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+ static NSString *cellIdentifier = @"AppCell";
+ UITableViewCell *cell;
+ if (([self.apps count] - 1) != indexPath.row) {
+ cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
+ if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
+
+ NSDictionary *app = self.apps[indexPath.row];
+
+ cell.textLabel.text = app[@"name"];
+ cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ • %@", app[@"version"], app[@"bundleID"]];
+ cell.imageView.image = [UIImage _applicationIconImageForBundleIdentifier:app[@"bundleID"] format:iconFormat() scale:[UIScreen mainScreen].scale];
+ } else {
+ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil];
+
+ cell.textLabel.text = @"Advanced";
+ cell.detailTextLabel.text = @"Decrypt app from a specified PID";
+ cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
+ }
+
+ return cell;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+ return 80.0f;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+ UIAlertController *alert;
+
+ if (([self.apps count] - 1) != indexPath.row) {
+ NSDictionary *app = self.apps[indexPath.row];
+
+ alert = [UIAlertController alertControllerWithTitle:@"Decrypt" message:[NSString stringWithFormat:@"Decrypt %@?", app[@"name"]] preferredStyle:UIAlertControllerStyleAlert];
+ UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
+ UIAlertAction *decrypt = [UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
+ decryptApp(app);
+ }];
+
+ [alert addAction:decrypt];
+ [alert addAction:cancel];
+ } else {
+ alert = [UIAlertController alertControllerWithTitle:@"Decrypt" message:@"Enter PID to decrypt" preferredStyle:UIAlertControllerStyleAlert];
+ [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
+ textField.placeholder = @"PID";
+ textField.keyboardType = UIKeyboardTypeNumberPad;
+ }];
+
+ UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
+ UIAlertAction *decrypt = [UIAlertAction actionWithTitle:@"Decrypt" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
+ NSString *pid = alert.textFields.firstObject.text;
+ decryptAppWithPID([pid intValue]);
+ }];
+
+ [alert addAction:decrypt];
+ [alert addAction:cancel];
+ }
+
+ [self presentViewController:alert animated:YES completion:nil];
+ [tableView deselectRowAtIndexPath:indexPath animated:YES];
+}
+
+@end
\ No newline at end of file
diff --git a/TDUtils.h b/TDUtils.h
new file mode 100644
index 0000000..d7f61de
--- /dev/null
+++ b/TDUtils.h
@@ -0,0 +1,58 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#import
+#import
+#import
+
+@interface UIApplication (tweakName)
++ (id)sharedApplication;
+- (BOOL)launchApplicationWithIdentifier:(id)arg1 suspended:(BOOL)arg2;
+@end
+
+@interface LSApplicationProxy : NSObject
+@property (readonly, nonatomic) NSString *bundleIdentifier; // ivar: _bundleIdentifier
+@property (readonly) NSString *shortVersionString;
+@property (readonly, nonatomic) NSString *canonicalExecutablePath;
+@property (getter=isLaunchProhibited) BOOL launchProhibited;
+@property (readonly, nonatomic) NSArray *appTags;
+@property(readonly) NSString * applicationType;
+- (NSString *)localizedName;
++ (instancetype)applicationProxyForIdentifier:(NSString*)identifier;
+@end
+
+@interface LSApplicationWorkspace : NSObject
++ (instancetype)defaultWorkspace;
+- (NSMutableArray *)allApplications;
+- (NSArray *)allInstalledApplications;
+@end
+
+@interface UIImage (Private)
++ (UIImage *)_applicationIconImageForBundleIdentifier:(NSString *)bundleIdentifier format:(NSUInteger)format scale:(CGFloat)scale;
+@end
+
+#define PROC_PIDPATHINFO 11
+#define PROC_PIDPATHINFO_SIZE (MAXPATHLEN)
+#define PROC_PIDPATHINFO_MAXSIZE (4 * MAXPATHLEN)
+#define PROC_ALL_PIDS 1
+#ifndef DEBUG
+# define NSLog(...) (void)0
+#endif
+
+int proc_pidpath(int pid, void *buffer, uint32_t buffersize);
+int proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize);
+NSArray *appList(void);
+NSUInteger iconFormat(void);
+NSArray *sysctl_ps(void);
+void decryptApp(NSDictionary *app);
+void decryptAppWithPID(pid_t pid);
+void bfinject_rocknroll(pid_t pid, NSString *appName, NSString *version);
+NSArray *decryptedFileList(void);
+NSString *docPath(void);
\ No newline at end of file
diff --git a/TDUtils.m b/TDUtils.m
new file mode 100644
index 0000000..c907ab7
--- /dev/null
+++ b/TDUtils.m
@@ -0,0 +1,372 @@
+#import "TDUtils.h"
+#import "TDDumpDecrypted.h"
+
+UIWindow *alertWindow = NULL;
+UIWindow *kw = NULL;
+UIViewController *root = NULL;
+UIAlertController *alertController = NULL;
+UIAlertController *doneController = NULL;
+UIAlertController *errorController = NULL;
+
+NSArray *appList(void) {
+ NSMutableArray *apps = [NSMutableArray array];
+
+ for (LSApplicationProxy *app in [[LSApplicationWorkspace defaultWorkspace] allInstalledApplications]) {
+ if (![[app applicationType] isEqualToString:@"User"]) continue;
+
+ NSString *bundleID = app.bundleIdentifier;
+ NSString *name = [app localizedName];
+ NSString *version = app.shortVersionString;
+ NSString *executable = [app canonicalExecutablePath];
+
+ NSDictionary *item = @{
+ @"bundleID":bundleID,
+ @"name":name,
+ @"version":version,
+ @"executable":executable
+ };
+
+ [apps addObject:item];
+ }
+
+ NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
+ [apps sortUsingDescriptors:@[descriptor]];
+
+ [apps addObject:@{@"bundleID":@"", @"name":@"", @"version":@"", @"executable":@""}];
+
+ return [apps copy];
+}
+
+NSUInteger iconFormat(void) {
+ return (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) ? 8 : 10;
+}
+
+NSArray *sysctl_ps(void) {
+ // int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
+ // size_t miblen = 4;
+ // size_t size;
+ // int st = sysctl(mib, miblen, NULL, &size, NULL, 0);
+ // struct kinfo_proc * process = NULL;
+ // struct kinfo_proc * newprocess = NULL;
+
+ // do {
+ // size += size / 10;
+ // newprocess = realloc(process, size);
+ // if (!newprocess){
+ // if (process){
+ // free(process);
+ // }
+ // return nil;
+ // }
+ // process = newprocess;
+ // st = sysctl(mib, miblen, process, &size, NULL, 0);
+ // } while (st == -1 && errno == ENOMEM);
+
+ // if (st == 0) {
+ // if (size % sizeof(struct kinfo_proc) == 0){
+ // int nprocess = size / sizeof(struct kinfo_proc);
+ // if (nprocess){
+ // NSMutableArray * array = [[NSMutableArray alloc] init];
+ // for (int i = nprocess - 1; i >= 0; i--){
+ // NSString *processID = [[NSString alloc] initWithFormat:@"%d", process[i].kp_proc.p_pid];
+ // NSString *processName = [[NSString alloc] initWithFormat:@"%s", process[i].kp_proc.p_comm];
+ // NSDictionary *dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processName, nil] forKeys:[NSArray arrayWithObjects:@"pid", @"proc_name", nil]];
+ // [array addObject:dict];
+ // }
+ // free(process);
+ // return array;
+ // }
+ // }
+ // }
+ NSMutableArray *array = [[NSMutableArray alloc] init];
+
+ int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
+ pid_t pids[numberOfProcesses];
+ bzero(pids, sizeof(pids));
+ proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));
+ for (int i = 0; i < numberOfProcesses; ++i) {
+ if (pids[i] == 0) { continue; }
+ char pathBuffer[PROC_PIDPATHINFO_MAXSIZE];
+ bzero(pathBuffer, PROC_PIDPATHINFO_MAXSIZE);
+ proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer));
+
+ if (strlen(pathBuffer) > 0) {
+ NSString *processID = [[NSString alloc] initWithFormat:@"%d", pids[i]];
+ NSString *processName = [[NSString stringWithUTF8String:pathBuffer] lastPathComponent];
+ NSDictionary *dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processName, nil] forKeys:[NSArray arrayWithObjects:@"pid", @"proc_name", nil]];
+
+ [array addObject:dict];
+ }
+ }
+
+ return [array copy];
+}
+
+void decryptApp(NSDictionary *app) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ alertWindow = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];
+ alertWindow.rootViewController = [UIViewController new];
+ alertWindow.windowLevel = UIWindowLevelAlert + 1;
+ [alertWindow makeKeyAndVisible];
+
+ // Show a "Decrypting!" alert on the device and block the UI
+
+ kw = alertWindow;
+ if([kw respondsToSelector:@selector(topmostPresentedViewController)])
+ root = [kw performSelector:@selector(topmostPresentedViewController)];
+ else
+ root = [kw rootViewController];
+ root.modalPresentationStyle = UIModalPresentationFullScreen;
+ });
+
+ NSLog(@"[trolldecrypt] spawning thread to do decryption in background...");
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ NSLog(@"[trolldecrypt] inside decryption thread.");
+
+ NSString *bundleID = app[@"bundleID"];
+ NSString *name = app[@"name"];
+ NSString *version = app[@"version"];
+ NSString *executable = app[@"executable"];
+ NSString *binaryName = [executable lastPathComponent];
+
+ NSLog(@"[trolldecrypt] bundleID: %@", bundleID);
+ NSLog(@"[trolldecrypt] name: %@", name);
+ NSLog(@"[trolldecrypt] version: %@", version);
+ NSLog(@"[trolldecrypt] executable: %@", executable);
+ NSLog(@"[trolldecrypt] binaryName: %@", binaryName);
+
+ [[UIApplication sharedApplication] launchApplicationWithIdentifier:bundleID suspended:YES];
+ sleep(1);
+
+ pid_t pid = -1;
+ NSArray *processes = sysctl_ps();
+ for (NSDictionary *process in processes) {
+ NSString *proc_name = process[@"proc_name"];
+ if ([proc_name isEqualToString:binaryName]) {
+ pid = [process[@"pid"] intValue];
+ break;
+ }
+ }
+
+ if (pid == -1) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [alertController dismissViewControllerAnimated:NO completion:nil];
+ NSLog(@"[trolldecrypt] failed to get pid for binary name: %@", binaryName);
+
+ errorController = [UIAlertController alertControllerWithTitle:@"Error: -1" message:[NSString stringWithFormat:@"Failed to get PID for binary name: %@", binaryName] preferredStyle:UIAlertControllerStyleAlert];
+ UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Ok", @"Ok") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
+ NSLog(@"[trolldecrypt] Ok action");
+ [errorController dismissViewControllerAnimated:NO completion:nil];
+ [kw removeFromSuperview];
+ kw.hidden = YES;
+ }];
+
+ [errorController addAction:okAction];
+ [root presentViewController:errorController animated:YES completion:nil];
+ });
+
+ return;
+ }
+
+ NSLog(@"[trolldecrypt] pid: %d", pid);
+
+ bfinject_rocknroll(pid, name, version);
+ });
+}
+
+void bfinject_rocknroll(pid_t pid, NSString *appName, NSString *version) {
+ NSLog(@"[trolldecrypt] Spawning thread to do decryption in the background...");
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ NSLog(@"[trolldecrypt] Inside decryption thread");
+
+ char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
+ // int proc_pidpath(pid, pathbuf, sizeof(pathbuf));
+ proc_pidpath(pid, pathbuf, sizeof(pathbuf));
+ const char *fullPathStr = pathbuf;
+
+
+ NSLog(@"[trolldecrypt] fullPathStr: %s", fullPathStr);
+ DumpDecrypted *dd = [[DumpDecrypted alloc] initWithPathToBinary:[NSString stringWithUTF8String:fullPathStr] appName:appName appVersion:version];
+ if(!dd) {
+ NSLog(@"[trolldecrypt] ERROR: failed to get DumpDecrypted instance");
+ return;
+ }
+
+ NSLog(@"[trolldecrypt] Full path to app: %s /// IPA File: %@", fullPathStr, [dd IPAPath]);
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ alertWindow = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];
+ alertWindow.rootViewController = [UIViewController new];
+ alertWindow.windowLevel = UIWindowLevelAlert + 1;
+ [alertWindow makeKeyAndVisible];
+
+ // Show a "Decrypting!" alert on the device and block the UI
+ alertController = [UIAlertController
+ alertControllerWithTitle:@"Decrypting"
+ message:@"Please wait, this will take a few seconds..."
+ preferredStyle:UIAlertControllerStyleAlert];
+
+ kw = alertWindow;
+ if([kw respondsToSelector:@selector(topmostPresentedViewController)])
+ root = [kw performSelector:@selector(topmostPresentedViewController)];
+ else
+ root = [kw rootViewController];
+ root.modalPresentationStyle = UIModalPresentationFullScreen;
+ [root presentViewController:alertController animated:YES completion:nil];
+ });
+
+ // Do the decryption
+ [dd createIPAFile:pid];
+
+ // Dismiss the alert box
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [alertController dismissViewControllerAnimated:NO completion:nil];
+
+ doneController = [UIAlertController alertControllerWithTitle:@"Decryption Complete!" message:[NSString stringWithFormat:@"IPA file saved to:\n%@", [dd IPAPath]] preferredStyle:UIAlertControllerStyleAlert];
+ UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Ok", @"Ok") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
+ NSLog(@"[trolldecrypt] Ok action");
+ [doneController dismissViewControllerAnimated:NO completion:nil];
+ [kw removeFromSuperview];
+ kw.hidden = YES;
+ }];
+
+ [doneController addAction:okAction];
+ [root presentViewController:doneController animated:YES completion:nil];
+ }); // dispatch on main
+
+ NSLog(@"[trolldecrypt] Over and out.");
+ while(1)
+ sleep(9999999);
+ }); // dispatch in background
+
+ NSLog(@"[trolldecrypt] All done, exiting constructor.");
+}
+
+NSArray *decryptedFileList(void) {
+ NSMutableArray *files = [NSMutableArray array];
+
+ // iterate through all files in the Documents directory
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSDirectoryEnumerator *directoryEnumerator = [fileManager enumeratorAtPath:docPath()];
+
+ NSString *file;
+ while (file = [directoryEnumerator nextObject]) {
+ if ([[file pathExtension] isEqualToString:@"ipa"]) {
+ NSString *filePath = [[docPath() stringByAppendingPathComponent:file] stringByStandardizingPath];
+
+ NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:filePath error:nil];
+ NSDate *modificationDate = [fileAttributes fileModificationDate];
+
+ NSDictionary *fileInfo = @{@"fileName": file, @"modificationDate": modificationDate};
+ [files addObject:fileInfo];
+ }
+ }
+
+ // Sort the array based on modification date
+ NSArray *sortedFiles = [files sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
+ NSDate *date1 = [obj1 objectForKey:@"modificationDate"];
+ NSDate *date2 = [obj2 objectForKey:@"modificationDate"];
+ return [date2 compare:date1];
+ }];
+
+ return [sortedFiles valueForKey:@"fileName"];
+}
+
+NSString *docPath(void) {
+ return [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
+}
+
+void decryptAppWithPID(pid_t pid) {
+ // generate App NSDictionary object to pass into decryptApp()
+ // proc_pidpath(self.pid, buffer, sizeof(buffer));
+ NSString *message = nil;
+ NSString *error = nil;
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ alertWindow = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];
+ alertWindow.rootViewController = [UIViewController new];
+ alertWindow.windowLevel = UIWindowLevelAlert + 1;
+ [alertWindow makeKeyAndVisible];
+
+ // Show a "Decrypting!" alert on the device and block the UI
+
+ kw = alertWindow;
+ if([kw respondsToSelector:@selector(topmostPresentedViewController)])
+ root = [kw performSelector:@selector(topmostPresentedViewController)];
+ else
+ root = [kw rootViewController];
+ root.modalPresentationStyle = UIModalPresentationFullScreen;
+ });
+
+ NSLog(@"[trolldecrypt] pid: %d", pid);
+
+ char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
+ proc_pidpath(pid, pathbuf, sizeof(pathbuf));
+
+ NSString *executable = [NSString stringWithUTF8String:pathbuf];
+ NSString *path = [executable stringByDeletingLastPathComponent];
+ NSDictionary *infoPlist = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Info.plist"]];
+ NSString *bundleID = infoPlist[@"CFBundleIdentifier"];
+
+ if (!bundleID) {
+ error = @"Error: -2";
+ message = [NSString stringWithFormat:@"Failed to get bundle id for pid: %d", pid];
+ }
+
+ LSApplicationProxy *app = [LSApplicationProxy applicationProxyForIdentifier:bundleID];
+ if (!app) {
+ error = @"Error: -3";
+ message = [NSString stringWithFormat:@"Failed to get LSApplicationProxy for bundle id: %@", bundleID];
+ }
+
+ if (message) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [alertController dismissViewControllerAnimated:NO completion:nil];
+ NSLog(@"[trolldecrypt] failed to get bundleid for pid: %d", pid);
+
+ errorController = [UIAlertController alertControllerWithTitle:error message:message preferredStyle:UIAlertControllerStyleAlert];
+ UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Ok", @"Ok") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
+ NSLog(@"[trolldecrypt] Ok action");
+ [errorController dismissViewControllerAnimated:NO completion:nil];
+ [kw removeFromSuperview];
+ kw.hidden = YES;
+ }];
+
+ [errorController addAction:okAction];
+ [root presentViewController:errorController animated:YES completion:nil];
+ });
+ }
+
+ NSLog(@"[trolldecrypt] app: %@", app);
+
+ NSString *name = [app localizedName];
+ NSString *version = app.shortVersionString;
+ if (!version) version = @"1.0";
+
+ NSString *exec = [app canonicalExecutablePath];
+
+ NSDictionary *appInfo = @{
+ @"bundleID":bundleID,
+ @"name":name,
+ @"version":version,
+ @"executable":exec
+ };
+
+ NSLog(@"[trolldecrypt] appInfo: %@", appInfo);
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [alertController dismissViewControllerAnimated:NO completion:nil];
+ UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Decrypt" message:[NSString stringWithFormat:@"Decrypt %@?", appInfo[@"name"]] preferredStyle:UIAlertControllerStyleAlert];
+ UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
+ UIAlertAction *decrypt = [UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
+ decryptApp(appInfo);
+ }];
+
+ [alert addAction:decrypt];
+ [alert addAction:cancel];
+
+ [root presentViewController:alert animated:YES completion:nil];
+ });
+}
\ No newline at end of file
diff --git a/control b/control
new file mode 100644
index 0000000..bee2982
--- /dev/null
+++ b/control
@@ -0,0 +1,8 @@
+Package: com.fiore.trolldecrypt
+Name: TrollDecrypt
+Version: 0.0.1
+Architecture: iphoneos-arm
+Description: An awesome application!
+Maintainer: fiore
+Author: fiore
+Section: Utilities
diff --git a/entitlements.plist b/entitlements.plist
new file mode 100644
index 0000000..357e5fb
--- /dev/null
+++ b/entitlements.plist
@@ -0,0 +1,38 @@
+
+
+
+
+ platform-application
+
+ application-identifier
+ com.fiore.trolldecrypt
+ com.apple.security.exception.files.absolute-path.read-write
+
+ /
+
+ com.apple.private.security.no-sandbox
+
+ com.apple.private.persona-mgmt
+
+ com.apple.private.MobileContainerManager.allowed
+
+ com.apple.private.security.container-manager
+
+ com.apple.private.security.storage.AppBundles
+
+ com.apple.private.security.storage.AppDataContainers
+
+ task_for_pid-allow
+
+ get-task-allow
+
+ com.apple.security.get-task-allow
+
+ proc_info-allow
+
+ com.apple.system-task-ports
+
+ com.apple.springboard.launchapplications
+
+
+
\ No newline at end of file
diff --git a/main.m b/main.m
new file mode 100644
index 0000000..ad03dbd
--- /dev/null
+++ b/main.m
@@ -0,0 +1,8 @@
+#import
+#import "TDAppDelegate.h"
+
+int main(int argc, char *argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass(TDAppDelegate.class));
+ }
+}