Compare commits

...

39 Commits

Author SHA1 Message Date
Sam Soffes d7ac059a8a Version 0.2.4 2013-07-03 08:58:01 -07:00
Joshua Garnham 9d322d173f Added tests for compressing and uncompressing files with permissions 2013-06-26 12:16:29 +01:00
Joshua Garnham c91865d01b Adds support for maintaining file permissions when compressing and decompressing 2013-06-25 17:11:08 +01:00
frytaz 548b3acbba Fix for file creation date + tests 2013-06-25 13:45:30 +02:00
djskinner 7627a1b4fc wrapped main loop in @autorelease pool
Massively reduces the memory overhead whilst unzipping
2013-06-17 15:33:44 +02:00
Sam Soffes 481ddf2096 Merge pull request #53 from randomsequence/master
Fix NSFileManager leak when building without ARC
2013-05-03 06:15:24 -07:00
Johnnie Walker b078433f2e Fix warning with -Widiomatic-parentheses enabled 2013-05-01 12:38:44 +01:00
Johnnie Walker ceae6ae819 Fix warning with -Wmissing-braces enabled 2013-05-01 12:36:32 +01:00
Johnnie Walker d7c7955cdc Fix NSFileManager leak when building without ARC 2013-05-01 12:03:48 +01:00
Sam Soffes ffbacdb288 Merge pull request #51 from carlj/master
Notice file date when save file
2013-04-23 02:03:25 -07:00
Carl Jahn 4ac78e3121 fixed bug: writeFileAtPath now notice the file date 2013-04-19 15:05:54 +02:00
Sam Soffes b4fa2e4739 Merge pull request #44 from iggycoder/master
zipping folders
2013-03-09 09:40:39 -08:00
Ingmar 7aea62f0dd - add folder zipping functionality
- fixed zipping test case [testZipping] (zipped an empty archive)
2013-03-09 05:36:20 -08:00
Sam Soffes 798a317bdc Merge pull request #40 from Keithbsmiley/master
Podspec fix
2013-03-03 10:55:22 -08:00
Sam Soffes ec5de8e02b Merge pull request #43 from levigroker/master
#define added to the .h which allows conditional compilation for third parties wishing to conditionally add functionality based on the presence of SSZipArchive.
2013-03-03 10:53:15 -08:00
Levi Brown a15c76e057 Fixed podspec.
Signed-off-by: Levi Brown <levi@grokers.net>
2013-03-01 17:17:35 -07:00
Levi Brown f7266f6b4d Adding #define of SSZipArchive header inclusion to allow for conditional compilation of libraries which can add functionality conditionally, if SSZipArchive is present.
Signed-off-by: Levi Brown <levi@grokers.net>
2013-03-01 14:40:28 -07:00
Sam Soffes d6f5b1c7a3 Update readme 2013-02-25 16:09:47 -08:00
Sam Soffes 2f05d42988 Add Travis CI 2013-02-25 06:46:56 -05:00
Sam Soffes d630ae5f5e Merge pull request #41 from xenosoz/master
This fixes a small typo.
2013-02-24 16:11:58 -08:00
Xenosoz Hwang 04605b7967 Fix bad loop end condition for unzip. 2013-02-24 10:40:21 -08:00
Keith Smiley 294cd2992b Fixed podspec 2013-02-07 11:45:12 -05:00
Sam Soffes a311e60107 Version 0.2.3
* Update podspec
* Fix remote
* Bump year
* Release changes since last release
2013-01-29 01:54:19 -05:00
Sam Soffes 69fb8f4a4c Merge pull request #34 from cvisprogrammer/master
added fclose to writeFile
2013-01-18 08:14:24 -08:00
Farooq Ahmad 1d163e4db5 Added fclose to writeFile
need fclose to avoid running out of file handles
2012-11-28 09:16:10 -08:00
Sam Soffes 3f5a7b30dc Merge pull request #28 from nivektric/master
Change clean_path to preserve_paths in podspec to pass validation
2012-07-10 12:01:07 -07:00
Kevin Monahan bdbab4d3b3 Change clean_path to preserve_paths in podspec to pass validation 2012-07-10 14:35:58 -04:00
Sam Soffes fdb1726299 Merge pull request #27 from nivektric/0.2.2
Bump version number in podspec
2012-07-09 21:39:27 -07:00
Kevin Monahan 709006228c Bump version number in podspec 2012-07-09 23:47:10 -04:00
Sam Soffes db0c62c481 Bump license year and add podspec 2012-06-02 13:32:57 -07:00
Sam Soffes d9ea638369 Merge pull request #23 from jparishy/master
Fix for issues with Unicode filenames and Symbolic Links. Fixes #14
2012-05-09 21:32:13 -07:00
Julius Parishy f18a98e551 Remote old debug NSLogs
Just taking out some NSLogs I missed when cleaning up the source.
2012-05-09 23:55:36 -04:00
Julius Parishy 557e869222 Remove files I accidentally unzipped.
They weren't needed and were cluttering up the directory.
2012-05-09 23:54:47 -04:00
Julius Parishy 26630b36af Fix for mailing tests regarding unicode filenames and symbolic links.
See my note about ZIPs lack of documentation for symbolic links. A lot
of this seems to be trial and error on my part as the implementation
isn't documented. This seems to do the trick, however, and all of the
tests are now passing on my end.

