692 lines
22 KiB
Objective-C
692 lines
22 KiB
Objective-C
/**
|
|
// ZipArchive.m
|
|
//
|
|
//
|
|
// Created by aish on 08-9-11.
|
|
// acsolu@gmail.com
|
|
// Copyright 2008 Inc. All rights reserved.
|
|
//
|
|
*/
|
|
|
|
#import "ZipArchive.h"
|
|
#import "zlib.h"
|
|
#import "zconf.h"
|
|
#include "minizip/zip.h"
|
|
#include "minizip/unzip.h"
|
|
|
|
|
|
@interface NSFileManager(ZipArchive)
|
|
- (NSDictionary *)_attributesOfItemAtPath:(NSString *)path followingSymLinks:(BOOL)followingSymLinks error:(NSError **)error;
|
|
@end
|
|
|
|
@interface ZipArchive ()
|
|
|
|
-(void) OutputErrorMessage:(NSString*) msg;
|
|
-(BOOL) OverWrite:(NSString*) file;
|
|
-(NSDate*) Date1980;
|
|
|
|
@property (nonatomic,copy) NSString* password;
|
|
@end
|
|
|
|
|
|
|
|
@implementation ZipArchive
|
|
@synthesize delegate = _delegate;
|
|
@synthesize numFiles = _numFiles;
|
|
@synthesize password = _password;
|
|
@synthesize unzippedFiles = _unzippedFiles;
|
|
@synthesize progressBlock = _progressBlock;
|
|
@synthesize stringEncoding = _stringEncoding;
|
|
|
|
-(id) init
|
|
{
|
|
return [self initWithFileManager:[NSFileManager defaultManager]];
|
|
}
|
|
|
|
-(id) initWithFileManager:(NSFileManager*) fileManager
|
|
{
|
|
if( self=[super init] )
|
|
{
|
|
_zipFile = NULL;
|
|
_fileManager = fileManager;
|
|
self.stringEncoding = NSUTF8StringEncoding;
|
|
self.compression = ZipArchiveCompressionDefault;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void) dealloc
|
|
{
|
|
// close any open file operations
|
|
[self CloseZipFile2];
|
|
[self UnzipCloseFile];
|
|
|
|
// release retained/copied properties.
|
|
[_password release];
|
|
[_delegate release];
|
|
[_unzippedFiles release];
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
/**
|
|
* Create a new zip file at the specified path, ready for new files to be added.
|
|
*
|
|
* @param zipFile the path of the zip file to create
|
|
* @returns BOOL YES on success
|
|
*/
|
|
|
|
-(BOOL) CreateZipFile2:(NSString*) zipFile
|
|
{
|
|
return [self CreateZipFile2:zipFile append:NO];
|
|
}
|
|
|
|
-(BOOL) CreateZipFile2:(NSString*) zipFile append:(BOOL)isAppend
|
|
{
|
|
_zipFile = zipOpen( (const char*)[zipFile UTF8String], (isAppend ? APPEND_STATUS_ADDINZIP : APPEND_STATUS_CREATE) );
|
|
if( !_zipFile )
|
|
return NO;
|
|
return YES;
|
|
}
|
|
|
|
/**
|
|
* Create a new zip file at the specified path, ready for new files to be added.
|
|
*
|
|
* @param zipFile the path of the zip file to create
|
|
* @param password a password used to encrypt the zip file
|
|
* @returns BOOL YES on success
|
|
*/
|
|
|
|
-(BOOL) CreateZipFile2:(NSString*) zipFile Password:(NSString*) password
|
|
{
|
|
self.password = password;
|
|
return [self CreateZipFile2:zipFile];
|
|
}
|
|
|
|
-(BOOL) CreateZipFile2:(NSString*) zipFile Password:(NSString*) password append:(BOOL)isAppend
|
|
{
|
|
self.password = password;
|
|
return [self CreateZipFile2:zipFile append:isAppend];
|
|
}
|
|
|
|
/**
|
|
* add an existing file on disk to the zip archive, compressing it.
|
|
*
|
|
* @param file the path to the file to compress
|
|
* @param newname the name of the file in the zip archive, ie: path relative to the zip archive root.
|
|
* @returns BOOL YES on success
|
|
*/
|
|
|
|
-(BOOL) addFileToZip:(NSString*) file newname:(NSString*) newname;
|
|
{
|
|
NSData *data = [NSData dataWithContentsOfFile:file];
|
|
NSError* error = nil;
|
|
NSDictionary* attr = [_fileManager _attributesOfItemAtPath:file followingSymLinks:YES error:&error];
|
|
BOOL result = [self addDataToZip:data fileAttributes:attr newname:newname];
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* add an existing file on disk to the zip archive, compressing it.
|
|
*
|
|
* @param data the data to compress
|
|
* @param attr the file attribute for data to add as file
|
|
* @param newname the name of the file in the zip archive, ie: path relative to the zip archive root.
|
|
* @returns BOOL YES on success
|
|
*/
|
|
|
|
-(BOOL) addDataToZip:(NSData*) data fileAttributes:(NSDictionary *)attr newname:(NSString*) newname
|
|
{
|
|
if (!data)
|
|
{
|
|
return NO;
|
|
}
|
|
if( !_zipFile )
|
|
return NO;
|
|
// tm_zip filetime;
|
|
|
|
zip_fileinfo zipInfo = {{0}};
|
|
|
|
NSDate* fileDate = nil;
|
|
|
|
if( attr )
|
|
fileDate = (NSDate*)[attr objectForKey:NSFileModificationDate];
|
|
|
|
if( fileDate == nil )
|
|
fileDate = [NSDate date];
|
|
|
|
|
|
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
|
|
NSDateComponents* components = [gregorianCalendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay |
|
|
NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:fileDate];
|
|
[gregorianCalendar release];
|
|
|
|
zipInfo.tmz_date.tm_sec = (uInt)components.second;
|
|
zipInfo.tmz_date.tm_min = (uInt)components.minute;
|
|
zipInfo.tmz_date.tm_hour = (uInt)components.hour;
|
|
zipInfo.tmz_date.tm_mday = (uInt)components.day;
|
|
zipInfo.tmz_date.tm_mon = (uInt)components.month;
|
|
zipInfo.tmz_date.tm_year = (uInt)components.year;
|
|
|
|
|
|
int ret ;
|
|
if( [_password length] == 0 )
|
|
{
|
|
ret = zipOpenNewFileInZip( _zipFile,
|
|
(const char*) [newname cStringUsingEncoding:self.stringEncoding],
|
|
&zipInfo,
|
|
NULL,0,
|
|
NULL,0,
|
|
NULL,//comment
|
|
Z_DEFLATED,
|
|
self.compression );
|
|
}
|
|
else
|
|
{
|
|
uLong crcValue = crc32( 0L,NULL, 0L );
|
|
crcValue = crc32( crcValue, (const Bytef*)[data bytes], (unsigned int)[data length] );
|
|
ret = zipOpenNewFileInZip3( _zipFile,
|
|
(const char*) [newname cStringUsingEncoding:self.stringEncoding],
|
|
&zipInfo,
|
|
NULL,0,
|
|
NULL,0,
|
|
NULL,//comment
|
|
Z_DEFLATED,
|
|
self.compression,
|
|
0,
|
|
15,
|
|
8,
|
|
Z_DEFAULT_STRATEGY,
|
|
[_password cStringUsingEncoding:NSASCIIStringEncoding],
|
|
crcValue );
|
|
}
|
|
if( ret!=Z_OK )
|
|
{
|
|
return NO;
|
|
}
|
|
unsigned int dataLen = (unsigned int)[data length];
|
|
ret = zipWriteInFileInZip( _zipFile, (const void*)[data bytes], dataLen);
|
|
if( ret!=Z_OK )
|
|
{
|
|
return NO;
|
|
}
|
|
ret = zipCloseFileInZip( _zipFile );
|
|
if( ret!=Z_OK )
|
|
return NO;
|
|
return YES;
|
|
}
|
|
|
|
/**
|
|
* Close a zip file after creating and added files to it.
|
|
*
|
|
* @returns BOOL YES on success
|
|
*/
|
|
|
|
-(BOOL) CloseZipFile2
|
|
{
|
|
self.password = nil;
|
|
if( _zipFile==NULL )
|
|
return NO;
|
|
BOOL ret = zipClose( _zipFile,NULL )==Z_OK?YES:NO;
|
|
_zipFile = NULL;
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* open an existing zip file ready for expanding.
|
|
*
|
|
* @param zipFile the path to a zip file to be opened.
|
|
* @returns BOOL YES on success
|
|
*/
|
|
|
|
-(BOOL) UnzipOpenFile:(NSString*) zipFile
|
|
{
|
|
// create an array to receive the list of unzipped files.
|
|
if (_unzippedFiles) [_unzippedFiles release];
|
|
_unzippedFiles = [[NSMutableArray alloc] initWithCapacity:1];
|
|
|
|
_unzFile = unzOpen( (const char*)[zipFile UTF8String] );
|
|
if( _unzFile )
|
|
{
|
|
unz_global_info globalInfo = {0};
|
|
if( unzGetGlobalInfo(_unzFile, &globalInfo )==UNZ_OK )
|
|
{
|
|
_numFiles = globalInfo.number_entry;
|
|
NSLog(@"%lu entries in the zip file", globalInfo.number_entry);
|
|
}
|
|
}
|
|
return _unzFile!=NULL;
|
|
}
|
|
|
|
/**
|
|
* open an existing zip file with a password ready for expanding.
|
|
*
|
|
* @param zipFile the path to a zip file to be opened.
|
|
* @param password the password to use decrpyting the file.
|
|
* @returns BOOL YES on success
|
|
*/
|
|
|
|
-(BOOL) UnzipOpenFile:(NSString*) zipFile Password:(NSString*) password
|
|
{
|
|
self.password = password;
|
|
return [self UnzipOpenFile:zipFile];
|
|
}
|
|
|
|
/**
|
|
* Expand all files in the zip archive into the specified directory.
|
|
*
|
|
* If a delegate has been set and responds to OverWriteOperation: it can
|
|
* return YES to overwrite a file, or NO to skip that file.
|
|
*
|
|
* On completion, the property `unzippedFiles` will be an array populated
|
|
* with the full paths of each file that was successfully expanded.
|
|
*
|
|
* @param path the directory where expanded files will be created
|
|
* @param overwrite should existing files be overwritten
|
|
* @returns BOOL YES on success
|
|
*/
|
|
|
|
-(BOOL) UnzipFileTo:(NSString*) path overWrite:(BOOL) overwrite
|
|
{
|
|
BOOL success = YES;
|
|
int index = 0;
|
|
int progress = -1;
|
|
int ret = unzGoToFirstFile( _unzFile );
|
|
unsigned char buffer[4096] = {0};
|
|
if( ret!=UNZ_OK )
|
|
{
|
|
[self OutputErrorMessage:@"Failed"];
|
|
}
|
|
|
|
const char* password = [_password cStringUsingEncoding:NSASCIIStringEncoding];
|
|
|
|
do{
|
|
@autoreleasepool {
|
|
if( [_password length]==0 )
|
|
ret = unzOpenCurrentFile( _unzFile );
|
|
else
|
|
ret = unzOpenCurrentFilePassword( _unzFile, password );
|
|
if( ret!=UNZ_OK )
|
|
{
|
|
[self OutputErrorMessage:@"Error occurs"];
|
|
success = NO;
|
|
break;
|
|
}
|
|
// reading data and write to file
|
|
int read ;
|
|
unz_file_info fileInfo ={0};
|
|
ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
|
|
if( ret!=UNZ_OK )
|
|
{
|
|
[self OutputErrorMessage:@"Error occurs while getting file info"];
|
|
success = NO;
|
|
unzCloseCurrentFile( _unzFile );
|
|
break;
|
|
}
|
|
char* filename = (char*) malloc( fileInfo.size_filename +1 );
|
|
unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
|
|
filename[fileInfo.size_filename] = '\0';
|
|
|
|
// check if it contains directory
|
|
NSString * strPath = [NSString stringWithCString:filename encoding:self.stringEncoding];
|
|
BOOL isDirectory = NO;
|
|
if( filename[fileInfo.size_filename-1]=='/' || filename[fileInfo.size_filename-1]=='\\')
|
|
isDirectory = YES;
|
|
free( filename );
|
|
if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound )
|
|
{// contains a path
|
|
strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
|
|
}
|
|
NSString* fullPath = [path stringByAppendingPathComponent:strPath];
|
|
|
|
if( isDirectory )
|
|
[_fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil];
|
|
else
|
|
[_fileManager createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
|
|
|
|
FILE* fp = NULL;
|
|
do
|
|
{
|
|
read = unzReadCurrentFile(_unzFile, buffer, 4096);
|
|
if (read >= 0)
|
|
{
|
|
if (fp == NULL) {
|
|
if( [_fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite )
|
|
{
|
|
if( ![self OverWrite:fullPath] )
|
|
{
|
|
// don't process any more of the file, but continue
|
|
break;
|
|
}
|
|
}
|
|
if (!isDirectory) {
|
|
fp = fopen( (const char*)[fullPath UTF8String], "wb");
|
|
if (fp == NULL) {
|
|
[self OutputErrorMessage:@"Failed to open output file for writing"];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fwrite(buffer, read, 1, fp );
|
|
}
|
|
else // if (read < 0)
|
|
{
|
|
ret = read; // result will be an error code
|
|
success = NO;
|
|
[self OutputErrorMessage:@"Failed to read zip file"];
|
|
}
|
|
} while (read > 0);
|
|
|
|
if (fp)
|
|
{
|
|
fclose( fp );
|
|
|
|
// add the full path of this file to the output array
|
|
[(NSMutableArray*)_unzippedFiles addObject:fullPath];
|
|
|
|
// set the orignal datetime property
|
|
if( fileInfo.tmu_date.tm_year!=0 )
|
|
{
|
|
NSDateComponents* components = [[NSDateComponents alloc] init];
|
|
components.second = fileInfo.tmu_date.tm_sec;
|
|
components.minute = fileInfo.tmu_date.tm_min;
|
|
components.hour = fileInfo.tmu_date.tm_hour;
|
|
components.day = fileInfo.tmu_date.tm_mday;
|
|
components.month = fileInfo.tmu_date.tm_mon + 1;
|
|
components.year = fileInfo.tmu_date.tm_year;
|
|
|
|
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
|
|
NSDate* orgDate = [[gregorianCalendar dateFromComponents:components] retain];
|
|
[components release];
|
|
[gregorianCalendar release];
|
|
|
|
NSDictionary* attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate]; //[_fileManager fileAttributesAtPath:fullPath traverseLink:YES];
|
|
if( attr )
|
|
{
|
|
// [attr setValue:orgDate forKey:NSFileCreationDate];
|
|
if( ![_fileManager setAttributes:attr ofItemAtPath:fullPath error:nil] )
|
|
{
|
|
// cann't set attributes
|
|
NSLog(@"Failed to set attributes");
|
|
}
|
|
|
|
}
|
|
[orgDate release];
|
|
orgDate = nil;
|
|
}
|
|
|
|
}
|
|
|
|
if (ret == UNZ_OK) {
|
|
ret = unzCloseCurrentFile( _unzFile );
|
|
if (ret != UNZ_OK) {
|
|
[self OutputErrorMessage:@"file was unzipped but failed crc check"];
|
|
success = NO;
|
|
}
|
|
}
|
|
|
|
if (ret == UNZ_OK) {
|
|
ret = unzGoToNextFile( _unzFile );
|
|
}
|
|
|
|
if (_progressBlock && _numFiles) {
|
|
index++;
|
|
int p = index*100/_numFiles;
|
|
progress = p;
|
|
_progressBlock(progress, index, _numFiles);
|
|
}
|
|
}
|
|
} while (ret==UNZ_OK && ret!=UNZ_END_OF_LIST_OF_FILE);
|
|
return success;
|
|
}
|
|
|
|
-(NSDictionary *)UnzipFileToMemory
|
|
{
|
|
NSMutableDictionary *fileDictionary = [NSMutableDictionary dictionary];
|
|
|
|
BOOL success = YES;
|
|
int index = 0;
|
|
int progress = -1;
|
|
int ret = unzGoToFirstFile( _unzFile );
|
|
unsigned char buffer[4096] = {0};
|
|
if( ret!=UNZ_OK )
|
|
{
|
|
[self OutputErrorMessage:@"Failed"];
|
|
}
|
|
|
|
const char* password = [_password cStringUsingEncoding:NSASCIIStringEncoding];
|
|
|
|
do{
|
|
@autoreleasepool {
|
|
if( [_password length]==0 )
|
|
ret = unzOpenCurrentFile( _unzFile );
|
|
else
|
|
ret = unzOpenCurrentFilePassword( _unzFile, password );
|
|
if( ret!=UNZ_OK )
|
|
{
|
|
[self OutputErrorMessage:@"Error occurs"];
|
|
success = NO;
|
|
break;
|
|
}
|
|
// reading data and write to file
|
|
int read ;
|
|
unz_file_info fileInfo ={0};
|
|
ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
|
|
if( ret!=UNZ_OK )
|
|
{
|
|
[self OutputErrorMessage:@"Error occurs while getting file info"];
|
|
success = NO;
|
|
unzCloseCurrentFile( _unzFile );
|
|
break;
|
|
}
|
|
char* filename = (char*) malloc( fileInfo.size_filename +1 );
|
|
unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
|
|
filename[fileInfo.size_filename] = '\0';
|
|
|
|
// check if it contains directory
|
|
NSString * strPath = [NSString stringWithCString:filename encoding:self.stringEncoding];
|
|
free( filename );
|
|
if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound )
|
|
{// contains a path
|
|
strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
|
|
}
|
|
|
|
NSMutableData *fileMutableData = [NSMutableData data];
|
|
do
|
|
{
|
|
read = unzReadCurrentFile(_unzFile, buffer, 4096);
|
|
if (read >= 0)
|
|
{
|
|
if (read != 0)
|
|
{
|
|
[fileMutableData appendBytes:buffer length:read];
|
|
}
|
|
}
|
|
else // if (read < 0)
|
|
{
|
|
ret = read; // result will be an error code
|
|
success = NO;
|
|
[self OutputErrorMessage:@"Failed to read zip file"];
|
|
}
|
|
} while (read > 0);
|
|
|
|
|
|
if (fileMutableData.length > 0)
|
|
{
|
|
NSData *fileData = [NSData dataWithData:fileMutableData];
|
|
[fileDictionary setObject:fileData forKey:strPath];
|
|
}
|
|
|
|
if (ret == UNZ_OK) {
|
|
ret = unzCloseCurrentFile( _unzFile );
|
|
if (ret != UNZ_OK) {
|
|
[self OutputErrorMessage:@"file was unzipped but failed crc check"];
|
|
success = NO;
|
|
}
|
|
}
|
|
|
|
if (ret == UNZ_OK) {
|
|
ret = unzGoToNextFile( _unzFile );
|
|
}
|
|
|
|
if (_progressBlock && _numFiles) {
|
|
index++;
|
|
int p = index*100/_numFiles;
|
|
progress = p;
|
|
_progressBlock(progress, index, _numFiles);
|
|
}
|
|
}
|
|
} while (ret==UNZ_OK && ret!=UNZ_END_OF_LIST_OF_FILE);
|
|
|
|
NSDictionary *resultDictionary = [NSDictionary dictionaryWithDictionary:fileDictionary];
|
|
return resultDictionary;
|
|
}
|
|
|
|
/**
|
|
* Close the zip file.
|
|
*
|
|
* @returns BOOL YES on success
|
|
*/
|
|
|
|
-(BOOL) UnzipCloseFile
|
|
{
|
|
self.password = nil;
|
|
if( _unzFile ) {
|
|
int err = unzClose( _unzFile );
|
|
_unzFile = nil;
|
|
return err ==UNZ_OK;
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return a list of filenames that are in the zip archive.
|
|
* No path information is available as this can be called before the zip is expanded.
|
|
*
|
|
* @returns NSArray list of filenames in the zip archive.
|
|
*/
|
|
|
|
-(NSArray*) getZipFileContents // list the contents of the zip archive. must be called after UnzipOpenFile
|
|
{
|
|
int ret = unzGoToFirstFile( _unzFile );
|
|
NSMutableArray * allFilenames = [NSMutableArray arrayWithCapacity:40];
|
|
|
|
if( ret!=UNZ_OK )
|
|
{
|
|
[self OutputErrorMessage:@"Failed"];
|
|
}
|
|
|
|
const char* password = [_password cStringUsingEncoding:NSASCIIStringEncoding];
|
|
|
|
do{
|
|
if( [_password length]==0 )
|
|
ret = unzOpenCurrentFile( _unzFile );
|
|
else
|
|
ret = unzOpenCurrentFilePassword( _unzFile, password );
|
|
if( ret!=UNZ_OK )
|
|
{
|
|
[self OutputErrorMessage:@"Error occured"];
|
|
break;
|
|
}
|
|
|
|
// reading data and write to file
|
|
unz_file_info fileInfo ={0};
|
|
ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
|
|
if( ret!=UNZ_OK )
|
|
{
|
|
[self OutputErrorMessage:@"Error occurs while getting file info"];
|
|
unzCloseCurrentFile( _unzFile );
|
|
break;
|
|
}
|
|
char* filename = (char*) malloc( fileInfo.size_filename +1 );
|
|
unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
|
|
filename[fileInfo.size_filename] = '\0';
|
|
|
|
// check if it contains directory
|
|
NSString * strPath = [NSString stringWithCString:filename encoding:NSASCIIStringEncoding];
|
|
free( filename );
|
|
if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound )
|
|
{// contains a path
|
|
strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
|
|
}
|
|
|
|
// Copy name to array
|
|
[allFilenames addObject:strPath];
|
|
|
|
unzCloseCurrentFile( _unzFile );
|
|
ret = unzGoToNextFile( _unzFile );
|
|
} while( ret==UNZ_OK && UNZ_OK!=UNZ_END_OF_LIST_OF_FILE );
|
|
|
|
// return an immutable array.
|
|
return [NSArray arrayWithArray:allFilenames];
|
|
}
|
|
|
|
|
|
#pragma mark wrapper for delegate
|
|
|
|
/**
|
|
* send the ErrorMessage: to the delegate if it responds to it.
|
|
*/
|
|
-(void) OutputErrorMessage:(NSString*) msg
|
|
{
|
|
if( _delegate && [_delegate respondsToSelector:@selector(ErrorMessage:)] )
|
|
[_delegate ErrorMessage:msg];
|
|
}
|
|
|
|
/**
|
|
* send the OverWriteOperation: selector to the delegate if it responds to it,
|
|
* returning the result, or YES by default.
|
|
*/
|
|
|
|
-(BOOL) OverWrite:(NSString*) file
|
|
{
|
|
if( _delegate && [_delegate respondsToSelector:@selector(OverWriteOperation:)] )
|
|
return [_delegate OverWriteOperation:file];
|
|
return YES;
|
|
}
|
|
|
|
#pragma mark get NSDate object for 1980-01-01
|
|
-(NSDate*) Date1980
|
|
{
|
|
NSDateComponents *comps = [[NSDateComponents alloc] init];
|
|
[comps setDay:1];
|
|
[comps setMonth:1];
|
|
[comps setYear:1980];
|
|
NSCalendar *gregorian = [[NSCalendar alloc]
|
|
initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
|
|
NSDate *date = [gregorian dateFromComponents:comps];
|
|
|
|
[comps release];
|
|
[gregorian release];
|
|
return date;
|
|
}
|
|
|
|
|
|
@end
|
|
|
|
|
|
@implementation NSFileManager(ZipArchive)
|
|
|
|
- (NSDictionary *)_attributesOfItemAtPath:(NSString *)path followingSymLinks:(BOOL)followingSymLinks error:(NSError **)error
|
|
{
|
|
// call file manager default action, which is to not follow symlinks
|
|
NSDictionary* results = [self attributesOfItemAtPath:path error:error];
|
|
if (followingSymLinks && results && (error ? *error == nil : YES)) {
|
|
if ([[results fileType] isEqualToString:NSFileTypeSymbolicLink]) {
|
|
// follow the symlink
|
|
NSString* realPath = [self destinationOfSymbolicLinkAtPath:path error:error];
|
|
if (realPath && (error ? *error == nil : YES)) {
|
|
return [self _attributesOfItemAtPath:realPath followingSymLinks:followingSymLinks error:error];
|
|
} else {
|
|
// failure to resolve symlink should be an error returning nil and error will already be set.
|
|
return nil;
|
|
}
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
@end
|
|
|