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