As always, send more problems my way.
2012-05-09 23:53:22 -04:00
Sam Soffes 581adbb98c Don't clean output director for debugging purposes 2012-05-09 09:54:16 -07:00
Sam Soffes d646bf93a2 Add failing test for #14 2012-05-09 09:53:06 -07:00
Sam Soffes b7598bc95f Version 0.2.1 2012-05-09 09:53:06 -07:00
Sam Soffes 236fcb7d65 Merge pull request #20 from florianbachmann/master
get rid of these three little warnings
2012-05-09 08:39:01 -07:00
Florian Bachmann 45009d71e7 get rid of these three warnings:
- Missing field 'tm_min' initializer
- Suggest braces around initialization of subobject
- Missing field 'dosDate' initializer
2012-05-09 11:17:44 +02:00
23 changed files with 592 additions and 181 deletions
+1
View File
@@ -4,3 +4,4 @@
*.perspectivev3
*.xcworkspace
xcuserdata
DerivedData
+3
View File
@@ -0,0 +1,3 @@
language: objective-c
before_install: "sudo gem update --system && bundle install"
script: bundle exec rake test --trace
+10 -2
View File
@@ -1,12 +1,20 @@
# 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
* Add unzipping delegate — [@uppfinnarn](http://github.com/uppfinnarn)
* Fix unzipping with passwords
* Fix modified at dates
* 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
+3
View File
@@ -0,0 +1,3 @@
source 'https://rubygems.org'
gem 'rake'
+10
View File
@@ -0,0 +1,10 @@
GEM
remote: https://rubygems.org/
specs:
rake (10.0.3)
PLATFORMS
ruby
DEPENDENCIES
rake
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2010-2011 Sam Soffes
Copyright (c) 2010-2013 Sam Soffes
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+6
View 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
+6
View File
@@ -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.
[![Build Status](https://staging.travis-ci.org/soffes/ssziparchive.png?branch=master)](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).
+7 -1
View File
@@ -3,9 +3,12 @@
// SSZipArchive
//
// Created by Sam Soffes on 7/21/10.
// Copyright (c) Sam Soffes 2010-2011. All rights reserved.
// 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 */
+240 -136
View File
@@ -3,7 +3,7 @@
// SSZipArchive
//
// Created by Sam Soffes on 7/21/10.
// Copyright (c) Sam Soffes 2010-2011. All rights reserved.
// Copyright (c) Sam Soffes 2010-2013. All rights reserved.
//
#import "SSZipArchive.h"
@@ -11,6 +11,8 @@
#import "zlib.h"
#import "zconf.h"
#include <sys/stat.h>
#define CHUNK 16384
@interface SSZipArchive ()
@@ -78,168 +80,192 @@
NSInteger currentFileNumber = 0;
do {
if ([password length] == 0) {
ret = unzOpenCurrentFile(zip);
} else {
ret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSASCIIStringEncoding]);
}
@autoreleasepool {
if ([password length] == 0) {
ret = unzOpenCurrentFile(zip);
} else {
ret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSASCIIStringEncoding]);
}
if (ret != UNZ_OK) {
success = NO;
break;
}
if (ret != UNZ_OK) {
success = NO;
break;
}
// Reading data and write to file
unz_file_info fileInfo;
memset(&fileInfo, 0, sizeof(unz_file_info));
// 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;
}
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];
}
// 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';
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 an uncompressed data size greater than
// zero (real directories have it equal to 0) and the included, uncompressed data is the
// symbolic link path.
//
//
// 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 ZipDirectoryVersion = 10;
const uLong ZipCompressionMethodStore = 0;
const uLong ZipCompressionMethodStore = 0;
BOOL fileIsSymbolicLink = NO;
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?
{
fileIsSymbolicLink = YES;
}
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\" is symbolic link? %@", filename, fileIsSymbolicLink ? @"Yes." : @"No.");
// 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);
// 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:@"/"];
}
// 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];
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 (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(!fileIsSymbolicLink)
[directoriesModificationDates addObject: [NSDictionary dictionaryWithObjectsAndKeys:fullPath, @"path", modDate, @"modDate", nil]];
if ([fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite) {
unzCloseCurrentFile(zip);
ret = unzGoToNextFile(zip);
continue;
}
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(!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 (readBytes > 0) {
fwrite(buffer, readBytes, 1, fp );
} else {
break;
}
}
if (fp) {
fclose(fp);
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];
// 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
}
}
else
{
// Get the path for the symbolic link
NSURL* symlinkURL = [NSURL fileURLWithPath:fullPath];
NSMutableString* destinationPath = [NSMutableString string];
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]];
}
int bytesRead = 0;
while((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0)
{
buffer[bytesRead] = 0;
[destinationPath appendString:[NSString stringWithUTF8String:(const char*)buffer]];
}
//NSLog(@"Symlinking to: %@", destinationPath);
//NSLog(@"Symlinking to: %@", destinationPath);
NSURL* destinationURL = [NSURL fileURLWithPath:destinationPath];
NSURL* destinationURL = [NSURL fileURLWithPath:destinationPath];
// Create the symbolic link
NSError* symlinkError = nil;
[fileManager createSymbolicLinkAtURL:symlinkURL withDestinationURL:destinationURL error:&symlinkError];
// 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);
}
}
if(symlinkError != nil)
{
NSLog(@"Failed to create symbolic link at \"%@\" to \"%@\". Error: %@", symlinkURL.absoluteString, destinationURL.absoluteString, symlinkError.localizedDescription);
}
}
unzCloseCurrentFile( zip );
ret = unzGoToNextFile( zip );
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];
// 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);
@@ -290,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];
@@ -326,20 +384,66 @@
}
- (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;
}
zipOpenNewFileInZip(_zip, [[path lastPathComponent] UTF8String], NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
const char *afileName;
if (!fileName) {
afileName = [path.lastPathComponent UTF8String];
}
else {
afileName = [fileName UTF8String];
}
zip_fileinfo zipInfo = {{0}};
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);
}
+15
View File
@@ -0,0 +1,15 @@
Pod::Spec.new do |s|
s.name = 'SSZipArchive'
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 => '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.header_dir = 'minizip'
s.library = 'z'
end
@@ -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>
Binary file not shown.
@@ -0,0 +1 @@
APPL????
@@ -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\
}
@@ -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 */; };
@@ -17,12 +18,14 @@
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 */
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; };
@@ -41,6 +44,7 @@
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>"; };
@@ -118,6 +122,8 @@
B215FB5E143AD505003AC546 /* SSZipArchiveTests */ = {
isa = PBXGroup;
children = (
AF313D08177B02A700478143 /* PermissionsTestApp.app */,
B2283D5C155AD80F00F9395A /* Unicode.zip */,
B215FB61143AD514003AC546 /* SSZipArchiveTests.m */,
B215FB5F143AD514003AC546 /* SSZipArchiveTests-Info.plist */,
C5AE4E63155A12760045F3ED /* IncorrectHeaders.zip */,
@@ -182,8 +188,10 @@
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -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>
+105 -11
View File
@@ -20,17 +20,21 @@
@implementation SSZipArchiveTests
- (void)setUp {
[[NSFileManager defaultManager] removeItemAtPath:[self _cachesPath:nil] error:nil];
}
//- (void)setUp {
// [[NSFileManager defaultManager] removeItemAtPath:[self _cachesPath:nil] error:nil];
//}
- (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"];
@@ -91,16 +106,95 @@
[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.");
}
- (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.
Binary file not shown.
BIN
View File
Binary file not shown.