Folder and subfolder zip functionality

Added functionality to zip folder and maintains subfolder tree
This commit is contained in:
Cpu86
2013-03-30 19:50:50 +01:00
parent cd0be3772a
commit 92f1142056
2 changed files with 242 additions and 40 deletions
+8 -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,10 +25,12 @@
// Zip
+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)filenames;
+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath;
- (id)initWithPath:(NSString *)path;
- (BOOL)open;
- (BOOL)writeFile:(NSString *)path;
- (BOOL)writeFile:(NSString *)filename basePath:(NSString *)base;
- (BOOL)writeData:(NSData *)data filename:(NSString *)filename;
- (BOOL)close;
@@ -43,3 +48,5 @@
- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
@end
#endif /* _SSZIPARCHIVE_H */
+234 -39
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 ()
@@ -105,11 +107,37 @@
[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;
@@ -137,41 +165,72 @@
NSLog(@"[SSZipArchive] Error: %@", err.localizedDescription);
}
[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;
}
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 = [[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");
}
}
}
}
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 );
@@ -183,7 +242,7 @@
}
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);
@@ -218,11 +277,31 @@
+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths {
BOOL success = NO;
NSMutableString *base;
SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path];
if ([zipArchive open]) {
/*--------------new code--------------*/
base = [NSMutableString stringWithCapacity:0];
for (NSString *path in paths) {
[zipArchive writeFile:path];
//extract the base path
[base setString:path];
if([[base substringFromIndex:([path length]-1)] isEqualToString:@"/"])
[base deleteCharactersInRange:NSMakeRange([path length]-1, 1)];
[base setString:[base substringToIndex:([base length]-[[path lastPathComponent] length])]];
//NSLog(@"base path: %@",base);
[zipArchive writeFile:[path lastPathComponent] basePath:base];
}
/*-----------------------------------*/
/*--------------old code-------------*/
/*for (NSString *path in paths) {
[zipArchive writeFile:path];
}*/
/*-----------------------------------*/
success = [zipArchive close];
}
@@ -234,6 +313,35 @@
}
+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath {
BOOL success = NO;
SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path];
if ([zipArchive open]) {
// use a local filemanager (queue/thread compatibility)
NSFileManager *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)
[zipArchive release];
#endif
return success;
}
- (id)initWithPath:(NSString *)path {
if ((self = [super init])) {
_path = [path copy];
@@ -269,25 +377,112 @@
zipInfo->tmz_date.tm_year = (unsigned int)components.year;
}
//Filename is the filename, or folder name, to be added to the zip file
//and base is the base path of the filename
//example:
// path of file to be added: /home/test/file.txt
// filename should be: file.txt
// and base should be: /home/test (with or without the "/", doesn't matter)
//
//to add a folder:
// path of the folder to be added: /home/test/folder/
// filename should be: folder (with or without the "/", doesn't matter)
// and base should be: /home/test (with or without the "/", doesn't matter)
//
- (BOOL)writeFile:(NSString *)path {
- (BOOL)writeFile:(NSString *)filename basePath:(NSString *)base {
NSArray *components;
NSString *path;
BOOL isDir;
int i;
NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened");
//NSLog(@"write file: %@",filename);
path = [base stringByAppendingPathComponent:filename]; //the actual file (or folder) path
if([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir] && isDir){
//NSLog(@"idDir");
//if is a folder, get its content
components = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
if(![components count]){
//if is an empty folder, add an empty one to the zip file
zipOpenNewFileInZip(_zip, [[filename stringByAppendingString:@"/"] UTF8String], NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED,Z_DEFAULT_COMPRESSION);
i=0; //just a placeholder for the "buffer" to be passed
zipWriteInFileInZip(_zip,&i, 0);
zipCloseFileInZip(_zip);
return YES;
}
//otherwise, step through the folder content
for(i=0;i<[components count];i++){
//and add each file (or subfolder) recursively
if(![self writeFile:[filename stringByAppendingPathComponent:[components objectAtIndex:i]] basePath:base])
return NO;
}
return YES;
}
//NSLog(@"regular file");
FILE *input = fopen([path UTF8String], "r");
if (NULL == input) {
return NO;
}
zipOpenNewFileInZip(_zip, [[path lastPathComponent] UTF8String], NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED,
zipOpenNewFileInZip(_zip, [filename UTF8String], NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
void *buffer = malloc(CHUNK);
unsigned int len = 0;
while (!feof(input)) {
len = (unsigned int) fread(buffer, 1, CHUNK, input);
zipWriteInFileInZip(_zip, buffer, len);
}
zipCloseFileInZip(_zip);
free(buffer);
return YES;
}
- (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];
}
zipOpenNewFileInZip(_zip, afileName, NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
void *buffer = malloc(CHUNK);
unsigned int len = 0;
while (!feof(input))
{
len = (unsigned int) fread(buffer, 1, CHUNK, input);
zipWriteInFileInZip(_zip, buffer, len);
}
zipCloseFileInZip(_zip);
free(buffer);
return YES;
@@ -301,7 +496,7 @@
if (!data) {
return NO;
}
zip_fileinfo zipInfo = {0};
zip_fileinfo zipInfo = {{0,0,0,0,0,0},0,0,0};
[self zipInfo:&zipInfo setDate:[NSDate date]];
zipOpenNewFileInZip(_zip, [filename UTF8String], &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);