Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f5a7b30dc | ||
|
|
bdbab4d3b3 | ||
|
|
fdb1726299 | ||
|
|
709006228c | ||
|
|
db0c62c481 | ||
|
|
d9ea638369 | ||
|
|
f18a98e551 | ||
|
|
557e869222 | ||
|
|
26630b36af | ||
|
|
581adbb98c | ||
|
|
d646bf93a2 | ||
|
|
b7598bc95f | ||
|
|
236fcb7d65 | ||
|
|
a46e35e2b8 | ||
|
|
e171229257 | ||
|
|
3a87f3ccfa | ||
|
|
df4ffca706 | ||
|
|
64c542e090 | ||
|
|
f900d38036 | ||
|
|
9070c825f8 | ||
|
|
bfc0904d14 | ||
|
|
45009d71e7 | ||
|
|
b27c74b04c | ||
|
|
b6f7f605fe | ||
|
|
f6eb58cc51 | ||
|
|
5651fb2c1b | ||
|
|
cd0be3772a | ||
|
|
a7c7978c42 | ||
|
|
f7e9630fd0 | ||
|
|
c4b61b7092 | ||
|
|
23426fd0de | ||
|
|
f78aa2c1be | ||
|
|
13edbb940e | ||
|
|
c05ee25f7f | ||
|
|
2ad10f1713 | ||
|
|
f487007ff2 | ||
|
|
dbad12bffb | ||
|
|
0a7c36ffb7 | ||
|
|
cd31818aa4 |
@@ -1,5 +1,21 @@
|
||||
# SSZipArchive Changelog
|
||||
|
||||
### Version 0.2.1
|
||||
|
||||
[Released May 9, 2012](https://github.com/samsoffes/sskeychain/tree/0.2.1)
|
||||
|
||||
* Support for symbolic links — [@jparishy](http://github.com/jparishy)
|
||||
* Fix several warnings
|
||||
|
||||
### Version 0.2.0
|
||||
|
||||
[Released May 7, 2012](https://github.com/samsoffes/sskeychain/tree/0.2.0)
|
||||
|
||||
* Add unzipping delegate — [@uppfinnarn](http://github.com/uppfinnarn)
|
||||
* Fix unzipping with passwords
|
||||
* Fix modified at dates — [@brantsears](http://github.com/brantsears)
|
||||
* Fix truncated files. Ignore the zip headers and unzip until there is no more file. — [@jparishy](http://github.com/jparishy)
|
||||
|
||||
### Version 0.1.2
|
||||
|
||||
[Released December 26, 2011](https://github.com/samsoffes/sskeychain/tree/0.1.2)
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2010-2011 Sam Soffes
|
||||
Copyright (c) 2010-2012 Sam Soffes
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SSZipArchive
|
||||
|
||||
SSZipArchive is a simple utility class for unzipping files originally based on [ZipArchive](http://code.google.com/p/ziparchive) by aish. Features:
|
||||
SSZipArchive is a simple utility class for zipping and unzipping files. Features:
|
||||
|
||||
* Unzipping zip files
|
||||
* Unzipping password protected zip files
|
||||
@@ -8,12 +8,15 @@ SSZipArchive is a simple utility class for unzipping files originally based on [
|
||||
* Appending to zip files
|
||||
* Zipping files
|
||||
* Zipping NSData with a filename
|
||||
* Works in ARC and non-ARC projects
|
||||
|
||||
## Adding to your project
|
||||
|
||||
1. Add `SSZipArchive.h`, `SSZipArchive.m`, and `minizip` to your project.
|
||||
2. Add the `libz` library to your target
|
||||
|
||||
You don't need to do anything regarding ARC. SSZipArchive will detect if you're not using ARC and add the required memory management code.
|
||||
|
||||
## Usage
|
||||
|
||||
``` objective-c
|
||||
@@ -37,4 +40,4 @@ SSZipArchive is licensed under the [MIT license](https://github.com/samsoffes/ss
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks [aish](http://code.google.com/p/ziparchive) for creating [ZipArchive](http://code.google.com/p/ziparchive), Johnnie Walker ([@randomsequence](https://github.com/randomsequence)) for implementing creation support, and John Engelhart ([@johnezang](https://github.com/johnezang)) for his help along the way.
|
||||
Thanks [aish](http://code.google.com/p/ziparchive) for creating [ZipArchive](http://code.google.com/p/ziparchive) which SSZipArchive is based on, Johnnie Walker ([@randomsequence](https://github.com/randomsequence)) for implementing creation support, and John Engelhart ([@johnezang](https://github.com/johnezang)) for all his amazing help along the way.
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "minizip/zip.h"
|
||||
#include "minizip/unzip.h"
|
||||
|
||||
@protocol SSZipArchiveDelegate;
|
||||
|
||||
@interface SSZipArchive : NSObject
|
||||
|
||||
@@ -15,6 +17,9 @@
|
||||
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination;
|
||||
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error;
|
||||
|
||||
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(id<SSZipArchiveDelegate>)delegate;
|
||||
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error delegate:(id<SSZipArchiveDelegate>)delegate;
|
||||
|
||||
// Zip
|
||||
+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)filenames;
|
||||
|
||||
@@ -25,3 +30,16 @@
|
||||
- (BOOL)close;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@protocol SSZipArchiveDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
- (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo;
|
||||
- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath;
|
||||
|
||||
- (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;
|
||||
|
||||
@end
|
||||
|
||||
282
SSZipArchive.m
282
SSZipArchive.m
@@ -8,14 +8,15 @@
|
||||
|
||||
#import "SSZipArchive.h"
|
||||
#include "minizip/zip.h"
|
||||
#include "minizip/unzip.h"
|
||||
#import "zlib.h"
|
||||
#import "zconf.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define CHUNK 16384
|
||||
|
||||
@interface SSZipArchive ()
|
||||
+ (NSDate *)_dateFor1980;
|
||||
+ (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime;
|
||||
@end
|
||||
|
||||
|
||||
@@ -29,11 +30,21 @@
|
||||
#pragma mark - Unzipping
|
||||
|
||||
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination {
|
||||
return [self unzipFileAtPath:path toDestination:destination overwrite:YES password:nil error:nil];
|
||||
return [self unzipFileAtPath:path toDestination:destination delegate:nil];
|
||||
}
|
||||
|
||||
|
||||
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error {
|
||||
return [self unzipFileAtPath:path toDestination:destination overwrite:overwrite password:password error:error delegate:nil];
|
||||
}
|
||||
|
||||
|
||||
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(id<SSZipArchiveDelegate>)delegate {
|
||||
return [self unzipFileAtPath:path toDestination:destination overwrite:YES password:nil error:nil delegate:delegate];
|
||||
}
|
||||
|
||||
|
||||
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error delegate:(id<SSZipArchiveDelegate>)delegate {
|
||||
// Begin opening
|
||||
zipFile zip = unzOpen((const char*)[path UTF8String]);
|
||||
if (zip == NULL) {
|
||||
@@ -57,11 +68,17 @@
|
||||
}
|
||||
|
||||
BOOL success = YES;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
unsigned char buffer[4096] = {0};
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSDate *nineteenEighty = [self _dateFor1980];
|
||||
NSMutableSet *directoriesModificationDates = [[NSMutableSet alloc] init];
|
||||
|
||||
// Message delegate
|
||||
if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipArchiveAtPath:zipInfo:)]) {
|
||||
[delegate zipArchiveWillUnzipArchiveAtPath:path zipInfo:globalInfo];
|
||||
}
|
||||
|
||||
NSInteger currentFileNumber = 0;
|
||||
do {
|
||||
if ([password length] == 0) {
|
||||
ret = unzOpenCurrentFile(zip);
|
||||
@@ -85,10 +102,42 @@
|
||||
break;
|
||||
}
|
||||
|
||||
// Message delegate
|
||||
if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {
|
||||
[delegate zipArchiveWillUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry
|
||||
archivePath:path fileInfo:fileInfo];
|
||||
}
|
||||
|
||||
char *filename = (char *)malloc(fileInfo.size_filename + 1);
|
||||
unzGetCurrentFileInfo(zip, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
|
||||
filename[fileInfo.size_filename] = '\0';
|
||||
|
||||
|
||||
//
|
||||
// NOTE
|
||||
// I used the ZIP spec from here:
|
||||
// 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 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 ZipCompressionMethodStore = 0;
|
||||
|
||||
BOOL fileIsSymbolicLink = NO;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Check if it contains directory
|
||||
NSString *strPath = [NSString stringWithCString:filename encoding:NSUTF8StringEncoding];
|
||||
BOOL isDirectory = NO;
|
||||
@@ -102,56 +151,124 @@
|
||||
strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
|
||||
}
|
||||
|
||||
NSString* fullPath = [destination stringByAppendingPathComponent:strPath];
|
||||
NSString *fullPath = [destination stringByAppendingPathComponent:strPath];
|
||||
NSError *err = nil;
|
||||
NSDate *modDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate];
|
||||
NSDictionary *directoryAttr = [NSDictionary dictionaryWithObjectsAndKeys:modDate, NSFileCreationDate, modDate, NSFileModificationDate, nil];
|
||||
|
||||
if (isDirectory) {
|
||||
[fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
[fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:directoryAttr error:&err];
|
||||
} else {
|
||||
[fileManager createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
[fileManager createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:directoryAttr error:&err];
|
||||
}
|
||||
|
||||
if ([fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite) {
|
||||
if (nil != err) {
|
||||
NSLog(@"[SSZipArchive] Error: %@", err.localizedDescription);
|
||||
}
|
||||
|
||||
if(!fileIsSymbolicLink)
|
||||
[directoriesModificationDates addObject: [NSDictionary dictionaryWithObjectsAndKeys:fullPath, @"path", modDate, @"modDate", nil]];
|
||||
|
||||
if ([fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite) {
|
||||
unzCloseCurrentFile(zip);
|
||||
ret = unzGoToNextFile(zip);
|
||||
continue;
|
||||
}
|
||||
|
||||
FILE *fp = fopen((const char*)[fullPath UTF8String], "wb");
|
||||
while (fp) {
|
||||
int readBytes = unzReadCurrentFile(zip, buffer, 4096);
|
||||
|
||||
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) {
|
||||
fclose(fp);
|
||||
|
||||
// Set the original datetime property
|
||||
if (fileInfo.dosDate != 0) {
|
||||
NSDate *orgDate = [[NSDate alloc] initWithTimeInterval:(NSTimeInterval)fileInfo.dosDate sinceDate:nineteenEighty];
|
||||
NSDictionary *attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate];
|
||||
|
||||
if (attr) {
|
||||
if ([fileManager setAttributes:attr ofItemAtPath:fullPath error:nil] == NO) {
|
||||
// Can't set attributes
|
||||
NSLog(@"Failed to set attributes");
|
||||
}
|
||||
}
|
||||
[orgDate release];
|
||||
}
|
||||
}
|
||||
if (readBytes > 0) {
|
||||
fwrite(buffer, readBytes, 1, fp );
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
|
||||
// Set the original datetime property
|
||||
if (fileInfo.dosDate != 0) {
|
||||
NSDate *orgDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate];
|
||||
NSDictionary *attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate];
|
||||
|
||||
if (attr) {
|
||||
if ([fileManager setAttributes:attr ofItemAtPath:fullPath error:nil] == NO) {
|
||||
// Can't set attributes
|
||||
NSLog(@"[SSZipArchive] Failed to set attributes");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the path for the symbolic link
|
||||
|
||||
NSURL* symlinkURL = [NSURL fileURLWithPath:fullPath];
|
||||
NSMutableString* destinationPath = [NSMutableString string];
|
||||
|
||||
int bytesRead = 0;
|
||||
while((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0)
|
||||
{
|
||||
buffer[bytesRead] = 0;
|
||||
[destinationPath appendString:[NSString stringWithUTF8String:(const char*)buffer]];
|
||||
}
|
||||
|
||||
//NSLog(@"Symlinking to: %@", destinationPath);
|
||||
|
||||
NSURL* destinationURL = [NSURL fileURLWithPath:destinationPath];
|
||||
|
||||
// Create the symbolic link
|
||||
NSError* symlinkError = nil;
|
||||
[fileManager createSymbolicLinkAtURL:symlinkURL withDestinationURL:destinationURL error:&symlinkError];
|
||||
|
||||
if(symlinkError != nil)
|
||||
{
|
||||
NSLog(@"Failed to create symbolic link at \"%@\" to \"%@\". Error: %@", symlinkURL.absoluteString, destinationURL.absoluteString, symlinkError.localizedDescription);
|
||||
}
|
||||
}
|
||||
|
||||
unzCloseCurrentFile( zip );
|
||||
ret = unzGoToNextFile( zip );
|
||||
|
||||
// Message delegate
|
||||
if ([delegate respondsToSelector:@selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {
|
||||
[delegate zipArchiveDidUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry
|
||||
archivePath:path fileInfo:fileInfo];
|
||||
}
|
||||
|
||||
currentFileNumber++;
|
||||
} while(ret == UNZ_OK && UNZ_OK != UNZ_END_OF_LIST_OF_FILE);
|
||||
|
||||
// Close
|
||||
unzClose(zip);
|
||||
|
||||
// The process of decompressing the .zip archive causes the modification times on the folders
|
||||
// to be set to the present time. So, when we are done, they need to be explicitly set.
|
||||
// set the modification date on all of the directories.
|
||||
NSError * err = nil;
|
||||
for (NSDictionary * d in directoriesModificationDates) {
|
||||
if (![[NSFileManager defaultManager] setAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[d objectForKey:@"modDate"], NSFileModificationDate, nil] ofItemAtPath:[d objectForKey:@"path"] error:&err]) {
|
||||
NSLog(@"[SSZipArchive] Set attributes failed for directory: %@.", [d objectForKey:@"path"]);
|
||||
}
|
||||
if (err) {
|
||||
NSLog(@"[SSZipArchive] Error setting directory file modification date attribute: %@",err.localizedDescription);
|
||||
}
|
||||
}
|
||||
|
||||
#if !__has_feature(objc_arc)
|
||||
[directoriesModificationDates release];
|
||||
#endif
|
||||
|
||||
// Message delegate
|
||||
if (success && [delegate respondsToSelector:@selector(zipArchiveDidUnzipArchiveAtPath:zipInfo:unzippedPath:)]) {
|
||||
[delegate zipArchiveDidUnzipArchiveAtPath:path zipInfo:globalInfo unzippedPath:destination];
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -167,7 +284,10 @@
|
||||
}
|
||||
success = [zipArchive close];
|
||||
}
|
||||
|
||||
#if !__has_feature(objc_arc)
|
||||
[zipArchive release];
|
||||
#endif
|
||||
|
||||
return success;
|
||||
}
|
||||
@@ -181,10 +301,12 @@
|
||||
}
|
||||
|
||||
|
||||
#if !__has_feature(objc_arc)
|
||||
- (void)dealloc {
|
||||
[_path release];
|
||||
[_path release];
|
||||
[super dealloc];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
- (BOOL)open {
|
||||
@@ -194,6 +316,19 @@
|
||||
}
|
||||
|
||||
|
||||
- (void)zipInfo:(zip_fileinfo*)zipInfo setDate:(NSDate*)date {
|
||||
NSCalendar *currentCalendar = [NSCalendar currentCalendar];
|
||||
uint flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
|
||||
NSDateComponents *components = [currentCalendar components:flags fromDate:date];
|
||||
zipInfo->tmz_date.tm_sec = (unsigned int)components.second;
|
||||
zipInfo->tmz_date.tm_min = (unsigned int)components.minute;
|
||||
zipInfo->tmz_date.tm_hour = (unsigned int)components.hour;
|
||||
zipInfo->tmz_date.tm_mday = (unsigned int)components.day;
|
||||
zipInfo->tmz_date.tm_mon = (unsigned int)components.month - 1;
|
||||
zipInfo->tmz_date.tm_year = (unsigned int)components.year;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)writeFile:(NSString *)path {
|
||||
NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened");
|
||||
|
||||
@@ -219,31 +354,26 @@
|
||||
|
||||
|
||||
- (BOOL)writeData:(NSData *)data filename:(NSString *)filename {
|
||||
NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened");
|
||||
NSAssert((data != NULL), @"Nil data");
|
||||
if (!_zip) {
|
||||
return NO;
|
||||
}
|
||||
if (!data) {
|
||||
return NO;
|
||||
}
|
||||
zip_fileinfo zipInfo = {{0,0,0,0,0,0},0,0,0};
|
||||
[self zipInfo:&zipInfo setDate:[NSDate date]];
|
||||
|
||||
zipOpenNewFileInZip(_zip, [filename UTF8String], NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
|
||||
zipOpenNewFileInZip(_zip, [filename UTF8String], &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
|
||||
|
||||
void *buffer = malloc(CHUNK);
|
||||
unsigned int offset = 0;
|
||||
NSUInteger length = [data length];
|
||||
unsigned int chunk_length = 0;
|
||||
|
||||
while (offset < length) {
|
||||
chunk_length = MIN(CHUNK, ((unsigned int) length)-offset);
|
||||
[data getBytes:&buffer range:NSMakeRange(offset, chunk_length)];
|
||||
zipWriteInFileInZip(_zip, buffer, chunk_length);
|
||||
offset += chunk_length;
|
||||
}
|
||||
zipWriteInFileInZip(_zip, data.bytes, (unsigned int)data.length);
|
||||
|
||||
zipCloseFileInZip(_zip);
|
||||
free(buffer);
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)close {
|
||||
NSAssert((_zip != NULL), @"Attempting to close an archive which was never opened");
|
||||
NSAssert((_zip != NULL), @"[SSZipArchive] Attempting to close an archive which was never opened");
|
||||
zipClose(_zip, NULL);
|
||||
return YES;
|
||||
}
|
||||
@@ -251,16 +381,40 @@
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
+ (NSDate *)_dateFor1980 {
|
||||
NSDateComponents *comps = [[NSDateComponents alloc] init];
|
||||
[comps setDay:1];
|
||||
[comps setMonth:1];
|
||||
[comps setYear:1980];
|
||||
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
|
||||
NSDate *date = [gregorian dateFromComponents:comps];
|
||||
// Format from http://newsgroups.derkeiler.com/Archive/Comp/comp.os.msdos.programmer/2009-04/msg00060.html
|
||||
// Two consecutive words, or a longword, YYYYYYYMMMMDDDDD hhhhhmmmmmmsssss
|
||||
// YYYYYYY is years from 1980 = 0
|
||||
// sssss is (seconds/2).
|
||||
//
|
||||
// 3658 = 0011 0110 0101 1000 = 0011011 0010 11000 = 27 2 24 = 2007-02-24
|
||||
// 7423 = 0111 0100 0010 0011 - 01110 100001 00011 = 14 33 2 = 14:33:06
|
||||
+ (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime {
|
||||
static const UInt32 kYearMask = 0xFE000000;
|
||||
static const UInt32 kMonthMask = 0x1E00000;
|
||||
static const UInt32 kDayMask = 0x1F0000;
|
||||
static const UInt32 kHourMask = 0xF800;
|
||||
static const UInt32 kMinuteMask = 0x7E0;
|
||||
static const UInt32 kSecondMask = 0x1F;
|
||||
|
||||
[comps release];
|
||||
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
|
||||
NSDateComponents *components = [[NSDateComponents alloc] init];
|
||||
|
||||
NSAssert(0xFFFFFFFF == (kYearMask | kMonthMask | kDayMask | kHourMask | kMinuteMask | kSecondMask), @"[SSZipArchive] MSDOS date masks don't add up");
|
||||
|
||||
[components setYear:1980 + ((msdosDateTime & kYearMask) >> 25)];
|
||||
[components setMonth:(msdosDateTime & kMonthMask) >> 21];
|
||||
[components setDay:(msdosDateTime & kDayMask) >> 16];
|
||||
[components setHour:(msdosDateTime & kHourMask) >> 11];
|
||||
[components setMinute:(msdosDateTime & kMinuteMask) >> 5];
|
||||
[components setSecond:(msdosDateTime & kSecondMask) * 2];
|
||||
|
||||
NSDate *date = [NSDate dateWithTimeInterval:0 sinceDate:[gregorian dateFromComponents:components]];
|
||||
|
||||
#if !__has_feature(objc_arc)
|
||||
[gregorian release];
|
||||
[components release];
|
||||
#endif
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
|
||||
18
SSZipArchive.podspec
Normal file
18
SSZipArchive.podspec
Normal file
@@ -0,0 +1,18 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'SSZipArchive'
|
||||
s.version = '0.2.2'
|
||||
s.summary = 'Utility class for zipping and unzipping files on iOS and Mac.'
|
||||
s.homepage = 'https://github.com/samsoffes/ssziparchive'
|
||||
s.author = { 'Sam Soffes' => 'sam@samsoff.es' }
|
||||
s.source = { :git => 'https://github.com/samsoffes/ssziparchive.git', :tag => '0.2.2' }
|
||||
s.description = 'SSZipArchive is a simple utility class for zipping and unzipping files on iOS and Mac.'
|
||||
s.source_files = 'SSZipArchive.*', 'minizip/*.{h,c}'
|
||||
s.library = 'z'
|
||||
s.preserve_paths = ['Tests', '.gitignore']
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
||||
# Maintain the dir structure for headers
|
||||
def s.copy_header_mapping(from)
|
||||
from
|
||||
end
|
||||
end
|
||||
BIN
Tests/IncorrectHeaders.zip
Normal file
BIN
Tests/IncorrectHeaders.zip
Normal file
Binary file not shown.
@@ -17,6 +17,10 @@
|
||||
B215FB6A143AD576003AC546 /* unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = B215FB53143AD460003AC546 /* unzip.c */; };
|
||||
B215FB6B143AD576003AC546 /* zip.c in Sources */ = {isa = PBXBuildFile; fileRef = B215FB55143AD460003AC546 /* zip.c */; };
|
||||
B215FB6D143AD6FF003AC546 /* TestArchive.zip in Resources */ = {isa = PBXBuildFile; fileRef = B215FB6C143AD6FF003AC546 /* TestArchive.zip */; };
|
||||
B2283D5D155AD80F00F9395A /* Unicode.zip in Resources */ = {isa = PBXBuildFile; fileRef = B2283D5C155AD80F00F9395A /* Unicode.zip */; };
|
||||
B23FCC7F1558F1B70026375C /* TestPasswordArchive.zip in Resources */ = {isa = PBXBuildFile; fileRef = B23FCC7E1558F1B70026375C /* TestPasswordArchive.zip */; };
|
||||
C5AE4E64155A12760045F3ED /* IncorrectHeaders.zip in Resources */ = {isa = PBXBuildFile; fileRef = C5AE4E63155A12760045F3ED /* IncorrectHeaders.zip */; };
|
||||
C5AE4E6D155A8B010045F3ED /* SymbolicLink.zip in Resources */ = {isa = PBXBuildFile; fileRef = C5AE4E6C155A8B010045F3ED /* SymbolicLink.zip */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@@ -35,10 +39,13 @@
|
||||
B215FB57143AD460003AC546 /* SSZipArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SSZipArchive.h; path = ../SSZipArchive.h; sourceTree = "<group>"; };
|
||||
B215FB58143AD460003AC546 /* SSZipArchive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SSZipArchive.m; path = ../SSZipArchive.m; sourceTree = "<group>"; };
|
||||
B215FB5F143AD514003AC546 /* SSZipArchiveTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SSZipArchiveTests-Info.plist"; sourceTree = "<group>"; };
|
||||
B215FB60143AD514003AC546 /* SSZipArchiveTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSZipArchiveTests.h; sourceTree = "<group>"; };
|
||||
B215FB61143AD514003AC546 /* SSZipArchiveTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSZipArchiveTests.m; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
B2283D5C155AD80F00F9395A /* Unicode.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = Unicode.zip; sourceTree = "<group>"; };
|
||||
B23FCC7E1558F1B70026375C /* TestPasswordArchive.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = TestPasswordArchive.zip; sourceTree = "<group>"; };
|
||||
C5AE4E63155A12760045F3ED /* IncorrectHeaders.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = IncorrectHeaders.zip; sourceTree = "<group>"; };
|
||||
C5AE4E6C155A8B010045F3ED /* SymbolicLink.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = SymbolicLink.zip; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -113,10 +120,13 @@
|
||||
B215FB5E143AD505003AC546 /* SSZipArchiveTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B215FB60143AD514003AC546 /* SSZipArchiveTests.h */,
|
||||
B2283D5C155AD80F00F9395A /* Unicode.zip */,
|
||||
B215FB61143AD514003AC546 /* SSZipArchiveTests.m */,
|
||||
B215FB5F143AD514003AC546 /* SSZipArchiveTests-Info.plist */,
|
||||
C5AE4E63155A12760045F3ED /* IncorrectHeaders.zip */,
|
||||
B215FB6C143AD6FF003AC546 /* TestArchive.zip */,
|
||||
B23FCC7E1558F1B70026375C /* TestPasswordArchive.zip */,
|
||||
C5AE4E6C155A8B010045F3ED /* SymbolicLink.zip */,
|
||||
);
|
||||
name = SSZipArchiveTests;
|
||||
sourceTree = "<group>";
|
||||
@@ -148,7 +158,7 @@
|
||||
B215FB06143AD3C7003AC546 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0420;
|
||||
LastUpgradeCheck = 0440;
|
||||
ORGANIZATIONNAME = "Sam Soffes";
|
||||
};
|
||||
buildConfigurationList = B215FB09143AD3C7003AC546 /* Build configuration list for PBXProject "SSZipArchive" */;
|
||||
@@ -174,6 +184,10 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B215FB6D143AD6FF003AC546 /* TestArchive.zip in Resources */,
|
||||
B23FCC7F1558F1B70026375C /* TestPasswordArchive.zip in Resources */,
|
||||
C5AE4E64155A12760045F3ED /* IncorrectHeaders.zip in Resources */,
|
||||
C5AE4E6D155A8B010045F3ED /* SymbolicLink.zip in Resources */,
|
||||
B2283D5D155AD80F00F9395A /* Unicode.zip in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -217,6 +231,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
@@ -243,6 +258,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
@@ -263,7 +279,6 @@
|
||||
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
|
||||
INFOPLIST_FILE = "SSZipArchiveTests-Info.plist";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
WRAPPER_EXTENSION = octest;
|
||||
};
|
||||
@@ -275,7 +290,6 @@
|
||||
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
|
||||
INFOPLIST_FILE = "SSZipArchiveTests-Info.plist";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
WRAPPER_EXTENSION = octest;
|
||||
};
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
//
|
||||
// SSZipArchiveTests.h
|
||||
// SSZipArchiveTests
|
||||
//
|
||||
// Created by Sam Soffes on 10/3/11.
|
||||
// Copyright (c) 2011 Sam Soffes. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SenTestingKit/SenTestingKit.h>
|
||||
|
||||
@interface SSZipArchiveTests : SenTestCase
|
||||
|
||||
- (void)testZipping;
|
||||
- (void)testUnzipping;
|
||||
|
||||
@end
|
||||
@@ -6,17 +6,27 @@
|
||||
// Copyright (c) 2011 Sam Soffes. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SSZipArchiveTests.h"
|
||||
#import "SSZipArchive.h"
|
||||
#import <SenTestingKit/SenTestingKit.h>
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
@interface SSZipArchiveTests : SenTestCase <SSZipArchiveDelegate>
|
||||
|
||||
- (NSString *)_cachesPath:(NSString *)directory;
|
||||
|
||||
- (NSString *)_calculateMD5Digest:(NSData *)data;
|
||||
|
||||
@interface SSZipArchiveTests ()
|
||||
- (NSString *)_cachesPath;
|
||||
@end
|
||||
|
||||
@implementation SSZipArchiveTests
|
||||
|
||||
//- (void)setUp {
|
||||
// [[NSFileManager defaultManager] removeItemAtPath:[self _cachesPath:nil] error:nil];
|
||||
//}
|
||||
|
||||
|
||||
- (void)testZipping {
|
||||
NSString *outputPath = [self _cachesPath];
|
||||
NSString *outputPath = [self _cachesPath:@"Zipped"];
|
||||
NSArray *inputPaths = [NSArray arrayWithObjects:
|
||||
[outputPath stringByAppendingPathComponent:@"Readme.markdown"],
|
||||
[outputPath stringByAppendingPathComponent:@"LICENSE"],
|
||||
@@ -31,30 +41,146 @@
|
||||
|
||||
- (void)testUnzipping {
|
||||
NSString *zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestArchive" ofType:@"zip"];
|
||||
NSString *outputPath = [self _cachesPath];
|
||||
NSString *outputPath = [self _cachesPath:@"Regular"];
|
||||
|
||||
[SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath];
|
||||
[SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath delegate:self];
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSString *testPath = [outputPath stringByAppendingPathComponent:@"Readme.markdown"];
|
||||
STAssertTrue([fileManager fileExistsAtPath:testPath], @"Readme unzipped");
|
||||
|
||||
testPath = [outputPath stringByAppendingPathComponent:@"LICENSE"];
|
||||
STAssertTrue([fileManager fileExistsAtPath:testPath], @"LICENSE unzipped");
|
||||
}
|
||||
|
||||
|
||||
- (void)testUnzippingWithPassword {
|
||||
NSString *zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestPasswordArchive" ofType:@"zip"];
|
||||
NSString *outputPath = [self _cachesPath:@"Password"];
|
||||
|
||||
// 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.
|
||||
// zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"LargeArchive" ofType:@"zip"];
|
||||
// outputPath = [[self _cachesPath] stringByAppendingPathComponent:@"large"];
|
||||
NSError *error = nil;
|
||||
[SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath overwrite:YES password:@"passw0rd" error:&error delegate:self];
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSString *testPath = [outputPath stringByAppendingPathComponent:@"Readme.markdown"];
|
||||
STAssertTrue([fileManager fileExistsAtPath:testPath], @"Readme unzipped");
|
||||
|
||||
testPath = [outputPath stringByAppendingPathComponent:@"LICENSE"];
|
||||
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.");
|
||||
}
|
||||
|
||||
- (void)testUnzippingWithSymlinkedFileInside {
|
||||
|
||||
NSString* zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"SymbolicLink" ofType:@"zip"];
|
||||
NSString* outputPath = [self _cachesPath:@"SymbolicLink"];
|
||||
|
||||
[SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath delegate:self];
|
||||
|
||||
NSString *testSymlinkFolder = [outputPath stringByAppendingPathComponent:@"SymbolicLink/GitHub.app"];
|
||||
NSString *testSymlinkFile = [outputPath stringByAppendingPathComponent:@"SymbolicLink/Icon.icns"];
|
||||
|
||||
NSError *error = nil;
|
||||
NSString *symlinkFolderPath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:testSymlinkFolder error:&error];
|
||||
bool symbolicLinkToFolderPersists = ((symlinkFolderPath != nil) && [symlinkFolderPath isEqualToString:@"/Applications/GitHub.app"]) && (error == nil);
|
||||
|
||||
error = nil;
|
||||
|
||||
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.
|
||||
//
|
||||
//- (void)testUnzippingLargeFiles {
|
||||
// NSString *zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"LargeArchive" ofType:@"zip"];
|
||||
// NSString *outputPath = [self _cachesPath:@"Large"];
|
||||
//
|
||||
// [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath];
|
||||
//}
|
||||
|
||||
|
||||
#pragma mark - SSZipArchiveDelegate
|
||||
|
||||
- (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo {
|
||||
NSLog(@"*** zipArchiveWillUnzipArchiveAtPath: `%@` zipInfo:", path);
|
||||
}
|
||||
|
||||
|
||||
- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath {
|
||||
NSLog(@"*** zipArchiveDidUnzipArchiveAtPath: `%@` zipInfo: unzippedPath: `%@`", path, unzippedPath);
|
||||
}
|
||||
|
||||
|
||||
- (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo {
|
||||
NSLog(@"*** zipArchiveWillUnzipFileAtIndex: `%ld` totalFiles: `%ld` archivePath: `%@` fileInfo:", fileIndex, totalFiles, archivePath);
|
||||
}
|
||||
|
||||
|
||||
- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo {
|
||||
NSLog(@"*** zipArchiveDidUnzipFileAtIndex: `%ld` totalFiles: `%ld` archivePath: `%@` fileInfo:", fileIndex, totalFiles, archivePath);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (NSString *)_cachesPath {
|
||||
return [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]
|
||||
stringByAppendingPathComponent:@"com.samsoffes.ssziparchive.tests"];
|
||||
- (NSString *)_cachesPath:(NSString *)directory {
|
||||
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]
|
||||
stringByAppendingPathComponent:@"com.samsoffes.ssziparchive.tests"];
|
||||
if (directory) {
|
||||
path = [path stringByAppendingPathComponent:directory];
|
||||
}
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
if (![fileManager fileExistsAtPath:path]) {
|
||||
[fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
// Taken from https://github.com/samsoffes/sstoolkit/blob/master/SSToolkit/NSData+SSToolkitAdditions.m
|
||||
- (NSString *)_calculateMD5Digest:(NSData *)data {
|
||||
unsigned char digest[CC_MD5_DIGEST_LENGTH], i;
|
||||
CC_MD5(data.bytes, (unsigned int)data.length, digest);
|
||||
NSMutableString *ms = [NSMutableString string];
|
||||
for (i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
|
||||
[ms appendFormat: @"%02x", (int)(digest[i])];
|
||||
}
|
||||
return [ms copy];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
BIN
Tests/SymbolicLink.zip
Normal file
BIN
Tests/SymbolicLink.zip
Normal file
Binary file not shown.
Binary file not shown.
BIN
Tests/TestPasswordArchive.zip
Normal file
BIN
Tests/TestPasswordArchive.zip
Normal file
Binary file not shown.
BIN
Tests/Unicode.zip
Normal file
BIN
Tests/Unicode.zip
Normal file
Binary file not shown.
@@ -68,9 +68,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef NOUNCRYPT
|
||||
#define NOUNCRYPT
|
||||
#endif
|
||||
//#ifndef NOUNCRYPT
|
||||
// #define NOUNCRYPT
|
||||
//#endif
|
||||
|
||||
#include "zlib.h"
|
||||
#include "unzip.h"
|
||||
@@ -1629,7 +1629,7 @@ extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method,
|
||||
if (password != NULL)
|
||||
{
|
||||
int i;
|
||||
s->pcrc_32_tab = get_crc_table();
|
||||
s->pcrc_32_tab = (const unsigned long*)get_crc_table();
|
||||
init_keys(password,s->keys,s->pcrc_32_tab);
|
||||
if (ZSEEK64(s->z_filefunc, s->filestream,
|
||||
s->pfile_in_zip_read->pos_in_zipfile +
|
||||
@@ -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) &&
|
||||
|
||||
@@ -1250,7 +1250,7 @@ extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename,
|
||||
unsigned char bufHead[RAND_HEAD_LEN];
|
||||
unsigned int sizeHead;
|
||||
zi->ci.encrypt = 1;
|
||||
zi->ci.pcrc_32_tab = get_crc_table();
|
||||
zi->ci.pcrc_32_tab = (const unsigned long*)get_crc_table();
|
||||
/*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
|
||||
|
||||
sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting);
|
||||
|
||||
Reference in New Issue
Block a user