2 * Copyright (c) 2008 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-2007 Apple Inc. All rights reserved.
25 Responsibility: Doug Davidson
28 #include <CoreFoundation/CFUUID.h>
29 #include "CFInternal.h"
30 #if DEPLOYMENT_TARGET_MACOSX
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);
53 #import "auto_stubs.h"
55 #define LOCK() __CFSpinLock(&CFUUIDGlobalDataLock)
56 #define UNLOCK() __CFSpinUnlock(&CFUUIDGlobalDataLock)
58 #define MALLOC(x) CFAllocatorAllocate(kCFAllocatorSystemDefault, x, 0)
59 #define FREE(x) CFAllocatorDeallocate(kCFAllocatorSystemDefault, x)
60 #define HASH(x) CFHashBytes((uint8_t *)x, 16)
63 /***** end of weak set */
65 static void __CFUUIDAddUniqueUUID(CFUUIDRef uuid
) {
66 __CFSpinLock(&CFUUIDGlobalDataLock
);
68 CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks
= {0, NULL
, NULL
, NULL
, __CFisEqualUUIDBytes
, __CFhashUUIDBytes
};
69 CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks
= {0, NULL
, NULL
, CFCopyDescription
, CFEqual
};
71 if (_uniquedUUIDs
== NULL
) {
72 _uniquedUUIDs
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &__CFUUIDBytesDictionaryKeyCallBacks
, &__CFnonRetainedUUIDDictionaryValueCallBacks
);
74 CFDictionarySetValue(_uniquedUUIDs
, &(uuid
->_bytes
), uuid
);
75 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
78 static void __CFUUIDRemoveUniqueUUID(CFUUIDRef uuid
) {
79 __CFSpinLock(&CFUUIDGlobalDataLock
);
80 if (_uniquedUUIDs
!= NULL
) {
81 CFDictionaryRemoveValue(_uniquedUUIDs
, &(uuid
->_bytes
));
83 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
86 static CFUUIDRef
__CFUUIDGetUniquedUUID(CFUUIDBytes
*bytes
) {
87 CFUUIDRef uuid
= NULL
;
88 __CFSpinLock(&CFUUIDGlobalDataLock
);
89 if (_uniquedUUIDs
!= NULL
) {
90 uuid
= (CFUUIDRef
)CFDictionaryGetValue(_uniquedUUIDs
, bytes
);
92 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
96 static void __CFUUIDDeallocate(CFTypeRef cf
) {
97 struct __CFUUID
*uuid
= (struct __CFUUID
*)cf
;
98 __CFUUIDRemoveUniqueUUID(uuid
);
101 static CFStringRef
__CFUUIDCopyDescription(CFTypeRef cf
) {
102 CFStringRef uuidStr
= CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
103 CFStringRef desc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFUUID %p> %@"), cf
, uuidStr
);
108 static CFStringRef
__CFUUIDCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
109 return CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
112 static CFTypeID __kCFUUIDTypeID
= _kCFRuntimeNotATypeID
;
114 static const CFRuntimeClass __CFUUIDClass
= {
122 __CFUUIDCopyFormattingDescription
,
123 __CFUUIDCopyDescription
126 __private_extern__
void __CFUUIDInitialize(void) {
127 __kCFUUIDTypeID
= _CFRuntimeRegisterClass(&__CFUUIDClass
);
130 CFTypeID
CFUUIDGetTypeID(void) {
131 return __kCFUUIDTypeID
;
134 static CFUUIDRef
__CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator
, CFUUIDBytes bytes
, Boolean isConst
) {
135 struct __CFUUID
*uuid
= (struct __CFUUID
*)__CFUUIDGetUniquedUUID(&bytes
);
139 size
= sizeof(struct __CFUUID
) - sizeof(CFRuntimeBase
);
140 uuid
= (struct __CFUUID
*)_CFRuntimeCreateInstance(allocator
, __kCFUUIDTypeID
, size
, NULL
);
142 if (NULL
== uuid
) return NULL
;
144 uuid
->_bytes
= bytes
;
146 __CFUUIDAddUniqueUUID(uuid
);
147 } else if (!isConst
) {
151 return (CFUUIDRef
)uuid
;
154 CFUUIDRef
CFUUIDCreate(CFAllocatorRef alloc
) {
155 /* Create a new bytes struct and then call the primitive. */
159 __CFSpinLock(&CFUUIDGlobalDataLock
);
160 #if (DEPLOYMENT_TARGET_MACOSX)
161 static Boolean useV1UUIDs
= false, checked
= false;
164 const char *value
= getenv("CFUUIDVersionNumber");
166 if (1 == strtoul_l(value
, NULL
, 0, NULL
)) useV1UUIDs
= true;
168 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionTiger
)) useV1UUIDs
= true;
172 if (useV1UUIDs
) uuid_generate_time(uuid
); else uuid_generate_random(uuid
);
173 memcpy(&bytes
, uuid
, sizeof(uuid
));
177 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
179 return (retval
== 0) ? __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false) : NULL
;
182 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
) {
184 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
195 bytes
.byte10
= byte10
;
196 bytes
.byte11
= byte11
;
197 bytes
.byte12
= byte12
;
198 bytes
.byte13
= byte13
;
199 bytes
.byte14
= byte14
;
200 bytes
.byte15
= byte15
;
202 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
205 static void _intToHexChars(UInt32 in
, UniChar
*out
, int digits
) {
209 while (--digits
>= 0) {
211 d
= 0x0FL
& (in
>> shift
);
213 *out
++ = (UniChar
)'0' + d
;
215 *out
++ = (UniChar
)'A' + (d
- 10);
220 static uint8_t _byteFromHexChars(UniChar
*in
) {
226 for (i
=0; i
<2; i
++) {
228 if ((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) {
229 d
= c
- (UniChar
)'0';
230 } else if ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) {
231 d
= c
- ((UniChar
)'a' - 10);
232 } else if ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F')) {
233 d
= c
- ((UniChar
)'A' - 10);
237 result
= (result
<< 4) | d
;
243 CF_INLINE Boolean
_isHexChar(UniChar c
) {
244 return ((((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) || ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) || ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F'))) ? true : false);
247 #define READ_A_BYTE(into) if (i+1 < len) { \
248 (into) = _byteFromHexChars(&(chars[i])); \
252 CFUUIDRef
CFUUIDCreateFromString(CFAllocatorRef alloc
, CFStringRef uuidStr
) {
253 /* Parse the string into a bytes struct and then call the primitive. */
259 if (uuidStr
== NULL
) return NULL
;
261 len
= CFStringGetLength(uuidStr
);
264 } else if (len
== 0) {
267 CFStringGetCharacters(uuidStr
, CFRangeMake(0, len
), chars
);
268 memset((void *)&bytes
, 0, sizeof(bytes
));
270 /* Skip initial random stuff */
271 while (!_isHexChar(chars
[i
]) && (i
< len
)) {
275 READ_A_BYTE(bytes
.byte0
);
276 READ_A_BYTE(bytes
.byte1
);
277 READ_A_BYTE(bytes
.byte2
);
278 READ_A_BYTE(bytes
.byte3
);
282 READ_A_BYTE(bytes
.byte4
);
283 READ_A_BYTE(bytes
.byte5
);
287 READ_A_BYTE(bytes
.byte6
);
288 READ_A_BYTE(bytes
.byte7
);
292 READ_A_BYTE(bytes
.byte8
);
293 READ_A_BYTE(bytes
.byte9
);
297 READ_A_BYTE(bytes
.byte10
);
298 READ_A_BYTE(bytes
.byte11
);
299 READ_A_BYTE(bytes
.byte12
);
300 READ_A_BYTE(bytes
.byte13
);
301 READ_A_BYTE(bytes
.byte14
);
302 READ_A_BYTE(bytes
.byte15
);
304 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
307 CFStringRef
CFUUIDCreateString(CFAllocatorRef alloc
, CFUUIDRef uuid
) {
308 CFMutableStringRef str
= CFStringCreateMutable(alloc
, 0);
311 // First segment (4 bytes, 8 digits + 1 dash)
312 _intToHexChars(uuid
->_bytes
.byte0
, buff
, 2);
313 _intToHexChars(uuid
->_bytes
.byte1
, &(buff
[2]), 2);
314 _intToHexChars(uuid
->_bytes
.byte2
, &(buff
[4]), 2);
315 _intToHexChars(uuid
->_bytes
.byte3
, &(buff
[6]), 2);
316 buff
[8] = (UniChar
)'-';
317 CFStringAppendCharacters(str
, buff
, 9);
319 // Second segment (2 bytes, 4 digits + 1 dash)
320 _intToHexChars(uuid
->_bytes
.byte4
, buff
, 2);
321 _intToHexChars(uuid
->_bytes
.byte5
, &(buff
[2]), 2);
322 buff
[4] = (UniChar
)'-';
323 CFStringAppendCharacters(str
, buff
, 5);
325 // Third segment (2 bytes, 4 digits + 1 dash)
326 _intToHexChars(uuid
->_bytes
.byte6
, buff
, 2);
327 _intToHexChars(uuid
->_bytes
.byte7
, &(buff
[2]), 2);
328 buff
[4] = (UniChar
)'-';
329 CFStringAppendCharacters(str
, buff
, 5);
331 // Fourth segment (2 bytes, 4 digits + 1 dash)
332 _intToHexChars(uuid
->_bytes
.byte8
, buff
, 2);
333 _intToHexChars(uuid
->_bytes
.byte9
, &(buff
[2]), 2);
334 buff
[4] = (UniChar
)'-';
335 CFStringAppendCharacters(str
, buff
, 5);
337 // Fifth segment (6 bytes, 12 digits)
338 _intToHexChars(uuid
->_bytes
.byte10
, buff
, 2);
339 _intToHexChars(uuid
->_bytes
.byte11
, &(buff
[2]), 2);
340 _intToHexChars(uuid
->_bytes
.byte12
, &(buff
[4]), 2);
341 _intToHexChars(uuid
->_bytes
.byte13
, &(buff
[6]), 2);
342 _intToHexChars(uuid
->_bytes
.byte14
, &(buff
[8]), 2);
343 _intToHexChars(uuid
->_bytes
.byte15
, &(buff
[10]), 2);
344 CFStringAppendCharacters(str
, buff
, 12);
349 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
) {
351 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
362 bytes
.byte10
= byte10
;
363 bytes
.byte11
= byte11
;
364 bytes
.byte12
= byte12
;
365 bytes
.byte13
= byte13
;
366 bytes
.byte14
= byte14
;
367 bytes
.byte15
= byte15
;
369 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, true);
372 CFUUIDBytes
CFUUIDGetUUIDBytes(CFUUIDRef uuid
) {
376 CF_EXPORT CFUUIDRef
CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc
, CFUUIDBytes bytes
) {
377 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);