diff --git a/Example/ObjectiveCExampleTests/SSZipArchiveTests.m b/Example/ObjectiveCExampleTests/SSZipArchiveTests.m index 1fe9316..e027f92 100644 --- a/Example/ObjectiveCExampleTests/SSZipArchiveTests.m +++ b/Example/ObjectiveCExampleTests/SSZipArchiveTests.m @@ -467,6 +467,17 @@ int twentyMB = 20 * 1024 * 1024; XCTAssert(fileSize < fileSize2, @"keepParentDirectory should produce a strictly bigger archive."); } +/// +- (void)testZippingNonDirectoryWithContentsOfDirectory { + NSString *inputPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestArchive" ofType:@"zip"]; + NSString *outputPath = [self _cachesPath:@"ZippingNonDirectory"]; + NSString *zipPath = [outputPath stringByAppendingPathComponent:@"ZippingNonDirectory.zip"]; + + BOOL success = [SSZipArchive createZipFileAtPath:zipPath withContentsOfDirectory:inputPath]; + XCTAssertTrue(!success, @"create zip success"); +} + +/// Using `keepParentDirectory:YES` - (void)testZippingAndUnzippingEmptyDirectoryWithPassword { NSString *inputPath = [self _cachesPath:@"Empty"]; @@ -477,12 +488,43 @@ int twentyMB = 20 * 1024 * 1024; BOOL success = [SSZipArchive createZipFileAtPath:zipPath withContentsOfDirectory:inputPath keepParentDirectory:YES withPassword:@"password"]; XCTAssertTrue(success, @"create zip failure"); - outputPath = [self _cachesPath:@"EmptyDirectory"]; + outputPath = [self _cachesPath:@"EmptyOutput"]; // unzipping a directory doesn't require a password id delegate = [ProgressDelegate new]; success = [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath overwrite:YES password:nil error:nil delegate:delegate]; XCTAssertTrue(success, @"unzip failure"); + + NSString *emptyPath = [outputPath stringByAppendingPathComponent:@"Empty"]; + BOOL isDirectory; + XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:emptyPath isDirectory:&isDirectory], @"Empty unzipped"); + XCTAssertTrue(isDirectory, @"Empty is a directory"); +} + +/// Using `withFilesAtPaths:` +- (void)testZippingAndUnzippingEmptyDirectoryWithFilesAtPaths { + + NSString *inputPath = [self _cachesPath:@"EmptyWithSubdirectory"]; + NSString *emptySubdirectory = [inputPath stringByAppendingPathComponent:@"Empty"]; + BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:emptySubdirectory withIntermediateDirectories:YES attributes:nil error:NULL]; + XCTAssertTrue(success, @"create folder failure"); + + // zipping files + NSString *outputPath = [self _cachesPath:@"Zipped"]; + NSString *zipPath = [outputPath stringByAppendingPathComponent:@"EmptyWithSubdirectory.zip"]; + success = [SSZipArchive createZipFileAtPath:zipPath withFilesAtPaths:@[emptySubdirectory]]; + XCTAssertTrue(success, @"create zip failure"); + + // unzipping files + outputPath = [self _cachesPath:@"EmptyWithSubdirectoryOutput"]; + id delegate = [ProgressDelegate new]; + success = [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath overwrite:YES password:nil error:nil delegate:delegate]; + XCTAssertTrue(success, @"unzip failure"); + + NSString *emptyPath = [outputPath stringByAppendingPathComponent:@"Empty"]; + BOOL isDirectory; + XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:emptyPath isDirectory:&isDirectory], @"Empty unzipped"); + XCTAssertTrue(isDirectory, @"Empty is a directory"); } - (void)testUnzippingEmptyArchive { @@ -592,14 +634,14 @@ int twentyMB = 20 * 1024 * 1024; // `LargeArchive.zip` to the project and uncomment out these lines to test. // //- (void)testUnzippingLargeFiles { -// NSString *zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"LargeArchive" ofType:@"zip"]; -// NSString *outputPath = [self _cachesPath:@"Large"]; +// NSString *zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"LargeArchive" ofType:@"zip"]; +// NSString *outputPath = [self _cachesPath:@"Large"]; // -// BOOL success = [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath]; -// XCTAssertTrue(success, @"unzip failure"); +// BOOL success = [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath]; +// XCTAssertTrue(success, @"unzip failure"); //} --(void)testShouldProvidePathOfUnzippedFileInDelegateCallback { +- (void)testShouldProvidePathOfUnzippedFileInDelegateCallback { CollectingDelegate *collector = [CollectingDelegate new]; NSString *zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestArchive" ofType:@"zip"]; NSString *outputPath = [self _cachesPath:@"Regular"]; @@ -692,7 +734,6 @@ int twentyMB = 20 * 1024 * 1024; XCTAssertTrue(iterations == noFiles, "All files should be present in the exported directory"); } -//PR #560 - (void)testSymlinkZippingWithFilesAtPaths { NSString *outputDir = [self _cachesPath:@"ZippingSymlinkWithFilesAtPaths"]; @@ -738,7 +779,6 @@ int twentyMB = 20 * 1024 * 1024; XCTAssertEqualObjects(realFilePath, realFilePathUnzip); } -//PR #560 - (void)testSymlinkZippingWithContentsOfDirectory { NSString *outputDir = [self _cachesPath:@"ZippingSymlinkWithContentsOfDirectory"]; @@ -811,7 +851,8 @@ int twentyMB = 20 * 1024 * 1024; path = [path stringByAppendingPathComponent:directory]; } - [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; + BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; + XCTAssertTrue(success, @"%@", path); return path; } diff --git a/SSZipArchive/SSZipArchive.h b/SSZipArchive/SSZipArchive.h index 7787464..30f1819 100644 --- a/SSZipArchive/SSZipArchive.h +++ b/SSZipArchive/SSZipArchive.h @@ -147,7 +147,7 @@ typedef NS_ENUM(NSInteger, SSZipArchiveErrorCode) { - (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 symlink files +/// write symlink files - (BOOL)writeSymlinkFileAtPath:(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; diff --git a/SSZipArchive/SSZipArchive.m b/SSZipArchive/SSZipArchive.m index aef89e8..96acc03 100644 --- a/SSZipArchive/SSZipArchive.m +++ b/SSZipArchive/SSZipArchive.m @@ -811,8 +811,19 @@ BOOL _fileIsSymbolicLink(const unz_file_info *fileInfo); BOOL success = [zipArchive open]; if (success) { NSUInteger total = paths.count, complete = 0; + // use a local fileManager (queue/thread compatibility) + NSFileManager *fileManager = [[NSFileManager alloc] init]; for (NSString *filePath in paths) { - success &= [zipArchive writeFile:filePath withPassword:password]; + BOOL isDir; + [fileManager fileExistsAtPath:filePath isDirectory:&isDir]; + if (!isDir) { + // file + success &= [zipArchive writeFile:filePath withPassword:password]; + } else { + // directory + // we ignore its content, to allow for archiving this path only + success &= [zipArchive writeFolderAtPath:filePath withFolderName:filePath.lastPathComponent withPassword:password]; + } if (progressHandler) { complete++; progressHandler(complete, total); @@ -861,9 +872,16 @@ BOOL _fileIsSymbolicLink(const unz_file_info *fileInfo); NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:directoryPath]; NSArray *allObjects = dirEnumerator.allObjects; NSUInteger total = allObjects.count, complete = 0; - if (keepParentDirectory && !total) { - allObjects = @[@""]; - total = 1; + if (!total) { + // let's check if it's an actual directory. + BOOL isDir; + [fileManager fileExistsAtPath:directoryPath isDirectory:&isDir]; + if (!isDir) { + success = NO; + } else if (keepParentDirectory) { + allObjects = @[@""]; + total = 1; + } } for (__strong NSString *fileName in allObjects) { NSString *fullFilePath = [directoryPath stringByAppendingPathComponent:fileName];