diff --git a/icon-extract.xcodeproj/project.pbxproj b/icon-extract.xcodeproj/project.pbxproj index f823ef8..9d52b02 100644 --- a/icon-extract.xcodeproj/project.pbxproj +++ b/icon-extract.xcodeproj/project.pbxproj @@ -9,8 +9,10 @@ /* Begin PBXBuildFile section */ 31067A13145C667500509BE2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 31067A12145C667500509BE2 /* Foundation.framework */; }; 31067A16145C667500509BE2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 31067A15145C667500509BE2 /* main.m */; }; - 31067A22145C67D400509BE2 /* PRHExtractIconFromFileOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 31067A21145C67D400509BE2 /* PRHExtractIconFromFileOperation.m */; }; + 31067A22145C67D400509BE2 /* PRHExtractIconsFromFileOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 31067A21145C67D400509BE2 /* PRHExtractIconsFromFileOperation.m */; }; 31067A24145C682A00509BE2 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 31067A23145C682A00509BE2 /* Carbon.framework */; }; + 31067A27145C77BF00509BE2 /* PRHResourceEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 31067A26145C77BF00509BE2 /* PRHResourceEnumerator.m */; }; + 31067A2A145C894F00509BE2 /* BundleResourceSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 31067A29145C894F00509BE2 /* BundleResourceSupport.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -30,9 +32,13 @@ 31067A12145C667500509BE2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 31067A15145C667500509BE2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 31067A18145C667500509BE2 /* icon-extract-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "icon-extract-Prefix.pch"; sourceTree = ""; }; - 31067A20145C67D400509BE2 /* PRHExtractIconFromFileOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PRHExtractIconFromFileOperation.h; sourceTree = ""; }; - 31067A21145C67D400509BE2 /* PRHExtractIconFromFileOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PRHExtractIconFromFileOperation.m; sourceTree = ""; }; + 31067A20145C67D400509BE2 /* PRHExtractIconsFromFileOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PRHExtractIconsFromFileOperation.h; sourceTree = ""; }; + 31067A21145C67D400509BE2 /* PRHExtractIconsFromFileOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PRHExtractIconsFromFileOperation.m; sourceTree = ""; }; 31067A23145C682A00509BE2 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; + 31067A25145C77BF00509BE2 /* PRHResourceEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PRHResourceEnumerator.h; sourceTree = ""; }; + 31067A26145C77BF00509BE2 /* PRHResourceEnumerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PRHResourceEnumerator.m; sourceTree = ""; }; + 31067A28145C894F00509BE2 /* BundleResourceSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BundleResourceSupport.h; sourceTree = ""; }; + 31067A29145C894F00509BE2 /* BundleResourceSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BundleResourceSupport.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -79,8 +85,12 @@ children = ( 31067A15145C667500509BE2 /* main.m */, 31067A17145C667500509BE2 /* Supporting Files */, - 31067A20145C67D400509BE2 /* PRHExtractIconFromFileOperation.h */, - 31067A21145C67D400509BE2 /* PRHExtractIconFromFileOperation.m */, + 31067A20145C67D400509BE2 /* PRHExtractIconsFromFileOperation.h */, + 31067A21145C67D400509BE2 /* PRHExtractIconsFromFileOperation.m */, + 31067A25145C77BF00509BE2 /* PRHResourceEnumerator.h */, + 31067A26145C77BF00509BE2 /* PRHResourceEnumerator.m */, + 31067A28145C894F00509BE2 /* BundleResourceSupport.h */, + 31067A29145C894F00509BE2 /* BundleResourceSupport.m */, ); path = "icon-extract"; sourceTree = ""; @@ -144,7 +154,9 @@ buildActionMask = 2147483647; files = ( 31067A16145C667500509BE2 /* main.m in Sources */, - 31067A22145C67D400509BE2 /* PRHExtractIconFromFileOperation.m in Sources */, + 31067A22145C67D400509BE2 /* PRHExtractIconsFromFileOperation.m in Sources */, + 31067A27145C77BF00509BE2 /* PRHResourceEnumerator.m in Sources */, + 31067A2A145C894F00509BE2 /* BundleResourceSupport.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/icon-extract/BundleResourceSupport.h b/icon-extract/BundleResourceSupport.h new file mode 100644 index 0000000..72e646c --- /dev/null +++ b/icon-extract/BundleResourceSupport.h @@ -0,0 +1,29 @@ +// +// BundleResourceSupport.h +// icon-extract +// +// Created by Peter Hosey on 2011-10-29. +// Copyright (c) 2011 Peter Hosey. All rights reserved. +// + +#pragma options align=packed +struct ResourceIDPair { + ResID localID; + ResID resourceID; +}; + +struct BundleLocalIDToToResourceIDMappingList { + ResType resourceType; //In the file reference mapping, always 'FREF' + UInt16 mappingCount; + struct ResourceIDPair mappings[1]; +}; +struct BundleResource { + ResType applicationSignature; + ResID applicationSignatureResourceID; + UInt16 arrayCount; + struct BundleLocalIDToToResourceIDMappingList iconMappingList; + struct BundleLocalIDToToResourceIDMappingList frefMappingList; +}; +#pragma options align=reset + +extern void PRHInstallBundleResourceFlipper(void); diff --git a/icon-extract/BundleResourceSupport.m b/icon-extract/BundleResourceSupport.m new file mode 100644 index 0000000..d513a3b --- /dev/null +++ b/icon-extract/BundleResourceSupport.m @@ -0,0 +1,100 @@ +// +// BundleResourceSupport.m +// icon-extract +// +// Created by Peter Hosey on 2011-10-29. +// Copyright (c) 2011 Peter Hosey. All rights reserved. +// + +#import "BundleResourceSupport.h" + +static OSStatus flipBundleMembers( + OSType dataDomain, + OSType dataType, + SInt16 id, + void *dataPtr, + ByteCount dataSize, + Boolean currentlyNative, + void *refcon +); + +extern void PRHInstallBundleResourceFlipper(void) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + CoreEndianInstallFlipper(kCoreEndianResourceManagerDomain, 'BNDL', flipBundleMembers, NULL); + }); +}; + +static inline void swapAccordingToSize(void *ptr, size_t size) { + switch(size) { + case 1: + break; + case 2:; + UInt16 *ptr16 = ptr; + *ptr16 = OSSwapInt16(*ptr16); + break; + case 4:; + UInt32 *ptr32 = ptr; + *ptr32 = OSSwapInt32(*ptr32); + break; + case 8:; + UInt64 *ptr64 = ptr; + *ptr64 = OSSwapInt64(*ptr64); + break; + } +} +#define IF_WITHIN_RANGE(start, member, dataSize) \ + if (((((void *)&(member)) - (void *)start) + sizeof(member)) <= dataSize) +#define SWAP_IF_WITHIN_RANGE(start, member, dataSize) do{\ + if (((((void *)&(member)) - (void *)start) + sizeof(member)) <= dataSize) { \ + swapAccordingToSize(&(member), sizeof(member)); \ + swapped = true; \ + } else \ + swapped = false; \ + }while(0) + +static bool swapMembersInMappingList(struct BundleResource *resPtr, struct BundleLocalIDToToResourceIDMappingList *mappingListPtr, ByteCount dataSize, bool currentlyNative) { + void *dataPtr = resPtr; + bool swapped = true; + + size_t expectedSizeFromIconMappingListStart = dataSize - ((void *)mappingListPtr - dataPtr); + SWAP_IF_WITHIN_RANGE(mappingListPtr, mappingListPtr->resourceType, expectedSizeFromIconMappingListStart); + UInt16 mappingCount = 0; + IF_WITHIN_RANGE(mappingListPtr, mappingListPtr->mappingCount, expectedSizeFromIconMappingListStart) { + mappingCount = currentlyNative ? mappingListPtr->mappingCount : OSSwapInt16(mappingListPtr->mappingCount); + } + SWAP_IF_WITHIN_RANGE(mappingListPtr, mappingListPtr->mappingCount, expectedSizeFromIconMappingListStart); + + struct ResourceIDPair *mappingsPtr = mappingListPtr->mappings; + size_t expectedSizeFromIconMappingsStart = dataSize - ((void *)mappingsPtr - dataPtr); + for (UInt16 i = 0; i < mappingCount; ++i) { + SWAP_IF_WITHIN_RANGE(mappingsPtr, mappingsPtr[i].localID, expectedSizeFromIconMappingsStart); + SWAP_IF_WITHIN_RANGE(mappingsPtr, mappingsPtr[i].resourceID, expectedSizeFromIconMappingsStart); + } + + return swapped; +} + +static OSStatus flipBundleMembers( + OSType dataDomain, + OSType dataType, + SInt16 id, + void *dataPtr, + ByteCount dataSize, + Boolean currentlyNative, + void *refcon +) { + bool swapped = true; + struct BundleResource *resPtr = dataPtr; + SWAP_IF_WITHIN_RANGE(resPtr, resPtr->applicationSignature, dataSize); + SWAP_IF_WITHIN_RANGE(resPtr, resPtr->applicationSignatureResourceID, dataSize); + SWAP_IF_WITHIN_RANGE(resPtr, resPtr->arrayCount, dataSize); + + if (swapped) { + swapped = swapMembersInMappingList(resPtr, &(resPtr->iconMappingList), dataSize, currentlyNative); + if (swapped) + swapped = swapMembersInMappingList(resPtr, &(resPtr->frefMappingList), dataSize, currentlyNative); + } + + return noErr; +} diff --git a/icon-extract/PRHExtractIconsFromFileOperation.h b/icon-extract/PRHExtractIconsFromFileOperation.h new file mode 100644 index 0000000..1cd25b9 --- /dev/null +++ b/icon-extract/PRHExtractIconsFromFileOperation.h @@ -0,0 +1,14 @@ +// +// PRHExtractIconFromFileOperation.h +// icon-extract +// +// Created by Peter Hosey on 2011-10-29. +// Copyright (c) 2011 Peter Hosey. All rights reserved. +// + +@interface PRHExtractIconsFromFileOperation : NSOperation + +@property(copy) NSURL *sourceURL; +@property(copy) NSURL *destinationDirectoryURL; + +@end diff --git a/icon-extract/PRHExtractIconsFromFileOperation.m b/icon-extract/PRHExtractIconsFromFileOperation.m new file mode 100644 index 0000000..6e05c88 --- /dev/null +++ b/icon-extract/PRHExtractIconsFromFileOperation.m @@ -0,0 +1,191 @@ +// +// PRHExtractIconFromFileOperation.m +// icon-extract +// +// Created by Peter Hosey on 2011-10-29. +// Copyright (c) 2011 Peter Hosey. All rights reserved. +// + +#import "PRHExtractIconsFromFileOperation.h" + +#import "PRHResourceEnumerator.h" +#import "BundleResourceSupport.h" + +@implementation PRHExtractIconsFromFileOperation +{ + FSRef sourceRef; + NSMutableData *iconFamilyElementsData; //The “elements” member of the IconFamilyResource structure. + NSString *destinationFilenameFormat; +} + +@synthesize sourceURL; +@synthesize destinationDirectoryURL; + +- (NSData *) dataForResourceWithType:(ResType)type ID:(ResID)ID { + NSData *data = nil; + + Handle resH = Get1Resource(type, ID); + if (resH) { + LoadResource(resH); + + HLock(resH); + data = [NSData dataWithBytes:*resH length:GetHandleSize(resH)]; + HUnlock(resH); + } + + return data; +} +- (OSStatus) extractExistingIconFamilyWithID:(ResID)ID { + NSData *icnsData = [self dataForResourceWithType:kIconFamilyType ID:ID]; + iconFamilyElementsData = [icnsData mutableCopy]; + return ResError(); +} +- (OSStatus) extractIconOfType:(ResType)type ID:(ResID)ID { + NSData *data = [self dataForResourceWithType:type ID:ID]; + OSStatus err = data ? noErr : ResError(); + if (data) { + [iconFamilyElementsData appendBytes:&type length:sizeof(ResType)]; + SInt32 size = (SInt32)OSSwapHostToBigInt32([data length]); + [iconFamilyElementsData appendBytes:&size length:sizeof(size)]; + [iconFamilyElementsData appendData:data]; + } + return err; +} +- (OSStatus) extractAllIconsWithID:(ResID)ID { + OSStatus err = noErr; + + err = [self extractExistingIconFamilyWithID:ID]; + + if (err == noErr) + err = [self extractIconOfType:kThumbnail32BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kThumbnail8BitMask ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kHuge32BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kHuge8BitMask ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kHuge8BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kHuge4BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kHuge1BitMask ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kLarge32BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kLarge8BitMask ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kLarge8BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kLarge4BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kLarge1BitMask ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kSmall32BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kSmall8BitMask ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kSmall8BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kSmall4BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kSmall1BitMask ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kMini8BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kMini4BitData ID:ID]; + if (err == noErr) + err = [self extractIconOfType:kMini1BitMask ID:ID]; + + return err; +} +- (OSStatus) extractIconsFromForkName:(struct HFSUniStr255 *)forkName { + ResFileRefNum refnum; + OSStatus err; + err = FSOpenResourceFile(&sourceRef, forkName->length, forkName->unicode, fsRdPerm, &refnum); + if (err != noErr) { + if (err != eofErr) + NSLog(@"FSOpenResourceFile returned %li/%s", (long)err, GetMacOSStatusCommentString(err)); + return err; + } + + NSMutableSet *processedIconResourceIDs = [NSMutableSet new]; + + PRHResourceEnumerator *bundlesEnum = [PRHResourceEnumerator newWithResourceType:'BNDL']; + for (PRHResource *bundleResource in bundlesEnum) { + const struct BundleResource *bundlePtr = [bundleResource.data bytes]; + const struct ResourceIDPair *mappings = bundlePtr->iconMappingList.mappings; + for (UInt16 i = 0; i < bundlePtr->iconMappingList.mappingCount; ++i) { + const ResID iconResourceID = mappings[i].resourceID; + + iconFamilyElementsData = [NSMutableData new]; + [self extractAllIconsWithID:iconResourceID]; + [processedIconResourceIDs addObject:[NSNumber numberWithShort:iconResourceID]]; + + NSString *destinationFilename = [NSString stringWithFormat:destinationFilenameFormat, (__bridge_transfer NSString *)UTCreateStringForOSType('BNDL'), iconResourceID]; + NSURL *destinationURL = [self.destinationDirectoryURL URLByAppendingPathComponent:destinationFilename isDirectory:NO]; + NSError *error = nil; + [iconFamilyElementsData writeToURL:destinationURL options:NSDataWritingAtomic error:&error]; + NSLog(@"Wrote icons found by %@ to %@: error is %@", bundleResource, destinationURL, error); + } + } + + PRHResourceEnumerator *modernIconsEnum = [PRHResourceEnumerator newWithResourceType:kIconFamilyType]; + PRHResource *iconResource; + for (iconResource in modernIconsEnum) { + if (![processedIconResourceIDs containsObject:[NSNumber numberWithShort:iconResource.ID]]) + { + iconFamilyElementsData = [NSMutableData new]; + [self extractAllIconsWithID:iconResource.ID]; + [processedIconResourceIDs addObject:[NSNumber numberWithShort:iconResource.ID]]; + + NSString *destinationFilename = [NSString stringWithFormat:destinationFilenameFormat, (__bridge_transfer NSString *)UTCreateStringForOSType(kIconFamilyType), iconResource.ID]; + NSURL *destinationURL = [self.destinationDirectoryURL URLByAppendingPathComponent:destinationFilename isDirectory:NO]; + NSError *error = nil; + [iconFamilyElementsData writeToURL:destinationURL options:NSDataWritingAtomic error:&error]; + NSLog(@"Wrote icons found by %@ to %@: error is %@", iconResource, destinationURL, error); + } + } + + PRHResourceEnumerator *eightBitIconsEnum = [PRHResourceEnumerator newWithResourceType:kLarge8BitData]; + for (iconResource in eightBitIconsEnum) { + if (![processedIconResourceIDs containsObject:[NSNumber numberWithShort:iconResource.ID]]) + { + iconFamilyElementsData = [NSMutableData new]; + [self extractAllIconsWithID:iconResource.ID]; + [processedIconResourceIDs addObject:[NSNumber numberWithShort:iconResource.ID]]; + + NSString *destinationFilename = [NSString stringWithFormat:destinationFilenameFormat, (__bridge_transfer NSString *)UTCreateStringForOSType(kLarge8BitData), iconResource.ID]; + NSURL *destinationURL = [self.destinationDirectoryURL URLByAppendingPathComponent:destinationFilename isDirectory:NO]; + NSError *error = nil; + [iconFamilyElementsData writeToURL:destinationURL options:NSDataWritingAtomic error:&error]; + NSLog(@"Wrote icons found by %@ to %@: error is %@", iconResource, destinationURL, error); + } + } + + CloseResFile(refnum); + err = ResError(); + return err; +} +- (void) main { + NSLog(@"%s starting", __func__); + bool success = CFURLGetFSRef((__bridge CFURLRef)self.sourceURL, &sourceRef); + if (!success) return; + + NSString *sourceFilename = [self.sourceURL lastPathComponent]; + NSString *sourceBaseFilename = [sourceFilename stringByDeletingPathExtension]; + destinationFilenameFormat = [sourceBaseFilename stringByAppendingString:@"-%@-%hd.icns"]; + + OSStatus err; + struct HFSUniStr255 forkName; + + err = FSGetResourceForkName(&forkName); + [self extractIconsFromForkName:&forkName]; + err = FSGetDataForkName(&forkName); + [self extractIconsFromForkName:&forkName]; + + destinationFilenameFormat = nil; + NSLog(@"%s finished", __func__); +} + +@end diff --git a/icon-extract/PRHResourceEnumerator.h b/icon-extract/PRHResourceEnumerator.h new file mode 100644 index 0000000..99557b4 --- /dev/null +++ b/icon-extract/PRHResourceEnumerator.h @@ -0,0 +1,31 @@ +// +// PRHResourceEnumerator.h +// icon-extract +// +// Created by Peter Hosey on 2011-10-29. +// Copyright (c) 2011 Peter Hosey. All rights reserved. +// + +//Yields resources of a given type from the current resource file (like Get1IndResource). + +@class PRHResource; + +@interface PRHResourceEnumerator : NSEnumerator + +- (id) initWithResourceType:(ResType)type; ++ (id) newWithResourceType:(ResType)type; + +//nextObject yields PRHResource objects. + +@end + +@interface PRHResource : NSObject + +@property(readonly) ResType type; +@property(readonly) ResID ID; +@property(readonly, strong) NSString *name; + +@property(readonly) Handle resourceHandle; +@property(nonatomic, readonly) NSData *data; + +@end diff --git a/icon-extract/PRHResourceEnumerator.m b/icon-extract/PRHResourceEnumerator.m new file mode 100644 index 0000000..b83421e --- /dev/null +++ b/icon-extract/PRHResourceEnumerator.m @@ -0,0 +1,103 @@ +// +// PRHResourceEnumerator.m +// icon-extract +// +// Created by Peter Hosey on 2011-10-29. +// Copyright (c) 2011 Peter Hosey. All rights reserved. +// + +#import "PRHResourceEnumerator.h" + +@interface PRHResource () + ++ (id) newWithType:(ResType)newType ID:(ResID)newID; +- (id) initWithType:(ResType)newType ID:(ResID)newID; + +@end + +@implementation PRHResourceEnumerator +{ + ResType type; + ResourceCount numResources; + ResourceIndex nextIndex; +} + +- (id) initWithResourceType:(ResType)newType { + if ((self = [super init])) { + type = newType; + numResources = Count1Resources(type); + nextIndex = 1; + } + return self; +} ++ (id) newWithResourceType:(ResType)newType { + return [[self alloc] initWithResourceType:newType]; +} + +- (id) nextObject { + PRHResource *resource = nil; + + Handle resH = Get1IndResource(type, nextIndex++); + if (resH) { + ResType thisType; + ResID thisID; + Str255 name_unused; + GetResInfo(resH, &thisID, &thisType, name_unused); + resource = [PRHResource newWithType:thisType ID:thisID]; + } + + return resource; +} + +@end + +@implementation PRHResource + +@synthesize type; +@synthesize ID; +@synthesize name; + +@synthesize resourceHandle; + ++ (id) newWithType:(ResType)newType ID:(ResID)newID { + return [[self alloc] initWithType:newType ID:newID]; +} +- (id) initWithType:(ResType)newType ID:(ResID)newID { + if ((self = [super init])) { + type = newType; + ID = newID; + + resourceHandle = Get1Resource(type, ID); + + ResType thisType_unused; + ResID thisID_unused; + Str255 name255; + GetResInfo(resourceHandle, &thisID_unused, &thisType_unused, name255); + name = (__bridge_transfer NSString *)CFStringCreateWithPascalString(kCFAllocatorDefault, name255, kCFStringEncodingMacRoman); + } + return self; +} + +- (NSData *) data { + NSData *data = nil; + + Handle resH = self.resourceHandle; + if (resH) { + LoadResource(resH); + + HLock(resH); + data = [NSData dataWithBytes:*resH length:GetHandleSize(resH)]; + HUnlock(resH); + } + + return data; +} + +- (NSString *) description { + return [NSString stringWithFormat:@"<%@ %p '%@' %hd>", [self class], self, + (__bridge_transfer NSString *)UTCreateStringForOSType(self.type), + self.ID + ]; +} + +@end diff --git a/icon-extract/main.m b/icon-extract/main.m index 2436c30..b842053 100644 --- a/icon-extract/main.m +++ b/icon-extract/main.m @@ -6,9 +6,46 @@ // Copyright (c) 2011 Peter Hosey. All rights reserved. // +#import "PRHExtractIconsFromFileOperation.h" + +#import "BundleResourceSupport.h" + int main (int argc, char **argv) { @autoreleasepool { - + PRHInstallBundleResourceFlipper(); + + NSOperationQueue *queue = [NSOperationQueue mainQueue]; + NSFileManager *mgr = [NSFileManager new]; + NSString *cwdPath = nil; + + NSEnumerator *argsEnum = [[[NSProcessInfo processInfo] arguments] objectEnumerator]; + [argsEnum nextObject]; //Drop the executable name/path on the floor + + NSString *arg; + for (arg in argsEnum) { + if (![arg isAbsolutePath]) { + if (!cwdPath) + cwdPath = [mgr currentDirectoryPath]; + arg = [cwdPath stringByAppendingPathComponent:arg]; + } + + NSURL *sourceURL = [NSURL fileURLWithPath:arg]; + NSString *sourceFilename = [sourceURL lastPathComponent]; + NSString *sourceBaseFilename = [sourceFilename stringByDeletingPathExtension]; + NSURL *destinationURL = [[sourceURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:[NSString stringWithFormat:@"%@-icons.out", sourceBaseFilename] isDirectory:YES]; + NSError *error = nil; + if (![mgr createDirectoryAtURL:destinationURL withIntermediateDirectories:NO attributes:nil error:&error]) { + NSLog(@"Couldn't create output directory at %@: %@", destinationURL, error); + continue; + } + + PRHExtractIconsFromFileOperation *op = [PRHExtractIconsFromFileOperation new]; + op.sourceURL = sourceURL; + op.destinationDirectoryURL = destinationURL; + [queue addOperation:op]; + } + + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; } return EXIT_SUCCESS; }