CFUUID.c
1 /* CFUUID.c 2 Copyright (c) 1999-2019, Apple Inc. and the Swift project authors 3 4 Portions Copyright (c) 2014-2019, Apple Inc. and the Swift project authors 5 Licensed under Apache License v2.0 with Runtime Library Exception 6 See http://swift.org/LICENSE.txt for license information 7 See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 8 Responsibility: Ben D. Jones 9 */ 10 11 #include <CoreFoundation/CFUUID.h> 12 #include "CFInternal.h" 13 #include "CFRuntime_Internal.h" 14 15 #if __has_include(<os/lock_private.h>) 16 #include <os/lock_private.h> 17 18 static CFMutableDictionaryRef _uniquedUUIDs = NULL; 19 static os_unfair_lock _uniquedUUIDsLock = OS_UNFAIR_LOCK_INIT; 20 21 CF_INLINE void LOCKED(dispatch_block_t work) { 22 os_unfair_lock_lock_with_options(&_uniquedUUIDsLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 23 work(); 24 os_unfair_lock_unlock(&_uniquedUUIDsLock); 25 } 26 27 #else 28 // Platforms without unfair lock 29 static CFMutableDictionaryRef _uniquedUUIDs = NULL; 30 static CFLock_t _uniquedUUIDsLock = CFLockInit; 31 32 CF_INLINE void LOCKED(void (^work)(void)) { 33 __CFLock(&_uniquedUUIDsLock); 34 work(); 35 __CFUnlock(&_uniquedUUIDsLock); 36 } 37 38 #endif 39 40 struct __CFUUID { 41 CFRuntimeBase _base; 42 CFUUIDBytes _bytes; 43 }; 44 45 typedef struct __CFUUID __CFUUID_t; 46 47 static CFHashCode __CFhashUUIDBytes(const void *ptr) { 48 return CFHashBytes((uint8_t *)ptr, 16); 49 } 50 51 static void __CFUUIDAddUniqueUUIDHasLock(CFUUIDRef uuid) { 52 CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks = {0, NULL, NULL, NULL, __CFisEqualUUIDBytes, __CFhashUUIDBytes}; 53 CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks = {0, NULL, NULL, CFCopyDescription, CFEqual}; 54 55 if (!_uniquedUUIDs) _uniquedUUIDs = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &__CFUUIDBytesDictionaryKeyCallBacks, &__CFnonRetainedUUIDDictionaryValueCallBacks); 56 CFDictionarySetValue(_uniquedUUIDs, &(uuid->_bytes), uuid); 57 } 58 59 static void __CFUUIDRemoveUniqueUUIDHasLock(CFUUIDRef uuid) { 60 if (_uniquedUUIDs) CFDictionaryRemoveValue(_uniquedUUIDs, &(uuid->_bytes)); 61 } 62 63 static CFUUIDRef __CFUUIDGetUniquedUUIDHasLock(const CFUUIDBytes *bytes) { 64 CFUUIDRef uuid = NULL; 65 if (_uniquedUUIDs) { 66 uuid = (CFUUIDRef)CFDictionaryGetValue(_uniquedUUIDs, bytes); 67 } 68 return uuid; 69 } 70 71 static void __CFUUIDDeallocate(CFTypeRef cf) { 72 __CFUUID_t *uuid = (__CFUUID_t *)cf; 73 LOCKED(^{ 74 __CFUUIDRemoveUniqueUUIDHasLock(uuid); 75 }); 76 } 77 78 static CFStringRef __CFUUIDCopyDescription(CFTypeRef cf) { 79 CFStringRef uuidStr = CFUUIDCreateString(CFGetAllocator(cf), (CFUUIDRef)cf); 80 CFStringRef desc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFUUID %p> %@"), cf, uuidStr); 81 CFRelease(uuidStr); 82 return desc; 83 } 84 85 static CFStringRef __CFUUIDCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { 86 return CFUUIDCreateString(CFGetAllocator(cf), (CFUUIDRef)cf); 87 } 88 89 const CFRuntimeClass __CFUUIDClass = { 90 0, 91 "CFUUID", 92 NULL, // init 93 NULL, // copy 94 __CFUUIDDeallocate, 95 NULL, // equal 96 NULL, // hash 97 __CFUUIDCopyFormattingDescription, 98 __CFUUIDCopyDescription 99 }; 100 101 CFTypeID CFUUIDGetTypeID(void) { 102 return _kCFRuntimeIDCFUUID; 103 } 104 105 static CFUUIDRef __CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator, CFUUIDBytes bytes, Boolean isConst) { 106 __block __CFUUID_t *uuid = NULL; 107 LOCKED(^{ 108 uuid = (__CFUUID_t *)__CFUUIDGetUniquedUUIDHasLock(&bytes); 109 if (!uuid) { 110 size_t size; 111 size = sizeof(__CFUUID_t) - sizeof(CFRuntimeBase); 112 uuid = (__CFUUID_t *)_CFRuntimeCreateInstance(allocator, CFUUIDGetTypeID(), size, NULL); 113 114 if (!uuid) return; 115 116 uuid->_bytes = bytes; 117 __CFUUIDAddUniqueUUIDHasLock(uuid); 118 } else if (!isConst) { 119 CFRetain(uuid); 120 } 121 122 if (isConst) { 123 #if !DEPLOYMENT_RUNTIME_SWIFT 124 __CFRuntimeSetRC(uuid, 0); // constant CFUUIDs should be immortal. This applies even to equivalent UUIDs created earlier that were *not* constant. 125 #else 126 CFRetain(uuid); // Swift doesn't support meddling with the retain count. Just ensure there is one retain here. 127 #endif 128 } 129 }); 130 131 return (CFUUIDRef)uuid; 132 } 133 134 #if TARGET_OS_WIN32 135 #include <Rpc.h> 136 #else 137 #if DEPLOYMENT_RUNTIME_SWIFT 138 #include "uuid/uuid.h" 139 #else 140 #include <uuid/uuid.h> 141 #endif 142 #endif 143 144 CFUUIDRef CFUUIDCreate(CFAllocatorRef alloc) { 145 /* Create a new bytes struct and then call the primitive. */ 146 __block CFUUIDBytes bytes; 147 __block uint32_t retval = 0; 148 149 LOCKED(^{ 150 #if TARGET_OS_WIN32 151 UUID u; 152 long rStatus = UuidCreate(&u); 153 if (RPC_S_OK != rStatus && RPC_S_UUID_LOCAL_ONLY != rStatus) retval = 1; 154 memmove(&bytes, &u, sizeof(bytes)); 155 #elif TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD 156 static int8_t useV1UUIDs = -1; 157 uuid_t uuid; 158 if (useV1UUIDs == -1) { 159 const char *value = __CFgetenv("CFUUIDVersionNumber"); 160 if (value) { 161 useV1UUIDs = (1 == strtoul_l(value, NULL, 0, NULL)) ? 1 : 0; 162 } 163 } 164 if (useV1UUIDs == 1) uuid_generate_time(uuid); else uuid_generate_random(uuid); 165 memcpy((void *)&bytes, uuid, sizeof(uuid)); 166 #else 167 //This bzero works around <rdar://problem/23381916>. It isn't actually needed, since the function will simply return NULL on this deployment target, anyway. 168 bzero(&bytes, sizeof(bytes)); 169 retval = 1; 170 #endif 171 }); 172 173 return (retval == 0) ? __CFUUIDCreateWithBytesPrimitive(alloc, bytes, false) : NULL; 174 } 175 176 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) { 177 CFUUIDBytes bytes; 178 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99 179 bytes.byte0 = byte0; 180 bytes.byte1 = byte1; 181 bytes.byte2 = byte2; 182 bytes.byte3 = byte3; 183 bytes.byte4 = byte4; 184 bytes.byte5 = byte5; 185 bytes.byte6 = byte6; 186 bytes.byte7 = byte7; 187 bytes.byte8 = byte8; 188 bytes.byte9 = byte9; 189 bytes.byte10 = byte10; 190 bytes.byte11 = byte11; 191 bytes.byte12 = byte12; 192 bytes.byte13 = byte13; 193 bytes.byte14 = byte14; 194 bytes.byte15 = byte15; 195 196 return __CFUUIDCreateWithBytesPrimitive(alloc, bytes, false); 197 } 198 199 static void _intToHexChars(UInt32 in, UniChar *out, int digits) { 200 int shift; 201 UInt32 d; 202 203 while (--digits >= 0) { 204 shift = digits << 2; 205 d = 0x0FL & (in >> shift); 206 if (d <= 9) { 207 *out++ = (UniChar)'0' + d; 208 } else { 209 *out++ = (UniChar)'A' + (d - 10); 210 } 211 } 212 } 213 214 static uint8_t _byteFromHexChars(UniChar *in) { 215 uint8_t result = 0; 216 UniChar c; 217 uint8_t d; 218 CFIndex i; 219 220 for (i=0; i<2; i++) { 221 c = in[i]; 222 if ((c >= (UniChar)'0') && (c <= (UniChar)'9')) { 223 d = c - (UniChar)'0'; 224 } else if ((c >= (UniChar)'a') && (c <= (UniChar)'f')) { 225 d = c - ((UniChar)'a' - 10); 226 } else if ((c >= (UniChar)'A') && (c <= (UniChar)'F')) { 227 d = c - ((UniChar)'A' - 10); 228 } else { 229 return 0; 230 } 231 result = (result << 4) | d; 232 } 233 234 return result; 235 } 236 237 CF_INLINE Boolean _isHexChar(UniChar c) { 238 return ((((c >= (UniChar)'0') && (c <= (UniChar)'9')) || ((c >= (UniChar)'a') && (c <= (UniChar)'f')) || ((c >= (UniChar)'A') && (c <= (UniChar)'F'))) ? true : false); 239 } 240 241 #define READ_A_BYTE(into) if (i+1 < len) { \ 242 (into) = _byteFromHexChars(&(chars[i])); \ 243 i+=2; \ 244 } 245 246 CFUUIDRef CFUUIDCreateFromString(CFAllocatorRef alloc, CFStringRef uuidStr) { 247 /* Parse the string into a bytes struct and then call the primitive. */ 248 CFUUIDBytes bytes; 249 UniChar chars[100]; 250 CFIndex len; 251 CFIndex i = 0; 252 253 if (uuidStr == NULL) return NULL; 254 255 len = CFStringGetLength(uuidStr); 256 if (len > 100) { 257 len = 100; 258 } else if (len == 0) { 259 return NULL; 260 } 261 CFStringGetCharacters(uuidStr, CFRangeMake(0, len), chars); 262 memset((void *)&bytes, 0, sizeof(bytes)); 263 264 /* Skip initial random stuff */ 265 while (!_isHexChar(chars[i]) && i < len) i++; 266 267 READ_A_BYTE(bytes.byte0); 268 READ_A_BYTE(bytes.byte1); 269 READ_A_BYTE(bytes.byte2); 270 READ_A_BYTE(bytes.byte3); 271 i++; 272 273 READ_A_BYTE(bytes.byte4); 274 READ_A_BYTE(bytes.byte5); 275 i++; 276 277 READ_A_BYTE(bytes.byte6); 278 READ_A_BYTE(bytes.byte7); 279 i++; 280 281 READ_A_BYTE(bytes.byte8); 282 READ_A_BYTE(bytes.byte9); 283 i++; 284 285 READ_A_BYTE(bytes.byte10); 286 READ_A_BYTE(bytes.byte11); 287 READ_A_BYTE(bytes.byte12); 288 READ_A_BYTE(bytes.byte13); 289 READ_A_BYTE(bytes.byte14); 290 READ_A_BYTE(bytes.byte15); 291 292 return __CFUUIDCreateWithBytesPrimitive(alloc, bytes, false); 293 } 294 295 CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid) { 296 CF_ASSERT_TYPE(_kCFRuntimeIDCFUUID, uuid); 297 298 CFMutableStringRef str = CFStringCreateMutable(alloc, 0); 299 UniChar buff[12]; 300 301 // First segment (4 bytes, 8 digits + 1 dash) 302 _intToHexChars(uuid->_bytes.byte0, buff, 2); 303 _intToHexChars(uuid->_bytes.byte1, &(buff[2]), 2); 304 _intToHexChars(uuid->_bytes.byte2, &(buff[4]), 2); 305 _intToHexChars(uuid->_bytes.byte3, &(buff[6]), 2); 306 buff[8] = (UniChar)'-'; 307 CFStringAppendCharacters(str, buff, 9); 308 309 // Second segment (2 bytes, 4 digits + 1 dash) 310 _intToHexChars(uuid->_bytes.byte4, buff, 2); 311 _intToHexChars(uuid->_bytes.byte5, &(buff[2]), 2); 312 buff[4] = (UniChar)'-'; 313 CFStringAppendCharacters(str, buff, 5); 314 315 // Third segment (2 bytes, 4 digits + 1 dash) 316 _intToHexChars(uuid->_bytes.byte6, buff, 2); 317 _intToHexChars(uuid->_bytes.byte7, &(buff[2]), 2); 318 buff[4] = (UniChar)'-'; 319 CFStringAppendCharacters(str, buff, 5); 320 321 // Fourth segment (2 bytes, 4 digits + 1 dash) 322 _intToHexChars(uuid->_bytes.byte8, buff, 2); 323 _intToHexChars(uuid->_bytes.byte9, &(buff[2]), 2); 324 buff[4] = (UniChar)'-'; 325 CFStringAppendCharacters(str, buff, 5); 326 327 // Fifth segment (6 bytes, 12 digits) 328 _intToHexChars(uuid->_bytes.byte10, buff, 2); 329 _intToHexChars(uuid->_bytes.byte11, &(buff[2]), 2); 330 _intToHexChars(uuid->_bytes.byte12, &(buff[4]), 2); 331 _intToHexChars(uuid->_bytes.byte13, &(buff[6]), 2); 332 _intToHexChars(uuid->_bytes.byte14, &(buff[8]), 2); 333 _intToHexChars(uuid->_bytes.byte15, &(buff[10]), 2); 334 CFStringAppendCharacters(str, buff, 12); 335 336 return str; 337 } 338 339 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) { 340 CFUUIDBytes bytes; 341 // CodeWarrior can't handle the structure assignment of bytes, so we must explode this - REW, 10/8/99 342 bytes.byte0 = byte0; 343 bytes.byte1 = byte1; 344 bytes.byte2 = byte2; 345 bytes.byte3 = byte3; 346 bytes.byte4 = byte4; 347 bytes.byte5 = byte5; 348 bytes.byte6 = byte6; 349 bytes.byte7 = byte7; 350 bytes.byte8 = byte8; 351 bytes.byte9 = byte9; 352 bytes.byte10 = byte10; 353 bytes.byte11 = byte11; 354 bytes.byte12 = byte12; 355 bytes.byte13 = byte13; 356 bytes.byte14 = byte14; 357 bytes.byte15 = byte15; 358 359 // The analyzer can't understand functions like __CFUUIDCreateWithBytesPrimitive which return retained objects based on a parameter. 360 #ifdef __clang_analyzer__ 361 return NULL; 362 #else 363 return __CFUUIDCreateWithBytesPrimitive(alloc, bytes, true); 364 #endif 365 } 366 367 CFUUIDBytes CFUUIDGetUUIDBytes(CFUUIDRef uuid) { 368 CF_ASSERT_TYPE(_kCFRuntimeIDCFUUID, uuid); 369 return uuid->_bytes; 370 } 371 372 CF_EXPORT CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes) { 373 return __CFUUIDCreateWithBytesPrimitive(alloc, bytes, false); 374 } 375 376 #undef READ_A_BYTE 377 378 #if DEPLOYMENT_RUNTIME_SWIFT 379 380 void _cf_uuid_clear(_cf_uuid_t uu) { uuid_clear(uu); } 381 int _cf_uuid_compare(const _cf_uuid_t uu1, const _cf_uuid_t uu2) { return uuid_compare(uu1, uu2); } 382 void _cf_uuid_copy(_cf_uuid_t dst, const _cf_uuid_t src) { uuid_copy(dst, src); } 383 void _cf_uuid_generate(_cf_uuid_t out) { uuid_generate(out); } 384 void _cf_uuid_generate_random(_cf_uuid_t out) { uuid_generate_random(out); } 385 void _cf_uuid_generate_time(_cf_uuid_t out) { uuid_generate_time(out); } 386 int _cf_uuid_is_null(const _cf_uuid_t uu) { return uuid_is_null(uu); } 387 int _cf_uuid_parse(const _cf_uuid_string_t in, _cf_uuid_t uu) { return uuid_parse(in, uu); } 388 void _cf_uuid_unparse(const _cf_uuid_t uu, _cf_uuid_string_t out) { uuid_unparse(uu, out); } 389 void _cf_uuid_unparse_lower(const _cf_uuid_t uu, _cf_uuid_string_t out) { uuid_unparse_lower(uu, out); } 390 void _cf_uuid_unparse_upper(const _cf_uuid_t uu, _cf_uuid_string_t out) { uuid_unparse_upper(uu, out); } 391 392 #endif