Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Work in progress. Everything's implemented, though not everything is …
…working; the output directory gets created, but not output files.
- Loading branch information
Peter Hosey
authored and
Peter Hosey
committed
Oct 29, 2011
1 parent
994620e
commit e70827b
Showing
8 changed files
with
524 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.