2 * Copyright (c) 2010 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-2009, Apple Inc. All rights reserved.
26 Responsibility: Doug Davidson
29 #include <CoreFoundation/CFUUID.h>
30 #include "CFInternal.h"
31 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
32 #include <uuid/uuid.h>
35 static CFMutableDictionaryRef _uniquedUUIDs
= NULL
;
36 static CFSpinLock_t CFUUIDGlobalDataLock
= CFSpinLockInit
;
43 static Boolean
__CFisEqualUUIDBytes(const void *ptr1
, const void *ptr2
) {
44 CFUUIDBytes
*p1
= (CFUUIDBytes
*)ptr1
;
45 CFUUIDBytes
*p2
= (CFUUIDBytes
*)ptr2
;
47 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);
50 static CFHashCode
__CFhashUUIDBytes(const void *ptr
) {
51 return CFHashBytes((uint8_t *)ptr
, 16);
55 * GC implementation of a weak set specifically designed for UUID
58 #define LOCK() __CFSpinLock(&CFUUIDGlobalDataLock)
59 #define UNLOCK() __CFSpinUnlock(&CFUUIDGlobalDataLock)
61 #define MALLOC(x) CFAllocatorAllocate(kCFAllocatorSystemDefault, x, 0)
62 #define FREE(x) CFAllocatorDeallocate(kCFAllocatorSystemDefault, x)
63 #define HASH(x) CFHashBytes((uint8_t *)x, 16)
65 #define READWEAK(location) auto_read_weak_reference(auto_zone(), (void**)location)
66 #define WRITEWEAK(location, value) auto_assign_weak_reference(auto_zone(), value, (void **)location, NULL)
69 unsigned long count
, size
;
70 struct __CFUUID
**weakPtrs
;
73 static _UUIDWeakSet_t _UUIDWeakSet
;
75 static void grow_has_lock(void);
77 // enter if not already present
78 static void enter_has_lock(struct __CFUUID
*candidate
) {
79 if (!candidate
) return;
80 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
81 if (!table
->size
) grow_has_lock();
82 unsigned long int hashValue
= HASH(&candidate
->_bytes
) & (table
->size
-1);
83 struct __CFUUID
*result
= table
->weakPtrs
[hashValue
];
85 if (result
== (void *)0x1 || result
== NULL
) {
86 table
->weakPtrs
[hashValue
] = NULL
; // so that we don't try to unregister 0x1
87 WRITEWEAK(&table
->weakPtrs
[hashValue
], (void *)candidate
);
91 if (result
) result
= (struct __CFUUID
*)READWEAK(&table
->weakPtrs
[hashValue
]);
93 // see if it is equal to candidate
94 if (__CFisEqualUUIDBytes(&result
->_bytes
, &candidate
->_bytes
)) {
95 // keep first one. There is a race if two threads both fail to find
96 // a candidate uuid then both try decide to create and enter one.
97 // Under non-GC one of them simply leaks.
101 // was zeroed by collector. Use this slot.
105 if (++hashValue
>= table
->size
) hashValue
= 0;
106 result
= table
->weakPtrs
[hashValue
];
110 static void *find_has_lock(CFUUIDBytes
*bytes
) {
111 if (!bytes
) return NULL
;
112 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
113 if (!table
->size
) return NULL
; // no entries
114 unsigned long int hashValue
= HASH(bytes
) & (table
->size
-1);
115 struct __CFUUID
*result
= table
->weakPtrs
[hashValue
];
117 if (result
== (void *)0x1) break;
118 if (result
) result
= (struct __CFUUID
*)READWEAK(&table
->weakPtrs
[hashValue
]);
120 // see if it is equal to bytes
121 if (__CFisEqualUUIDBytes(&result
->_bytes
, bytes
)) return result
;
124 if (++hashValue
>= table
->size
) hashValue
= 0;
125 result
= table
->weakPtrs
[hashValue
];
131 static void grow_has_lock() {
132 _UUIDWeakSet_t
*table
= &_UUIDWeakSet
;
133 if (table
->size
== 0) {
135 table
->weakPtrs
= (struct __CFUUID
**)MALLOC(sizeof(struct __CFUUID
*)*table
->size
);
136 for (int i
= 0; i
< table
->size
; ++i
) table
->weakPtrs
[i
] = (struct __CFUUID
*)0x1;
141 table
->size
= table
->size
*2;
142 struct __CFUUID
**oldPtrs
= table
->weakPtrs
;
143 table
->weakPtrs
= (struct __CFUUID
**)MALLOC(sizeof(struct __CFUUID
*)*table
->size
);
144 for (int i
= 0; i
< table
->size
; ++i
) table
->weakPtrs
[i
] = (struct __CFUUID
*)0x1;
145 for (int i
= 0; i
< table
->size
/ 2; ++i
) {
146 if (oldPtrs
[i
] == (struct __CFUUID
*)0x1) continue; // available field, ignore
147 if (oldPtrs
[i
] == NULL
) continue; // zero'ed by collector, ignore
148 enter_has_lock((struct __CFUUID
*)READWEAK(&oldPtrs
[i
])); // read, then enter (but enter must check for NULL)
149 WRITEWEAK(&oldPtrs
[i
], NULL
); // unregister
154 /***** end of weak set */
156 static void __CFUUIDAddUniqueUUID(CFUUIDRef uuid
) {
157 CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks
= {0, NULL
, NULL
, NULL
, __CFisEqualUUIDBytes
, __CFhashUUIDBytes
};
158 CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks
= {0, NULL
, NULL
, CFCopyDescription
, CFEqual
};
160 __CFSpinLock(&CFUUIDGlobalDataLock
);
161 if (kCFUseCollectableAllocator
) {
162 enter_has_lock((struct __CFUUID
*)uuid
);
163 if (_UUIDWeakSet
.count
> (3 * _UUIDWeakSet
.size
/ 4)) grow_has_lock();
164 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
167 if (!_uniquedUUIDs
) _uniquedUUIDs
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &__CFUUIDBytesDictionaryKeyCallBacks
, &__CFnonRetainedUUIDDictionaryValueCallBacks
);
168 CFDictionarySetValue(_uniquedUUIDs
, &(uuid
->_bytes
), uuid
);
169 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
172 static void __CFUUIDRemoveUniqueUUID(CFUUIDRef uuid
) {
173 __CFSpinLock(&CFUUIDGlobalDataLock
);
174 if (_uniquedUUIDs
) CFDictionaryRemoveValue(_uniquedUUIDs
, &(uuid
->_bytes
));
175 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
178 static CFUUIDRef
__CFUUIDGetUniquedUUID(CFUUIDBytes
*bytes
) {
179 CFUUIDRef uuid
= NULL
;
180 __CFSpinLock(&CFUUIDGlobalDataLock
);
181 if (kCFUseCollectableAllocator
) {
182 uuid
= (CFUUIDRef
)find_has_lock(bytes
);
183 } else if (_uniquedUUIDs
) {
184 uuid
= (CFUUIDRef
)CFDictionaryGetValue(_uniquedUUIDs
, bytes
);
186 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
190 static void __CFUUIDDeallocate(CFTypeRef cf
) {
191 if (kCFUseCollectableAllocator
) return;
193 struct __CFUUID
*uuid
= (struct __CFUUID
*)cf
;
194 __CFUUIDRemoveUniqueUUID(uuid
);
197 static CFStringRef
__CFUUIDCopyDescription(CFTypeRef cf
) {
198 CFStringRef uuidStr
= CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
199 CFStringRef desc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFUUID %p> %@"), cf
, uuidStr
);
204 static CFStringRef
__CFUUIDCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
205 return CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
208 static CFTypeID __kCFUUIDTypeID
= _kCFRuntimeNotATypeID
;
210 static const CFRuntimeClass __CFUUIDClass
= {
218 __CFUUIDCopyFormattingDescription
,
219 __CFUUIDCopyDescription
222 __private_extern__
void __CFUUIDInitialize(void) {
223 __kCFUUIDTypeID
= _CFRuntimeRegisterClass(&__CFUUIDClass
);
226 CFTypeID
CFUUIDGetTypeID(void) {
227 return __kCFUUIDTypeID
;
230 static CFUUIDRef
__CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator
, CFUUIDBytes bytes
, Boolean isConst
) {
231 struct __CFUUID
*uuid
= (struct __CFUUID
*)__CFUUIDGetUniquedUUID(&bytes
);
234 size
= sizeof(struct __CFUUID
) - sizeof(CFRuntimeBase
);
235 uuid
= (struct __CFUUID
*)_CFRuntimeCreateInstance(kCFUseCollectableAllocator
? kCFAllocatorSystemDefault
: allocator
, __kCFUUIDTypeID
, size
, NULL
);
237 if (!uuid
) return NULL
;
239 uuid
->_bytes
= bytes
;
240 __CFUUIDAddUniqueUUID(uuid
);
241 } else if (!isConst
) {
244 return (CFUUIDRef
)uuid
;
247 #if DEPLOYMENT_TARGET_WINDOWS
251 CFUUIDRef
CFUUIDCreate(CFAllocatorRef alloc
) {
252 /* Create a new bytes struct and then call the primitive. */
256 __CFSpinLock(&CFUUIDGlobalDataLock
);
257 #if DEPLOYMENT_TARGET_WINDOWS
259 long rStatus
= UuidCreate(&u
);
260 if (RPC_S_OK
!= rStatus
&& RPC_S_UUID_LOCAL_ONLY
!= rStatus
) retval
= 1;
261 memmove(&bytes
, &u
, sizeof(bytes
));
262 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
263 static Boolean useV1UUIDs
= false, checked
= false;
266 const char *value
= __CFgetenv("CFUUIDVersionNumber");
268 if (1 == strtoul_l(value
, NULL
, 0, NULL
)) useV1UUIDs
= true;
270 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionTiger
)) useV1UUIDs
= true;
274 if (useV1UUIDs
) uuid_generate_time(uuid
); else uuid_generate_random(uuid
);
275 memcpy(&bytes
, uuid
, sizeof(uuid
));
279 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
281 return (retval
== 0) ? __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false) : NULL
;
284 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
) {
286 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
297 bytes
.byte10
= byte10
;
298 bytes
.byte11
= byte11
;
299 bytes
.byte12
= byte12
;
300 bytes
.byte13
= byte13
;
301 bytes
.byte14
= byte14
;
302 bytes
.byte15
= byte15
;
304 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
307 static void _intToHexChars(UInt32 in
, UniChar
*out
, int digits
) {
311 while (--digits
>= 0) {
313 d
= 0x0FL
& (in
>> shift
);
315 *out
++ = (UniChar
)'0' + d
;
317 *out
++ = (UniChar
)'A' + (d
- 10);
322 static uint8_t _byteFromHexChars(UniChar
*in
) {
328 for (i
=0; i
<2; i
++) {
330 if ((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) {
331 d
= c
- (UniChar
)'0';
332 } else if ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) {
333 d
= c
- ((UniChar
)'a' - 10);
334 } else if ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F')) {
335 d
= c
- ((UniChar
)'A' - 10);
339 result
= (result
<< 4) | d
;
345 CF_INLINE Boolean
_isHexChar(UniChar c
) {
346 return ((((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) || ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) || ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F'))) ? true : false);
349 #define READ_A_BYTE(into) if (i+1 < len) { \
350 (into) = _byteFromHexChars(&(chars[i])); \
354 CFUUIDRef
CFUUIDCreateFromString(CFAllocatorRef alloc
, CFStringRef uuidStr
) {
355 /* Parse the string into a bytes struct and then call the primitive. */
361 if (uuidStr
== NULL
) return NULL
;
363 len
= CFStringGetLength(uuidStr
);
366 } else if (len
== 0) {
369 CFStringGetCharacters(uuidStr
, CFRangeMake(0, len
), chars
);
370 memset((void *)&bytes
, 0, sizeof(bytes
));
372 /* Skip initial random stuff */
373 while (!_isHexChar(chars
[i
]) && i
< len
) i
++;
375 READ_A_BYTE(bytes
.byte0
);
376 READ_A_BYTE(bytes
.byte1
);
377 READ_A_BYTE(bytes
.byte2
);
378 READ_A_BYTE(bytes
.byte3
);
381 READ_A_BYTE(bytes
.byte4
);
382 READ_A_BYTE(bytes
.byte5
);
385 READ_A_BYTE(bytes
.byte6
);
386 READ_A_BYTE(bytes
.byte7
);
389 READ_A_BYTE(bytes
.byte8
);
390 READ_A_BYTE(bytes
.byte9
);
393 READ_A_BYTE(bytes
.byte10
);
394 READ_A_BYTE(bytes
.byte11
);
395 READ_A_BYTE(bytes
.byte12
);
396 READ_A_BYTE(bytes
.byte13
);
397 READ_A_BYTE(bytes
.byte14
);
398 READ_A_BYTE(bytes
.byte15
);
400 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
403 CFStringRef
CFUUIDCreateString(CFAllocatorRef alloc
, CFUUIDRef uuid
) {
404 CFMutableStringRef str
= CFStringCreateMutable(alloc
, 0);
407 // First segment (4 bytes, 8 digits + 1 dash)
408 _intToHexChars(uuid
->_bytes
.byte0
, buff
, 2);
409 _intToHexChars(uuid
->_bytes
.byte1
, &(buff
[2]), 2);
410 _intToHexChars(uuid
->_bytes
.byte2
, &(buff
[4]), 2);
411 _intToHexChars(uuid
->_bytes
.byte3
, &(buff
[6]), 2);
412 buff
[8] = (UniChar
)'-';
413 CFStringAppendCharacters(str
, buff
, 9);
415 // Second segment (2 bytes, 4 digits + 1 dash)
416 _intToHexChars(uuid
->_bytes
.byte4
, buff
, 2);
417 _intToHexChars(uuid
->_bytes
.byte5
, &(buff
[2]), 2);
418 buff
[4] = (UniChar
)'-';
419 CFStringAppendCharacters(str
, buff
, 5);
421 // Third segment (2 bytes, 4 digits + 1 dash)
422 _intToHexChars(uuid
->_bytes
.byte6
, buff
, 2);
423 _intToHexChars(uuid
->_bytes
.byte7
, &(buff
[2]), 2);
424 buff
[4] = (UniChar
)'-';
425 CFStringAppendCharacters(str
, buff
, 5);
427 // Fourth segment (2 bytes, 4 digits + 1 dash)
428 _intToHexChars(uuid
->_bytes
.byte8
, buff
, 2);
429 _intToHexChars(uuid
->_bytes
.byte9
, &(buff
[2]), 2);
430 buff
[4] = (UniChar
)'-';
431 CFStringAppendCharacters(str
, buff
, 5);
433 // Fifth segment (6 bytes, 12 digits)
434 _intToHexChars(uuid
->_bytes
.byte10
, buff
, 2);
435 _intToHexChars(uuid
->_bytes
.byte11
, &(buff
[2]), 2);
436 _intToHexChars(uuid
->_bytes
.byte12
, &(buff
[4]), 2);
437 _intToHexChars(uuid
->_bytes
.byte13
, &(buff
[6]), 2);
438 _intToHexChars(uuid
->_bytes
.byte14
, &(buff
[8]), 2);
439 _intToHexChars(uuid
->_bytes
.byte15
, &(buff
[10]), 2);
440 CFStringAppendCharacters(str
, buff
, 12);
445 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
) {
447 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
458 bytes
.byte10
= byte10
;
459 bytes
.byte11
= byte11
;
460 bytes
.byte12
= byte12
;
461 bytes
.byte13
= byte13
;
462 bytes
.byte14
= byte14
;
463 bytes
.byte15
= byte15
;
465 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, true);
468 CFUUIDBytes
CFUUIDGetUUIDBytes(CFUUIDRef uuid
) {
472 CF_EXPORT CFUUIDRef
CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc
, CFUUIDBytes bytes
) {
473 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);