2 * Copyright (c) 2015 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-2014, 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
, ^{
40 dispatch_queue_attr_t dqattr
= dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL
, qos_class_main(), 0);
41 CFUUIDGlobalDataLock
= dispatch_queue_create("com.apple.CFUUID", dqattr
);
43 dispatch_sync(CFUUIDGlobalDataLock
, work
);
47 // Platforms without dispatch
49 static CFMutableDictionaryRef _uniquedUUIDs
= NULL
;
50 static CFLock_t _uniquedUUIDsLock
= CFLockInit
;
52 CF_INLINE
void LOCKED(void (^work
)(void)) {
53 __CFLock(&_uniquedUUIDsLock
);
55 __CFUnlock(&_uniquedUUIDsLock
);
65 typedef struct __CFUUID __CFUUID_t
;
67 static Boolean
__CFisEqualUUIDBytes(const void *ptr1
, const void *ptr2
) {
68 CFUUIDBytes
*p1
= (CFUUIDBytes
*)ptr1
;
69 CFUUIDBytes
*p2
= (CFUUIDBytes
*)ptr2
;
71 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);
74 static CFHashCode
__CFhashUUIDBytes(const void *ptr
) {
75 return CFHashBytes((uint8_t *)ptr
, 16);
79 * GC implementation of a weak set specifically designed for UUID
82 #define MALLOC(x) CFAllocatorAllocate(kCFAllocatorSystemDefault, x, 0)
83 #define FREE(x) CFAllocatorDeallocate(kCFAllocatorSystemDefault, x)
84 #define HASH(x) CFHashBytes((uint8_t *)x, 16)
86 #define READWEAK(location) objc_read_weak((id *)location)
87 #define WRITEWEAK(location, value) objc_assign_weak((id)value, (id *)location)
90 unsigned long count
, size
;
91 __CFUUID_t
**weakPtrs
;
94 static _UUIDWeakSet_t _UUIDWeakSet
;
96 static void grow_has_lock(void);
98 // enter if not already present
99 static void enter_has_lock(__CFUUID_t
*candidate
) {
100 if (!candidate
) return;
101 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
102 if (!table
->size
) grow_has_lock();
103 unsigned long int hashValue
= HASH(&candidate
->_bytes
) & (table
->size
-1);
104 __CFUUID_t
*result
= table
->weakPtrs
[hashValue
];
106 if (result
== (void *)0x1 || result
== NULL
) {
107 table
->weakPtrs
[hashValue
] = NULL
; // so that we don't try to unregister 0x1
108 WRITEWEAK(&table
->weakPtrs
[hashValue
], (void *)candidate
);
112 if (result
) result
= (__CFUUID_t
*)READWEAK(&table
->weakPtrs
[hashValue
]);
114 // see if it is equal to candidate
115 if (__CFisEqualUUIDBytes(&result
->_bytes
, &candidate
->_bytes
)) {
116 // keep first one. There is a race if two threads both fail to find
117 // a candidate uuid then both try decide to create and enter one.
118 // Under non-GC one of them simply leaks.
122 // was zeroed by collector. Use this slot.
126 if (++hashValue
>= table
->size
) hashValue
= 0;
127 result
= table
->weakPtrs
[hashValue
];
131 static void *find_has_lock(const CFUUIDBytes
*bytes
) {
132 if (!bytes
) return NULL
;
133 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
134 if (!table
->size
) return NULL
; // no entries
135 unsigned long int hashValue
= HASH(bytes
) & (table
->size
-1);
136 __CFUUID_t
*result
= table
->weakPtrs
[hashValue
];
138 if (result
== (void *)0x1) break;
139 if (result
) result
= (__CFUUID_t
*)READWEAK(&table
->weakPtrs
[hashValue
]);
141 // see if it is equal to bytes
142 if (__CFisEqualUUIDBytes(&result
->_bytes
, bytes
)) return result
;
145 if (++hashValue
>= table
->size
) hashValue
= 0;
146 result
= table
->weakPtrs
[hashValue
];
152 static void grow_has_lock() {
153 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
154 if (table
->size
== 0) {
156 table
->weakPtrs
= (__CFUUID_t
**)MALLOC(sizeof(__CFUUID_t
*)*table
->size
);
157 for (int i
= 0; i
< table
->size
; ++i
) table
->weakPtrs
[i
] = (__CFUUID_t
*)0x1;
162 table
->size
= table
->size
*2;
163 __CFUUID_t
**oldPtrs
= table
->weakPtrs
;
164 table
->weakPtrs
= (__CFUUID_t
**)MALLOC(sizeof(__CFUUID_t
*)*table
->size
);
165 for (int i
= 0; i
< table
->size
; ++i
) table
->weakPtrs
[i
] = (__CFUUID_t
*)0x1;
166 for (int i
= 0; i
< table
->size
/ 2; ++i
) {
167 if (oldPtrs
[i
] == (__CFUUID_t
*)0x1) continue; // available field, ignore
168 if (oldPtrs
[i
] == NULL
) continue; // zero'ed by collector, ignore
169 enter_has_lock((__CFUUID_t
*)READWEAK(&oldPtrs
[i
])); // read, then enter (but enter must check for NULL)
170 WRITEWEAK(&oldPtrs
[i
], NULL
); // unregister
175 /***** end of weak set */
177 static void __CFUUIDAddUniqueUUIDHasLock(CFUUIDRef uuid
) {
178 CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks
= {0, NULL
, NULL
, NULL
, __CFisEqualUUIDBytes
, __CFhashUUIDBytes
};
179 CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks
= {0, NULL
, NULL
, CFCopyDescription
, CFEqual
};
181 if (kCFUseCollectableAllocator
) {
182 enter_has_lock((__CFUUID_t
*)uuid
);
183 if (_UUIDWeakSet
.count
> (3 * _UUIDWeakSet
.size
/ 4)) grow_has_lock();
185 if (!_uniquedUUIDs
) _uniquedUUIDs
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &__CFUUIDBytesDictionaryKeyCallBacks
, &__CFnonRetainedUUIDDictionaryValueCallBacks
);
186 CFDictionarySetValue(_uniquedUUIDs
, &(uuid
->_bytes
), uuid
);
190 static void __CFUUIDRemoveUniqueUUIDHasLock(CFUUIDRef uuid
) {
191 if (_uniquedUUIDs
) CFDictionaryRemoveValue(_uniquedUUIDs
, &(uuid
->_bytes
));
194 static CFUUIDRef
__CFUUIDGetUniquedUUIDHasLock(const CFUUIDBytes
*bytes
) {
195 CFUUIDRef uuid
= NULL
;
196 if (kCFUseCollectableAllocator
) {
197 uuid
= (CFUUIDRef
)find_has_lock(bytes
);
198 } else if (_uniquedUUIDs
) {
199 uuid
= (CFUUIDRef
)CFDictionaryGetValue(_uniquedUUIDs
, bytes
);
204 static void __CFUUIDDeallocate(CFTypeRef cf
) {
205 if (kCFUseCollectableAllocator
) return;
207 __CFUUID_t
*uuid
= (__CFUUID_t
*)cf
;
209 __CFUUIDRemoveUniqueUUIDHasLock(uuid
);
213 static CFStringRef
__CFUUIDCopyDescription(CFTypeRef cf
) {
214 CFStringRef uuidStr
= CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
215 CFStringRef desc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFUUID %p> %@"), cf
, uuidStr
);
220 static CFStringRef
__CFUUIDCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
221 return CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
224 static CFTypeID __kCFUUIDTypeID
= _kCFRuntimeNotATypeID
;
226 static const CFRuntimeClass __CFUUIDClass
= {
234 __CFUUIDCopyFormattingDescription
,
235 __CFUUIDCopyDescription
238 CFTypeID
CFUUIDGetTypeID(void) {
239 static dispatch_once_t initOnce
;
240 dispatch_once(&initOnce
, ^{ __kCFUUIDTypeID
= _CFRuntimeRegisterClass(&__CFUUIDClass
); });
241 return __kCFUUIDTypeID
;
244 static CFUUIDRef
__CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator
, CFUUIDBytes bytes
, Boolean isConst
) {
245 __block __CFUUID_t
*uuid
= NULL
;
247 uuid
= (__CFUUID_t
*)__CFUUIDGetUniquedUUIDHasLock(&bytes
);
250 size
= sizeof(__CFUUID_t
) - sizeof(CFRuntimeBase
);
251 uuid
= (__CFUUID_t
*)_CFRuntimeCreateInstance(kCFUseCollectableAllocator
? kCFAllocatorSystemDefault
: allocator
, CFUUIDGetTypeID(), size
, NULL
);
255 uuid
->_bytes
= bytes
;
256 __CFUUIDAddUniqueUUIDHasLock(uuid
);
257 } else if (!isConst
) {
262 return (CFUUIDRef
)uuid
;
265 #if DEPLOYMENT_TARGET_WINDOWS
267 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
268 #include <uuid/uuid.h>
271 CFUUIDRef
CFUUIDCreate(CFAllocatorRef alloc
) {
272 /* Create a new bytes struct and then call the primitive. */
273 __block CFUUIDBytes bytes
;
274 __block
uint32_t retval
= 0;
277 #if DEPLOYMENT_TARGET_WINDOWS
279 long rStatus
= UuidCreate(&u
);
280 if (RPC_S_OK
!= rStatus
&& RPC_S_UUID_LOCAL_ONLY
!= rStatus
) retval
= 1;
281 memmove(&bytes
, &u
, sizeof(bytes
));
282 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
283 static Boolean useV1UUIDs
= false, checked
= false;
286 const char *value
= __CFgetenv("CFUUIDVersionNumber");
288 if (1 == strtoul_l(value
, NULL
, 0, NULL
)) useV1UUIDs
= true;
292 if (useV1UUIDs
) uuid_generate_time(uuid
); else uuid_generate_random(uuid
);
293 memcpy((void *)&bytes
, uuid
, sizeof(uuid
));
299 return (retval
== 0) ? __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false) : NULL
;
302 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
) {
304 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
315 bytes
.byte10
= byte10
;
316 bytes
.byte11
= byte11
;
317 bytes
.byte12
= byte12
;
318 bytes
.byte13
= byte13
;
319 bytes
.byte14
= byte14
;
320 bytes
.byte15
= byte15
;
322 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
325 static void _intToHexChars(UInt32 in
, UniChar
*out
, int digits
) {
329 while (--digits
>= 0) {
331 d
= 0x0FL
& (in
>> shift
);
333 *out
++ = (UniChar
)'0' + d
;
335 *out
++ = (UniChar
)'A' + (d
- 10);
340 static uint8_t _byteFromHexChars(UniChar
*in
) {
346 for (i
=0; i
<2; i
++) {
348 if ((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) {
349 d
= c
- (UniChar
)'0';
350 } else if ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) {
351 d
= c
- ((UniChar
)'a' - 10);
352 } else if ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F')) {
353 d
= c
- ((UniChar
)'A' - 10);
357 result
= (result
<< 4) | d
;
363 CF_INLINE Boolean
_isHexChar(UniChar c
) {
364 return ((((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) || ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) || ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F'))) ? true : false);
367 #define READ_A_BYTE(into) if (i+1 < len) { \
368 (into) = _byteFromHexChars(&(chars[i])); \
372 CFUUIDRef
CFUUIDCreateFromString(CFAllocatorRef alloc
, CFStringRef uuidStr
) {
373 /* Parse the string into a bytes struct and then call the primitive. */
379 if (uuidStr
== NULL
) return NULL
;
381 len
= CFStringGetLength(uuidStr
);
384 } else if (len
== 0) {
387 CFStringGetCharacters(uuidStr
, CFRangeMake(0, len
), chars
);
388 memset((void *)&bytes
, 0, sizeof(bytes
));
390 /* Skip initial random stuff */
391 while (!_isHexChar(chars
[i
]) && i
< len
) i
++;
393 READ_A_BYTE(bytes
.byte0
);
394 READ_A_BYTE(bytes
.byte1
);
395 READ_A_BYTE(bytes
.byte2
);
396 READ_A_BYTE(bytes
.byte3
);
399 READ_A_BYTE(bytes
.byte4
);
400 READ_A_BYTE(bytes
.byte5
);
403 READ_A_BYTE(bytes
.byte6
);
404 READ_A_BYTE(bytes
.byte7
);
407 READ_A_BYTE(bytes
.byte8
);
408 READ_A_BYTE(bytes
.byte9
);
411 READ_A_BYTE(bytes
.byte10
);
412 READ_A_BYTE(bytes
.byte11
);
413 READ_A_BYTE(bytes
.byte12
);
414 READ_A_BYTE(bytes
.byte13
);
415 READ_A_BYTE(bytes
.byte14
);
416 READ_A_BYTE(bytes
.byte15
);
418 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
421 CFStringRef
CFUUIDCreateString(CFAllocatorRef alloc
, CFUUIDRef uuid
) {
422 CFMutableStringRef str
= CFStringCreateMutable(alloc
, 0);
425 // First segment (4 bytes, 8 digits + 1 dash)
426 _intToHexChars(uuid
->_bytes
.byte0
, buff
, 2);
427 _intToHexChars(uuid
->_bytes
.byte1
, &(buff
[2]), 2);
428 _intToHexChars(uuid
->_bytes
.byte2
, &(buff
[4]), 2);
429 _intToHexChars(uuid
->_bytes
.byte3
, &(buff
[6]), 2);
430 buff
[8] = (UniChar
)'-';
431 CFStringAppendCharacters(str
, buff
, 9);
433 // Second segment (2 bytes, 4 digits + 1 dash)
434 _intToHexChars(uuid
->_bytes
.byte4
, buff
, 2);
435 _intToHexChars(uuid
->_bytes
.byte5
, &(buff
[2]), 2);
436 buff
[4] = (UniChar
)'-';
437 CFStringAppendCharacters(str
, buff
, 5);
439 // Third segment (2 bytes, 4 digits + 1 dash)
440 _intToHexChars(uuid
->_bytes
.byte6
, buff
, 2);
441 _intToHexChars(uuid
->_bytes
.byte7
, &(buff
[2]), 2);
442 buff
[4] = (UniChar
)'-';
443 CFStringAppendCharacters(str
, buff
, 5);
445 // Fourth segment (2 bytes, 4 digits + 1 dash)
446 _intToHexChars(uuid
->_bytes
.byte8
, buff
, 2);
447 _intToHexChars(uuid
->_bytes
.byte9
, &(buff
[2]), 2);
448 buff
[4] = (UniChar
)'-';
449 CFStringAppendCharacters(str
, buff
, 5);
451 // Fifth segment (6 bytes, 12 digits)
452 _intToHexChars(uuid
->_bytes
.byte10
, buff
, 2);
453 _intToHexChars(uuid
->_bytes
.byte11
, &(buff
[2]), 2);
454 _intToHexChars(uuid
->_bytes
.byte12
, &(buff
[4]), 2);
455 _intToHexChars(uuid
->_bytes
.byte13
, &(buff
[6]), 2);
456 _intToHexChars(uuid
->_bytes
.byte14
, &(buff
[8]), 2);
457 _intToHexChars(uuid
->_bytes
.byte15
, &(buff
[10]), 2);
458 CFStringAppendCharacters(str
, buff
, 12);
463 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
) {
465 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
476 bytes
.byte10
= byte10
;
477 bytes
.byte11
= byte11
;
478 bytes
.byte12
= byte12
;
479 bytes
.byte13
= byte13
;
480 bytes
.byte14
= byte14
;
481 bytes
.byte15
= byte15
;
483 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, true);
486 CFUUIDBytes
CFUUIDGetUUIDBytes(CFUUIDRef uuid
) {
490 CF_EXPORT CFUUIDRef
CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc
, CFUUIDBytes bytes
) {
491 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);