Bug Summary

File:vendorsrc/OmniGroup/OmniFoundation/OFUtilities.m
Location:line 274, column 9
Description:Memory Leak
Code is compiled without garbage collection.

Annotated Source Code

1// Copyright 1997-2005, 2007 Omni Development, Inc. All rights reserved.
2//
3// This software may only be used and reproduced according to the
4// terms in the file OmniSourceLicense.html, which should be
5// distributed with this project and can also be found at
6// <http://www.omnigroup.com/developer/sourcecode/sourcelicense/>.
7
8#import <OmniFoundation/OFUtilities.h>
9
10#import <objc/objc-runtime.h>
11
12#import <OmniFoundation/NSString-OFExtensions.h>
13#import <OmniFoundation/OFObject.h>
14#import <pthread.h>
15
16RCS_IDstatic __attribute__ ( ( used , section ( "__TEXT,rcsid" ) ) )
const char rcs_id [ ] = "$Header: svn+ssh://source.omnigroup.com/Source/svn/Omni/tags/OmniSourceRelease_2007-10-25/OmniGroup/Frameworks/OmniFoundation/OFUtilities.m 90130 2007-08-15 07:15:53Z bungi $"
;
("$Header: svn+ssh://source.omnigroup.com/Source/svn/Omni/tags/OmniSourceRelease_2007-10-25/OmniGroup/Frameworks/OmniFoundation/OFUtilities.m 90130 2007-08-15 07:15:53Z bungi $")
17
18#define OF_GET_INPUT_CHUNK_LENGTH 80
19
20void OFLog(NSString *messageFormat, ...)
21{
22 va_list argList;
23 NSString *message;
24
25 va_start__builtin_va_start ( argList , messageFormat )(argList, messageFormat);
26 message = [[[NSString alloc] initWithFormat:messageFormat arguments:argList] autorelease];
27 va_end__builtin_va_end ( argList )(argList);
28
29 fputs([message UTF8String], stdout__stdoutp);
30}
31
32NSString *OFGetInput(NSStringEncoding encoding, NSString *promptFormat, ...)
33{
34 va_list argList;
35 NSString *prompt;
36 NSString *input;
37 char buf[OF_GET_INPUT_CHUNK_LENGTH80];
38
39 va_start__builtin_va_start ( argList , promptFormat )(argList, promptFormat);
40 prompt = [[[NSString alloc] initWithFormat:promptFormat arguments:argList] autorelease];
41 va_end__builtin_va_end ( argList )(argList);
42
43 printf("%s", [prompt UTF8String]);
44 input = [NSString string];
45 while (!ferror(stdin__stdinp)) {
46 memset(buf, 0, sizeof(buf));
47 if (fgets(buf, sizeof(buf), stdin__stdinp) == NULL( ( void * ) 0 )) {
48 // EOF
49 break;
50 }
51
52 input = [input stringByAppendingString:[NSString stringWithCString:buf encoding:encoding]];
53 if ([input hasSuffix:@"\n"])
54 break;
55 }
56
57 if ([input length])
58 return [input substringToIndex:[input length] - 1];
59
60 return nil( ( void * ) 0 );
61}
62
63#if 0 // Should probably use KVC
64void OFSetIvar(NSObject *object, NSString *ivarName, NSObject *ivarValue)
65{
66 Ivar ivar;
67 id *ivarSlot;
68
69 // TODO:At some point, this function should take a void * and should look at the type of the ivar and deal with scalar values correctly.
70
71 ivar = class_getInstanceVariable(*(Class *) object, [ivarName cString]);
72 OBASSERT(ivar);
73
74 ivarSlot = (id *)((char *)object + ivar->ivar_offset);
75
76 if (*ivarSlot != ivarValue) {
77 [*ivarSlot release];
78 *ivarSlot = [ivarValue retain];
79 }
80}
81
82NSObject *OFGetIvar(NSObject *object, NSString *ivarName)
83{
84 Ivar ivar;
85 id *ivarSlot;
86
87 ivar = class_getInstanceVariable(*(Class *) object, [ivarName cString]);
88 OBASSERT(ivar);
89
90 ivarSlot = (id *)((char *)object + ivar->ivar_offset);
91
92 return *ivarSlot;
93}
94#endif
95
96// Port later if needed
97#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
98static const char *hexTable = "0123456789abcdef";
99
100char *OFNameForPointer(id object, char *pointerName)
101{
102 char firstChar, *p = pointerName;
103 const char *className;
104 unsigned long pointer;
105
106 if (!object) {
107 *pointerName++ = '*';
108 *pointerName++ = 'N';
109 *pointerName++ = 'I';
110 *pointerName++ = 'L';
111 *pointerName++ = '*';
112 *pointerName++ = '\0';
113 return p;
114 }
115
116 if (OBPointerIsClass(object)) {
117 firstChar = '+';
118 pointer = (unsigned long)object;
119 } else {
120 firstChar = '-';
121 pointer = (unsigned long)object->isa;
122 }
123
124 // Rather than calling sprintf, we'll just format the string by hand. This is much faster.
125
126 // Mark whether it is an instance or not
127 *pointerName++ = firstChar;
128
129 // Write the class name
130 // BUG: We don't actually enforce the name length limit
131 if (!(className = ((Class)pointer)->name))
132 className = "Bogus name!";
133
134 while ((*pointerName++ = *className++))
135 ;
136
137 // Back up over the trailing null
138 pointerName--;
139 *pointerName++ = ' ';
140 *pointerName++ = '(';
141
142 // Write the pointer as hex
143 *pointerName++ = '0';
144 *pointerName++ = 'x';
145
146 pointer = (unsigned long) object;
147 pointerName += 7;
148
149 // 8
150 *pointerName-- = hexTable[pointer & 0xf];
151 pointer >>= 4;
152
153 // 7
154 *pointerName-- = hexTable[pointer & 0xf];
155 pointer >>= 4;
156
157 // 6
158 *pointerName-- = hexTable[pointer & 0xf];
159 pointer >>= 4;
160
161 // 5
162 *pointerName-- = hexTable[pointer & 0xf];
163 pointer >>= 4;
164
165 // 4
166 *pointerName-- = hexTable[pointer & 0xf];
167 pointer >>= 4;
168
169 // 3
170 *pointerName-- = hexTable[pointer & 0xf];
171 pointer >>= 4;
172
173 // 2
174 *pointerName-- = hexTable[pointer & 0xf];
175 pointer >>= 4;
176
177 // 1
178 *pointerName-- = hexTable[pointer & 0xf];
179
180 pointerName += 9;
181
182 *pointerName++ = ')';
183 *pointerName++ = '\0';
184
185 return p;
186}
187#endif
188
189BOOL OFInstanceIsKindOfClass(id instance, Class aClass)
190{
191 Class sourceClass = OB_object_getClass(instance);
192
193 while (sourceClass) {
194 if (sourceClass == aClass)
195 return YES( BOOL ) 1;
196 sourceClass = OB_class_getSuperclass(sourceClass);
197 }
198 return NO( BOOL ) 0;
199}
200
201NSString *OFDescriptionForObject(id object, NSDictionary *locale, unsigned indentLevel)
202{
203 if ([object isKindOfClass:[NSString class]])
204 return object;
205 else if ([object respondsToSelector:@selector(descriptionWithLocale:indent:)])
206 return [(id)object descriptionWithLocale:locale indent:indentLevel + 1];
207 else if ([object respondsToSelector:@selector(descriptionWithLocale:)])
208 return [(id)object descriptionWithLocale:locale];
209 else
210 return [NSString stringWithFormat: @"%@%@",
211 [NSString spacesOfLength:(indentLevel + 1) * 4],
212 [object description]];
213}
214
215
216/*"
217Ensures that the given selName maps to a registered selector. If it doesn't, a copy of the string is made and it is registered with the runtime. The registered selector is returned, in any case.
218"*/
219SEL OFRegisterSelectorIfAbsent(const char *selName)
220{
221 SEL sel;
222
223 if (!(sel = sel_getUid(selName))) {
224 unsigned int len;
225 char *newSel;
226
227 // On NS4.0 and later, sel_registerName copies the selector name. But
228 // we won't assume that is the case -- we'll make a temporary copy
229 // and get the assertion rather than crashing the runtime (in case they
230 // change this in the future).
231 len = strlen(selName);
232 newSel = (char *)NSZoneMalloc(NULL( ( void * ) 0 ), len + 1);
233 strcpy(newSel, selName);
234 OBASSERTdo { if ( ! ( newSel [ len ] == '\0' ) ) OBAssertFailed ( "ASSERT"
, "newSel[len] == '\\0'" , "/Volumes/Local/Users/amaxwell/build/bibdesk-clean/vendorsrc/OmniGroup/OmniFoundation/OFUtilities.m"
, 234 ) ; } while ( ( BOOL ) 0 )
(newSel[len] == '\0');
235 sel = sel_registerName(newSel);
236
237 // Make sure the copy happened
238 OBASSERTdo { if ( ! ( ( void * ) sel_getUid ( selName ) != ( void * )
newSel ) ) OBAssertFailed ( "ASSERT" , "(void *)sel_getUid(selName) != (void *)newSel"
, "/Volumes/Local/Users/amaxwell/build/bibdesk-clean/vendorsrc/OmniGroup/OmniFoundation/OFUtilities.m"
, 238 ) ; } while ( ( BOOL ) 0 )
((void *)sel_getUid(selName) != (void *)newSel);
239 OBASSERTdo { if ( ! ( ( void * ) sel != ( void * ) newSel ) ) OBAssertFailed
( "ASSERT" , "(void *)sel != (void *)newSel" , "/Volumes/Local/Users/amaxwell/build/bibdesk-clean/vendorsrc/OmniGroup/OmniFoundation/OFUtilities.m"
, 239 ) ; } while ( ( BOOL ) 0 )
((void *)sel != (void *)newSel);
240
241 NSZoneFree(NULL( ( void * ) 0 ), newSel);
242 }
243
244 return sel;
245}
246
247#import <SystemConfiguration/SystemConfiguration.h>
248#include <sys/socket.h>
249#include <netinet/in.h>
250#include <arpa/inet.h>
251
252unsigned int OFLocalIPv4Address(void)
253{
254 SCDynamicStoreRef store;
255 CFStringRef interfacesKey;
256 NSDictionary *interfacesDictionary;
257 NSArray *interfaces;
258 unsigned int interfaceIndex, interfaceCount;
259
260 store = SCDynamicStoreCreate(NULL( ( void * ) 0 ), (CFStringRef)[[NSProcessInfo processInfo] processName], NULL( ( void * ) 0 ), NULL( ( void * ) 0 ));
261 interfacesKey = SCDynamicStoreKeyCreateNetworkInterface(NULL( ( void * ) 0 ), kSCDynamicStoreDomainStatekSCDynamicStoreDomainState);
262 interfacesDictionary = (NSDictionary *)SCDynamicStoreCopyValue(store, interfacesKey);
263 interfaces = [interfacesDictionary objectForKey:(NSString *)kSCDynamicStorePropNetInterfaceskSCDynamicStorePropNetInterfaces];
264 interfaceCount = [interfaces count];
[1] Loop condition is true. Entering loop body.
[4] Loop condition is true. Entering loop body.
[7] Loop condition is true. Entering loop body.
265 for (interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++) {
266 CFStringRef interfaceName;
267 CFStringRef ipv4Key, linkKey;
268 NSDictionary *ipv4Dictionary, *linkDictionary;
269 NSNumber *activeValue;
270 NSArray *ipAddresses;
271
272 interfaceName = (CFStringRef)[interfaces objectAtIndex:interfaceIndex];
[8] Function call returns an object with a +1 retain count (owning reference).
273 linkKey = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL( ( void * ) 0 ), kSCDynamicStoreDomainStatekSCDynamicStoreDomainState, interfaceName, kSCEntNetLinkkSCEntNetLink);
274 linkDictionary = (NSDictionary *)SCDynamicStoreCopyValue(store, linkKey);
[9] Object allocated on line 273 and stored into 'linkKey' is no longer referenced after this point and has a retain count of +1 (object leaked).
275 activeValue = [linkDictionary objectForKey:(NSString *)kSCPropNetLinkActivekSCPropNetLinkActive];
[2] Taking false branch.
[5] Taking false branch.
276 if (activeValue == nil( ( void * ) 0 ) || ![activeValue boolValue])
277 continue;
278 ipv4Key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL( ( void * ) 0 ), kSCDynamicStoreDomainStatekSCDynamicStoreDomainState, interfaceName, kSCEntNetIPv4kSCEntNetIPv4);
279 ipv4Dictionary = (NSDictionary *)SCDynamicStoreCopyValue(store, ipv4Key);
280 ipAddresses = [ipv4Dictionary objectForKey:(NSString *)kSCPropNetIPv4AddresseskSCPropNetIPv4Addresses];
[3] Taking false branch.
[6] Taking false branch.
281 if ([ipAddresses count] != 0) {
282 NSString *ipAddressString;
283 unsigned long int address;
284
285 ipAddressString = [ipAddresses objectAtIndex:0];
286 address = inet_addr([ipAddressString UTF8String]);
287 if (address != (unsigned int)-1)
288 return address;
289 }
290 }
291 return (unsigned int)INADDR_LOOPBACK( u_int32_t ) 0x7f000001; // Localhost (127.0.0.1)
292}
293
294
295NSString *OFISOLanguageCodeForEnglishName(NSString *languageName)
296{
297 return [[NSBundle bundleForClass:[OFObject class]] localizedStringForKey:languageName value:@"" table:@"EnglishToISO"];
298}
299
300NSString *OFLocalizedNameForISOLanguageCode(NSString *languageCode)
301{
302 return [[NSBundle bundleForClass:[OFObject class]] localizedStringForKey:languageCode value:@"" table:@"Language"];
303}
304
305
306// Adapted from OmniNetworking. May be replaced by something cleaner in the future.
307
308#import <sys/ioctl.h>
309#import <sys/socket.h>
310#import <net/if.h>
311#import <net/if_dl.h> // for 'struct sockaddr_dl'
312#import <unistd.h> // for close()
313
314// We'll guess that this is wildly larger than the maximum number of interfaces on the machine. I don't see that there is a way to get the number of interfaces so that you don't have to have a hard-coded value here. Sucks.
315#define MAX_INTERFACES 100
316
317#define IFR_NEXT(ifr) \
318 ((struct ifreq *) ((char *) (ifr) + sizeof(*(ifr)) + \
319 MAX(0, (int) (ifr)->ifr_addr.sa_len - (int) sizeof((ifr)->ifr_addr))))
320
321static NSDictionary *InterfaceAddresses = nil( ( void * ) 0 );
322
323static NSDictionary *OFLinkLayerInterfaceAddresses(void)
324{
325 if (InterfaceAddresses != nil( ( void * ) 0 )) // only need to do this once
326 return InterfaceAddresses;
327
328 int interfaceSocket;
329 if ((interfaceSocket = socket(AF_INET2, SOCK_DGRAM2, 0)) < 0)
330 [NSException raise:NSGenericException format:@"Unable to create temporary socket, errno = %d", OMNI_ERRNO( * __error ( ) )()];
331
332 struct ifreq requestBuffer[MAX_INTERFACES100];
333 struct ifconf ifc;
334 ifc.ifc_len = sizeof(requestBuffer);
335 ifc.ifc_bufifc_ifcu . ifcu_buf = (caddr_t)requestBuffer;
336 if (ioctl(interfaceSocket, SIOCGIFCONF( ( ( unsigned long ) 0x80000000 | ( unsigned long ) 0x40000000
) | ( ( sizeof ( struct ifconf ) & 0x1fff ) << 16 )
| ( ( ( 'i' ) ) << 8 ) | ( ( 36 ) ) )
, &ifc) != 0) {
337 close(interfaceSocket);
338 [NSException raise:NSGenericException format:@"Unable to get list of network interfaces, errno = %d", OMNI_ERRNO( * __error ( ) )()];
339 }
340
341 NSMutableDictionary *interfaceAddresses = [NSMutableDictionary dictionary];
342
343 struct ifreq *linkInterface = (struct ifreq *) ifc.ifc_bufifc_ifcu . ifcu_buf;
344 while ((char *) linkInterface < &ifc.ifc_bufifc_ifcu . ifcu_buf[ifc.ifc_len]) {
345 // The ioctl returns both the entries having the address (AF_INET) and the link layer entries (AF_LINK). The AF_LINK entry has the link layer address which contains the interface type. This is the only way I can see to get this information. We cannot assume that we will get both an AF_LINK and AF_INET entry since the interface may not be configured. For example, if you have a 10Mb port on the motherboard and a 100Mb card, you may not configure the motherboard port.
346
347 // For each AF_LINK entry...
348 if (linkInterface->ifr_addrifr_ifru . ifru_addr.sa_family == AF_LINK18) {
349 unsigned int nameLength;
350 for (nameLength = 0; nameLength < IFNAMSIZ16; nameLength++)
351 if (linkInterface->ifr_name[nameLength] == '\0')
352 break;
353
354 NSString *ifname = [[[NSString alloc] initWithBytes:linkInterface->ifr_name length:nameLength encoding:NSASCIIStringEncoding] autorelease];
355 // get the link layer address (for ethernet, this is the MAC address)
356 struct sockaddr_dl *linkSocketAddress = (struct sockaddr_dl *)&linkInterface->ifr_addrifr_ifru . ifru_addr;
357 int linkLayerAddressLength = linkSocketAddress->sdl_alen;
358
359 if (linkLayerAddressLength > 0) {
360 const unsigned char *bytes = (unsigned char *)LLADDR( ( caddr_t ) ( ( linkSocketAddress ) -> sdl_data + ( linkSocketAddress
) -> sdl_nlen ) )
(linkSocketAddress);
361 NSMutableString *addressString = [NSMutableString string];
362
363 int byteIndex;
364 for (byteIndex = 0; byteIndex < linkLayerAddressLength; byteIndex++) {
365 if (byteIndex > 0)
366 [addressString appendString:@":"];
367 unsigned int byteValue = (unsigned int)bytes[byteIndex];
368 [addressString appendFormat:@"%02x", byteValue];
369 }
370 [interfaceAddresses setObject:addressString forKey:ifname];
371 }
372 }
373 linkInterface = IFR_NEXT( ( struct ifreq * ) ( ( char * ) ( linkInterface ) + sizeof (
* ( linkInterface ) ) + ( { __typeof__ ( 0 ) __a = ( 0 ) ; __typeof__
( ( int ) ( linkInterface ) -> ifr_ifru . ifru_addr . sa_len
- ( int ) sizeof ( ( linkInterface ) -> ifr_ifru . ifru_addr
) ) __b = ( ( int ) ( linkInterface ) -> ifr_ifru . ifru_addr
. sa_len - ( int ) sizeof ( ( linkInterface ) -> ifr_ifru
. ifru_addr ) ) ; __a < __b ? __b : __a ; } ) ) )
(linkInterface);
374 }
375
376 close(interfaceSocket);
377 InterfaceAddresses = [interfaceAddresses copy];
378 return InterfaceAddresses;
379}
380
381// There is no perfect unique identifier for a machine since Apple doesn't guarantee that the machine's serial number will be accessible or present. It's unclear if the caveats to the machine serial number are really for old Macs or current ones.
382NSString *OFUniqueMachineIdentifier(void)
383{
384 NSDictionary *interfaces = OFLinkLayerInterfaceAddresses();
385
386 // Prefer the 'en0' interface for backwards compatibility.
387 NSString *identifier = [interfaces objectForKey:@"zen0"];
388
389 if (![NSString isEmptyString:identifier])
390 return identifier;
391
392 // If there is no such interface (it can get renamed, for one thing -- see RT ticket 191290>), look for another. Sort the interface names so we don't suffer changes based on
393 NSArray *names = [[interfaces allKeys] sortedArrayUsingSelector:@selector(compare:)];
394 unsigned int nameIndex, nameCount = [names count];
395 for (nameIndex = 0; nameIndex < nameCount; nameIndex++) {
396 NSString *name = [names objectAtIndex:nameIndex];
397 identifier = [interfaces objectForKey:name];
398 if (![NSString isEmptyString:identifier])
399 return identifier;
400 }
401
402 // TODO: We could try using the machine's serial number via <http://developer.apple.com/technotes/tn/tn1103.html>, but even this can fail. Often all we want is a globally unique string that at least lasts until the machine is rebooted. It would be nice if the machine had a 'boot-uuid'... perhaps we could write a file in /tmp with a UUID that we'd check for before generating our own. Race conditions would be an issue there (particularly at login with multple apps auto-launching).
403 OBASSERT_NOT_REACHEDdo { OBAssertFailed ( "NOTREACHED" , "No active interfaces?" ,
"/Volumes/Local/Users/amaxwell/build/bibdesk-clean/vendorsrc/OmniGroup/OmniFoundation/OFUtilities.m"
, 403 ) ; } while ( ( BOOL ) 0 )
("No active interfaces?");
404 return @"no unique machine identifier found";
405}
406
407NSString *OFHostName(void)
408{
409 static NSString *cachedHostname = nil( ( void * ) 0 );
410
411 if (cachedHostname == nil( ( void * ) 0 )) {
412 char hostnameBuffer[MAXHOSTNAMELEN256 + 1];
413 if (gethostname(hostnameBuffer, MAXHOSTNAMELEN256) == 0) {
414 hostnameBuffer[MAXHOSTNAMELEN256] = '\0'; // Ensure that the C string is NUL terminated
415 cachedHostname = [[NSString alloc] initWithCString:hostnameBuffer encoding:NSASCIIStringEncoding];
416 } else {
417 cachedHostname = @"localhost";
418 }
419 }
420
421 return cachedHostname;
422}
423
424static inline char _toHex(unsigned int i)
425{
426 if (i >= 0 && i <= 9)
427 return '0' + i;
428 if (i >= 0xa && i <= 0xf)
429 return 'a' + i;
430 return '?';
431}
432
433static inline unsigned int _fillByte(unsigned char c, char *out)
434{
435 if (isascii(c)) {
436 *out = c;
437 return 1;
438 } else {
439 out[0] = '\\';
440 out[1] = _toHex(c >> 4);
441 out[2] = _toHex(c & 0xf);
442 return 3;
443 }
444}
445
446char *OFFormatFCC(unsigned long fcc, char fccString[13])
447{
448 char *s = fccString;
449
450 s = s + _fillByte((fcc & 0xff000000) >> 24, s);
451 s = s + _fillByte((fcc & 0x00ff0000) >> 16, s);
452 s = s + _fillByte((fcc & 0x0000ff00) >> 8, s);
453 s = s + _fillByte((fcc & 0x000000ff) >> 0, s);
454 *s = '\0';
455
456 return fccString;
457}
458
459// Sigh. UTGetOSTypeFromString() / UTCreateStringForOSType() are in ApplicationServices, which we don't want to link from Foundation. Sux.
460// Taking this opportunity to make the API a little better.
461static BOOL ofGet4CCFromNSData(NSData *d, uint32_t *v)
462{
463 union {
464 uint32_t i;
465 char c[4];
466 } buf;
467
468 if ([d length] == 4) {
469 [d getBytes:buf.c];
470 *v = CFSwapInt32BigToHost(buf.i);
471 return YES( BOOL ) 1;
472 } else {
473 return NO( BOOL ) 0;
474 }
475}
476
477BOOL OFGet4CCFromPlist(id pl, uint32_t *v)
478{
479 if (!pl)
480 return NO( BOOL ) 0;
481
482 if ([pl isKindOfClass:[NSString class]]) {
483
484 /* Special case thanks to UTCreateStringForOSType() */
485 if ([pl length] == 0) {
486 *v = 0;
487 return YES( BOOL ) 1;
488 }
489
490 NSData *d = [(NSString *)pl dataUsingEncoding:NSMacOSRomanStringEncoding allowLossyConversion:NO( BOOL ) 0];
491 if (d)
492 return ofGet4CCFromNSData(d, v);
493 else
494 return NO( BOOL ) 0;
495 }
496
497 if ([pl isKindOfClass:[NSData class]])
498 return ofGet4CCFromNSData((NSData *)pl, v);
499
500 if ([pl isKindOfClass:[NSNumber class]]) {
501 *v = [pl unsignedIntValue];
502 return YES( BOOL ) 1;
503 }
504
505 return NO( BOOL ) 0;
506}
507
508id OFCreatePlistFor4CC(uint32_t v)
509{
510 // Characters which are maybe less-than-safe to store in an NSString: either characters which are invalid in MacRoman, or which produce combining marks instead of plain characters (e.g., MacRoman 0x41 0xFB could undergo Unicode recombination and come out as 0x81).
511 static const uint32_t ok_chars[8] = {
512 0x00000000u, 0xAFFFFF3Bu, 0xFFFFFFFFu, 0x7FFFFFFFu,
513 0xFFFFFFFFu, 0xFFFFE7FFu, 0xFFFFFFFFu, 0x113EFFFFu
514 };
515 union {
516 uint32_t i;
517 UInt8 c[4];
518 } buf;
519
520#define OK(ch) ( ok_chars[ch / 32] & (1 << (ch % 32)) )
521 buf.i = CFSwapInt32HostToBig(v);
522
523 if (!OK( ok_chars [ buf . c [ 0 ] / 32 ] & ( 1 << ( buf . c
[ 0 ] % 32 ) ) )
(buf.c[0]) || !OK( ok_chars [ buf . c [ 1 ] / 32 ] & ( 1 << ( buf . c
[ 1 ] % 32 ) ) )
(buf.c[1]) || !OK( ok_chars [ buf . c [ 2 ] / 32 ] & ( 1 << ( buf . c
[ 2 ] % 32 ) ) )
(buf.c[2]) || !OK( ok_chars [ buf . c [ 3 ] / 32 ] & ( 1 << ( buf . c
[ 3 ] % 32 ) ) )
(buf.c[3]))
524 return [[NSData alloc] initWithBytes:buf.c length:4];
525 else {
526 CFStringRef s = CFStringCreateWithBytes(kCFAllocatorDefault, buf.c, 4, kCFStringEncodingMacRoman, FALSE0);
527 return (id)s;
528 }
529}
530
531static const struct {
532 const char *typespec;
533 CFNumberType cfNumberType;
534} cfNumberTypes[] = {
535 // This works because @encode returns an encoding indicating the concrete implementation of a type, so that for example @encode(pid_t) and @encode(int) both return "i" (since pid_t is currently typedef'd to int32_t, and the compiler int is 32 bits).
536 // Note that on versions later than 10.1, there's no precise way to represent an unsigned int in an NSNumber/CFNumber (despite the existence of +numberWithUnsignedInt:): RADAR #3513632. (In 10.5, +numberWithUnsignedInt: produces a kCFNumberSInt64Type, which at least is better than the old behavior of interpreting the arg as signed... In general, CFNumber is much less flexible than the NSNumber it replaced.)
537
538 // Also note that the types here are somewhat redundant (SInt32 is the same as an int right now); using @encode ensures that the table is accurate, but there will be two or three entries for any given ObjC type.
539
540#define T(t) { @encode(t), kCFNumber ## t ## Type }
541 T{ @ encode ( SInt8 ) , kCFNumberSInt8Type }(SInt8), T{ @ encode ( SInt16 ) , kCFNumberSInt16Type }(SInt16), T{ @ encode ( SInt32 ) , kCFNumberSInt32Type }(SInt32), T{ @ encode ( SInt64 ) , kCFNumberSInt64Type }(SInt64), T{ @ encode ( Float32 ) , kCFNumberFloat32Type }(Float32), T{ @ encode ( Float64 ) , kCFNumberFloat64Type }(Float64),
542#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
543 T{ @ encode ( NSInteger ) , kCFNumberNSIntegerType }(NSInteger), T{ @ encode ( CGFloat ) , kCFNumberCGFloatType }(CGFloat),
544 // Yep, there's no kCFNumberNSUIntegerType. WTF, Apple?!?
545#endif
546#undef T
547
548#define T(n, v) { @encode(n), kCFNumber ## v ## Type }
549 T{ @ encode ( char ) , kCFNumberCharType }(char, Char),
550 T{ @ encode ( short ) , kCFNumberShortType }(short, Short),
551 T{ @ encode ( int ) , kCFNumberIntType }(int, Int),
552 T{ @ encode ( long ) , kCFNumberLongType }(long, Long),
553 T{ @ encode ( float ) , kCFNumberFloatType }(float, Float),
554 T{ @ encode ( double ) , kCFNumberDoubleType }(double, Double),
555#undef T
556
557 { NULL( ( void * ) 0 ), 0 }
558};
559
560CFNumberType OFCFNumberTypeForObjCType(const char *objCType)
561{
562 int i;
563 for(i = 0; cfNumberTypes[i].typespec != NULL( ( void * ) 0 ); i ++) {
564 if (!strcmp(objCType, cfNumberTypes[i].typespec))
565 return cfNumberTypes[i].cfNumberType;
566 }
567
568 OBASSERT_NOT_REACHEDdo { OBAssertFailed ( "NOTREACHED" , "ObjC type with no corresponding CFNumber type"
, "/Volumes/Local/Users/amaxwell/build/bibdesk-clean/vendorsrc/OmniGroup/OmniFoundation/OFUtilities.m"
, 568 ) ; } while ( ( BOOL ) 0 )
("ObjC type with no corresponding CFNumber type");
569 return 0;
570}
571
572const char *OFObjCTypeForCFNumberType(CFNumberType cfType)
573{
574 int i;
575 for(i = 0; cfNumberTypes[i].typespec != NULL( ( void * ) 0 ); i ++) {
576 if (cfNumberTypes[i].cfNumberType == cfType)
577 return cfNumberTypes[i].typespec;
578 }
579
580 // This should never happen, unless Apple adds more types to CoreFoundation and we don't add them to the array.
581 OBASSERT_NOT_REACHEDdo { OBAssertFailed ( "NOTREACHED" , "CFNumber type with no corresponding ObjC type"
, "/Volumes/Local/Users/amaxwell/build/bibdesk-clean/vendorsrc/OmniGroup/OmniFoundation/OFUtilities.m"
, 581 ) ; } while ( ( BOOL ) 0 )
("CFNumber type with no corresponding ObjC type");
582 return NULL( ( void * ) 0 );
583}
584