2 * Copyright (c) 2005 Apple Computer, 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 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Doug Davidson
28 #include <CoreFoundation/CFUUID.h>
29 #include "CFInternal.h"
31 extern uint32_t _CFGenerateUUID(uint8_t *uuid_bytes
);
33 static CFMutableDictionaryRef _uniquedUUIDs
= NULL
;
34 static CFSpinLock_t CFUUIDGlobalDataLock
= 0;
41 static Boolean
__CFisEqualUUIDBytes(const void *ptr1
, const void *ptr2
) {
42 CFUUIDBytes
*p1
= (CFUUIDBytes
*)ptr1
;
43 CFUUIDBytes
*p2
= (CFUUIDBytes
*)ptr2
;
45 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);
48 static CFHashCode
__CFhashUUIDBytes(const void *ptr
) {
49 return CFHashBytes((uint8_t *)ptr
, 16);
52 static CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks
= {0, NULL
, NULL
, NULL
, __CFisEqualUUIDBytes
, __CFhashUUIDBytes
};
53 static CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks
= {0, NULL
, NULL
, CFCopyDescription
, CFEqual
};
55 static void __CFUUIDAddUniqueUUID(CFUUIDRef uuid
) {
56 __CFSpinLock(&CFUUIDGlobalDataLock
);
57 if (_uniquedUUIDs
== NULL
) {
58 /* Allocate table from default allocator */
59 // XXX_PCB these need to weakly hold the UUIDs, otherwise, they will never be collected.
60 _uniquedUUIDs
= CFDictionaryCreateMutable(kCFAllocatorMallocZone
, 0, &__CFUUIDBytesDictionaryKeyCallBacks
, &__CFnonRetainedUUIDDictionaryValueCallBacks
);
62 CFDictionarySetValue(_uniquedUUIDs
, &(uuid
->_bytes
), uuid
);
63 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
66 static void __CFUUIDRemoveUniqueUUID(CFUUIDRef uuid
) {
67 __CFSpinLock(&CFUUIDGlobalDataLock
);
68 if (_uniquedUUIDs
!= NULL
) {
69 CFDictionaryRemoveValue(_uniquedUUIDs
, &(uuid
->_bytes
));
71 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
74 static CFUUIDRef
__CFUUIDGetUniquedUUID(CFUUIDBytes
*bytes
) {
75 CFUUIDRef uuid
= NULL
;
76 __CFSpinLock(&CFUUIDGlobalDataLock
);
77 if (_uniquedUUIDs
!= NULL
) {
78 uuid
= CFDictionaryGetValue(_uniquedUUIDs
, bytes
);
80 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
84 static void __CFUUIDDeallocate(CFTypeRef cf
) {
85 struct __CFUUID
*uuid
= (struct __CFUUID
*)cf
;
86 __CFUUIDRemoveUniqueUUID(uuid
);
89 static CFStringRef
__CFUUIDCopyDescription(CFTypeRef cf
) {
90 CFStringRef uuidStr
= CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
91 CFStringRef desc
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<CFUUID 0x%x> %@"), cf
, uuidStr
);
96 static CFStringRef
__CFUUIDCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
97 return CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
100 static CFTypeID __kCFUUIDTypeID
= _kCFRuntimeNotATypeID
;
102 static const CFRuntimeClass __CFUUIDClass
= {
110 __CFUUIDCopyFormattingDescription
,
111 __CFUUIDCopyDescription
114 __private_extern__
void __CFUUIDInitialize(void) {
115 __kCFUUIDTypeID
= _CFRuntimeRegisterClass(&__CFUUIDClass
);
118 CFTypeID
CFUUIDGetTypeID(void) {
119 return __kCFUUIDTypeID
;
122 static CFUUIDRef
__CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator
, CFUUIDBytes bytes
, Boolean isConst
) {
123 struct __CFUUID
*uuid
= (struct __CFUUID
*)__CFUUIDGetUniquedUUID(&bytes
);
127 size
= sizeof(struct __CFUUID
) - sizeof(CFRuntimeBase
);
128 uuid
= (struct __CFUUID
*)_CFRuntimeCreateInstance(allocator
, __kCFUUIDTypeID
, size
, NULL
);
130 if (NULL
== uuid
) return NULL
;
132 uuid
->_bytes
= bytes
;
134 __CFUUIDAddUniqueUUID(uuid
);
135 } else if (!isConst
) {
139 return (CFUUIDRef
)uuid
;
142 CFUUIDRef
CFUUIDCreate(CFAllocatorRef alloc
) {
143 /* Create a new bytes struct and then call the primitive. */
147 __CFSpinLock(&CFUUIDGlobalDataLock
);
148 retval
= _CFGenerateUUID((uint8_t *)&bytes
);
149 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
151 return (retval
== 0) ? __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false) : NULL
;
154 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
) {
156 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
167 bytes
.byte10
= byte10
;
168 bytes
.byte11
= byte11
;
169 bytes
.byte12
= byte12
;
170 bytes
.byte13
= byte13
;
171 bytes
.byte14
= byte14
;
172 bytes
.byte15
= byte15
;
174 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
177 static void _intToHexChars(UInt32 in
, UniChar
*out
, int digits
) {
181 while (--digits
>= 0) {
183 d
= 0x0FL
& (in
>> shift
);
185 *out
++ = (UniChar
)'0' + d
;
187 *out
++ = (UniChar
)'A' + (d
- 10);
192 static uint8_t _byteFromHexChars(UniChar
*in
) {
198 for (i
=0; i
<2; i
++) {
200 if ((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) {
201 d
= c
- (UniChar
)'0';
202 } else if ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) {
203 d
= c
- ((UniChar
)'a' - 10);
204 } else if ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F')) {
205 d
= c
- ((UniChar
)'A' - 10);
209 result
= (result
<< 4) | d
;
215 CF_INLINE Boolean
_isHexChar(UniChar c
) {
216 return ((((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) || ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) || ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F'))) ? true : false);
219 #define READ_A_BYTE(into) if (i+1 < len) { \
220 (into) = _byteFromHexChars(&(chars[i])); \
224 CFUUIDRef
CFUUIDCreateFromString(CFAllocatorRef alloc
, CFStringRef uuidStr
) {
225 /* Parse the string into a bytes struct and then call the primitive. */
231 if (uuidStr
== NULL
) return NULL
;
233 len
= CFStringGetLength(uuidStr
);
236 } else if (len
== 0) {
239 CFStringGetCharacters(uuidStr
, CFRangeMake(0, len
), chars
);
240 memset((void *)&bytes
, 0, sizeof(bytes
));
242 /* Skip initial random stuff */
243 while (!_isHexChar(chars
[i
]) && (i
< len
)) {
247 READ_A_BYTE(bytes
.byte0
);
248 READ_A_BYTE(bytes
.byte1
);
249 READ_A_BYTE(bytes
.byte2
);
250 READ_A_BYTE(bytes
.byte3
);
254 READ_A_BYTE(bytes
.byte4
);
255 READ_A_BYTE(bytes
.byte5
);
259 READ_A_BYTE(bytes
.byte6
);
260 READ_A_BYTE(bytes
.byte7
);
264 READ_A_BYTE(bytes
.byte8
);
265 READ_A_BYTE(bytes
.byte9
);
269 READ_A_BYTE(bytes
.byte10
);
270 READ_A_BYTE(bytes
.byte11
);
271 READ_A_BYTE(bytes
.byte12
);
272 READ_A_BYTE(bytes
.byte13
);
273 READ_A_BYTE(bytes
.byte14
);
274 READ_A_BYTE(bytes
.byte15
);
276 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
279 CFStringRef
CFUUIDCreateString(CFAllocatorRef alloc
, CFUUIDRef uuid
) {
280 CFMutableStringRef str
= CFStringCreateMutable(alloc
, 0);
283 // First segment (4 bytes, 8 digits + 1 dash)
284 _intToHexChars(uuid
->_bytes
.byte0
, buff
, 2);
285 _intToHexChars(uuid
->_bytes
.byte1
, &(buff
[2]), 2);
286 _intToHexChars(uuid
->_bytes
.byte2
, &(buff
[4]), 2);
287 _intToHexChars(uuid
->_bytes
.byte3
, &(buff
[6]), 2);
288 buff
[8] = (UniChar
)'-';
289 CFStringAppendCharacters(str
, buff
, 9);
291 // Second segment (2 bytes, 4 digits + 1 dash)
292 _intToHexChars(uuid
->_bytes
.byte4
, buff
, 2);
293 _intToHexChars(uuid
->_bytes
.byte5
, &(buff
[2]), 2);
294 buff
[4] = (UniChar
)'-';
295 CFStringAppendCharacters(str
, buff
, 5);
297 // Third segment (2 bytes, 4 digits + 1 dash)
298 _intToHexChars(uuid
->_bytes
.byte6
, buff
, 2);
299 _intToHexChars(uuid
->_bytes
.byte7
, &(buff
[2]), 2);
300 buff
[4] = (UniChar
)'-';
301 CFStringAppendCharacters(str
, buff
, 5);
303 // Fourth segment (2 bytes, 4 digits + 1 dash)
304 _intToHexChars(uuid
->_bytes
.byte8
, buff
, 2);
305 _intToHexChars(uuid
->_bytes
.byte9
, &(buff
[2]), 2);
306 buff
[4] = (UniChar
)'-';
307 CFStringAppendCharacters(str
, buff
, 5);
309 // Fifth segment (6 bytes, 12 digits)
310 _intToHexChars(uuid
->_bytes
.byte10
, buff
, 2);
311 _intToHexChars(uuid
->_bytes
.byte11
, &(buff
[2]), 2);
312 _intToHexChars(uuid
->_bytes
.byte12
, &(buff
[4]), 2);
313 _intToHexChars(uuid
->_bytes
.byte13
, &(buff
[6]), 2);
314 _intToHexChars(uuid
->_bytes
.byte14
, &(buff
[8]), 2);
315 _intToHexChars(uuid
->_bytes
.byte15
, &(buff
[10]), 2);
316 CFStringAppendCharacters(str
, buff
, 12);
321 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
) {
323 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
334 bytes
.byte10
= byte10
;
335 bytes
.byte11
= byte11
;
336 bytes
.byte12
= byte12
;
337 bytes
.byte13
= byte13
;
338 bytes
.byte14
= byte14
;
339 bytes
.byte15
= byte15
;
341 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, true);
344 CFUUIDBytes
CFUUIDGetUUIDBytes(CFUUIDRef uuid
) {
348 CF_EXPORT CFUUIDRef
CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc
, CFUUIDBytes bytes
) {
349 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);