diff --git a/Tests/IncorrectHeaders.zip b/Tests/IncorrectHeaders.zip new file mode 100644 index 0000000..b70f748 Binary files /dev/null and b/Tests/IncorrectHeaders.zip differ diff --git a/Tests/SSZipArchive.xcodeproj/project.pbxproj b/Tests/SSZipArchive.xcodeproj/project.pbxproj index 2696521..f398753 100644 --- a/Tests/SSZipArchive.xcodeproj/project.pbxproj +++ b/Tests/SSZipArchive.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ B215FB6B143AD576003AC546 /* zip.c in Sources */ = {isa = PBXBuildFile; fileRef = B215FB55143AD460003AC546 /* zip.c */; }; B215FB6D143AD6FF003AC546 /* TestArchive.zip in Resources */ = {isa = PBXBuildFile; fileRef = B215FB6C143AD6FF003AC546 /* TestArchive.zip */; }; B23FCC7F1558F1B70026375C /* TestPasswordArchive.zip in Resources */ = {isa = PBXBuildFile; fileRef = B23FCC7E1558F1B70026375C /* TestPasswordArchive.zip */; }; + C5AE4E64155A12760045F3ED /* IncorrectHeaders.zip in Resources */ = {isa = PBXBuildFile; fileRef = C5AE4E63155A12760045F3ED /* IncorrectHeaders.zip */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -40,6 +41,7 @@ B215FB64143AD527003AC546 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; B215FB6C143AD6FF003AC546 /* TestArchive.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = TestArchive.zip; sourceTree = ""; }; B23FCC7E1558F1B70026375C /* TestPasswordArchive.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = TestPasswordArchive.zip; sourceTree = ""; }; + C5AE4E63155A12760045F3ED /* IncorrectHeaders.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = IncorrectHeaders.zip; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -116,6 +118,7 @@ children = ( B215FB61143AD514003AC546 /* SSZipArchiveTests.m */, B215FB5F143AD514003AC546 /* SSZipArchiveTests-Info.plist */, + C5AE4E63155A12760045F3ED /* IncorrectHeaders.zip */, B215FB6C143AD6FF003AC546 /* TestArchive.zip */, B23FCC7E1558F1B70026375C /* TestPasswordArchive.zip */, ); @@ -176,6 +179,7 @@ files = ( B215FB6D143AD6FF003AC546 /* TestArchive.zip in Resources */, B23FCC7F1558F1B70026375C /* TestPasswordArchive.zip in Resources */, + C5AE4E64155A12760045F3ED /* IncorrectHeaders.zip in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Tests/SSZipArchiveTests.m b/Tests/SSZipArchiveTests.m index e8368ea..6bb542c 100644 --- a/Tests/SSZipArchiveTests.m +++ b/Tests/SSZipArchiveTests.m @@ -8,11 +8,14 @@ #import "SSZipArchive.h" #import +#import @interface SSZipArchiveTests : SenTestCase - (NSString *)_cachesPath:(NSString *)directory; +- (NSString *)_calculateMD5Digest:(NSData *)data; + @end @implementation SSZipArchiveTests @@ -66,6 +69,21 @@ STAssertTrue([fileManager fileExistsAtPath:testPath], @"LICENSE unzipped"); } +- (void)testUnzippingTruncatedFileFix { + NSString* zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"IncorrectHeaders" ofType:@"zip"]; + NSString* outputPath = [self _cachesPath:@"IncorrectHeaders"]; + + [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath delegate:self]; + + NSString* intendedReadmeTxtMD5 = @"31ac96301302eb388070c827447290b5"; + + NSString* filePath = [outputPath stringByAppendingPathComponent:@"IncorrectHeaders/Readme.txt"]; + NSData* data = [NSData dataWithContentsOfFile:filePath]; + + NSString* actualReadmeTxtMD5 = [self _calculateMD5Digest:data]; + STAssertTrue([actualReadmeTxtMD5 isEqualToString:intendedReadmeTxtMD5], @"Readme.txt MD5 digest should match original."); +} + // 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. @@ -117,4 +135,17 @@ return path; } +- (NSString *)_calculateMD5Digest:(NSData *)data +{ + unsigned char buffer[CC_MD5_DIGEST_LENGTH]; + CC_MD5([data bytes], [data length], buffer); + + NSMutableString* digest = [NSMutableString string]; + + for(int i = 0; i < CC_MD5_DIGEST_LENGTH; ++i) + [digest appendFormat:@"%02x", buffer[i]]; + + return digest; +} + @end diff --git a/minizip/unzip.c b/minizip/unzip.c index 6e7c285..5a51d8a 100755 --- a/minizip/unzip.c +++ b/minizip/unzip.c @@ -1718,10 +1718,24 @@ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) pfile_in_zip_read_info->stream.avail_out = (uInt)len; + // NOTE: + // This bit of code seems to try to set the amount of space in the output buffer based on the + // value stored in the headers stored in the .zip file. However, if those values are incorrect + // it may result in a loss of data when uncompresssing that file. The compressed data is still + // legit and will deflate without knowing the uncompressed code so this tidbit is unnecessary and + // may cause issues for some .zip files. + // + // It's removed in here to fix those issues. + // + // See: https://github.com/samsoffes/ssziparchive/issues/16 + // + + /* if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && (!(pfile_in_zip_read_info->raw))) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + */ if ((len>pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in) &&