Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 124 lines (101 sloc) 3.556 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
//
// 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"

@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
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
FILE *fp = NULL, *cmdFP = NULL;

// 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;

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);
[pool drain];
}

- (void)extractTAR
{
return [self extractArchivePipingDataToCommand:@"tar -xC \"$DESTINATION\""];
}

- (void)extractTGZ
{
return [self extractArchivePipingDataToCommand:@"tar -zxC \"$DESTINATION\""];
}

- (void)extractTBZ
{
return [self extractArchivePipingDataToCommand:@"tar -jxC \"$DESTINATION\""];
}

- (void)extractZIP
{
return [self extractArchivePipingDataToCommand:@"ditto -x -k - \"$DESTINATION\""];
}

+ (void)load
{
[self registerImplementation:self];
}

@end
Something went wrong with that request. Please try again.