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