From 2385ac92417251be8be3d94653edd185bb47e5f8 Mon Sep 17 00:00:00 2001 From: Zacharyl Landau Date: Wed, 16 Jul 2014 11:28:25 -0700 Subject: [PATCH] Add a delegate for cancelling unzips This adds a zipArchiveShouldUnzipFileAtIndex, which is called before each call to zipArchiveWillUnzipFileAtIndex, allowing a delegate to cancel the unzip progress. --- SSZipArchive/SSZipArchive.h | 1 + SSZipArchive/SSZipArchive.m | 12 +++++++- Tests/SSZipArchiveTests.m | 60 +++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/SSZipArchive/SSZipArchive.h b/SSZipArchive/SSZipArchive.h index 9546b77..816460c 100644 --- a/SSZipArchive/SSZipArchive.h +++ b/SSZipArchive/SSZipArchive.h @@ -43,6 +43,7 @@ - (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; diff --git a/SSZipArchive/SSZipArchive.m b/SSZipArchive/SSZipArchive.m index 7bdcb1f..36ffe60 100644 --- a/SSZipArchive/SSZipArchive.m +++ b/SSZipArchive/SSZipArchive.m @@ -72,6 +72,7 @@ } BOOL success = YES; + BOOL canceled = NO; int ret = 0; unsigned char buffer[4096] = {0}; NSFileManager *fileManager = [NSFileManager defaultManager]; @@ -113,6 +114,15 @@ 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]; @@ -299,7 +309,7 @@ [delegate zipArchiveDidUnzipArchiveAtPath:path zipInfo:globalInfo unzippedPath:destination]; } // final progress event = 100% - if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) { + if (!canceled && [delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) { [delegate zipArchiveProgressEvent:fileSize total:fileSize]; } diff --git a/Tests/SSZipArchiveTests.m b/Tests/SSZipArchiveTests.m index df43385..195bb47 100644 --- a/Tests/SSZipArchiveTests.m +++ b/Tests/SSZipArchiveTests.m @@ -10,6 +10,35 @@ #import #import +@interface CancelDelegate : NSObject +@property (nonatomic, assign) int numFilesUnzipped; +@property (nonatomic, assign) int numFilesToUnzip; +@property (nonatomic, assign) BOOL didUnzipArchive; +@property (nonatomic, assign) int loaded; +@property (nonatomic, assign) int total; +@end + +@implementation CancelDelegate +- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo +{ + _numFilesUnzipped = fileIndex + 1; +} +- (BOOL)zipArchiveShouldUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo +{ + //return YES; + return _numFilesUnzipped < _numFilesToUnzip; +} +- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath +{ + _didUnzipArchive = YES; +} +- (void)zipArchiveProgressEvent:(NSInteger)loaded total:(NSInteger)total +{ + _loaded = loaded; + _total = total; +} +@end + @interface SSZipArchiveTests : XCTestCase @end @@ -251,6 +280,32 @@ XCTAssertEqual(fileAttributes[NSFilePosixPermissions], preZipAttributes[NSFilePosixPermissions], @"File permissions should be retained during compression and de-compression"); } +- (void)testUnzippingWithCancel { + NSString *zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestArchive" ofType:@"zip"]; + NSString *outputPath = [self _cachesPath:@"Cancel1"]; + + CancelDelegate *delegate = [[CancelDelegate alloc] init]; + delegate.numFilesToUnzip = 1; + + [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath delegate:delegate]; + + XCTAssertEqual(delegate.numFilesUnzipped, 1); + XCTAssertFalse(delegate.didUnzipArchive); + XCTAssertNotEqual(delegate.loaded, delegate.total); + + outputPath = [self _cachesPath:@"Cancel2"]; + + delegate = [[CancelDelegate alloc] init]; + delegate.numFilesToUnzip = 1000; + + [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath delegate:delegate]; + + XCTAssertEqual(delegate.numFilesUnzipped, 2); + XCTAssertTrue(delegate.didUnzipArchive); + XCTAssertEqual(delegate.loaded, delegate.total); + +} + // Commented out to avoid checking in several gig file into the repository. Simply add a file named // `LargeArchive.zip` to the project and uncomment out these lines to test. // @@ -273,6 +328,11 @@ NSLog(@"*** zipArchiveDidUnzipArchiveAtPath: `%@` zipInfo: unzippedPath: `%@`", path, unzippedPath); } +- (BOOL)zipArchiveShouldUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo +{ + NSLog(@"*** zipArchiveShouldUnzipFileAtIndex: `%d` totalFiles: `%d` archivePath: `%@` fileInfo:", (int)fileIndex, (int)totalFiles, archivePath); + return YES; +} - (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo { NSLog(@"*** zipArchiveWillUnzipFileAtIndex: `%d` totalFiles: `%d` archivePath: `%@` fileInfo:", (int)fileIndex, (int)totalFiles, archivePath);