Bug Summary

File:Frameworks/Adium Framework/Source/IconFamily.m
Location:line 1028, column 3
Description:dead store

Annotated Source Code

1// IconFamily.m
2// IconFamily class implementation
3// by Troy Stephens, Thomas Schnitzer, David Remahl, Nathan Day, Ben Haller, Sven Janssen, Peter Hosey, Conor Dearden, and Elliot Glaysher
4// version 0.9.2
5//
6// Project Home Page:
7// http://homepage.mac.com/troy_stephens/software/objects/IconFamily/
8//
9// Problems, shortcomings, and uncertainties that I'm aware of are flagged
10// with "NOTE:". Please address bug reports, bug fixes, suggestions, etc.
11// to me at troy_stephens@mac.com
12
13/*
14 Copyright (c) 2001-2006 Troy N. Stephens
15
16 Use and distribution of this source code is governed by the MIT License, whose terms are as follows.
17
18 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23*/
24
25#import <Adium/IconFamily.h>
26#import <Adium/NSString+CarbonFSRefCreation.h>
27
28@interface IconFamily (Internals)
29
30+ (NSImage*) resampleImage:(NSImage*)image toIconWidth:(int)width usingImageInterpolation:(NSImageInterpolation)imageInterpolation;
31
32+ (Handle) get32BitDataFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize;
33
34+ (Handle) get8BitDataFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize;
35
36+ (Handle) get8BitMaskFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize;
37
38+ (Handle) get1BitMaskFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize;
39
40- (BOOL) addResourceType:(OSType)type asResID:(int)resID;
41
42@end
43
44@implementation IconFamily
45
46+ (IconFamily*) iconFamily
47{
48 return [[[IconFamily alloc] init] autorelease];
49}
50
51+ (IconFamily*) iconFamilyWithContentsOfFile:(NSString*)path
52{
53 return [[[IconFamily alloc] initWithContentsOfFile:path] autorelease];
54}
55
56+ (IconFamily*) iconFamilyWithIconOfFile:(NSString*)path
57{
58 return [[[IconFamily alloc] initWithIconOfFile:path] autorelease];
59}
60
61+ (IconFamily*) iconFamilyWithIconFamilyHandle:(IconFamilyHandle)hNewIconFamily
62{
63 return [[[IconFamily alloc] initWithIconFamilyHandle:hNewIconFamily] autorelease];
64}
65
66+ (IconFamily*) iconFamilyWithSystemIcon:(int)fourByteCode
67{
68 return [[[IconFamily alloc] initWithSystemIcon:fourByteCode] autorelease];
69}
70
71+ (IconFamily*) iconFamilyWithThumbnailsOfImage:(NSImage*)image
72{
73 return [[[IconFamily alloc] initWithThumbnailsOfImage:image] autorelease];
74}
75
76+ (IconFamily*) iconFamilyWithThumbnailsOfImage:(NSImage*)image usingImageInterpolation:(NSImageInterpolation)imageInterpolation
77{
78 return [[[IconFamily alloc] initWithThumbnailsOfImage:image usingImageInterpolation:imageInterpolation] autorelease];
79}
80
81// This is IconFamily's designated initializer. It creates a new IconFamily that initially has no elements.
82//
83// The proper way to do this is to simply allocate a zero-sized handle (not to be confused with an empty handle) and assign it to hIconFamily. This technique works on Mac OS X 10.2 as well as on 10.0.x and 10.1.x. Our previous technique of allocating an IconFamily struct with a resourceSize of 0 no longer works as of Mac OS X 10.2.
84- init
85{
86 self = [super init];
87 if (self) {
88 hIconFamily = (IconFamilyHandle) NewHandle( 0 );
89 if (hIconFamily == NULL( ( void * ) 0 )) {
90 [self autorelease];
91 return nil0;
92 }
93 }
94 return self;
95}
96
97- initWithContentsOfFile:(NSString*)path
98{
99 FSRef ref;
100 OSStatus result;
101
102 self = [self init];
103 if (self) {
104 if (hIconFamily) {
105 DisposeHandle( (Handle)hIconFamily );
106 hIconFamily = NULL( ( void * ) 0 );
107 }
108 if (![path getFSRef:&ref createFileIfNecessary:NO( BOOL ) 0]) {
109 [self autorelease];
110 return nil0;
111 }
112 result = ReadIconFromFSRef( &ref, &hIconFamily );
113 if (result != noErr) {
114 [self autorelease];
115 return nil0;
116 }
117 }
118 return self;
119}
120
121- initWithIconFamilyHandle:(IconFamilyHandle)hNewIconFamily
122{
123 self = [self init];
124 if (self) {
125 if (hIconFamily) {
126 DisposeHandle( (Handle)hIconFamily );
127 hIconFamily = NULL( ( void * ) 0 );
128 }
129 // NOTE: Do we have to somehow "retain" the handle
130 // (increment its reference count)?
131 hIconFamily = hNewIconFamily;
132 }
133 return self;
134}
135
136- initWithIconOfFile:(NSString*)path
137{
138 IconRef iconRef;
139 OSStatus result;
140 SInt16 label;
141 FSRef ref;
142
143 self = [self init];
144 if (self)
145 {
146 if (hIconFamily)
147 {
148 DisposeHandle( (Handle)hIconFamily );
149 hIconFamily = NULL( ( void * ) 0 );
150 }
151
152 if( ![path getFSRef:&ref createFileIfNecessary:NO( BOOL ) 0] )
153 {
154 [self autorelease];
155 return nil0;
156 }
157
158 result = GetIconRefFromFileInfo(
159 &ref,
160 /*inFileNameLength*/ 0,
161 /*inFileName*/ NULL( ( void * ) 0 ),
162 kFSCatInfoNone,
163 /*inCatalogInfo*/ NULL( ( void * ) 0 ),
164 kIconServicesNormalUsageFlag,
165 &iconRef,
166 &label );
167
168 if (result != noErr)
169 {
170 [self autorelease];
171 return nil0;
172 }
173
174 result = IconRefToIconFamily(
175 iconRef,
176 kSelectorAllAvailableData,
177 &hIconFamily );
178
179 ReleaseIconRef( iconRef );
180
181 if (result != noErr || !hIconFamily)
182 {
183 [self autorelease];
184 return nil0;
185 }
186 }
187 return self;
188}
189
190- initWithSystemIcon:(int)fourByteCode
191{
192 IconRef iconRef;
193 OSErr result;
194
195 self = [self init];
196 if (self)
197 {
198 if (hIconFamily)
199 {
200 DisposeHandle( (Handle)hIconFamily );
201 hIconFamily = NULL( ( void * ) 0 );
202 }
203
204 result = GetIconRef(kOnSystemDisk, kSystemIconsCreator, fourByteCode, &iconRef);
205
206 if (result != noErr)
207 {
208 [self autorelease];
209 return nil0;
210 }
211
212 result = IconRefToIconFamily(
213 iconRef,
214 kSelectorAllAvailableData,
215 &hIconFamily );
216
217 if (result != noErr || !hIconFamily)
218 {
219 [self autorelease];
220 return nil0;
221 }
222
223 ReleaseIconRef( iconRef );
224 }
225 return self;
226}
227
228- initWithThumbnailsOfImage:(NSImage*)image
229{
230 // The default is to use a high degree of antialiasing, producing a smooth image.
231 return [self initWithThumbnailsOfImage:image usingImageInterpolation:NSImageInterpolationHigh];
232}
233
234- initWithThumbnailsOfImage:(NSImage*)image usingImageInterpolation:(NSImageInterpolation)imageInterpolation
235{
236 NSImage* iconImage128x128;
237 NSImage* iconImage32x32;
238 NSImage* iconImage16x16;
239 NSBitmapImageRep* iconBitmap128x128;
240 NSBitmapImageRep* iconBitmap32x32;
241 NSBitmapImageRep* iconBitmap16x16;
242 NSImage* bitmappedIconImage128x128;
243
244 // Start with a new, empty IconFamily.
245 self = [self init];
246 if (self == nil0)
247 return nil0;
248
249 // Resample the given image to create a 128x128 pixel, 32-bit RGBA
250 // version, and use that as our "thumbnail" (128x128) icon and mask.
251 //
252 // Our +resampleImage:toIconWidth:... method, in its present form,
253 // returns an NSImage that contains an NSCacheImageRep, rather than
254 // an NSBitmapImageRep. We convert to an NSBitmapImageRep, so that
255 // our methods can scan the image data, using initWithFocusedViewRect:.
256 iconImage128x128 = [IconFamily resampleImage:image toIconWidth:128 usingImageInterpolation:imageInterpolation];
257 [iconImage128x128 lockFocus];
258 iconBitmap128x128 = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, 128, 128)];
259 [iconImage128x128 unlockFocus];
260 if (iconBitmap128x128) {
261 [self setIconFamilyElement:kThumbnail32BitData fromBitmapImageRep:iconBitmap128x128];
262 [self setIconFamilyElement:kThumbnail8BitMask fromBitmapImageRep:iconBitmap128x128];
263 }
264
265 // Create an NSImage with the iconBitmap128x128 NSBitmapImageRep, that we
266 // can resample to create the smaller icon family elements. (This is
267 // most likely more efficient than resampling from the original image again,
268 // particularly if it is large. It produces a slightly different result, but
269 // the difference is minor and should not be objectionable...)
270 bitmappedIconImage128x128 = [[NSImage alloc] initWithSize:NSMakeSize(128,128)];
271 [bitmappedIconImage128x128 addRepresentation:iconBitmap128x128];
272
273 // Resample the 128x128 image to create a 32x32 pixel, 32-bit RGBA version,
274 // and use that as our "large" (32x32) icon and 8-bit mask.
275 iconImage32x32 = [IconFamily resampleImage:bitmappedIconImage128x128 toIconWidth:32 usingImageInterpolation:imageInterpolation];
276 [iconImage32x32 lockFocus];
277 iconBitmap32x32 = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, 32, 32)];
278 [iconImage32x32 unlockFocus];
279 if (iconBitmap32x32) {
280 [self setIconFamilyElement:kLarge32BitData fromBitmapImageRep:iconBitmap32x32];
281 [self setIconFamilyElement:kLarge8BitData fromBitmapImageRep:iconBitmap32x32];
282 [self setIconFamilyElement:kLarge8BitMask fromBitmapImageRep:iconBitmap32x32];
283 [self setIconFamilyElement:kLarge1BitMask fromBitmapImageRep:iconBitmap32x32];
284 }
285
286 // Resample the 128x128 image to create a 16x16 pixel, 32-bit RGBA version,
287 // and use that as our "small" (16x16) icon and 8-bit mask.
288 iconImage16x16 = [IconFamily resampleImage:bitmappedIconImage128x128 toIconWidth:16 usingImageInterpolation:imageInterpolation];
289 [iconImage16x16 lockFocus];
290 iconBitmap16x16 = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, 16, 16)];
291 [iconImage16x16 unlockFocus];
292 if (iconBitmap16x16) {
293 [self setIconFamilyElement:kSmall32BitData fromBitmapImageRep:iconBitmap16x16];
294 [self setIconFamilyElement:kSmall8BitData fromBitmapImageRep:iconBitmap16x16];
295 [self setIconFamilyElement:kSmall8BitMask fromBitmapImageRep:iconBitmap16x16];
296 [self setIconFamilyElement:kSmall1BitMask fromBitmapImageRep:iconBitmap16x16];
297 }
298
299 // Release all of the images that we created and no longer need.
300 [bitmappedIconImage128x128 release];
301 [iconBitmap128x128 release];
302 [iconBitmap32x32 release];
303 [iconBitmap16x16 release];
304
305 // Return the new icon family!
306 return self;
307}
308
309- (void) dealloc
310{
311 DisposeHandle( (Handle)hIconFamily );
312 [super dealloc];
313}
314
315- (NSBitmapImageRep*) bitmapImageRepWithAlphaForIconFamilyElement:(OSType)elementType;
316{
317 NSBitmapImageRep* bitmapImageRep;
318 int pixelsWide;
319 Handle hRawBitmapData;
320 Handle hRawMaskData;
321 OSType maskElementType;
322 OSErr result;
323 unsigned long* pRawBitmapData;
324 unsigned long* pRawBitmapDataEnd;
325 unsigned char* pRawMaskData;
326 unsigned char* pBitmapImageRepBitmapData;
327
328 // Make sure elementType is a valid type that we know how to handle, and
329 // figure out the dimensions and bit depth of the bitmap for that type.
330 switch (elementType) {
331 // 'it32' 128x128 32-bit RGB image
332 case kThumbnail32BitData:
333 maskElementType = kThumbnail8BitMask;
334 pixelsWide = 128;
335 break;
336
337 // 'il32' 32x32 32-bit RGB image
338 case kLarge32BitData:
339 maskElementType = kLarge8BitMask;
340 pixelsWide = 32;
341 break;
342
343 // 'is32' 16x16 32-bit RGB image
344 case kSmall32BitData:
345 maskElementType = kSmall8BitMask;
346 pixelsWide = 16;
347 break;
348
349 default:
350 return nil0;
351 }
352
353 // Get the raw, uncompressed bitmap data for the requested element.
354 hRawBitmapData = NewHandle( pixelsWide * pixelsWide * 4 );
355 result = GetIconFamilyData( hIconFamily, elementType, hRawBitmapData );
356 if (result != noErr) {
357 DisposeHandle( hRawBitmapData );
358 return nil0;
359 }
360
361 // Get the corresponding raw, uncompressed 8-bit mask data.
362 hRawMaskData = NewHandle( pixelsWide * pixelsWide );
363 result = GetIconFamilyData( hIconFamily, maskElementType, hRawMaskData );
364 if (result != noErr) {
365 DisposeHandle( hRawMaskData );
366 hRawMaskData = NULL( ( void * ) 0 );
367 }
368
369 // The retrieved raw bitmap data is stored in memory as 32 bit per pixel, 8 bit per sample xRGB data. (The sample order provided by IconServices is the same, regardless of whether we're running on a big-endian (PPC) or little-endian (Intel) architecture.) With proper attention to byte order, we can fold the mask data into the color data in-place, producing RGBA data suitable for handing off to NSBitmapImageRep.
370 HLock( hRawBitmapData );
371 pRawBitmapData = (unsigned long*) *hRawBitmapData;
372 pRawBitmapDataEnd = pRawBitmapData + pixelsWide * pixelsWide;
373 if (hRawMaskData) {
374 HLock( hRawMaskData );
375 pRawMaskData = (unsigned char*) *hRawMaskData;
376 while (pRawBitmapData < pRawBitmapDataEnd) {
377 *pRawBitmapData = NSSwapBigLongToHost((NSSwapHostLongToBig(*pRawBitmapData) << 8) | *pRawMaskData++);
378 ++pRawBitmapData;
379 }
380 HUnlock( hRawMaskData );
381 } else {
382 while (pRawBitmapData < pRawBitmapDataEnd) {
383 *pRawBitmapData = NSSwapBigLongToHost((NSSwapHostLongToBig(*pRawBitmapData) << 8) | 0xff);
384 ++pRawBitmapData;
385 }
386 }
387
388 // Create a new NSBitmapImageRep with the given bitmap data. Note that
389 // when creating the NSBitmapImageRep we pass in NULL for the "planes"
390 // parameter. This causes the new NSBitmapImageRep to allocate its own
391 // buffer for the bitmap data (which it will own and release when the
392 // NSBitmapImageRep is released), rather than referencing the bitmap
393 // data we pass in (which will soon disappear when we call
394 // DisposeHandle() below!). (See the NSBitmapImageRep documentation for
395 // the -initWithBitmapDataPlanes:... method, where this is explained.)
396 //
397 // Once we have the new NSBitmapImageRep, we get a pointer to its
398 // bitmapData and copy our bitmap data in.
399 bitmapImageRep = [[[NSBitmapImageRep alloc]
400 initWithBitmapDataPlanes:NULL( ( void * ) 0 )
401 pixelsWide:pixelsWide
402 pixelsHigh:pixelsWide
403 bitsPerSample:8
404 samplesPerPixel:4
405 hasAlpha:YES( BOOL ) 1
406 isPlanar:NO( BOOL ) 0
407 colorSpaceName:NSDeviceRGBColorSpace // NOTE: is this right?
408 bytesPerRow:0
409 bitsPerPixel:0] autorelease];
410 pBitmapImageRepBitmapData = [bitmapImageRep bitmapData];
411 if (pBitmapImageRepBitmapData) {
412 memcpy( pBitmapImageRepBitmapData, *hRawBitmapData,
413 pixelsWide * pixelsWide * 4 );
414 }
415 HUnlock( hRawBitmapData );
416
417 // Free the retrieved raw data.
418 DisposeHandle( hRawBitmapData );
419 if (hRawMaskData)
420 DisposeHandle( hRawMaskData );
421
422 // Return nil if the NSBitmapImageRep didn't give us a buffer to copy into.
423 if (pBitmapImageRepBitmapData == NULL( ( void * ) 0 ))
424 return nil0;
425
426 // Return the new NSBitmapImageRep.
427 return bitmapImageRep;
428}
429
430- (NSImage*) imageWithAllReps
431{
432 NSImage* image = NULL( ( void * ) 0 );
433 image = [[[NSImage alloc] initWithData:[NSData dataWithBytes:*hIconFamily length:GetHandleSize((Handle)hIconFamily)]] autorelease];
434 return image;
435}
436
437- (BOOL) setIconFamilyElement:(OSType)elementType fromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep
438{
439 Handle hRawData = NULL( ( void * ) 0 );
440 OSErr result;
441
442 switch (elementType) {
443 // 'it32' 128x128 32-bit RGB image
444 case kThumbnail32BitData:
445 hRawData = [IconFamily get32BitDataFromBitmapImageRep:bitmapImageRep requiredPixelSize:128];
446 break;
447
448 // 't8mk' 128x128 8-bit alpha mask
449 case kThumbnail8BitMask:
450 hRawData = [IconFamily get8BitMaskFromBitmapImageRep:bitmapImageRep requiredPixelSize:128];
451 break;
452
453 // 'il32' 32x32 32-bit RGB image
454 case kLarge32BitData:
455 hRawData = [IconFamily get32BitDataFromBitmapImageRep:bitmapImageRep requiredPixelSize:32];
456 break;
457
458 // 'l8mk' 32x32 8-bit alpha mask
459 case kLarge8BitMask:
460 hRawData = [IconFamily get8BitMaskFromBitmapImageRep:bitmapImageRep requiredPixelSize:32];
461 break;
462
463 // 'ICN#' 32x32 1-bit alpha mask
464 case kLarge1BitMask:
465 hRawData = [IconFamily get1BitMaskFromBitmapImageRep:bitmapImageRep requiredPixelSize:32];
466 break;
467
468 // 'icl8' 32x32 8-bit indexed image data
469 case kLarge8BitData:
470 hRawData = [IconFamily get8BitDataFromBitmapImageRep:bitmapImageRep requiredPixelSize:32];
471 break;
472
473 // 'is32' 16x16 32-bit RGB image
474 case kSmall32BitData:
475 hRawData = [IconFamily get32BitDataFromBitmapImageRep:bitmapImageRep requiredPixelSize:16];
476 break;
477
478 // 's8mk' 16x16 8-bit alpha mask
479 case kSmall8BitMask:
480 hRawData = [IconFamily get8BitMaskFromBitmapImageRep:bitmapImageRep requiredPixelSize:16];
481 break;
482
483 // 'ics#' 16x16 1-bit alpha mask
484 case kSmall1BitMask:
485 hRawData = [IconFamily get1BitMaskFromBitmapImageRep:bitmapImageRep requiredPixelSize:16];
486 break;
487
488 // 'ics8' 16x16 8-bit indexed image data
489 case kSmall8BitData:
490 hRawData = [IconFamily get8BitDataFromBitmapImageRep:bitmapImageRep requiredPixelSize:16];
491 break;
492
493 default:
494 return NO( BOOL ) 0;
495 }
496
497 // NSLog(@"setIconFamilyElement:%@ fromBitmapImageRep:%@ generated handle %p of size %d", NSFileTypeForHFSTypeCode(elementType), bitmapImageRep, hRawData, GetHandleSize(hRawData));
498
499 if (hRawData == NULL( ( void * ) 0 ))
500 {
501 NSLog(@"Null data returned to setIconFamilyElement:fromBitmapImageRep:");
502 return NO( BOOL ) 0;
503 }
504
505 result = SetIconFamilyData( hIconFamily, elementType, hRawData );
506 DisposeHandle( hRawData );
507
508 if (result != noErr)
509 {
510 NSLog(@"SetIconFamilyData() returned error %d", result);
511 return NO( BOOL ) 0;
512 }
513
514 return YES( BOOL ) 1;
515}
516
517- (BOOL) setAsCustomIconForFile:(NSString*)path
518{
519 return( [self setAsCustomIconForFile:path withCompatibility:NO( BOOL ) 0] );
520}
521
522- (BOOL) setAsCustomIconForFile:(NSString*)path withCompatibility:(BOOL)compat
523{
524 FSRef targetFileFSRef;
525 FSRef parentDirectoryFSRef;
526 SInt16 file;
527 OSStatus result;
528 struct FSCatalogInfo catInfo;
529 struct FileInfo *finderInfo = (struct FileInfo *)&catInfo.finderInfo;
530 Handle hExistingCustomIcon;
531 Handle hIconFamilyCopy;
532 NSString *parentDirectory;
533
534 // Before we do anything, get the original modification time for the target file.
535 NSDate* modificationDate = [[[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:NO( BOOL ) 0] objectForKey:NSFileModificationDate];
536
537 if ([path isAbsolutePath])
538 parentDirectory = [path stringByDeletingLastPathComponent];
539 else
540 parentDirectory = [[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:[path stringByDeletingLastPathComponent]];
541
542 // Get an FSRef for the target file's parent directory that we can use in
543 // the FSCreateResFile() and FNNotify() calls below.
544 if (![parentDirectory getFSRef:&parentDirectoryFSRef createFileIfNecessary:NO( BOOL ) 0])
545 return NO( BOOL ) 0;
546
547 // Get the name of the file, for FSCreateResFile.
548 struct HFSUniStr255 filename;
549 NSString *filenameString = [path lastPathComponent];
550 filename.length = [filenameString length];
551 [filenameString getCharacters:filename.unicode];
552
553 // Make sure the file has a resource fork that we can open. (Although
554 // this sounds like it would clobber an existing resource fork, the Carbon
555 // Resource Manager docs for this function say that's not the case. If
556 // the file already has a resource fork, we receive a result code of
557 // dupFNErr, which is not really an error per se, but just a notification
558 // to us that creating a new resource fork for the file was not necessary.)
559 FSCreateResFile(
560 &parentDirectoryFSRef,
561 filename.length,
562 filename.unicode,
563 kFSCatInfoNone,
564 /*catalogInfo/*/ NULL( ( void * ) 0 ),
565 &targetFileFSRef,
566 /*newSpec*/ NULL( ( void * ) 0 ));
567 result = ResError();
568 if (result == dupFNErr) {
569 // If the call to FSCreateResFile() returned dupFNErr, targetFileFSRef will not have been set, so create it from the path.
570 if (![path getFSRef:&targetFileFSRef createFileIfNecessary:NO( BOOL ) 0])
571 return NO( BOOL ) 0;
572 } else if (result != noErr) {
573 return NO( BOOL ) 0;
574 }
575
576 // Open the file's resource fork.
577 file = FSOpenResFile( &targetFileFSRef, fsRdWrPerm );
578 if (file == -1)
579 return NO( BOOL ) 0;
580
581 // Make a copy of the icon family data to pass to AddResource().
582 // (AddResource() takes ownership of the handle we pass in; after the
583 // CloseResFile() call its master pointer will be set to 0xffffffff.
584 // We want to keep the icon family data, so we make a copy.)
585 // HandToHand() returns the handle of the copy in hIconFamily.
586 hIconFamilyCopy = (Handle) hIconFamily;
587 result = HandToHand( &hIconFamilyCopy );
588 if (result != noErr) {
589 CloseResFile( file );
590 return NO( BOOL ) 0;
591 }
592
593 // Remove the file's existing kCustomIconResource of type kIconFamilyType
594 // (if any).
595 hExistingCustomIcon = GetResource( kIconFamilyType, kCustomIconResource );
596 if( hExistingCustomIcon )
597 RemoveResource( hExistingCustomIcon );
598
599 // Now add our icon family as the file's new custom icon.
600 AddResource( (Handle)hIconFamilyCopy, kIconFamilyType,
601 kCustomIconResource, "\p");
602 if (ResError() != noErr) {
603 CloseResFile( file );
604 return NO( BOOL ) 0;
605 }
606
607 if( compat )
608 {
609 [self addResourceType:kLarge8BitData asResID:kCustomIconResource];
610 [self addResourceType:kLarge1BitMask asResID:kCustomIconResource];
611 [self addResourceType:kSmall8BitData asResID:kCustomIconResource];
612 [self addResourceType:kSmall1BitMask asResID:kCustomIconResource];
613 }
614
615 // Close the file's resource fork, flushing the resource map and new icon
616 // data out to disk.
617 CloseResFile( file );
618 if (ResError() != noErr)
619 return NO( BOOL ) 0;
620
621 // Prepare to get the Finder info.
622
623 // Now we need to set the file's Finder info so the Finder will know that
624 // it has a custom icon. Start by getting the file's current finder info:
625 result = FSGetCatalogInfo(
626 &targetFileFSRef,
627 kFSCatInfoFinderInfo,
628 &catInfo,
629 /*outName*/ NULL( ( void * ) 0 ),
630 /*fsSpec*/ NULL( ( void * ) 0 ),
631 /*parentRef*/ NULL( ( void * ) 0 ));
632 if (result != noErr)
633 return NO( BOOL ) 0;
634
635 // Set the kHasCustomIcon flag, and clear the kHasBeenInited flag.
636 //
637 // From Apple's "CustomIcon" code sample:
638 // "set bit 10 (has custom icon) and unset the inited flag
639 // kHasBeenInited is 0x0100 so the mask will be 0xFEFF:"
640 // finderInfo.fdFlags = 0xFEFF & (finderInfo.fdFlags | kHasCustomIcon ) ;
641 finderInfo->finderFlags = (finderInfo->finderFlags | kHasCustomIcon ) & ~kHasBeenInited;
642
643 // Now write the Finder info back.
644 result = FSSetCatalogInfo( &targetFileFSRef, kFSCatInfoFinderInfo, &catInfo );
645 if (result != noErr)
646 return NO( BOOL ) 0;
647
648 // Now set the modification time back to when the file was actually last modified.
649 NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys:modificationDate, NSFileModificationDate, nil0];
650 [[NSFileManager defaultManager] changeFileAttributes:attributes atPath:path];
651
652 // Notify the system that the directory containing the file has changed, to
653 // give Finder the chance to find out about the file's new custom icon.
654 result = FNNotify( &parentDirectoryFSRef, kFNDirectoryModifiedMessage, kNilOptions );
655 if (result != noErr)
656 return NO( BOOL ) 0;
657
658 return YES( BOOL ) 1;
659}
660
661+ (BOOL) removeCustomIconFromFile:(NSString*)path
662{
663 FSRef targetFileFSRef;
664 FSRef parentDirectoryFSRef;
665 SInt16 file;
666 OSStatus result;
667 struct FSCatalogInfo catInfo;
668 struct FileInfo *finderInfo = (struct FileInfo *)&catInfo.finderInfo;
669 Handle hExistingCustomIcon;
670
671 // Get an FSRef for the target file.
672 if (![path getFSRef:&targetFileFSRef createFileIfNecessary:NO( BOOL ) 0])
673 return NO( BOOL ) 0;
674
675 // Open the file's resource fork, if it has one.
676 file = FSOpenResFile( &targetFileFSRef, fsRdWrPerm );
677 if (file == -1)
678 return NO( BOOL ) 0;
679
680 // Remove the file's existing kCustomIconResource of type kIconFamilyType
681 // (if any).
682 hExistingCustomIcon = GetResource( kIconFamilyType, kCustomIconResource );
683 if( hExistingCustomIcon )
684 RemoveResource( hExistingCustomIcon );
685
686 // Close the file's resource fork, flushing the resource map out to disk.
687 CloseResFile( file );
688 if (ResError() != noErr)
689 return NO( BOOL ) 0;
690
691 // Now we need to set the file's Finder info so the Finder will know that
692 // it has no custom icon. Start by getting the file's current Finder info.
693 // Also get an FSRef for its parent directory, that we can use in the
694 // FNNotify() call below.
695 result = FSGetCatalogInfo(
696 &targetFileFSRef,
697 kFSCatInfoFinderInfo,
698 &catInfo,
699 /*outName*/ NULL( ( void * ) 0 ),
700 /*fsSpec*/ NULL( ( void * ) 0 ),
701 &parentDirectoryFSRef );
702 if (result != noErr)
703 return NO( BOOL ) 0;
704
705 // Clear the kHasCustomIcon flag and the kHasBeenInited flag.
706 finderInfo->finderFlags = finderInfo->finderFlags & ~(kHasCustomIcon | kHasBeenInited);
707
708 // Now write the Finder info back.
709 result = FSSetCatalogInfo( &targetFileFSRef, kFSCatInfoFinderInfo, &catInfo );
710 if (result != noErr)
711 return NO( BOOL ) 0;
712
713 // Notify the system that the directory containing the file has changed, to give Finder the chance to find out about the file's new custom icon.
714 result = FNNotify( &parentDirectoryFSRef, kFNDirectoryModifiedMessage, kNilOptions );
715 if (result != noErr)
716 return NO( BOOL ) 0;
717
718 return YES( BOOL ) 1;
719}
720
721- (BOOL) setAsCustomIconForDirectory:(NSString*)path
722{
723 return [self setAsCustomIconForDirectory:path withCompatibility:NO( BOOL ) 0];
724}
725
726- (BOOL) setAsCustomIconForDirectory:(NSString*)path withCompatibility:(BOOL)compat
727{
728 NSFileManager *fm = [NSFileManager defaultManager];
729 BOOL isDir;
730 BOOL exists;
731 NSString *iconrPath;
732 FSRef targetFolderFSRef, iconrFSRef;
733 SInt16 file;
734 OSErr result;
735 struct HFSUniStr255 filename;
736 struct FSCatalogInfo catInfo;
737 Handle hExistingCustomIcon;
738 Handle hIconFamilyCopy;
739
740 // Confirm that "path" exists and specifies a directory.
741 exists = [fm fileExistsAtPath:path isDirectory:&isDir];
742 if( !isDir || !exists )
743 return NO( BOOL ) 0;
744
745 // Get an FSRef for the folder.
746 if( ![path getFSRef:&targetFolderFSRef createFileIfNecessary:NO( BOOL ) 0] )
747 return NO( BOOL ) 0;
748
749 // Remove and re-create any existing "Icon\r" file in the directory, and get an FSRef for it.
750 iconrPath = [path stringByAppendingPathComponent:@"Icon\r"];
751 if( [fm fileExistsAtPath:iconrPath] )
752 {
753 if( ![fm removeFileAtPath:iconrPath handler:nil0] )
754 return NO( BOOL ) 0;
755 }
756 if( ![iconrPath getFSRef:&iconrFSRef createFileIfNecessary:YES( BOOL ) 1] )
757 return NO( BOOL ) 0;
758
759 // Get type and creator information for the Icon file.
760 result = FSGetCatalogInfo(
761 &iconrFSRef,
762 kFSCatInfoFinderInfo,
763 &catInfo,
764 /*outName*/ NULL( ( void * ) 0 ),
765 /*fsSpec*/ NULL( ( void * ) 0 ),
766 /*parentRef*/ NULL( ( void * ) 0 ) );
767 if( result == fnfErr ) {
768 // The file doesn't exist. Prepare to create it.
769
770 struct FileInfo *finderInfo = (struct FileInfo *)catInfo.finderInfo;
771
772 // These are the file type and creator given to Icon files created by
773 // the Finder.
774 finderInfo->fileType = 'icon';
775 finderInfo->fileCreator = 'MACS';
776
777 // Icon files should be invisible.
778 finderInfo->finderFlags = kIsInvisible;
779
780 // Because the inited flag is not set in finderFlags above, the Finder
781 // will ignore the location, unless it's in the 'magic rectangle' of
782 // { -24,000, -24,000, -16,000, -16,000 } (technote TB42).
783 // So we need to make sure to set this to zero anyway, so that the
784 // Finder will position it automatically. If the user makes the Icon
785 // file visible for any reason, we don't want it to be positioned in an
786 // exotic corner of the window.
787 finderInfo->location.h = finderInfo->location.v = 0;
788
789 // Standard reserved-field practice.
790 finderInfo->reservedField = 0;
791 } else if( result != noErr )
792 return NO( BOOL ) 0;
793
794 // Get the filename, to be applied to the Icon file.
795 filename.length = [@"Icon\r" length];
796 [@"Icon\r" getCharacters:filename.unicode];
797
798 // Make sure the file has a resource fork that we can open. (Although
799 // this sounds like it would clobber an existing resource fork, the Carbon
800 // Resource Manager docs for this function say that's not the case.)
801 FSCreateResFile(
802 &targetFolderFSRef,
803 filename.length,
804 filename.unicode,
805 kFSCatInfoFinderInfo,
806 &catInfo,
807 &iconrFSRef,
808 /*newSpec*/ NULL( ( void * ) 0 ));
809 result = ResError();
810 if (!(result == noErr || result == dupFNErr))
811 return NO( BOOL ) 0;
812
813 // Open the file's resource fork.
814 file = FSOpenResFile( &iconrFSRef, fsRdWrPerm );
815 if (file == -1)
816 return NO( BOOL ) 0;
817
818 // Make a copy of the icon family data to pass to AddResource().
819 // (AddResource() takes ownership of the handle we pass in; after the
820 // CloseResFile() call its master pointer will be set to 0xffffffff.
821 // We want to keep the icon family data, so we make a copy.)
822 // HandToHand() returns the handle of the copy in hIconFamily.
823 hIconFamilyCopy = (Handle) hIconFamily;
824 result = HandToHand( &hIconFamilyCopy );
825 if (result != noErr) {
826 CloseResFile( file );
827 return NO( BOOL ) 0;
828 }
829
830 // Remove the file's existing kCustomIconResource of type kIconFamilyType
831 // (if any).
832 hExistingCustomIcon = GetResource( kIconFamilyType, kCustomIconResource );
833 if( hExistingCustomIcon )
834 RemoveResource( hExistingCustomIcon );
835
836 // Now add our icon family as the file's new custom icon.
837 AddResource( (Handle)hIconFamilyCopy, kIconFamilyType,
838 kCustomIconResource, "\p");
839
840 if (ResError() != noErr) {
841 CloseResFile( file );
842 return NO( BOOL ) 0;
843 }
844
845 if( compat )
846 {
847 [self addResourceType:kLarge8BitData asResID:kCustomIconResource];
848 [self addResourceType:kLarge1BitMask asResID:kCustomIconResource];
849 [self addResourceType:kSmall8BitData asResID:kCustomIconResource];
850 [self addResourceType:kSmall1BitMask asResID:kCustomIconResource];
851 }
852
853 // Close the file's resource fork, flushing the resource map and new icon
854 // data out to disk.
855 CloseResFile( file );
856 if (ResError() != noErr)
857 return NO( BOOL ) 0;
858
859 result = FSGetCatalogInfo( &targetFolderFSRef,
860 kFSCatInfoFinderInfo,
861 &catInfo,
862 /*outName*/ NULL( ( void * ) 0 ),
863 /*fsSpec*/ NULL( ( void * ) 0 ),
864 /*parentRef*/ NULL( ( void * ) 0 ));
865 if( result != noErr )
866 return NO( BOOL ) 0;
867
868 // Tell the Finder that the folder now has a custom icon.
869 ((struct FolderInfo *)catInfo.finderInfo)->finderFlags = ( ((struct FolderInfo *)catInfo.finderInfo)->finderFlags | kHasCustomIcon ) & ~kHasBeenInited;
870
871 result = FSSetCatalogInfo( &targetFolderFSRef,
872 kFSCatInfoFinderInfo,
873 &catInfo);
874 if( result != noErr )
875 return NO( BOOL ) 0;
876
877 // Notify the system that the target directory has changed, to give Finder
878 // the chance to find out about its new custom icon.
879 result = FNNotify( &targetFolderFSRef, kFNDirectoryModifiedMessage, kNilOptions );
880 if (result != noErr)
881 return NO( BOOL ) 0;
882
883 return YES( BOOL ) 1;
884}
885
886- (BOOL) writeToFile:(NSString*)path
887{
888 NSData* iconData = nil0;
889
890 HLock((Handle)hIconFamily);
891
892 iconData = [NSData dataWithBytes:*hIconFamily length:GetHandleSize((Handle)hIconFamily)];
893 BOOL success = [iconData writeToFile:path atomically:NO( BOOL ) 0];
894
895 HUnlock((Handle)hIconFamily);
896
897 return success;
898}
899
900@end
901
902@implementation IconFamily (Internals)
903
904+ (NSImage*) resampleImage:(NSImage*)image toIconWidth:(int)iconWidth usingImageInterpolation:(NSImageInterpolation)imageInterpolation
905{
906 NSGraphicsContext* graphicsContext;
907 BOOL wasAntialiasing;
908 NSImageInterpolation previousImageInterpolation;
909 NSImage* newImage;
910 NSImage* workingImage;
911 NSImageRep* workingImageRep;
912 NSSize size, pixelSize, newSize;
913 NSRect iconRect;
914 NSRect targetRect;
915
916 // Create a working copy of the image and scale its size down to fit in
917 // the square area of the icon.
918 //
919 // It seems like there should be a more memory-efficient alternative to
920 // first duplicating the entire original image, but I don't know what it
921 // is. We need to change some properties ("size" and "scalesWhenResized")
922 // of the original image, but we shouldn't change the original, so a copy
923 // is necessary.
924 workingImage = [image copyWithZone:[image zone]];
925 [workingImage setScalesWhenResized:YES( BOOL ) 1];
926 size = [workingImage size];
927 workingImageRep = [workingImage bestRepresentationForDevice:nil0];
928 if ([workingImageRep isKindOfClass:[NSBitmapImageRep class]]) {
929 pixelSize.width = [workingImageRep pixelsWide];
930 pixelSize.height = [workingImageRep pixelsHigh];
931 if (!NSEqualSizes( size, pixelSize )) {
932 [workingImage setSize:pixelSize];
933 [workingImageRep setSize:pixelSize];
934 size = pixelSize;
935 }
936 }
937 if (size.width >= size.height) {
938 newSize.width = iconWidth;
939 newSize.height = floor( (float) iconWidth * size.height / size.width + 0.5 );
940 } else {
941 newSize.height = iconWidth;
942 newSize.width = floor( (float) iconWidth * size.width / size.height + 0.5 );
943 }
944 [workingImage setSize:newSize];
945
946 // Create a new image the size of the icon, and clear it to transparent.
947 newImage = [[NSImage alloc] initWithSize:NSMakeSize(iconWidth,iconWidth)];
948 [newImage lockFocus];
949 iconRect.origin.x = iconRect.origin.y = 0;
950 iconRect.size.width = iconRect.size.height = iconWidth;
951 [[NSColor clearColor] set];
952 NSRectFill( iconRect );
953
954 // Set current graphics context to use antialiasing and high-quality
955 // image scaling.
956 graphicsContext = [NSGraphicsContext currentContext];
957 wasAntialiasing = [graphicsContext shouldAntialias];
958 previousImageInterpolation = [graphicsContext imageInterpolation];
959 [graphicsContext setShouldAntialias:YES( BOOL ) 1];
960 [graphicsContext setImageInterpolation:imageInterpolation];
961
962 // Composite the working image into the icon bitmap, centered.
963 targetRect.origin.x = ((float)iconWidth - newSize.width ) / 2.0;
964 targetRect.origin.y = ((float)iconWidth - newSize.height) / 2.0;
965 targetRect.size.width = newSize.width;
966 targetRect.size.height = newSize.height;
967 [workingImageRep drawInRect:targetRect];
968
969 // Restore previous graphics context settings.
970 [graphicsContext setShouldAntialias:wasAntialiasing];
971 [graphicsContext setImageInterpolation:previousImageInterpolation];
972
973 [newImage unlockFocus];
974
975 [workingImage release];
976
977 // Return the new image!
978 return [newImage autorelease];
979}
980
981+ (Handle) get32BitDataFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize
982{
983 Handle hRawData;
984 unsigned char* pRawData;
985 Size rawDataSize;
986 unsigned char* pSrc;
987 unsigned char* pDest;
988 int x, y;
989 unsigned char alphaByte;
990 float oneOverAlpha;
991
992 // Get information about the bitmapImageRep.
993 int pixelsWide = [bitmapImageRep pixelsWide];
994 int pixelsHigh = [bitmapImageRep pixelsHigh];
995 int bitsPerSample = [bitmapImageRep bitsPerSample];
996 int samplesPerPixel = [bitmapImageRep samplesPerPixel];
997 int bitsPerPixel = [bitmapImageRep bitsPerPixel];
998 BOOL isPlanar = [bitmapImageRep isPlanar];
999 int bytesPerRow = [bitmapImageRep bytesPerRow];
1000 unsigned char* bitmapData = [bitmapImageRep bitmapData];
1001
1002 // Make sure bitmap has the required dimensions.
1003 if (pixelsWide != requiredPixelSize || pixelsHigh != requiredPixelSize)
1004 return NULL( ( void * ) 0 );
1005
1006 // So far, this code only handles non-planar 32-bit RGBA and 24-bit RGB source bitmaps.
1007 // This could be made more flexible with some additional programming to accommodate other possible
1008 // formats...
1009 if (isPlanar)
1010 {
1011 NSLog(@"get32BitDataFromBitmapImageRep:requiredPixelSize: returning NULL due to isPlanar == YES");
1012 return NULL( ( void * ) 0 );
1013 }
1014 if (bitsPerSample != 8)
1015 {
1016 NSLog(@"get32BitDataFromBitmapImageRep:requiredPixelSize: returning NULL due to bitsPerSample == %d", bitsPerSample);
1017 return NULL( ( void * ) 0 );
1018 }
1019
1020 if (((samplesPerPixel == 3) && (bitsPerPixel == 24)) || ((samplesPerPixel == 4) && (bitsPerPixel == 32)))
1021 {
1022 rawDataSize = pixelsWide * pixelsHigh * 4;
1023 hRawData = NewHandle( rawDataSize );
1024 if (hRawData == NULL( ( void * ) 0 ))
1025 return NULL( ( void * ) 0 );
1026 pRawData = (unsigned char*) *hRawData;
1027
Value stored to 'pSrc' is never read
1028 pSrc = bitmapData;
1029 pDest = pRawData;
1030
1031 if (bitsPerPixel == 32) {
1032 for (y = 0; y < pixelsHigh; y++) {
1033 pSrc = bitmapData + y * bytesPerRow;
1034 for (x = 0; x