2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Doug Davidson
30 #include <CoreFoundation/CFUUID.h>
31 #include "CFInternal.h"
33 /* uuid_t already defined in RPCDCE.H (WIN32 header)
34 * (Aleksey Dukhnyakov)
36 #if defined(__WIN32__)
37 #define UUID_T_DEFINED 1
40 #if !defined(UUID_T_DEFINED)
41 #define UUID_T_DEFINED 1
45 * Universal Unique ID. Note this definition will result is a 16-byte
46 * structure regardless what platform it is on.
50 unsigned long time_low
;
51 unsigned short time_mid
;
52 unsigned short time_hi_and_version
;
53 unsigned char clock_seq_hi_and_reserved
;
54 unsigned char clock_seq_low
;
55 unsigned char node
[6];
58 typedef struct uuid_t uuid_t
;
62 extern unsigned long _CFGenerateUUID(uuid_t
*uuid
);
64 static CFMutableDictionaryRef _uniquedUUIDs
= NULL
;
65 static CFSpinLock_t CFUUIDGlobalDataLock
= 0;
72 static Boolean
__CFisEqualUUIDBytes(const void *ptr1
, const void *ptr2
) {
73 CFUUIDBytes
*p1
= (CFUUIDBytes
*)ptr1
;
74 CFUUIDBytes
*p2
= (CFUUIDBytes
*)ptr2
;
76 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);
79 static CFHashCode
__CFhashUUIDBytes(const void *ptr
) {
80 return CFHashBytes((uint8_t *)ptr
, 16);
83 static CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks
= {0, NULL
, NULL
, NULL
, __CFisEqualUUIDBytes
, __CFhashUUIDBytes
};
84 static CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks
= {0, NULL
, NULL
, CFCopyDescription
, CFEqual
};
86 static void __CFUUIDAddUniqueUUID(CFUUIDRef uuid
) {
87 __CFSpinLock(&CFUUIDGlobalDataLock
);
88 if (_uniquedUUIDs
== NULL
) {
89 /* Allocate table from default allocator */
90 _uniquedUUIDs
= CFDictionaryCreateMutable(NULL
, 0, &__CFUUIDBytesDictionaryKeyCallBacks
, &__CFnonRetainedUUIDDictionaryValueCallBacks
);
92 CFDictionarySetValue(_uniquedUUIDs
, &(uuid
->_bytes
), uuid
);
93 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
96 static void __CFUUIDRemoveUniqueUUID(CFUUIDRef uuid
) {
97 __CFSpinLock(&CFUUIDGlobalDataLock
);
98 if (_uniquedUUIDs
!= NULL
) {
99 CFDictionaryRemoveValue(_uniquedUUIDs
, &(uuid
->_bytes
));
101 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
104 static CFUUIDRef
__CFUUIDGetUniquedUUID(CFUUIDBytes
*bytes
) {
105 CFUUIDRef uuid
= NULL
;
106 __CFSpinLock(&CFUUIDGlobalDataLock
);
107 if (_uniquedUUIDs
!= NULL
) {
108 uuid
= CFDictionaryGetValue(_uniquedUUIDs
, bytes
);
110 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
114 static void __CFUUIDDeallocate(CFTypeRef cf
) {
115 struct __CFUUID
*uuid
= (struct __CFUUID
*)cf
;
116 __CFUUIDRemoveUniqueUUID(uuid
);
119 static CFStringRef
__CFUUIDCopyDescription(CFTypeRef cf
) {
120 CFStringRef uuidStr
= CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
121 CFStringRef desc
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<CFUUID 0x%x> %@"), cf
, uuidStr
);
126 static CFStringRef
__CFUUIDCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
127 return CFUUIDCreateString(CFGetAllocator(cf
), (CFUUIDRef
)cf
);
130 static CFTypeID __kCFUUIDTypeID
= _kCFRuntimeNotATypeID
;
132 static const CFRuntimeClass __CFUUIDClass
= {
140 __CFUUIDCopyFormattingDescription
,
141 __CFUUIDCopyDescription
144 __private_extern__
void __CFUUIDInitialize(void) {
145 __kCFUUIDTypeID
= _CFRuntimeRegisterClass(&__CFUUIDClass
);
148 CFTypeID
CFUUIDGetTypeID(void) {
149 return __kCFUUIDTypeID
;
152 static CFUUIDRef
__CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator
, CFUUIDBytes bytes
, Boolean isConst
) {
153 struct __CFUUID
*uuid
= (struct __CFUUID
*)__CFUUIDGetUniquedUUID(&bytes
);
157 size
= sizeof(struct __CFUUID
) - sizeof(CFRuntimeBase
);
158 uuid
= (struct __CFUUID
*)_CFRuntimeCreateInstance(allocator
, __kCFUUIDTypeID
, size
, NULL
);
160 if (NULL
== uuid
) return NULL
;
162 uuid
->_bytes
= bytes
;
164 __CFUUIDAddUniqueUUID(uuid
);
165 } else if (!isConst
) {
169 return (CFUUIDRef
)uuid
;
172 CFUUIDRef
CFUUIDCreate(CFAllocatorRef alloc
) {
173 /* Create a new bytes struct and then call the primitive. */
175 unsigned long retval
= 0;
177 __CFSpinLock(&CFUUIDGlobalDataLock
);
178 retval
= _CFGenerateUUID((uuid_t
*)&bytes
);
179 __CFSpinUnlock(&CFUUIDGlobalDataLock
);
181 return (retval
== 0) ? __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false) : NULL
;
184 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
) {
186 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
197 bytes
.byte10
= byte10
;
198 bytes
.byte11
= byte11
;
199 bytes
.byte12
= byte12
;
200 bytes
.byte13
= byte13
;
201 bytes
.byte14
= byte14
;
202 bytes
.byte15
= byte15
;
204 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
207 static void _intToHexChars(UInt32 in
, UniChar
*out
, int digits
) {
211 while (--digits
>= 0) {
213 d
= 0x0FL
& (in
>> shift
);
215 *out
++ = (UniChar
)'0' + d
;
217 *out
++ = (UniChar
)'A' + (d
- 10);
222 static uint8_t _byteFromHexChars(UniChar
*in
) {
228 for (i
=0; i
<2; i
++) {
230 if ((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) {
231 d
= c
- (UniChar
)'0';
232 } else if ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) {
233 d
= c
- ((UniChar
)'a' - 10);
234 } else if ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F')) {
235 d
= c
- ((UniChar
)'A' - 10);
239 result
= (result
<< 4) | d
;
245 CF_INLINE Boolean
_isHexChar(UniChar c
) {
246 return ((((c
>= (UniChar
)'0') && (c
<= (UniChar
)'9')) || ((c
>= (UniChar
)'a') && (c
<= (UniChar
)'f')) || ((c
>= (UniChar
)'A') && (c
<= (UniChar
)'F'))) ? true : false);
249 #define READ_A_BYTE(into) if (i+1 < len) { \
250 (into) = _byteFromHexChars(&(chars[i])); \
254 CFUUIDRef
CFUUIDCreateFromString(CFAllocatorRef alloc
, CFStringRef uuidStr
) {
255 /* Parse the string into a bytes struct and then call the primitive. */
261 if (uuidStr
== NULL
) return NULL
;
263 len
= CFStringGetLength(uuidStr
);
266 } else if (len
== 0) {
269 CFStringGetCharacters(uuidStr
, CFRangeMake(0, len
), chars
);
270 memset((void *)&bytes
, 0, sizeof(bytes
));
272 /* Skip initial random stuff */
273 while (!_isHexChar(chars
[i
]) && (i
< len
)) {
277 READ_A_BYTE(bytes
.byte0
);
278 READ_A_BYTE(bytes
.byte1
);
279 READ_A_BYTE(bytes
.byte2
);
280 READ_A_BYTE(bytes
.byte3
);
284 READ_A_BYTE(bytes
.byte4
);
285 READ_A_BYTE(bytes
.byte5
);
289 READ_A_BYTE(bytes
.byte6
);
290 READ_A_BYTE(bytes
.byte7
);
294 READ_A_BYTE(bytes
.byte8
);
295 READ_A_BYTE(bytes
.byte9
);
299 READ_A_BYTE(bytes
.byte10
);
300 READ_A_BYTE(bytes
.byte11
);
301 READ_A_BYTE(bytes
.byte12
);
302 READ_A_BYTE(bytes
.byte13
);
303 READ_A_BYTE(bytes
.byte14
);
304 READ_A_BYTE(bytes
.byte15
);
306 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);
309 CFStringRef
CFUUIDCreateString(CFAllocatorRef alloc
, CFUUIDRef uuid
) {
310 CFMutableStringRef str
= CFStringCreateMutable(alloc
, 0);
313 // First segment (4 bytes, 8 digits + 1 dash)
314 _intToHexChars(uuid
->_bytes
.byte0
, buff
, 2);
315 _intToHexChars(uuid
->_bytes
.byte1
, &(buff
[2]), 2);
316 _intToHexChars(uuid
->_bytes
.byte2
, &(buff
[4]), 2);
317 _intToHexChars(uuid
->_bytes
.byte3
, &(buff
[6]), 2);
318 buff
[8] = (UniChar
)'-';
319 CFStringAppendCharacters(str
, buff
, 9);
321 // Second segment (2 bytes, 4 digits + 1 dash)
322 _intToHexChars(uuid
->_bytes
.byte4
, buff
, 2);
323 _intToHexChars(uuid
->_bytes
.byte5
, &(buff
[2]), 2);
324 buff
[4] = (UniChar
)'-';
325 CFStringAppendCharacters(str
, buff
, 5);
327 // Third segment (2 bytes, 4 digits + 1 dash)
328 _intToHexChars(uuid
->_bytes
.byte6
, buff
, 2);
329 _intToHexChars(uuid
->_bytes
.byte7
, &(buff
[2]), 2);
330 buff
[4] = (UniChar
)'-';
331 CFStringAppendCharacters(str
, buff
, 5);
333 // Fourth segment (2 bytes, 4 digits + 1 dash)
334 _intToHexChars(uuid
->_bytes
.byte8
, buff
, 2);
335 _intToHexChars(uuid
->_bytes
.byte9
, &(buff
[2]), 2);
336 buff
[4] = (UniChar
)'-';
337 CFStringAppendCharacters(str
, buff
, 5);
339 // Fifth segment (6 bytes, 12 digits)
340 _intToHexChars(uuid
->_bytes
.byte10
, buff
, 2);
341 _intToHexChars(uuid
->_bytes
.byte11
, &(buff
[2]), 2);
342 _intToHexChars(uuid
->_bytes
.byte12
, &(buff
[4]), 2);
343 _intToHexChars(uuid
->_bytes
.byte13
, &(buff
[6]), 2);
344 _intToHexChars(uuid
->_bytes
.byte14
, &(buff
[8]), 2);
345 _intToHexChars(uuid
->_bytes
.byte15
, &(buff
[10]), 2);
346 CFStringAppendCharacters(str
, buff
, 12);
351 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
) {
353 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
364 bytes
.byte10
= byte10
;
365 bytes
.byte11
= byte11
;
366 bytes
.byte12
= byte12
;
367 bytes
.byte13
= byte13
;
368 bytes
.byte14
= byte14
;
369 bytes
.byte15
= byte15
;
371 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, true);
374 CFUUIDBytes
CFUUIDGetUUIDBytes(CFUUIDRef uuid
) {
378 CF_EXPORT CFUUIDRef
CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc
, CFUUIDBytes bytes
) {
379 return __CFUUIDCreateWithBytesPrimitive(alloc
, bytes
, false);