]> git.saurik.com Git - apple/cf.git/blob - Base.subproj/CFUUID.c
CF-299.31.tar.gz
[apple/cf.git] / Base.subproj / CFUUID.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* CFUUID.c
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Doug Davidson
28 */
29
30 #include <CoreFoundation/CFUUID.h>
31 #include "CFInternal.h"
32
33 /* uuid_t already defined in RPCDCE.H (WIN32 header)
34 * (Aleksey Dukhnyakov)
35 */
36 #if defined(__WIN32__)
37 #define UUID_T_DEFINED 1
38 #endif
39
40 #if !defined(UUID_T_DEFINED)
41 #define UUID_T_DEFINED 1
42
43 /* uuid
44 *
45 * Universal Unique ID. Note this definition will result is a 16-byte
46 * structure regardless what platform it is on.
47 */
48
49 struct uuid_t {
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];
56 };
57
58 typedef struct uuid_t uuid_t;
59
60 #endif
61
62 extern unsigned long _CFGenerateUUID(uuid_t *uuid);
63
64 static CFMutableDictionaryRef _uniquedUUIDs = NULL;
65 static CFSpinLock_t CFUUIDGlobalDataLock = 0;
66
67 struct __CFUUID {
68 CFRuntimeBase _base;
69 CFUUIDBytes _bytes;
70 };
71
72 static Boolean __CFisEqualUUIDBytes(const void *ptr1, const void *ptr2) {
73 CFUUIDBytes *p1 = (CFUUIDBytes *)ptr1;
74 CFUUIDBytes *p2 = (CFUUIDBytes *)ptr2;
75
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);
77 }
78
79 static CFHashCode __CFhashUUIDBytes(const void *ptr) {
80 return CFHashBytes((uint8_t *)ptr, 16);
81 }
82
83 static CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks = {0, NULL, NULL, NULL, __CFisEqualUUIDBytes, __CFhashUUIDBytes};
84 static CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks = {0, NULL, NULL, CFCopyDescription, CFEqual};
85
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);
91 }
92 CFDictionarySetValue(_uniquedUUIDs, &(uuid->_bytes), uuid);
93 __CFSpinUnlock(&CFUUIDGlobalDataLock);
94 }
95
96 static void __CFUUIDRemoveUniqueUUID(CFUUIDRef uuid) {
97 __CFSpinLock(&CFUUIDGlobalDataLock);
98 if (_uniquedUUIDs != NULL) {
99 CFDictionaryRemoveValue(_uniquedUUIDs, &(uuid->_bytes));
100 }
101 __CFSpinUnlock(&CFUUIDGlobalDataLock);
102 }
103
104 static CFUUIDRef __CFUUIDGetUniquedUUID(CFUUIDBytes *bytes) {
105 CFUUIDRef uuid = NULL;
106 __CFSpinLock(&CFUUIDGlobalDataLock);
107 if (_uniquedUUIDs != NULL) {
108 uuid = CFDictionaryGetValue(_uniquedUUIDs, bytes);
109 }
110 __CFSpinUnlock(&CFUUIDGlobalDataLock);
111 return uuid;
112 }
113
114 static void __CFUUIDDeallocate(CFTypeRef cf) {
115 struct __CFUUID *uuid = (struct __CFUUID *)cf;
116 __CFUUIDRemoveUniqueUUID(uuid);
117 }
118
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);
122 CFRelease(uuidStr);
123 return desc;
124 }
125
126 static CFStringRef __CFUUIDCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
127 return CFUUIDCreateString(CFGetAllocator(cf), (CFUUIDRef)cf);
128 }
129
130 static CFTypeID __kCFUUIDTypeID = _kCFRuntimeNotATypeID;
131
132 static const CFRuntimeClass __CFUUIDClass = {
133 0,
134 "CFUUID",
135 NULL, // init
136 NULL, // copy
137 __CFUUIDDeallocate,
138 NULL, // equal
139 NULL, // hash
140 __CFUUIDCopyFormattingDescription,
141 __CFUUIDCopyDescription
142 };
143
144 __private_extern__ void __CFUUIDInitialize(void) {
145 __kCFUUIDTypeID = _CFRuntimeRegisterClass(&__CFUUIDClass);
146 }
147
148 CFTypeID CFUUIDGetTypeID(void) {
149 return __kCFUUIDTypeID;
150 }
151
152 static CFUUIDRef __CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator, CFUUIDBytes bytes, Boolean isConst) {
153 struct __CFUUID *uuid = (struct __CFUUID *)__CFUUIDGetUniquedUUID(&bytes);
154
155 if (uuid == NULL) {
156 UInt32 size;
157 size = sizeof(struct __CFUUID) - sizeof(CFRuntimeBase);
158 uuid = (struct __CFUUID *)_CFRuntimeCreateInstance(allocator, __kCFUUIDTypeID, size, NULL);
159
160 if (NULL == uuid) return NULL;
161
162 uuid->_bytes = bytes;
163
164 __CFUUIDAddUniqueUUID(uuid);
165 } else if (!isConst) {
166 CFRetain(uuid);
167 }
168
169 return (CFUUIDRef)uuid;
170 }
171
172 CFUUIDRef CFUUIDCreate(CFAllocatorRef alloc) {
173 /* Create a new bytes struct and then call the primitive. */
174 CFUUIDBytes bytes;
175 unsigned long retval = 0;
176
177 __CFSpinLock(&CFUUIDGlobalDataLock);
178 retval = _CFGenerateUUID((uuid_t *)&bytes);
179 __CFSpinUnlock(&CFUUIDGlobalDataLock);
180
181 return (retval == 0) ? __CFUUIDCreateWithBytesPrimitive(alloc, bytes, false) : NULL;
182 }
183
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) {
185 CFUUIDBytes bytes;
186 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
187 bytes.byte0 = byte0;
188 bytes.byte1 = byte1;
189 bytes.byte2 = byte2;
190 bytes.byte3 = byte3;
191 bytes.byte4 = byte4;
192 bytes.byte5 = byte5;
193 bytes.byte6 = byte6;
194 bytes.byte7 = byte7;
195 bytes.byte8 = byte8;
196 bytes.byte9 = byte9;
197 bytes.byte10 = byte10;
198 bytes.byte11 = byte11;
199 bytes.byte12 = byte12;
200 bytes.byte13 = byte13;
201 bytes.byte14 = byte14;
202 bytes.byte15 = byte15;
203
204 return __CFUUIDCreateWithBytesPrimitive(alloc, bytes, false);
205 }
206
207 static void _intToHexChars(UInt32 in, UniChar *out, int digits) {
208 int shift;
209 UInt32 d;
210
211 while (--digits >= 0) {
212 shift = digits << 2;
213 d = 0x0FL & (in >> shift);
214 if (d <= 9) {
215 *out++ = (UniChar)'0' + d;
216 } else {
217 *out++ = (UniChar)'A' + (d - 10);
218 }
219 }
220 }
221
222 static uint8_t _byteFromHexChars(UniChar *in) {
223 uint8_t result = 0;
224 UniChar c;
225 uint8_t d;
226 CFIndex i;
227
228 for (i=0; i<2; i++) {
229 c = in[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);
236 } else {
237 return 0;
238 }
239 result = (result << 4) | d;
240 }
241
242 return result;
243 }
244
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);
247 }
248
249 #define READ_A_BYTE(into) if (i+1 < len) { \
250 (into) = _byteFromHexChars(&(chars[i])); \
251 i+=2; \
252 }
253
254 CFUUIDRef CFUUIDCreateFromString(CFAllocatorRef alloc, CFStringRef uuidStr) {
255 /* Parse the string into a bytes struct and then call the primitive. */
256 CFUUIDBytes bytes;
257 UniChar chars[100];
258 CFIndex len;
259 CFIndex i = 0;
260
261 if (uuidStr == NULL) return NULL;
262
263 len = CFStringGetLength(uuidStr);
264 if (len > 100) {
265 len = 100;
266 } else if (len == 0) {
267 return NULL;
268 }
269 CFStringGetCharacters(uuidStr, CFRangeMake(0, len), chars);
270 memset((void *)&bytes, 0, sizeof(bytes));
271
272 /* Skip initial random stuff */
273 while (!_isHexChar(chars[i]) && (i < len)) {
274 i++;
275 }
276
277 READ_A_BYTE(bytes.byte0);
278 READ_A_BYTE(bytes.byte1);
279 READ_A_BYTE(bytes.byte2);
280 READ_A_BYTE(bytes.byte3);
281
282 i++;
283
284 READ_A_BYTE(bytes.byte4);
285 READ_A_BYTE(bytes.byte5);
286
287 i++;
288
289 READ_A_BYTE(bytes.byte6);
290 READ_A_BYTE(bytes.byte7);
291
292 i++;
293
294 READ_A_BYTE(bytes.byte8);
295 READ_A_BYTE(bytes.byte9);
296
297 i++;
298
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);
305
306 return __CFUUIDCreateWithBytesPrimitive(alloc, bytes, false);
307 }
308
309 CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid) {
310 CFMutableStringRef str = CFStringCreateMutable(alloc, 0);
311 UniChar buff[12];
312
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);
320
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);
326
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);
332
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);
338
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);
347
348 return str;
349 }
350
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) {
352 CFUUIDBytes bytes;
353 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99
354 bytes.byte0 = byte0;
355 bytes.byte1 = byte1;
356 bytes.byte2 = byte2;
357 bytes.byte3 = byte3;
358 bytes.byte4 = byte4;
359 bytes.byte5 = byte5;
360 bytes.byte6 = byte6;
361 bytes.byte7 = byte7;
362 bytes.byte8 = byte8;
363 bytes.byte9 = byte9;
364 bytes.byte10 = byte10;
365 bytes.byte11 = byte11;
366 bytes.byte12 = byte12;
367 bytes.byte13 = byte13;
368 bytes.byte14 = byte14;
369 bytes.byte15 = byte15;
370
371 return __CFUUIDCreateWithBytesPrimitive(alloc, bytes, true);
372 }
373
374 CFUUIDBytes CFUUIDGetUUIDBytes(CFUUIDRef uuid) {
375 return uuid->_bytes;
376 }
377
378 CF_EXPORT CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes) {
379 return __CFUUIDCreateWithBytesPrimitive(alloc, bytes, false);
380 }
381
382 #undef READ_A_BYTE
383