diff --git a/SSZipArchive.m b/SSZipArchive.m index ccd7691..cb48b91 100644 --- a/SSZipArchive.m +++ b/SSZipArchive.m @@ -11,6 +11,8 @@ #import "zlib.h" #import "zconf.h" +#include + #define CHUNK 16384 @interface SSZipArchive () @@ -116,23 +118,28 @@ // http://www.pkware.com/documents/casestudies/APPNOTE.TXT // // ...to deduce this method of detecting whether the file in the ZIP is a symbolic link. - // If it is, it is listed as a directory but has an uncompressed data size greater than - // zero (real directories have it equal to 0) and the included, uncompressed data is the - // symbolic link path. + // If it is, it is listed as a directory but has a data size greater than zero (real + // directories have it equal to 0) and the included, uncompressed data is the symbolic link path. + // + // ZIP files did not originally include support for symbolic links so the specification + // doesn't include anything in them that isn't part of a unix extension that isn't being used + // by the archivers we're testing. Most of this is figured out through trial and error and + // reading ZIP headers in hex editors. This seems to do the trick though. // - const uLong ZipDirectoryVersion = 10; const uLong ZipCompressionMethodStore = 0; BOOL fileIsSymbolicLink = NO; - if((fileInfo.version_needed == ZipDirectoryVersion) && // Is it a directory? - (fileInfo.compression_method == ZipCompressionMethodStore) && // Is it compressed? - (fileInfo.compressed_size > 0)) // Is there any data there? + if((fileInfo.compression_method == ZipCompressionMethodStore) && // Is it compressed? + (S_ISDIR(fileInfo.external_fa)) && // Is it marked as a directory + (fileInfo.compressed_size > 0)) // Is there any data? { fileIsSymbolicLink = YES; } + NSLog(@"%s, link: %@, dir: %@", filename, S_ISLNK(fileInfo.external_fa) ? @"Yes" : @"NO", S_ISDIR(fileInfo.external_fa) ? @"Yes" : @"No"); + //NSLog(@"\"%s\" is symbolic link? %@", filename, fileIsSymbolicLink ? @"Yes." : @"No."); // Check if it contains directory diff --git "a/Tests/Hello.\n" "b/Tests/Hello.\n" new file mode 100644 index 0000000..18832d3 --- /dev/null +++ "b/Tests/Hello.\n" @@ -0,0 +1 @@ +Hello. diff --git "a/Tests/Nothing to see here. Move along.\n" "b/Tests/Nothing to see here. Move along.\n" new file mode 100644 index 0000000..c7ddc72 --- /dev/null +++ "b/Tests/Nothing to see here. Move along.\n" @@ -0,0 +1 @@ +Nothing to see here. Move along. diff --git a/Tests/SSZipArchiveTests.m b/Tests/SSZipArchiveTests.m index 98f1a75..bc45c64 100644 --- a/Tests/SSZipArchiveTests.m +++ b/Tests/SSZipArchiveTests.m @@ -91,16 +91,35 @@ [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath delegate:self]; - NSString* testSymlink = [outputPath stringByAppendingPathComponent:@"SymbolicLink/GitHub.app"]; + NSString *testSymlinkFolder = [outputPath stringByAppendingPathComponent:@"SymbolicLink/GitHub.app"]; + NSString *testSymlinkFile = [outputPath stringByAppendingPathComponent:@"SymbolicLink/Icon.icns"]; - NSError* error = nil; - NSString* symlinkPath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:testSymlink error:&error]; + NSError *error = nil; + NSString *symlinkFolderPath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:testSymlinkFolder error:&error]; + bool symbolicLinkToFolderPersists = ((symlinkFolderPath != nil) && [symlinkFolderPath isEqualToString:@"/Applications/GitHub.app"]) && (error == nil); - bool symbolicLinkPersists = ((symlinkPath != nil) && [symlinkPath isEqualToString:@"/Applications/GitHub.app"]) && (error == nil); + error = nil; - STAssertTrue(symbolicLinkPersists, @"Symbolic links should persist from the original archive to the outputted files."); + NSString *symlinkFilePath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:testSymlinkFile error:&error]; + bool symbolicLinkToFilePersists = ((symlinkFilePath != nil) && [symlinkFilePath isEqualToString:@"/Applications/GitHub.app/Contents/Resources/AppIcon.icns"]) && (error == nil); + + STAssertTrue(symbolicLinkToFilePersists && symbolicLinkToFolderPersists, @"Symbolic links should persist from the original archive to the outputted files."); } +- (void)testUnzippingWithUnicodeFilenameInside { + + NSString* zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"Unicode" ofType:@"zip"]; + NSString* outputPath = [self _cachesPath:@"Unicode"]; + + [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath delegate:self]; + + bool unicodeFilenameWasExtracted = [[NSFileManager defaultManager] fileExistsAtPath:[outputPath stringByAppendingPathComponent:@"Accént.txt"]]; + + bool unicodeFolderWasExtracted = [[NSFileManager defaultManager] fileExistsAtPath:[outputPath stringByAppendingPathComponent:@"Fólder/Nothing.txt"]]; + + STAssertTrue(unicodeFilenameWasExtracted, @"Files with filenames in unicode should be extracted properly."); + STAssertTrue(unicodeFolderWasExtracted, @"Folders with names in unicode should be extracted propertly."); +} // 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. diff --git a/Tests/SymbolicLink.zip b/Tests/SymbolicLink.zip index 952827d..d2296a1 100644 Binary files a/Tests/SymbolicLink.zip and b/Tests/SymbolicLink.zip differ diff --git a/Tests/SymbolicLink/GitHub.app b/Tests/SymbolicLink/GitHub.app new file mode 120000 index 0000000..495a80a --- /dev/null +++ b/Tests/SymbolicLink/GitHub.app @@ -0,0 +1 @@ +/Applications/GitHub.app \ No newline at end of file diff --git a/Tests/SymbolicLink/Icon.icns b/Tests/SymbolicLink/Icon.icns new file mode 120000 index 0000000..26497fb --- /dev/null +++ b/Tests/SymbolicLink/Icon.icns @@ -0,0 +1 @@ +/Applications/GitHub.app/Contents/Resources/AppIcon.icns \ No newline at end of file