Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7ac059a8a | ||
|
|
9d322d173f | ||
|
|
c91865d01b | ||
|
|
548b3acbba | ||
|
|
7627a1b4fc | ||
|
|
481ddf2096 | ||
|
|
b078433f2e | ||
|
|
ceae6ae819 | ||
|
|
d7c7955cdc | ||
|
|
ffbacdb288 | ||
|
|
4ac78e3121 | ||
|
|
b4fa2e4739 | ||
|
|
7aea62f0dd | ||
|
|
798a317bdc | ||
|
|
ec5de8e02b | ||
|
|
a15c76e057 | ||
|
|
f7266f6b4d | ||
|
|
d6f5b1c7a3 | ||
|
|
2f05d42988 | ||
|
|
d630ae5f5e | ||
|
|
04605b7967 | ||
|
|
294cd2992b |
3
.travis.yml
Normal file
3
.travis.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
language: objective-c
|
||||
before_install: "sudo gem update --system && bundle install"
|
||||
script: bundle exec rake test --trace
|
||||
10
Gemfile.lock
Normal file
10
Gemfile.lock
Normal file
@@ -0,0 +1,10 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
rake (10.0.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
rake
|
||||
6
Rakefile
Normal file
6
Rakefile
Normal file
@@ -0,0 +1,6 @@
|
||||
desc 'Run the tests'
|
||||
task :test do
|
||||
system 'xcodebuild -project Tests/SSZipArchive.xcodeproj -scheme SSZipArchiveTests TEST_AFTER_BUILD=YES'
|
||||
end
|
||||
|
||||
task :default => :test
|
||||
@@ -34,6 +34,12 @@ NSArray *inputPaths = [NSArray arrayWithObjects:
|
||||
[SSZipArchive createZipFileAtPath:zippedPath withFilesAtPaths:inputPaths];
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
Simply, open the Xcode project in the Tests directory and press Command-U to run the tests.
|
||||
|
||||
[](https://staging.travis-ci.org/soffes/ssziparchive)
|
||||
|
||||
## License
|
||||
|
||||
SSZipArchive is licensed under the [MIT license](https://github.com/samsoffes/ssziparchive/raw/master/LICENSE). A slightly modified version of [Minizip](http://www.winimage.com/zLibDll/minizip.html) 1.1 is also included and is licensed under the [Zlib license](http://www.zlib.net/zlib_license.html).
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
// Copyright (c) Sam Soffes 2010-2013. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef _SSZIPARCHIVE_H
|
||||
#define _SSZIPARCHIVE_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include "minizip/unzip.h"
|
||||
|
||||
@@ -22,6 +25,7 @@
|
||||
|
||||
// Zip
|
||||
+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)filenames;
|
||||
+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath;
|
||||
|
||||
- (id)initWithPath:(NSString *)path;
|
||||
- (BOOL)open;
|
||||
@@ -43,3 +47,5 @@
|
||||
- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* _SSZIPARCHIVE_H */
|
||||
|
||||
434
SSZipArchive.m
434
SSZipArchive.m
@@ -80,169 +80,192 @@
|
||||
|
||||
NSInteger currentFileNumber = 0;
|
||||
do {
|
||||
if ([password length] == 0) {
|
||||
ret = unzOpenCurrentFile(zip);
|
||||
} else {
|
||||
ret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
}
|
||||
|
||||
if (ret != UNZ_OK) {
|
||||
success = NO;
|
||||
break;
|
||||
}
|
||||
|
||||
// Reading data and write to file
|
||||
unz_file_info fileInfo;
|
||||
memset(&fileInfo, 0, sizeof(unz_file_info));
|
||||
|
||||
ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
|
||||
if (ret != UNZ_OK) {
|
||||
success = NO;
|
||||
unzCloseCurrentFile(zip);
|
||||
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;
|
||||
if (filename[fileInfo.size_filename-1] == '/' || filename[fileInfo.size_filename-1] == '\\') {
|
||||
isDirectory = YES;
|
||||
}
|
||||
free(filename);
|
||||
|
||||
// Contains a path
|
||||
if ([strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location != NSNotFound) {
|
||||
strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
|
||||
}
|
||||
|
||||
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:directoryAttr error:&err];
|
||||
} else {
|
||||
[fileManager createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:directoryAttr error:&err];
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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 = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate];
|
||||
NSDictionary *attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate];
|
||||
@autoreleasepool {
|
||||
if ([password length] == 0) {
|
||||
ret = unzOpenCurrentFile(zip);
|
||||
} else {
|
||||
ret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
}
|
||||
|
||||
if (ret != UNZ_OK) {
|
||||
success = NO;
|
||||
break;
|
||||
}
|
||||
|
||||
// Reading data and write to file
|
||||
unz_file_info fileInfo;
|
||||
memset(&fileInfo, 0, sizeof(unz_file_info));
|
||||
|
||||
ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
|
||||
if (ret != UNZ_OK) {
|
||||
success = NO;
|
||||
unzCloseCurrentFile(zip);
|
||||
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;
|
||||
if (filename[fileInfo.size_filename-1] == '/' || filename[fileInfo.size_filename-1] == '\\') {
|
||||
isDirectory = YES;
|
||||
}
|
||||
free(filename);
|
||||
|
||||
// Contains a path
|
||||
if ([strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location != NSNotFound) {
|
||||
strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
|
||||
}
|
||||
|
||||
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:directoryAttr error:&err];
|
||||
} else {
|
||||
[fileManager createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:directoryAttr error:&err];
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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 = [[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 - whilst setting modification date");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attr) {
|
||||
if ([fileManager setAttributes:attr ofItemAtPath:fullPath error:nil] == NO) {
|
||||
// Can't set attributes
|
||||
NSLog(@"[SSZipArchive] Failed to set attributes");
|
||||
// Set the original permissions on the file
|
||||
if (fileInfo.external_fa != 0) {
|
||||
// Get the permissions
|
||||
uLong permissions = fileInfo.external_fa >> 16;
|
||||
|
||||
// Store it into a NSNumber
|
||||
NSNumber *permissionsValue = @(permissions);
|
||||
|
||||
// Retrieve any existing attributes
|
||||
NSMutableDictionary *attrs = [[NSMutableDictionary alloc] initWithDictionary:[fileManager attributesOfItemAtPath:fullPath error:nil]];
|
||||
|
||||
// Set the value in the attributes dict
|
||||
attrs[NSFilePosixPermissions] = permissionsValue;
|
||||
|
||||
// Update attributes
|
||||
if ([fileManager setAttributes:attrs ofItemAtPath:fullPath error:nil] == NO) {
|
||||
// Unable to set the permissions attribute
|
||||
NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting permissions");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
|
||||
currentFileNumber++;
|
||||
} while(ret == UNZ_OK && UNZ_OK != UNZ_END_OF_LIST_OF_FILE);
|
||||
} while(ret == UNZ_OK && ret != UNZ_END_OF_LIST_OF_FILE);
|
||||
|
||||
// Close
|
||||
unzClose(zip);
|
||||
@@ -293,6 +316,38 @@
|
||||
}
|
||||
|
||||
|
||||
+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath {
|
||||
BOOL success = NO;
|
||||
|
||||
NSFileManager *fileManager = nil;
|
||||
SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path];
|
||||
|
||||
if ([zipArchive open]) {
|
||||
// use a local filemanager (queue/thread compatibility)
|
||||
fileManager = [[NSFileManager alloc] init];
|
||||
NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:directoryPath];
|
||||
|
||||
NSString *fileName;
|
||||
while ((fileName = [dirEnumerator nextObject])) {
|
||||
BOOL isDir;
|
||||
NSString *fullFilePath = [directoryPath stringByAppendingPathComponent:fileName];
|
||||
[fileManager fileExistsAtPath:fullFilePath isDirectory:&isDir];
|
||||
if (!isDir) {
|
||||
[zipArchive writeFileAtPath:fullFilePath withFileName:fileName];
|
||||
}
|
||||
}
|
||||
success = [zipArchive close];
|
||||
}
|
||||
|
||||
#if !__has_feature(objc_arc)
|
||||
[fileManager release];
|
||||
[zipArchive release];
|
||||
#endif
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
- (id)initWithPath:(NSString *)path {
|
||||
if ((self = [super init])) {
|
||||
_path = [path copy];
|
||||
@@ -329,27 +384,72 @@
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)writeFile:(NSString *)path {
|
||||
NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened");
|
||||
- (BOOL)writeFile:(NSString *)path
|
||||
{
|
||||
return [self writeFileAtPath:path withFileName:nil];
|
||||
}
|
||||
|
||||
// supports writing files with logical folder/directory structure
|
||||
// *path* is the absolute path of the file that will be compressed
|
||||
// *fileName* is the relative name of the file how it is stored within the zip e.g. /folder/subfolder/text1.txt
|
||||
- (BOOL)writeFileAtPath:(NSString *)path withFileName:(NSString *)fileName {
|
||||
NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened");
|
||||
|
||||
FILE *input = fopen([path UTF8String], "r");
|
||||
if (NULL == input) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
const char *afileName;
|
||||
if (!fileName) {
|
||||
afileName = [path.lastPathComponent UTF8String];
|
||||
}
|
||||
else {
|
||||
afileName = [fileName UTF8String];
|
||||
}
|
||||
|
||||
zip_fileinfo zipInfo = {{0}};
|
||||
|
||||
zipOpenNewFileInZip(_zip, [[path lastPathComponent] UTF8String], NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED,
|
||||
Z_DEFAULT_COMPRESSION);
|
||||
|
||||
NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error: nil];
|
||||
if( attr )
|
||||
{
|
||||
NSDate *fileDate = (NSDate *)[attr objectForKey:NSFileModificationDate];
|
||||
if( fileDate )
|
||||
{
|
||||
[self zipInfo:&zipInfo setDate: fileDate ];
|
||||
}
|
||||
|
||||
// Write permissions into the external attributes, for details on this see here: http://unix.stackexchange.com/a/14727
|
||||
// Get the permissions value from the files attributes
|
||||
NSNumber *permissionsValue = (NSNumber *)[attr objectForKey:NSFilePosixPermissions];
|
||||
if (permissionsValue) {
|
||||
// Get the short value for the permissions
|
||||
short permissionsShort = permissionsValue.shortValue;
|
||||
|
||||
// Convert this into an octal by adding 010000, 010000 being the flag for a regular file
|
||||
NSInteger permissionsOctal = 0100000 + permissionsShort;
|
||||
|
||||
// Convert this into a long value
|
||||
uLong permissionsLong = @(permissionsOctal).unsignedLongValue;
|
||||
|
||||
// Store this into the external file attributes once it has been shifted 16 places left to form part of the second from last byte
|
||||
zipInfo.external_fa = permissionsLong << 16L;
|
||||
}
|
||||
}
|
||||
|
||||
zipOpenNewFileInZip(_zip, afileName, &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
|
||||
|
||||
void *buffer = malloc(CHUNK);
|
||||
unsigned int len = 0;
|
||||
while (!feof(input)) {
|
||||
|
||||
while (!feof(input))
|
||||
{
|
||||
len = (unsigned int) fread(buffer, 1, CHUNK, input);
|
||||
zipWriteInFileInZip(_zip, buffer, len);
|
||||
}
|
||||
|
||||
|
||||
zipCloseFileInZip(_zip);
|
||||
free(buffer);
|
||||
fclose(input);
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'SSZipArchive'
|
||||
s.version = '0.2.3'
|
||||
s.version = '0.2.4'
|
||||
s.summary = 'Utility class for zipping and unzipping files on iOS and Mac.'
|
||||
s.description = 'SSZipArchive is a simple utility class for zipping and unzipping files on iOS and Mac.'
|
||||
s.homepage = 'https://github.com/soffes/ssziparchive'
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
s.author = { 'Sam Soffes' => 'sam@soff.es' }
|
||||
s.source = { :git => 'https://github.com/soffes/ssziparchive.git', :tag => '0.2.3' }
|
||||
s.source = { :git => 'https://github.com/soffes/ssziparchive.git', :tag => 'v0.2.4' }
|
||||
s.ios.deployment_target = '4.0'
|
||||
s.osx.deployment_target = '10.6'
|
||||
s.source_files = 'SSZipArchive.{h,m}', 'minizip/*.{h,c}'
|
||||
s.preserve_paths = 'minizip'
|
||||
s.header_dir = 'minizip'
|
||||
s.library = 'z'
|
||||
end
|
||||
|
||||
48
Tests/PermissionsTestApp.app/Contents/Info.plist
Normal file
48
Tests/PermissionsTestApp.app/Contents/Info.plist
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildMachineOSBuild</key>
|
||||
<string>13A476u</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>TestProject</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.squaredtiki.TestProject</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>TestProject</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>DTCompiler</key>
|
||||
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||
<key>DTPlatformBuild</key>
|
||||
<string>5A11314m</string>
|
||||
<key>DTPlatformVersion</key>
|
||||
<string>GM</string>
|
||||
<key>DTSDKBuild</key>
|
||||
<string>13A476n</string>
|
||||
<key>DTSDKName</key>
|
||||
<string>macosx10.9</string>
|
||||
<key>DTXcode</key>
|
||||
<string>0500</string>
|
||||
<key>DTXcodeBuild</key>
|
||||
<string>5A11314m</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.9</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2013 TestBench. All rights reserved.</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
Tests/PermissionsTestApp.app/Contents/MacOS/TestProject
Executable file
BIN
Tests/PermissionsTestApp.app/Contents/MacOS/TestProject
Executable file
Binary file not shown.
1
Tests/PermissionsTestApp.app/Contents/PkgInfo
Normal file
1
Tests/PermissionsTestApp.app/Contents/PkgInfo
Normal file
@@ -0,0 +1 @@
|
||||
APPL????
|
||||
BIN
Tests/PermissionsTestApp.app/Contents/Resources/Assets.car
Normal file
BIN
Tests/PermissionsTestApp.app/Contents/Resources/Assets.car
Normal file
Binary file not shown.
BIN
Tests/PermissionsTestApp.app/Contents/Resources/Base.lproj/MainMenu.nib
generated
Normal file
BIN
Tests/PermissionsTestApp.app/Contents/Resources/Base.lproj/MainMenu.nib
generated
Normal file
Binary file not shown.
@@ -0,0 +1,29 @@
|
||||
{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
\paperw9840\paperh8400
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
|
||||
|
||||
\f0\b\fs24 \cf0 Engineering:
|
||||
\b0 \
|
||||
Some people\
|
||||
\
|
||||
|
||||
\b Human Interface Design:
|
||||
\b0 \
|
||||
Some other people\
|
||||
\
|
||||
|
||||
\b Testing:
|
||||
\b0 \
|
||||
Hopefully not nobody\
|
||||
\
|
||||
|
||||
\b Documentation:
|
||||
\b0 \
|
||||
Whoever\
|
||||
\
|
||||
|
||||
\b With special thanks to:
|
||||
\b0 \
|
||||
Mom\
|
||||
}
|
||||
Binary file not shown.
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
AF313D09177B02A700478143 /* PermissionsTestApp.app in Resources */ = {isa = PBXBuildFile; fileRef = AF313D08177B02A700478143 /* PermissionsTestApp.app */; };
|
||||
B215FB32143AD3C7003AC546 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B215FB31143AD3C7003AC546 /* SenTestingKit.framework */; };
|
||||
B215FB63143AD514003AC546 /* SSZipArchiveTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B215FB61143AD514003AC546 /* SSZipArchiveTests.m */; };
|
||||
B215FB65143AD527003AC546 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B215FB64143AD527003AC546 /* libz.dylib */; };
|
||||
@@ -24,6 +25,7 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
AF313D08177B02A700478143 /* PermissionsTestApp.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = PermissionsTestApp.app; sourceTree = "<group>"; };
|
||||
B215FB18143AD3C7003AC546 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
B215FB30143AD3C7003AC546 /* SSZipArchiveTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SSZipArchiveTests.octest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B215FB31143AD3C7003AC546 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
@@ -120,6 +122,7 @@
|
||||
B215FB5E143AD505003AC546 /* SSZipArchiveTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AF313D08177B02A700478143 /* PermissionsTestApp.app */,
|
||||
B2283D5C155AD80F00F9395A /* Unicode.zip */,
|
||||
B215FB61143AD514003AC546 /* SSZipArchiveTests.m */,
|
||||
B215FB5F143AD514003AC546 /* SSZipArchiveTests-Info.plist */,
|
||||
@@ -185,6 +188,7 @@
|
||||
files = (
|
||||
B215FB6D143AD6FF003AC546 /* TestArchive.zip in Resources */,
|
||||
B23FCC7F1558F1B70026375C /* TestPasswordArchive.zip in Resources */,
|
||||
AF313D09177B02A700478143 /* PermissionsTestApp.app in Resources */,
|
||||
C5AE4E64155A12760045F3ED /* IncorrectHeaders.zip in Resources */,
|
||||
C5AE4E6D155A8B010045F3ED /* SymbolicLink.zip in Resources */,
|
||||
B2283D5D155AD80F00F9395A /* Unicode.zip in Resources */,
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0460"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B215FB2F143AD3C7003AC546"
|
||||
BuildableName = "SSZipArchiveTests.octest"
|
||||
BlueprintName = "SSZipArchiveTests"
|
||||
ReferencedContainer = "container:SSZipArchive.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B215FB2F143AD3C7003AC546"
|
||||
BuildableName = "SSZipArchiveTests.octest"
|
||||
BlueprintName = "SSZipArchiveTests"
|
||||
ReferencedContainer = "container:SSZipArchive.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -26,11 +26,15 @@
|
||||
|
||||
|
||||
- (void)testZipping {
|
||||
NSString *outputPath = [self _cachesPath:@"Zipped"];
|
||||
// use extracted files from [-testUnzipping]
|
||||
NSString *inputPath = [self _cachesPath:@"Regular"];
|
||||
NSArray *inputPaths = [NSArray arrayWithObjects:
|
||||
[outputPath stringByAppendingPathComponent:@"Readme.markdown"],
|
||||
[outputPath stringByAppendingPathComponent:@"LICENSE"],
|
||||
[inputPath stringByAppendingPathComponent:@"Readme.markdown"],
|
||||
[inputPath stringByAppendingPathComponent:@"LICENSE"],
|
||||
nil];
|
||||
|
||||
NSString *outputPath = [self _cachesPath:@"Zipped"];
|
||||
|
||||
NSString *archivePath = [outputPath stringByAppendingPathComponent:@"CreatedArchive.zip"];
|
||||
[SSZipArchive createZipFileAtPath:archivePath withFilesAtPaths:inputPaths];
|
||||
|
||||
@@ -38,6 +42,17 @@
|
||||
STAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:archivePath], @"Archive created");
|
||||
}
|
||||
|
||||
- (void)testDirectoryZipping {
|
||||
// use Unicode as folder (has a file in root and a file in subfolder)
|
||||
NSString *inputPath = [self _cachesPath:@"Unicode"];
|
||||
|
||||
NSString *outputPath = [self _cachesPath:@"FolderZipped"];
|
||||
NSString *archivePath = [outputPath stringByAppendingPathComponent:@"ArchiveWithFolders.zip"];
|
||||
|
||||
[SSZipArchive createZipFileAtPath:archivePath withContentsOfDirectory:inputPath];
|
||||
STAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:archivePath], @"Folder Archive created");
|
||||
}
|
||||
|
||||
|
||||
- (void)testUnzipping {
|
||||
NSString *zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestArchive" ofType:@"zip"];
|
||||
@@ -121,6 +136,66 @@
|
||||
STAssertTrue(unicodeFolderWasExtracted, @"Folders with names in unicode should be extracted propertly.");
|
||||
}
|
||||
|
||||
- (void)testZippingAndUnzippingForDate {
|
||||
|
||||
NSString *inputPath = [self _cachesPath:@"Regular"];
|
||||
NSArray *inputPaths = [NSArray arrayWithObjects:
|
||||
[inputPath stringByAppendingPathComponent:@"Readme.markdown"],
|
||||
nil];
|
||||
|
||||
NSDictionary *originalFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[inputPath stringByAppendingPathComponent:@"Readme.markdown"] error:nil];
|
||||
|
||||
NSString *outputPath = [self _cachesPath:@"ZippedDate"];
|
||||
NSString *archivePath = [outputPath stringByAppendingPathComponent:@"CreatedArchive.zip"];
|
||||
|
||||
[SSZipArchive createZipFileAtPath:archivePath withFilesAtPaths:inputPaths];
|
||||
[SSZipArchive unzipFileAtPath:archivePath toDestination:outputPath delegate:self];
|
||||
|
||||
NSDictionary *createdFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[outputPath stringByAppendingPathComponent:@"Readme.markdown"] error:nil];
|
||||
|
||||
STAssertEquals(originalFileAttributes[NSFileCreationDate], createdFileAttributes[@"NSFileCreationDate"], @"Orginal file creationDate should match created one");
|
||||
}
|
||||
|
||||
- (void)testZippingAndUnzippingForPermissions {
|
||||
// File we're going to test permissions on before and after zipping
|
||||
NSString *targetFile = @"/Contents/MacOS/TestProject";
|
||||
|
||||
|
||||
/********** Zipping ********/
|
||||
|
||||
// The .app file we're going to zip up
|
||||
NSString *inputFile = [[NSBundle mainBundle] pathForResource:@"PermissionsTestApp" ofType:@"app"];
|
||||
|
||||
// The path to the target file in the app before zipping
|
||||
NSString *targetFilePreZipPath = [inputFile stringByAppendingPathComponent:targetFile];
|
||||
|
||||
// Atribtues for the target file before zipping
|
||||
NSDictionary *preZipAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:targetFilePreZipPath error:nil];
|
||||
|
||||
// Directory to output our created zip file
|
||||
NSString *outputDir = [self _cachesPath:@"PermissionsTest"];
|
||||
// The path to where the archive shall be created
|
||||
NSString *archivePath = [outputDir stringByAppendingPathComponent:@"TestAppArchive.zip"];
|
||||
|
||||
// Create the zip file using the contents of the .app file as the input
|
||||
[SSZipArchive createZipFileAtPath:archivePath withContentsOfDirectory:inputFile];
|
||||
|
||||
|
||||
/********** Un-zipping *******/
|
||||
|
||||
// Using this newly created zip file, unzip it
|
||||
[SSZipArchive unzipFileAtPath:archivePath toDestination:outputDir];
|
||||
|
||||
// Get the path to the target file after unzipping
|
||||
NSString *targetFilePath = [outputDir stringByAppendingPathComponent:@"/Contents/MacOS/TestProject"];
|
||||
|
||||
// Get the file attributes of the target file following the unzipping
|
||||
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:targetFilePath error:nil];
|
||||
|
||||
// Compare the value of the permissions attribute to assert equality
|
||||
STAssertEquals(fileAttributes[NSFilePosixPermissions], preZipAttributes[NSFilePosixPermissions], @"File permissions should be retained during compression and de-compression");
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user