Merge remote-tracking branch 'ZipArchive/master'

This commit is contained in:
David Evans
2017-01-23 19:09:20 +00:00
9 changed files with 173 additions and 92 deletions
@@ -265,7 +265,7 @@
8DFE19E21BDA9FF300709011 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0710;
LastUpgradeCheck = 0820;
TargetAttributes = {
8DFE19E91BDA9FF300709011 = {
CreatedOnToolsVersion = 7.1;
@@ -488,8 +488,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -532,8 +534,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -173,7 +173,22 @@
XCTAssertTrue([fileManager fileExistsAtPath:testPath], @"LICENSE unzipped");
}
- (void)testPasswordCheck {
- (void)testValidatePassword {
NSString *zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestPasswordArchive" ofType:@"zip"];
NSError *error = nil;
BOOL fileHasValidPassword = [SSZipArchive isPasswordValidForArchiveAtPath:zipPath password:@"passw0rd" error:&error];
XCTAssertTrue(fileHasValidPassword,@"Valid password reports true.");
BOOL fileHasInvalidValidPassword = [SSZipArchive isPasswordValidForArchiveAtPath:zipPath password:@"passw0rd123" error:&error];
XCTAssertFalse(fileHasInvalidValidPassword,@"Invalid password reports false.");
}
- (void)testFilePasswordCheck {
NSString *zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestArchive" ofType:@"zip"];
BOOL protected = [SSZipArchive isFilePasswordProtectedAtPath:zipPath];
+3 -3
View File
@@ -1,5 +1,5 @@
PODS:
- SSZipArchive (1.6.2)
- SSZipArchive (1.7)
DEPENDENCIES:
- SSZipArchive (from `..`)
@@ -9,8 +9,8 @@ EXTERNAL SOURCES:
:path: ".."
SPEC CHECKSUMS:
SSZipArchive: 428eb1ac8d37dd133404d30f422b23958c1f9acc
SSZipArchive: 63f8e11cfcc33e03e4cd666b4359ea8bd6facd0c
PODFILE CHECKSUM: ae5fb993e5dc339b15e10067d1e60549fa585f32
COCOAPODS: 1.1.0.rc.2
COCOAPODS: 1.1.1
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'SSZipArchive'
s.version = '1.6.2'
s.version = '1.7'
s.summary = 'Utility class for zipping and unzipping files on iOS, tvOS, watchOS, and Mac.'
s.description = 'SSZipArchive is a simple utility class for zipping and unzipping files on iOS, tvOS, watchOS, and Mac.'
s.homepage = 'https://github.com/ZipArchive/ZipArchive'
+3 -3
View File
@@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
// 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;
@@ -39,14 +40,14 @@ NS_ASSUME_NONNULL_BEGIN
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError *error))completionHandler;
completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * __nullable error))completionHandler;
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
overwrite:(BOOL)overwrite
password:(nullable NSString *)password
progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError *error))completionHandler;
completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * __nullable error))completionHandler;
// Zip
@@ -60,7 +61,6 @@ NS_ASSUME_NONNULL_BEGIN
+ (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;
- (instancetype)initWithPath:(NSString *)path;
@property (NS_NONATOMIC_IOSONLY, readonly) BOOL open;
+135 -78
View File
@@ -59,6 +59,75 @@
return NO;
}
+ (BOOL)isPasswordValidForArchiveAtPath:(NSString *)path password:(NSString *)pw error:(NSError **)error {
if (error) {
*error = nil;
}
zipFile zip = unzOpen((const char*)[path UTF8String]);
if (zip == NULL) {
if (error) {
*error = [NSError errorWithDomain:@"SSZipArchiveErrorDomain"
code:-1
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:NSASCIIStringEncoding]);
}
if (ret != UNZ_OK) {
if (ret != UNZ_BADPASSWORD) {
if (error) {
*error = [NSError errorWithDomain:@"SSZipArchiveErrorDomain"
code:-2
userInfo:@{NSLocalizedDescriptionKey: @"failed to open first file in zip file"}];
}
}
return NO;
}
unz_file_info fileInfo = {0};
ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
if (ret != UNZ_OK) {
if (error) {
*error = [NSError errorWithDomain:@"SSZipArchiveErrorDomain"
code:-3
userInfo:@{NSLocalizedDescriptionKey: @"failed to retrieve info for file"}];
}
return NO;
} else if((fileInfo.flag & 1) == 1) {
unsigned char buffer[10] = {0};
int readBytes = unzReadCurrentFile(zip, buffer, (unsigned)MIN(10UL,fileInfo.uncompressed_size));
if (readBytes < 0) {
// Let's assume the invalid password caused this error
if (readBytes != Z_DATA_ERROR) {
if (error) {
*error = [NSError errorWithDomain:@"SSZipArchiveErrorDomain"
code:-4
userInfo:@{NSLocalizedDescriptionKey: @"failed to read contents of file entry"}];
}
}
return NO;
}
return YES;
}
unzCloseCurrentFile(zip);
ret = unzGoToNextFile(zip);
} while (ret==UNZ_OK && UNZ_OK!=UNZ_END_OF_LIST_OF_FILE);
}
// No password required
return YES;
}
#pragma mark - Unzipping
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination
@@ -86,7 +155,7 @@
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 *error))completionHandler
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];
}
@@ -94,7 +163,7 @@
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError *error))completionHandler
completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * __nullable error))completionHandler
{
return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:YES password:nil error:nil delegate:nil progressHandler:progressHandler completionHandler:completionHandler];
}
@@ -118,7 +187,7 @@
error:(NSError **)error
delegate:(id<SSZipArchiveDelegate>)delegate
progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError *error))completionHandler
completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * __nullable error))completionHandler
{
// Begin opening
zipFile zip = unzOpen((const char*)[path UTF8String]);
@@ -304,77 +373,80 @@
}
if (!fileIsSymbolicLink) {
FILE *fp = fopen((const char*)[fullPath UTF8String], "wb");
while (fp) {
int readBytes = unzReadCurrentFile(zip, buffer, 4096);
if (readBytes > 0) {
fwrite(buffer, readBytes, 1, fp );
} else {
break;
}
}
if (fp) {
if ([[[fullPath pathExtension] lowercaseString] isEqualToString:@"zip"]) {
NSLog(@"Unzipping nested .zip file: %@", [fullPath lastPathComponent]);
if ([self unzipFileAtPath:fullPath toDestination:[fullPath stringByDeletingLastPathComponent] overwrite:overwrite password:password error:nil delegate:nil ]) {
[[NSFileManager defaultManager] removeItemAtPath:fullPath error:nil];
// ensure we are not creating stale file entries
int readBytes = unzReadCurrentFile(zip, buffer, 4096);
if (readBytes >= 0) {
FILE *fp = fopen((const char*)[fullPath UTF8String], "wb");
while (fp) {
if (readBytes > 0) {
fwrite(buffer, readBytes, 1, fp );
} else {
break;
}
readBytes = unzReadCurrentFile(zip, buffer, 4096);
}
fclose(fp);
if (preserveAttributes) {
// Set the original datetime property
if (fileInfo.dosDate != 0) {
NSDate *orgDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate];
NSDictionary *attr = @{NSFileModificationDate: orgDate};
if (attr) {
if ([fileManager setAttributes:attr ofItemAtPath:fullPath error:nil] == NO) {
// Can't set attributes
NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting modification date");
if (fp) {
if ([[[fullPath pathExtension] lowercaseString] isEqualToString:@"zip"]) {
NSLog(@"Unzipping nested .zip file: %@", [fullPath lastPathComponent]);
if ([self unzipFileAtPath:fullPath toDestination:[fullPath stringByDeletingLastPathComponent] overwrite:overwrite password:password error:nil delegate:nil ]) {
[[NSFileManager defaultManager] removeItemAtPath:fullPath error:nil];
}
}
fclose(fp);
if (preserveAttributes) {
// Set the original datetime property
if (fileInfo.dosDate != 0) {
NSDate *orgDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate];
NSDictionary *attr = @{NSFileModificationDate: orgDate};
if (attr) {
if ([fileManager setAttributes:attr ofItemAtPath:fullPath error:nil] == NO) {
// Can't set attributes
NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting modification date");
}
}
}
}
// Set the original permissions on the file
uLong permissions = fileInfo.external_fa >> 16;
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 original permissions on the file
uLong permissions = fileInfo.external_fa >> 16;
if (permissions != 0) {
// Store it into a NSNumber
NSNumber *permissionsValue = @(permissions);
// Set the value in the attributes dict
attrs[NSFilePosixPermissions] = permissionsValue;
// Retrieve any existing attributes
NSMutableDictionary *attrs = [[NSMutableDictionary alloc] initWithDictionary:[fileManager attributesOfItemAtPath:fullPath error:nil]];
// Update attributes
if ([fileManager setAttributes:attrs ofItemAtPath:fullPath error:nil] == NO) {
// Unable to set the permissions attribute
NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting permissions");
}
// Set the value in the attributes dict
attrs[NSFilePosixPermissions] = permissionsValue;
// Update attributes
if ([fileManager setAttributes:attrs ofItemAtPath:fullPath error:nil] == NO) {
// Unable to set the permissions attribute
NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting permissions");
}
#if !__has_feature(objc_arc)
[attrs release];
[attrs release];
#endif
}
}
}
}
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
{
// 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;
}
}
}
}
@@ -519,15 +591,6 @@
+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory withPassword:(nullable NSString *)password{
return [self createZipFileAtPath:password
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 {
BOOL success = NO;
NSFileManager *fileManager = nil;
@@ -537,10 +600,8 @@
// use a local filemanager (queue/thread compatibility)
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) {
while ((fileName = [dirEnumerator nextObject])) {
BOOL isDir;
NSString *fullFilePath = [directoryPath stringByAppendingPathComponent:fileName];
[fileManager fileExistsAtPath:fullFilePath isDirectory:&isDir];
@@ -562,10 +623,6 @@
[zipArchive writeFileAtPath:tempFilePath withFileName:tempFileFilename withPassword:password];
}
}
complete++;
if (progressHandler) {
progressHandler(complete, total);
}
}
success = [zipArchive close];
}
@@ -828,4 +885,4 @@
return date;
}
@end
@end
+8 -4
View File
@@ -1190,7 +1190,8 @@ extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, in
return UNZ_INTERNALERROR;
#ifdef HAVE_AES
if (s->cur_file_info.compression_method == AES_METHOD) {
unsigned char passverify[AES_PWVERIFYSIZE];
unsigned char passverify_archive[AES_PWVERIFYSIZE];
unsigned char passverify_password[AES_PWVERIFYSIZE];
unsigned char saltvalue[AES_MAXSALTLENGTH];
uInt saltlength;
@@ -1202,11 +1203,14 @@ extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, in
if (ZREAD64(s->z_filefunc, s->filestream, saltvalue, saltlength) != saltlength)
return UNZ_INTERNALERROR;
if (ZREAD64(s->z_filefunc, s->filestream, passverify, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE)
if (ZREAD64(s->z_filefunc, s->filestream, passverify_archive, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE)
return UNZ_INTERNALERROR;
fcrypt_init((int)s->cur_file_info_internal.aes_encryption_mode, (unsigned char *)password, (unsigned int)strlen(password), saltvalue,
passverify, &s->pfile_in_zip_read->aes_ctx);
fcrypt_init(s->cur_file_info_internal.aes_encryption_mode, password, strlen(password), saltvalue,
passverify_password, &s->pfile_in_zip_read->aes_ctx);
if (memcmp(passverify_archive, passverify_password, AES_PWVERIFYSIZE) != 0)
return UNZ_BADPASSWORD;
pfile_in_zip_read_info->rest_read_compressed -= saltlength + AES_PWVERIFYSIZE;
pfile_in_zip_read_info->rest_read_compressed -= AES_AUTHCODESIZE;
+1
View File
@@ -57,6 +57,7 @@ typedef voidp unzFile;
#define UNZ_BADZIPFILE (-103)
#define UNZ_INTERNALERROR (-104)
#define UNZ_CRCERROR (-105)
#define UNZ_BADPASSWORD (-106)
/***************************************************************************/