| | 183 | |
|---|
| | 184 | /* Shamelessly ripped from Sparkle */ |
|---|
| | 185 | - (BOOL)_extractArchivePath:archivePath toDestination:(NSString *)destination pipingDataToCommand:(NSString *)command |
|---|
| | 186 | { |
|---|
| | 187 | // Get the file size. |
|---|
| | 188 | NSNumber *fs = [[[NSFileManager defaultManager] fileAttributesAtPath:archivePath traverseLink:NO] objectForKey:NSFileSize]; |
|---|
| | 189 | if (fs == nil) { return NO; } |
|---|
| | 190 | |
|---|
| | 191 | // Thank you, Allan Odgaard! |
|---|
| | 192 | // (who wrote the following extraction alg.) |
|---|
| | 193 | |
|---|
| | 194 | long current = 0; |
|---|
| | 195 | FILE *fp, *cmdFP; |
|---|
| | 196 | sig_t oldSigPipeHandler = signal(SIGPIPE, SIG_IGN); |
|---|
| | 197 | if ((fp = fopen([archivePath UTF8String], "r"))) |
|---|
| | 198 | { |
|---|
| | 199 | setenv("DESTINATION", [destination fileSystemRepresentation], 1); |
|---|
| | 200 | if ((cmdFP = popen([command cString], "w"))) |
|---|
| | 201 | { |
|---|
| | 202 | char buf[32*1024]; |
|---|
| | 203 | long len; |
|---|
| | 204 | while((len = fread(buf, 1, 32 * 1024, fp))) |
|---|
| | 205 | { |
|---|
| | 206 | current += len; |
|---|
| | 207 | |
|---|
| | 208 | fwrite(buf, 1, len, cmdFP); |
|---|
| | 209 | |
|---|
| | 210 | } |
|---|
| | 211 | pclose(cmdFP); |
|---|
| | 212 | } |
|---|
| | 213 | fclose(fp); |
|---|
| | 214 | } |
|---|
| | 215 | signal(SIGPIPE, oldSigPipeHandler); |
|---|
| | 216 | return YES; |
|---|
| | 217 | } |
|---|
| | 218 | |
|---|
| | 219 | - (BOOL)installArchive:(NSString *)archivePath forPiece:(NSString *)component type:(ComponentType)type withMyVersion:(NSString *)myVersion andAuthorization:(AuthorizationRef *)auth |
|---|
| | 220 | { |
|---|
| | 221 | NSString *containingDir = nil; |
|---|
| | 222 | switch(type) |
|---|
| | 223 | { |
|---|
| | 224 | case ComponentTypeCoreAudio: |
|---|
| | 225 | containingDir = [self coreAudioComponentDir]; |
|---|
| | 226 | break; |
|---|
| | 227 | case ComponentTypeQuickTime: |
|---|
| | 228 | containingDir = [self quickTimeComponentDir]; |
|---|
| | 229 | break; |
|---|
| | 230 | } |
|---|
| | 231 | InstallStatus pieceStatus = [self installStatusForComponent:component type:type withMyVersion:myVersion]; |
|---|
| | 232 | if(pieceStatus == InstallStatusOutdated) |
|---|
| | 233 | { |
|---|
| | 234 | //Remove the old one here |
|---|
| | 235 | //XXX what about authorized |
|---|
| | 236 | int tag = 0; |
|---|
| | 237 | BOOL result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:containingDir destination:@"" files:[NSArray arrayWithObject:component] tag:&tag]; |
|---|
| | 238 | if(result == NO) |
|---|
| | 239 | return NO; |
|---|
| | 240 | } |
|---|
| | 241 | if(pieceStatus != InstallStatusInstalled) |
|---|
| | 242 | { |
|---|
| | 243 | //Decompress and install new one |
|---|
| | 244 | //XXX Need to do authorized version as well |
|---|
| | 245 | BOOL result = [self _extractArchivePath:archivePath toDestination:containingDir pipingDataToCommand:@"ditto -x -k - \"$DESTINATION\""]; |
|---|
| | 246 | if(result == NO) |
|---|
| | 247 | return NO; |
|---|
| | 248 | } |
|---|
| | 249 | return YES; |
|---|
| | 250 | } |
|---|
| | 251 | |
|---|
| | 252 | - (void)install:(id)sender |
|---|
| | 253 | { |
|---|
| | 254 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|---|
| | 255 | NSDictionary *infoDict = [[self bundle] infoDictionary]; |
|---|
| | 256 | NSDictionary *myComponentsInfo = [infoDict objectForKey:ComponentInfoDictionaryKey]; |
|---|
| | 257 | NSString *componentPath = [[[self bundle] resourcePath] stringByAppendingPathComponent:@"Components"]; |
|---|
| | 258 | NSString *coreAudioComponentPath = [componentPath stringByAppendingPathComponent:@"CoreAudio"]; |
|---|
| | 259 | NSString *quickTimeComponentPath = [componentPath stringByAppendingPathComponent:@"QuickTime"]; |
|---|
| | 260 | |
|---|
| | 261 | [self installArchive:[componentPath stringByAppendingPathComponent:@"Perian.zip"] forPiece:@"Perian.component" type:ComponentTypeQuickTime withMyVersion:[infoDict objectForKey:BundleVersionKey] andAuthorization:NULL]; |
|---|
| | 262 | |
|---|
| | 263 | NSEnumerator *componentEnum = [myComponentsInfo objectEnumerator]; |
|---|
| | 264 | NSDictionary *myComponent = nil; |
|---|
| | 265 | while((myComponent = [componentEnum nextObject]) != nil) |
|---|
| | 266 | { |
|---|
| | 267 | NSString *archivePath = nil; |
|---|
| | 268 | ComponentType type = [[myComponent objectForKey:ComponentTypeKey] intValue]; |
|---|
| | 269 | switch(type) |
|---|
| | 270 | { |
|---|
| | 271 | case ComponentTypeCoreAudio: |
|---|
| | 272 | archivePath = [coreAudioComponentPath stringByAppendingPathComponent:[myComponent objectForKey:ComponentArchiveNameKey]]; |
|---|
| | 273 | break; |
|---|
| | 274 | case ComponentTypeQuickTime: |
|---|
| | 275 | archivePath = [quickTimeComponentPath stringByAppendingPathComponent:[myComponent objectForKey:ComponentArchiveNameKey]]; |
|---|
| | 276 | break; |
|---|
| | 277 | } |
|---|
| | 278 | [self installArchive:archivePath forPiece:[myComponent objectForKey:ComponentNameKey] type:type withMyVersion:[myComponent objectForKey:BundleVersionKey] andAuthorization:NULL]; |
|---|
| | 279 | } |
|---|
| | 280 | [self performSelectorOnMainThread:@selector(installComplete:) withObject:nil waitUntilDone:NO]; |
|---|
| | 281 | [pool release]; |
|---|
| | 282 | } |
|---|
| | 283 | |
|---|
| | 284 | - (void)uninstall:(id)sender |
|---|
| | 285 | { |
|---|
| | 286 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|---|
| | 287 | NSDictionary *infoDict = [[self bundle] infoDictionary]; |
|---|
| | 288 | NSDictionary *myComponentsInfo = [infoDict objectForKey:ComponentInfoDictionaryKey]; |
|---|
| | 289 | |
|---|
| | 290 | //XXX what about authorized |
|---|
| | 291 | int tag = 0; |
|---|
| | 292 | BOOL result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[self quickTimeComponentDir] destination:@"" files:[NSArray arrayWithObject:@"Perian.component"] tag:&tag]; |
|---|
| | 293 | |
|---|
| | 294 | NSEnumerator *componentEnum = [myComponentsInfo objectEnumerator]; |
|---|
| | 295 | NSDictionary *myComponent = nil; |
|---|
| | 296 | while((myComponent = [componentEnum nextObject]) != nil) |
|---|
| | 297 | { |
|---|
| | 298 | ComponentType type = [[myComponent objectForKey:ComponentTypeKey] intValue]; |
|---|
| | 299 | NSString *directory = nil; |
|---|
| | 300 | switch(type) |
|---|
| | 301 | { |
|---|
| | 302 | case ComponentTypeCoreAudio: |
|---|
| | 303 | directory = [self coreAudioComponentDir]; |
|---|
| | 304 | break; |
|---|
| | 305 | case ComponentTypeQuickTime: |
|---|
| | 306 | directory = [self quickTimeComponentDir]; |
|---|
| | 307 | break; |
|---|
| | 308 | } |
|---|
| | 309 | BOOL result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:directory destination:@"" files:[myComponent objectForKey:ComponentNameKey] tag:&tag]; |
|---|
| | 310 | } |
|---|
| | 311 | [self performSelectorOnMainThread:@selector(installComplete:) withObject:nil waitUntilDone:NO]; |
|---|
| | 312 | [pool release]; |
|---|
| | 313 | } |
|---|
| | 314 | |
|---|