145 lines
4.0 KiB
Objective-C
145 lines
4.0 KiB
Objective-C
//
|
|
// SUPipedUnarchiver.m
|
|
// Sparkle
|
|
//
|
|
// Created by Andy Matuschak on 6/16/08.
|
|
// Copyright 2008 Andy Matuschak. All rights reserved.
|
|
//
|
|
|
|
#import "SUPipedUnarchiver.h"
|
|
#import "SUUnarchiver_Private.h"
|
|
#import "SULog.h"
|
|
|
|
|
|
@implementation SUPipedUnarchiver
|
|
|
|
+ (SEL)selectorConformingToTypeOfPath:(NSString *)path
|
|
{
|
|
static NSDictionary *typeSelectorDictionary;
|
|
if (!typeSelectorDictionary)
|
|
typeSelectorDictionary = [[NSDictionary dictionaryWithObjectsAndKeys:@"extractZIP", @".zip", @"extractTAR", @".tar",
|
|
@"extractTGZ", @".tar.gz", @"extractTGZ", @".tgz",
|
|
@"extractTBZ", @".tar.bz2", @"extractTBZ", @".tbz", nil] retain];
|
|
|
|
NSString *lastPathComponent = [path lastPathComponent];
|
|
NSEnumerator *typeEnumerator = [typeSelectorDictionary keyEnumerator];
|
|
id currentType;
|
|
while ((currentType = [typeEnumerator nextObject]))
|
|
{
|
|
if ([currentType length] > [lastPathComponent length]) continue;
|
|
if ([[lastPathComponent substringFromIndex:[lastPathComponent length] - [currentType length]] isEqualToString:currentType])
|
|
return NSSelectorFromString([typeSelectorDictionary objectForKey:currentType]);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
- (void)start
|
|
{
|
|
[NSThread detachNewThreadSelector:[[self class] selectorConformingToTypeOfPath:archivePath] toTarget:self withObject:nil];
|
|
}
|
|
|
|
+ (BOOL)canUnarchivePath:(NSString *)path
|
|
{
|
|
return ([self selectorConformingToTypeOfPath:path] != nil);
|
|
}
|
|
|
|
// This method abstracts the types that use a command line tool piping data from stdin.
|
|
- (void)extractArchivePipingDataToCommand:(NSString *)command
|
|
{
|
|
// *** GETS CALLED ON NON-MAIN THREAD!!!
|
|
|
|
|
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
FILE *fp = NULL, *cmdFP = NULL;
|
|
char *oldDestinationString = NULL;
|
|
|
|
SULog(@"Extracting %@ using '%@'",archivePath,command);
|
|
|
|
// Get the file size.
|
|
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
|
|
NSNumber *fs = [[[NSFileManager defaultManager] fileAttributesAtPath:archivePath traverseLink:NO] objectForKey:NSFileSize];
|
|
#else
|
|
NSNumber *fs = [[[NSFileManager defaultManager] attributesOfItemAtPath:archivePath error:nil] objectForKey:NSFileSize];
|
|
#endif
|
|
if (fs == nil) goto reportError;
|
|
|
|
// Thank you, Allan Odgaard!
|
|
// (who wrote the following extraction alg.)
|
|
fp = fopen([archivePath fileSystemRepresentation], "r");
|
|
if (!fp) goto reportError;
|
|
|
|
oldDestinationString = getenv("DESTINATION");
|
|
setenv("DESTINATION", [[archivePath stringByDeletingLastPathComponent] fileSystemRepresentation], 1);
|
|
cmdFP = popen([command fileSystemRepresentation], "w");
|
|
size_t written;
|
|
if (!cmdFP) goto reportError;
|
|
|
|
char buf[32*1024];
|
|
size_t len;
|
|
while((len = fread(buf, 1, 32*1024, fp)))
|
|
{
|
|
written = fwrite(buf, 1, len, cmdFP);
|
|
if( written < len )
|
|
{
|
|
pclose(cmdFP);
|
|
goto reportError;
|
|
}
|
|
|
|
[self performSelectorOnMainThread:@selector(notifyDelegateOfExtractedLength:) withObject:[NSNumber numberWithUnsignedLong:len] waitUntilDone:NO];
|
|
}
|
|
pclose(cmdFP);
|
|
|
|
if( ferror( fp ) )
|
|
goto reportError;
|
|
|
|
[self performSelectorOnMainThread:@selector(notifyDelegateOfSuccess) withObject:nil waitUntilDone:NO];
|
|
goto finally;
|
|
|
|
reportError:
|
|
[self performSelectorOnMainThread:@selector(notifyDelegateOfFailure) withObject:nil waitUntilDone:NO];
|
|
|
|
finally:
|
|
if (fp)
|
|
fclose(fp);
|
|
if (oldDestinationString)
|
|
setenv("DESTINATION", oldDestinationString, 1);
|
|
else
|
|
unsetenv("DESTINATION");
|
|
[pool release];
|
|
}
|
|
|
|
- (void)extractTAR
|
|
{
|
|
// *** GETS CALLED ON NON-MAIN THREAD!!!
|
|
|
|
return [self extractArchivePipingDataToCommand:@"tar -xC \"$DESTINATION\""];
|
|
}
|
|
|
|
- (void)extractTGZ
|
|
{
|
|
// *** GETS CALLED ON NON-MAIN THREAD!!!
|
|
|
|
return [self extractArchivePipingDataToCommand:@"tar -zxC \"$DESTINATION\""];
|
|
}
|
|
|
|
- (void)extractTBZ
|
|
{
|
|
// *** GETS CALLED ON NON-MAIN THREAD!!!
|
|
|
|
return [self extractArchivePipingDataToCommand:@"tar -jxC \"$DESTINATION\""];
|
|
}
|
|
|
|
- (void)extractZIP
|
|
{
|
|
// *** GETS CALLED ON NON-MAIN THREAD!!!
|
|
|
|
return [self extractArchivePipingDataToCommand:@"ditto -x -k - \"$DESTINATION\""];
|
|
}
|
|
|
|
+ (void)load
|
|
{
|
|
[self registerImplementation:self];
|
|
}
|
|
|
|
@end
|