2 * Copyright (c) 2012 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@
25 Copyright (c) 1999-2012, Apple Inc. All rights reserved.
26 Responsibility: David Smith
29 #include <CoreFoundation/CFUUID.h>
30 #include "CFInternal.h"
32 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
33 #include <dispatch/dispatch.h>
35 static CFMutableDictionaryRef _uniquedUUIDs
= NULL
;
36 CF_INLINE
void LOCKED(dispatch_block_t work
) {
37 static dispatch_once_t guard
;
38 static dispatch_queue_t CFUUIDGlobalDataLock
;
39 dispatch_once(&guard
, ^{ CFUUIDGlobalDataLock
= dispatch_queue_create("CFUUID global uniquing table lock", 0); });
40 dispatch_sync(CFUUIDGlobalDataLock
, work
);
44 // Platforms without dispatch
46 static CFMutableDictionaryRef _uniquedUUIDs
= NULL
;
47 static CFSpinLock_t _uniquedUUIDsLock
= CFSpinLockInit
;
49 CF_INLINE
void LOCKED(void (^work
)(void)) {
50 __CFSpinLock(&_uniquedUUIDsLock
);
52 __CFSpinUnlock(&_uniquedUUIDsLock
);
62 typedef struct __CFUUID __CFUUID_t
;
64 static Boolean
__CFisEqualUUIDBytes(const void *ptr1
, const void *ptr2
) {
65 CFUUIDBytes
*p1
= (CFUUIDBytes
*)ptr1
;
66 CFUUIDBytes
*p2
= (CFUUIDBytes
*)ptr2
;
68 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);
71 static CFHashCode
__CFhashUUIDBytes(const void *ptr
) {
72 return CFHashBytes((uint8_t *)ptr
, 16);
76 * GC implementation of a weak set specifically designed for UUID
79 #define MALLOC(x) CFAllocatorAllocate(kCFAllocatorSystemDefault, x, 0)
80 #define FREE(x) CFAllocatorDeallocate(kCFAllocatorSystemDefault, x)
81 #define HASH(x) CFHashBytes((uint8_t *)x, 16)
83 #define READWEAK(location) objc_read_weak((id *)location)
84 #define WRITEWEAK(location, value) objc_assign_weak((id)value, (id *)location)
87 unsigned long count
, size
;
88 __CFUUID_t
**weakPtrs
;
91 static _UUIDWeakSet_t _UUIDWeakSet
;
93 static void grow_has_lock(void);
95 // enter if not already present
96 static void enter_has_lock(__CFUUID_t
*candidate
) {
97 if (!candidate
) return;
98 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
99 if (!table
->size
) grow_has_lock();
100 unsigned long int hashValue
= HASH(&candidate
->_bytes
) & (table
->size
-1);
101 __CFUUID_t
*result
= table
->weakPtrs
[hashValue
];
103 if (result
== (void *)0x1 || result
== NULL
) {
104 table
->weakPtrs
[hashValue
] = NULL
; // so that we don't try to unregister 0x1
105 WRITEWEAK(&table
->weakPtrs
[hashValue
], (void *)candidate
);
109 if (result
) result
= (__CFUUID_t
*)READWEAK(&table
->weakPtrs
[hashValue
]);
111 // see if it is equal to candidate
112 if (__CFisEqualUUIDBytes(&result
->_bytes
, &candidate
->_bytes
)) {
113 // keep first one. There is a race if two threads both fail to find
114 // a candidate uuid then both try decide to create and enter one.
115 // Under non-GC one of them simply leaks.
119 // was zeroed by collector. Use this slot.
123 if (++hashValue
>= table
->size
) hashValue
= 0;
124 result
= table
->weakPtrs
[hashValue
];
128 static void *find_has_lock(const CFUUIDBytes
*bytes
) {
129 if (!bytes
) return NULL
;
130 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
131 if (!table
->size
) return NULL
; // no entries
132 unsigned long int hashValue
= HASH(bytes
) & (table
->size
-1);
133 __CFUUID_t
*result
= table
->weakPtrs
[hashValue
];
135 if (result
== (void *)0x1) break;
136 if (result
) result
= (__CFUUID_t
*)READWEAK(&table
->weakPtrs
[hashValue
]);
138 // see if it is equal to bytes
139 if (__CFisEqualUUIDBytes(&result
->_bytes
, bytes
)) return result
;
142 if (++hashValue
>= table
->size
) hashValue
= 0;
143 result
= table
->weakPtrs
[hashValue
];
149 static void grow_has_lock() {
150 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
151 if (table
->size
== 0) {
153 table
->weakPtrs
= (__CFUUID_t
**)MALLOC(sizeof(__CFUUID_t
*)*table
->size
);
154 for (int i
= 0; i
< table
->size
; ++i
) table
->weakPtrs
[i
] = (__CFUUID_t
*)0x1;
159 table
->size
= table
->size
*2;
160 __CFUUID_t
**oldPtrs
= table
->weakPtrs
;
161 table
->weakPtrs
= (__CFUUID_t
**)MALLOC(sizeof(__CFUUID_t
*)*table
->size
);
162 for (int i
= 0; i
< table
->size
; ++i
) table
->weakPtrs
[i
] = (__CFUUID_t
*)0x1;
163 for (int i
= 0; i
< table
->size
/ 2; ++i
) {
164 if (oldPtrs
[i
] == (__CFUUID_t
*)0x1) continue; // available field, ignore
165 if (oldPtrs
[i
] == NULL
) continue; // zero'ed by collector, ignore
166 enter_has_lock((__CFUUID_t
*)READWEAK(&oldPtrs
[i
])); // read, then enter (but enter must check for NULL)
167 WRITEWEAK(&oldPtrs
[i
], NULL
); // unregister
172 /***** end of weak set */
174 static void __CFUUIDAddUniqueUUIDHasLock(CFUUIDRef uuid
) {
175 CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks
= {0, NULL
, NULL
, NULL
, __CFisEqualUUIDBytes
, __CFhashUUIDBytes
};
176 CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks
= {0, NULL
, NULL
, CFCopyDescription
, CFEqual
};
178 if (kCFUseCollectableAllocator
) {
179 enter_has_lock((__CFUUID_t
*)uuid
);
180 if (_UUIDWeakSet
.count
> (3 * _UUIDWeakSet
.size
/ 4)) grow_has_lock();
182 if (!_uniquedUUIDs
) _uniquedUUIDs
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &__CFUUIDBytesDictionaryKeyCallBacks
, &__CFnonRetainedUUIDDictionaryValueCallBacks
);
183 CFDictionarySetValue(_uniquedUUIDs
, &(uuid
->_bytes
), uuid
);
187 static void __CFUUIDRemoveUniqueUUIDHasLock(CFUUIDRef uuid
) {
188 if (_uniquedUUIDs
) CFDictionaryRemoveValue(_uniquedUUIDs
, &(uuid
->_bytes
));
191 static CFUUIDRef
__CFUUIDGetUniquedUUIDHasLock(const CFUUIDBytes
*bytes
) {
192 CFUUIDRef uuid
= NULL
;
193 if (kCFUseCollectableAllocator
) {
194 uuid
= (CFUUIDRef
)find_has_lock(bytes
);
195 } else if (_uniquedUUIDs
) {
196 uuid
= (CFUUIDRef
)CFDictionaryGetValue(_uniquedUUIDs
, bytes
);
201 static void __CFUUIDDeallocate(CFTypeRef cf
) {
202 if (kCFUseCollectableAllocator
) return;
204 __CFUUID_t
*uuid
= (__CFUUID_t
*)cf
;
206 __CFUUIDRemoveUniqueUUIDHasLock(uuid
);
210 static CFStringRef
__CFUUIDCopyDescription(CFTypeRef cf
) {
211 CFStringRef uuidStr
= CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
212 CFStringRef desc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFUUID %p> %@"), cf
, uuidStr
);
217 static CFStringRef
__CFUUIDCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
218 return CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
221 static CFTypeID __kCFUUIDTypeID
= _kCFRuntimeNotATypeID
;
223 static const CFRuntimeClass __CFUUIDClass
= {
231 __CFUUIDCopyFormattingDescription
,
232 __CFUUIDCopyDescription
235 __private_extern__
void __CFUUIDInitialize(void) {
236 __kCFUUIDTypeID
= _CFRuntimeRegisterClass(&__CFUUIDClass
);
239 CFTypeID
CFUUIDGetTypeID(void) {
240 return __kCFUUIDTypeID
;
243 static CFUUIDRef
__CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator
, CFUUIDBytes bytes
, Boolean isConst
) {
244 __block __CFUUID_t
*uuid
= NULL
;
246 uuid
= (__CFUUID_t
*)__CFUUIDGetUniquedUUIDHasLock(&bytes
);
249 size
= sizeof(__CFUUID_t
) - sizeof(CFRuntimeBase
);
250 uuid
= (__CFUUID_t
*)_CFRuntimeCreateInstance(kCFUseCollectableAllocator
? kCFAllocatorSystemDefault
: allocator
, __kCFUUIDTypeID
, size
, NULL
);
254 uuid
->_bytes
= bytes
;
255 __CFUUIDAddUniqueUUIDHasLock(uuid
);
256 } else if (!isConst
) {
261 return (CFUUIDRef
)uuid
;
264 #if DEPLOYMENT_TARGET_WINDOWS
266 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
267 #include <uuid/uuid.h>
270 CFUUIDRef
CFUUIDCreate(CFAllocatorRef alloc
) {
271 /* Create a new bytes struct and then call the primitive. */
272 __block CFUUIDBytes bytes
;
273 __block
uint32_t retval
= 0;
276 #if DEPLOYMENT_TARGET_WINDOWS
278 long rStatus
= UuidCreate(&u
);
279 if (RPC_S_OK
!= rStatus
&& RPC_S_UUID_LOCAL_ONLY
!= rStatus
) retval
= 1;
280 memmove(&bytes
, &u
, sizeof(bytes
));
281 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
282 static Boolean useV1UUIDs
= false, checked
= false;
285 const char *value
= __CFgetenv("CFUUIDVersionNumber");
287 if (1 == strtoul_l(value
, NULL
, 0, NULL
)) useV1UUIDs
= true;
291 if (useV1UUIDs
) uuid_generate_time(uuid
); else uuid_generate_random(uuid
);
292 memcpy((void *)&bytes
, uuid
, sizeof(uuid
));
298 return (retval
== 0) ? __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false) : NULL
;
301 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
) {
303 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
314 bytes
.byte10
= byte10
;
315 bytes
.byte11
= byte11
;
316 bytes
.byte12
= byte12
;
317 bytes
.byte13
= byte13
;
318 bytes
.byte14
= byte14
;
319 bytes
.byte15
= byte15
;
321 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
324 static void _intToHexChars(UInt32 in
, UniChar
*out
, int digits
) {
328 while (--digits
>= 0) {
330 d
= 0x0FL
& (in
>> shift
);
332 *out
++ = (UniChar
)'0' + d
;
334 *out
++ = (UniChar
)'A' + (d
- 10);
339 static uint8_t _byteFromHexChars(UniChar
*in
) {
345 for (i
=0; i
<2; i
++) {
347 if ((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) {
348 d
= c
- (UniChar
)'0';
349 } else if ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) {
350 d
= c
- ((UniChar
)'a' - 10);
351 } else if ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F')) {
352 d
= c
- ((UniChar
)'A' - 10);
356 result
= (result
<< 4) | d
;
362 CF_INLINE Boolean
_isHexChar(UniChar c
) {
363 return ((((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) || ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) || ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F'))) ? true : false);
366 #define READ_A_BYTE(into) if (i+1 < len) { \
367 (into) = _byteFromHexChars(&(chars[i])); \
371 CFUUIDRef
CFUUIDCreateFromString(CFAllocatorRef alloc
, CFStringRef uuidStr
) {
372 /* Parse the string into a bytes struct and then call the primitive. */
378 if (uuidStr
== NULL
) return NULL
;
380 len
= CFStringGetLength(uuidStr
);
383 } else if (len
== 0) {
386 CFStringGetCharacters(uuidStr
, CFRangeMake(0, len
), chars
);
387 memset((void *)&bytes
, 0, sizeof(bytes
));
389 /* Skip initial random stuff */
390 while (!_isHexChar(chars
[i
]) && i
< len
) i
++;
392 READ_A_BYTE(bytes
.byte0
);
393 READ_A_BYTE(bytes
.byte1
);
394 READ_A_BYTE(bytes
.byte2
);
395 READ_A_BYTE(bytes
.byte3
);
398 READ_A_BYTE(bytes
.byte4
);
399 READ_A_BYTE(bytes
.byte5
);
402 READ_A_BYTE(bytes
.byte6
);
403 READ_A_BYTE(bytes
.byte7
);
406 READ_A_BYTE(bytes
.byte8
);
407 READ_A_BYTE(bytes
.byte9
);
410 READ_A_BYTE(bytes
.byte10
);
411 READ_A_BYTE(bytes
.byte11
);
412 READ_A_BYTE(bytes
.byte12
);
413 READ_A_BYTE(bytes
.byte13
);
414 READ_A_BYTE(bytes
.byte14
);
415 READ_A_BYTE(bytes
.byte15
);
417 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
420 CFStringRef
CFUUIDCreateString(CFAllocatorRef alloc
, CFUUIDRef uuid
) {
421 CFMutableStringRef str
= CFStringCreateMutable(alloc
, 0);
424 // First segment (4 bytes, 8 digits + 1 dash)
425 _intToHexChars(uuid
->_bytes
.byte0
, buff
, 2);
426 _intToHexChars(uuid
->_bytes
.byte1
, &(buff
[2]), 2);
427 _intToHexChars(uuid
->_bytes
.byte2
, &(buff
[4]), 2);
428 _intToHexChars(uuid
->_bytes
.byte3
, &(buff
[6]), 2);
429 buff
[8] = (UniChar
)'-';
430 CFStringAppendCharacters(str
, buff
, 9);
432 // Second segment (2 bytes, 4 digits + 1 dash)
433 _intToHexChars(uuid
->_bytes
.byte4
, buff
, 2);
434 _intToHexChars(uuid
->_bytes
.byte5
, &(buff
[2]), 2);
435 buff
[4] = (UniChar
)'-';
436 CFStringAppendCharacters(str
, buff
, 5);
438 // Third segment (2 bytes, 4 digits + 1 dash)
439 _intToHexChars(uuid
->_bytes
.byte6
, buff
, 2);
440 _intToHexChars(uuid
->_bytes
.byte7
, &(buff
[2]), 2);
441 buff
[4] = (UniChar
)'-';
442 CFStringAppendCharacters(str
, buff
, 5);
444 // Fourth segment (2 bytes, 4 digits + 1 dash)
445 _intToHexChars(uuid
->_bytes
.byte8
, buff
, 2);
446 _intToHexChars(uuid
->_bytes
.byte9
, &(buff
[2]), 2);
447 buff
[4] = (UniChar
)'-';
448 CFStringAppendCharacters(str
, buff
, 5);
450 // Fifth segment (6 bytes, 12 digits)
451 _intToHexChars(uuid
->_bytes
.byte10
, buff
, 2);
452 _intToHexChars(uuid
->_bytes
.byte11
, &(buff
[2]), 2);
453 _intToHexChars(uuid
->_bytes
.byte12
, &(buff
[4]), 2);
454 _intToHexChars(uuid
->_bytes
.byte13
, &(buff
[6]), 2);
455 _intToHexChars(uuid
->_bytes
.byte14
, &(buff
[8]), 2);
456 _intToHexChars(uuid
->_bytes
.byte15
, &(buff
[10]), 2);
457 CFStringAppendCharacters(str
, buff
, 12);
462 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
) {
464 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
475 bytes
.byte10
= byte10
;
476 bytes
.byte11
= byte11
;
477 bytes
.byte12
= byte12
;
478 bytes
.byte13
= byte13
;
479 bytes
.byte14
= byte14
;
480 bytes
.byte15
= byte15
;
482 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, true);
485 CFUUIDBytes
CFUUIDGetUUIDBytes(CFUUIDRef uuid
) {
489 CF_EXPORT CFUUIDRef
CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc
, CFUUIDBytes bytes
) {
490 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);