2 * Copyright (c) 2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright (c) 1999-2009, Apple Inc. All rights reserved.
25 Responsibility: Doug Davidson
28 #include <CoreFoundation/CFUUID.h>
29 #include "CFInternal.h"
30 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
31 #include <uuid/uuid.h>
34 static CFMutableDictionaryRef _uniquedUUIDs
= NULL
;
35 static CFSpinLock_t CFUUIDGlobalDataLock
= CFSpinLockInit
;
42 static Boolean
__CFisEqualUUIDBytes(const void *ptr1
, const void *ptr2
) {
43 CFUUIDBytes
*p1
= (CFUUIDBytes
*)ptr1
;
44 CFUUIDBytes
*p2
= (CFUUIDBytes
*)ptr2
;
46 return (((p1
->byte0
== p2
->byte0
) && (p1
->byte1
== p2
->byte1
) && (p1
->byte2
== p2
->byte2
) && (p1
->byte3
== p2
->byte3
) && (p1
->byte4
== p2
->byte4
) && (p1
->byte5
== p2
->byte5
) && (p1
->byte6
== p2
->byte6
) && (p1
->byte7
== p2
->byte7
) && (p1
->byte8
== p2
->byte8
) && (p1
->byte9
== p2
->byte9
) && (p1
->byte10
== p2
->byte10
) && (p1
->byte11
== p2
->byte11
) && (p1
->byte12
== p2
->byte12
) && (p1
->byte13
== p2
->byte13
) && (p1
->byte14
== p2
->byte14
) && (p1
->byte15
== p2
->byte15
)) ? true : false);
49 static CFHashCode
__CFhashUUIDBytes(const void *ptr
) {
50 return CFHashBytes((uint8_t *)ptr
, 16);
54 * GC implementation of a weak set specifically designed for UUID
57 #define LOCK() __CFSpinLock(&CFUUIDGlobalDataLock)
58 #define UNLOCK() __CFSpinUnlock(&CFUUIDGlobalDataLock)
60 #define MALLOC(x) CFAllocatorAllocate(kCFAllocatorSystemDefault, x, 0)
61 #define FREE(x) CFAllocatorDeallocate(kCFAllocatorSystemDefault, x)
62 #define HASH(x) CFHashBytes((uint8_t *)x, 16)
64 #define READWEAK(location) auto_read_weak_reference(auto_zone(), (void**)location)
65 #define WRITEWEAK(location, value) auto_assign_weak_reference(auto_zone(), value, (void **)location, NULL)
68 unsigned long count
, size
;
69 struct __CFUUID
**weakPtrs
;
72 static _UUIDWeakSet_t _UUIDWeakSet
;
74 static void grow_has_lock(void);
76 // enter if not already present
77 static void enter_has_lock(struct __CFUUID
*candidate
) {
78 if (!candidate
) return;
79 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
80 if (!table
->size
) grow_has_lock();
81 unsigned long int hashValue
= HASH(&candidate
->_bytes
) & (table
->size
-1);
82 struct __CFUUID
*result
= table
->weakPtrs
[hashValue
];
84 if (result
== (void *)0x1 || result
== NULL
) {
85 table
->weakPtrs
[hashValue
] = NULL
; // so that we don't try to unregister 0x1
86 WRITEWEAK(&table
->weakPtrs
[hashValue
], (void *)candidate
);
90 if (result
) result
= (struct __CFUUID
*)READWEAK(&table
->weakPtrs
[hashValue
]);
92 // see if it is equal to candidate
93 if (__CFisEqualUUIDBytes(&result
->_bytes
, &candidate
->_bytes
)) {
94 // keep first one. There is a race if two threads both fail to find
95 // a candidate uuid then both try decide to create and enter one.
96 // Under non-GC one of them simply leaks.
100 // was zeroed by collector. Use this slot.
104 if (++hashValue
>= table
->size
) hashValue
= 0;
105 result
= table
->weakPtrs
[hashValue
];
109 static void *find_has_lock(CFUUIDBytes
*bytes
) {
110 if (!bytes
) return NULL
;
111 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
112 if (!table
->size
) return NULL
; // no entries
113 unsigned long int hashValue
= HASH(bytes
) & (table
->size
-1);
114 struct __CFUUID
*result
= table
->weakPtrs
[hashValue
];
116 if (result
== (void *)0x1) break;
117 if (result
) result
= (struct __CFUUID
*)READWEAK(&table
->weakPtrs
[hashValue
]);
119 // see if it is equal to bytes
120 if (__CFisEqualUUIDBytes(&result
->_bytes
, bytes
)) return result
;
123 if (++hashValue
>= table
->size
) hashValue
= 0;
124 result
= table
->weakPtrs
[hashValue
];
130 static void grow_has_lock() {
131 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
132 if (table
->size
== 0) {
134 table
->weakPtrs
= (struct __CFUUID
**)MALLOC(sizeof(struct __CFUUID
*)*table
->size
);
135 for (int i
= 0; i
< table
->size
; ++i
) table
->weakPtrs
[i
] = (struct __CFUUID
*)0x1;
140 table
->size
= table
->size
*2;
141 struct __CFUUID
**oldPtrs
= table
->weakPtrs
;
142 table
->weakPtrs
= (struct __CFUUID
**)MALLOC(sizeof(struct __CFUUID
*)*table
->size
);
143 for (int i
= 0; i
< table
->size
; ++i
) table
->weakPtrs
[i
] = (struct __CFUUID
*)0x1;
144 for (int i
= 0; i
< table
->size
/ 2; ++i
) {
145 if (oldPtrs
[i
] == (struct __CFUUID
*)0x1) continue; // available field, ignore
146 if (oldPtrs
[i
] == NULL
) continue; // zero'ed by collector, ignore
147 enter_has_lock((struct __CFUUID
*)READWEAK(&oldPtrs
[i
])); // read, then enter (but enter must check for NULL)
148 WRITEWEAK(&oldPtrs
[i
], NULL
); // unregister
153 /***** end of weak set */
155 static void __CFUUIDAddUniqueUUID(CFUUIDRef uuid
) {
156 CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks
= {0, NULL
, NULL
, NULL
, __CFisEqualUUIDBytes
, __CFhashUUIDBytes
};
157 CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks
= {0, NULL
, NULL
, CFCopyDescription
, CFEqual
};
159 __CFSpinLock(&CFUUIDGlobalDataLock
);
160 if (kCFUseCollectableAllocator
) {
161 enter_has_lock((struct __CFUUID
*)uuid
);
162 if (_UUIDWeakSet
.count
> (3 * _UUIDWeakSet
.size
/ 4)) grow_has_lock();
163 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
166 if (!_uniquedUUIDs
) _uniquedUUIDs
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &__CFUUIDBytesDictionaryKeyCallBacks
, &__CFnonRetainedUUIDDictionaryValueCallBacks
);
167 CFDictionarySetValue(_uniquedUUIDs
, &(uuid
->_bytes
), uuid
);
168 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
171 static void __CFUUIDRemoveUniqueUUID(CFUUIDRef uuid
) {
172 __CFSpinLock(&CFUUIDGlobalDataLock
);
173 if (_uniquedUUIDs
) CFDictionaryRemoveValue(_uniquedUUIDs
, &(uuid
->_bytes
));
174 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
177 static CFUUIDRef
__CFUUIDGetUniquedUUID(CFUUIDBytes
*bytes
) {
178 CFUUIDRef uuid
= NULL
;
179 __CFSpinLock(&CFUUIDGlobalDataLock
);
180 if (kCFUseCollectableAllocator
) {
181 uuid
= (CFUUIDRef
)find_has_lock(bytes
);
182 } else if (_uniquedUUIDs
) {
183 uuid
= (CFUUIDRef
)CFDictionaryGetValue(_uniquedUUIDs
, bytes
);
185 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
189 static void __CFUUIDDeallocate(CFTypeRef cf
) {
190 if (kCFUseCollectableAllocator
) return;
192 struct __CFUUID
*uuid
= (struct __CFUUID
*)cf
;
193 __CFUUIDRemoveUniqueUUID(uuid
);
196 static CFStringRef
__CFUUIDCopyDescription(CFTypeRef cf
) {
197 CFStringRef uuidStr
= CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
198 CFStringRef desc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFUUID %p> %@"), cf
, uuidStr
);
203 static CFStringRef
__CFUUIDCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
204 return CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
207 static CFTypeID __kCFUUIDTypeID
= _kCFRuntimeNotATypeID
;
209 static const CFRuntimeClass __CFUUIDClass
= {
217 __CFUUIDCopyFormattingDescription
,
218 __CFUUIDCopyDescription
221 __private_extern__
void __CFUUIDInitialize(void) {
222 __kCFUUIDTypeID
= _CFRuntimeRegisterClass(&__CFUUIDClass
);
225 CFTypeID
CFUUIDGetTypeID(void) {
226 return __kCFUUIDTypeID
;
229 static CFUUIDRef
__CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator
, CFUUIDBytes bytes
, Boolean isConst
) {
230 struct __CFUUID
*uuid
= (struct __CFUUID
*)__CFUUIDGetUniquedUUID(&bytes
);
233 size
= sizeof(struct __CFUUID
) - sizeof(CFRuntimeBase
);
234 uuid
= (struct __CFUUID
*)_CFRuntimeCreateInstance(kCFUseCollectableAllocator
? kCFAllocatorSystemDefault
: allocator
, __kCFUUIDTypeID
, size
, NULL
);
236 if (!uuid
) return NULL
;
238 uuid
->_bytes
= bytes
;
239 __CFUUIDAddUniqueUUID(uuid
);
240 } else if (!isConst
) {
243 return (CFUUIDRef
)uuid
;
246 #if DEPLOYMENT_TARGET_WINDOWS
250 CFUUIDRef
CFUUIDCreate(CFAllocatorRef alloc
) {
251 /* Create a new bytes struct and then call the primitive. */
255 __CFSpinLock(&CFUUIDGlobalDataLock
);
256 #if DEPLOYMENT_TARGET_WINDOWS
258 long rStatus
= UuidCreate(&u
);
259 if (RPC_S_OK
!= rStatus
&& RPC_S_UUID_LOCAL_ONLY
!= rStatus
) retval
= 1;
260 memmove(&bytes
, &u
, sizeof(bytes
));
261 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
262 static Boolean useV1UUIDs
= false, checked
= false;
265 const char *value
= __CFgetenv("CFUUIDVersionNumber");
267 if (1 == strtoul_l(value
, NULL
, 0, NULL
)) useV1UUIDs
= true;
269 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionTiger
)) useV1UUIDs
= true;
273 if (useV1UUIDs
) uuid_generate_time(uuid
); else uuid_generate_random(uuid
);
274 memcpy(&bytes
, uuid
, sizeof(uuid
));
278 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
280 return (retval
== 0) ? __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false) : NULL
;
283 CFUUIDRef
CFUUIDCreateWithBytes(CFAllocatorRef alloc
, uint8_t byte0
, uint8_t byte1
, uint8_t byte2
, uint8_t byte3
, uint8_t byte4
, uint8_t byte5
, uint8_t byte6
, uint8_t byte7
, uint8_t byte8
, uint8_t byte9
, uint8_t byte10
, uint8_t byte11
, uint8_t byte12
, uint8_t byte13
, uint8_t byte14
, uint8_t byte15
) {
285 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
296 bytes
.byte10
= byte10
;
297 bytes
.byte11
= byte11
;
298 bytes
.byte12
= byte12
;
299 bytes
.byte13
= byte13
;
300 bytes
.byte14
= byte14
;
301 bytes
.byte15
= byte15
;
303 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
306 static void _intToHexChars(UInt32 in
, UniChar
*out
, int digits
) {
310 while (--digits
>= 0) {
312 d
= 0x0FL
& (in
>> shift
);
314 *out
++ = (UniChar
)'0' + d
;
316 *out
++ = (UniChar
)'A' + (d
- 10);
321 static uint8_t _byteFromHexChars(UniChar
*in
) {
327 for (i
=0; i
<2; i
++) {
329 if ((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) {
330 d
= c
- (UniChar
)'0';
331 } else if ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) {
332 d
= c
- ((UniChar
)'a' - 10);
333 } else if ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F')) {
334 d
= c
- ((UniChar
)'A' - 10);
338 result
= (result
<< 4) | d
;
344 CF_INLINE Boolean
_isHexChar(UniChar c
) {
345 return ((((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) || ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) || ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F'))) ? true : false);
348 #define READ_A_BYTE(into) if (i+1 < len) { \
349 (into) = _byteFromHexChars(&(chars[i])); \
353 CFUUIDRef
CFUUIDCreateFromString(CFAllocatorRef alloc
, CFStringRef uuidStr
) {
354 /* Parse the string into a bytes struct and then call the primitive. */
360 if (uuidStr
== NULL
) return NULL
;
362 len
= CFStringGetLength(uuidStr
);
365 } else if (len
== 0) {
368 CFStringGetCharacters(uuidStr
, CFRangeMake(0, len
), chars
);
369 memset((void *)&bytes
, 0, sizeof(bytes
));
371 /* Skip initial random stuff */
372 while (!_isHexChar(chars
[i
]) && i
< len
) i
++;
374 READ_A_BYTE(bytes
.byte0
);
375 READ_A_BYTE(bytes
.byte1
);
376 READ_A_BYTE(bytes
.byte2
);
377 READ_A_BYTE(bytes
.byte3
);
380 READ_A_BYTE(bytes
.byte4
);
381 READ_A_BYTE(bytes
.byte5
);
384 READ_A_BYTE(bytes
.byte6
);
385 READ_A_BYTE(bytes
.byte7
);
388 READ_A_BYTE(bytes
.byte8
);
389 READ_A_BYTE(bytes
.byte9
);
392 READ_A_BYTE(bytes
.byte10
);
393 READ_A_BYTE(bytes
.byte11
);
394 READ_A_BYTE(bytes
.byte12
);
395 READ_A_BYTE(bytes
.byte13
);
396 READ_A_BYTE(bytes
.byte14
);
397 READ_A_BYTE(bytes
.byte15
);
399 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
402 CFStringRef
CFUUIDCreateString(CFAllocatorRef alloc
, CFUUIDRef uuid
) {
403 CFMutableStringRef str
= CFStringCreateMutable(alloc
, 0);
406 // First segment (4 bytes, 8 digits + 1 dash)
407 _intToHexChars(uuid
->_bytes
.byte0
, buff
, 2);
408 _intToHexChars(uuid
->_bytes
.byte1
, &(buff
[2]), 2);
409 _intToHexChars(uuid
->_bytes
.byte2
, &(buff
[4]), 2);
410 _intToHexChars(uuid
->_bytes
.byte3
, &(buff
[6]), 2);
411 buff
[8] = (UniChar
)'-';
412 CFStringAppendCharacters(str
, buff
, 9);
414 // Second segment (2 bytes, 4 digits + 1 dash)
415 _intToHexChars(uuid
->_bytes
.byte4
, buff
, 2);
416 _intToHexChars(uuid
->_bytes
.byte5
, &(buff
[2]), 2);
417 buff
[4] = (UniChar
)'-';
418 CFStringAppendCharacters(str
, buff
, 5);
420 // Third segment (2 bytes, 4 digits + 1 dash)
421 _intToHexChars(uuid
->_bytes
.byte6
, buff
, 2);
422 _intToHexChars(uuid
->_bytes
.byte7
, &(buff
[2]), 2);
423 buff
[4] = (UniChar
)'-';
424 CFStringAppendCharacters(str
, buff
, 5);
426 // Fourth segment (2 bytes, 4 digits + 1 dash)
427 _intToHexChars(uuid
->_bytes
.byte8
, buff
, 2);
428 _intToHexChars(uuid
->_bytes
.byte9
, &(buff
[2]), 2);
429 buff
[4] = (UniChar
)'-';
430 CFStringAppendCharacters(str
, buff
, 5);
432 // Fifth segment (6 bytes, 12 digits)
433 _intToHexChars(uuid
->_bytes
.byte10
, buff
, 2);
434 _intToHexChars(uuid
->_bytes
.byte11
, &(buff
[2]), 2);
435 _intToHexChars(uuid
->_bytes
.byte12
, &(buff
[4]), 2);
436 _intToHexChars(uuid
->_bytes
.byte13
, &(buff
[6]), 2);
437 _intToHexChars(uuid
->_bytes
.byte14
, &(buff
[8]), 2);
438 _intToHexChars(uuid
->_bytes
.byte15
, &(buff
[10]), 2);
439 CFStringAppendCharacters(str
, buff
, 12);
444 CFUUIDRef
CFUUIDGetConstantUUIDWithBytes(CFAllocatorRef alloc
, uint8_t byte0
, uint8_t byte1
, uint8_t byte2
, uint8_t byte3
, uint8_t byte4
, uint8_t byte5
, uint8_t byte6
, uint8_t byte7
, uint8_t byte8
, uint8_t byte9
, uint8_t byte10
, uint8_t byte11
, uint8_t byte12
, uint8_t byte13
, uint8_t byte14
, uint8_t byte15
) {
446 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
457 bytes
.byte10
= byte10
;
458 bytes
.byte11
= byte11
;
459 bytes
.byte12
= byte12
;
460 bytes
.byte13
= byte13
;
461 bytes
.byte14
= byte14
;
462 bytes
.byte15
= byte15
;
464 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, true);
467 CFUUIDBytes
CFUUIDGetUUIDBytes(CFUUIDRef uuid
) {
471 CF_EXPORT CFUUIDRef
CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc
, CFUUIDBytes bytes
) {
472 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);