/ CoreFoundation / Preferences.subproj / CFApplicationPreferences.c
CFApplicationPreferences.c
  1  /*	CFApplicationPreferences.c
  2  	Copyright (c) 1998-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: David Smith
  9  */
 10  
 11  #include <CoreFoundation/CFPreferences.h>
 12  #include "CFInternal.h"
 13  #include <CoreFoundation/CFUniChar.h>
 14  #include <CoreFoundation/CFNumber.h>
 15  #include <CoreFoundation/CFString.h>
 16  #include <CoreFoundation/CFLocale.h>
 17  #include <CoreFoundation/CFNumberFormatter.h>
 18  #include <CoreFoundation/CFDateFormatter.h>
 19  #include <sys/types.h>
 20  #if TARGET_OS_MAC
 21  #include <unistd.h>
 22  #endif
 23  
 24  static Boolean _CFApplicationPreferencesSynchronizeNoLock(_CFApplicationPreferences *self);
 25  void _CFPreferencesDomainSetMultiple(CFPreferencesDomainRef domain, CFDictionaryRef dict);
 26  static void updateDictRep(_CFApplicationPreferences *self);
 27  static void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList);
 28  void _CFApplicationPreferencesSet(_CFApplicationPreferences *self, CFStringRef defaultName, CFTypeRef value);
 29  void _CFApplicationPreferencesRemove(_CFApplicationPreferences *self, CFStringRef defaultName);
 30  void _CFDeallocateApplicationPreferences(_CFApplicationPreferences *self);
 31  Boolean _CFApplicationPreferencesSynchronize(_CFApplicationPreferences *self);
 32  Boolean _CFApplicationPreferencesContainsDomainNoLock(_CFApplicationPreferences *self, CFPreferencesDomainRef domain);
 33  void _CFApplicationPreferencesAddSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName);
 34  void _CFApplicationPreferencesRemoveSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName);
 35  static CFTypeRef _CFApplicationPreferencesCreateValueForKey2(_CFApplicationPreferences *self, CFStringRef defaultName);
 36  void _CFApplicationPreferencesRemoveDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain);
 37  
 38  CF_PRIVATE void _CFPreferencesDomainSet(CFPreferencesDomainRef domain, CFStringRef key, CFTypeRef _Nullable value);
 39  CF_PRIVATE CFDictionaryRef _CFPreferencesDomainDeepCopyDictionary(CFPreferencesDomainRef domain);
 40  CF_PRIVATE void _CFPreferencesPurgeDomainCache(void);
 41  CF_PRIVATE CFPreferencesDomainRef _CFPreferencesStandardDomain(CFStringRef domainName, CFStringRef userName, CFStringRef hostName);
 42  CF_PRIVATE Boolean _CFSynchronizeDomainCache(void);
 43  CF_PRIVATE CFAllocatorRef __CFPreferencesAllocator(void);
 44  CF_PRIVATE _CFApplicationPreferences *_CFStandardApplicationPreferences(CFStringRef appName);
 45  
 46  
 47  // Right now, nothing is getting destroyed pretty much ever.  We probably don't want this to be the case, but it's very tricky - domains live in the cache as well as a given application's preferences, and since they're not CFTypes, there's no reference count.  Also, it's not clear we ever want domains destroyed.  When they're synchronized, they clear their internal state (to force reading from the disk again), so they're not very big.... REW, 12/17/98
 48  
 49  CFPropertyListRef CFPreferencesCopyAppValue(CFStringRef key, CFStringRef appName) {
 50      _CFApplicationPreferences *standardPrefs;
 51      CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
 52      CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
 53      
 54      standardPrefs = _CFStandardApplicationPreferences(appName);
 55      return standardPrefs ? _CFApplicationPreferencesCreateValueForKey2(standardPrefs, key) : NULL;
 56  }
 57  
 58  CF_EXPORT Boolean CFPreferencesAppBooleanValue(CFStringRef key, CFStringRef appName, Boolean *keyExistsAndHasValidFormat) {
 59      CFPropertyListRef value;
 60      Boolean result, valid;
 61      CFTypeID typeID = 0;
 62      CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
 63      CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
 64  
 65      if (!keyExistsAndHasValidFormat) {
 66          keyExistsAndHasValidFormat = &valid;
 67      }
 68      value = CFPreferencesCopyAppValue(key, appName);
 69      if (!value) {
 70          *keyExistsAndHasValidFormat = false;
 71          return false;
 72      }
 73      typeID = CFGetTypeID(value);
 74      if (typeID == CFStringGetTypeID()) {
 75          if (CFStringCompare((CFStringRef)value, CFSTR("true"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare((CFStringRef)value, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
 76              *keyExistsAndHasValidFormat = true;
 77              result = true;
 78          } else if (CFStringCompare((CFStringRef)value, CFSTR("false"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare((CFStringRef)value, CFSTR("NO"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
 79              *keyExistsAndHasValidFormat = true;
 80              result = false;
 81          } else {
 82              *keyExistsAndHasValidFormat = false;
 83              result = false;
 84          }
 85      } else if (typeID == CFNumberGetTypeID()) {
 86          if (CFNumberIsFloatType((CFNumberRef)value)) {
 87              *keyExistsAndHasValidFormat = false;
 88              result = false;
 89          } else {
 90              int i;
 91              *keyExistsAndHasValidFormat = true;
 92              CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &i);
 93              result = (i == 0) ? false : true;
 94          }
 95      } else if (typeID == CFBooleanGetTypeID()) {
 96          result = (value == kCFBooleanTrue);
 97          *keyExistsAndHasValidFormat = true;
 98      } else {
 99          // Unknown type
100          result = false;
101          *keyExistsAndHasValidFormat = false;
102      }
103      CFRelease(value);
104      return result;
105  }
106  
107  CF_PRIVATE CFIndex CFPreferencesAppIntegerValue(CFStringRef key, CFStringRef appName, Boolean *keyExistsAndHasValidFormat) {
108      CFPropertyListRef value;
109      CFIndex result;
110      CFTypeID typeID = 0;
111      Boolean valid;
112      CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
113      CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
114  
115      value = CFPreferencesCopyAppValue(key, appName);
116      if (!keyExistsAndHasValidFormat) {
117          keyExistsAndHasValidFormat = &valid;
118      }
119      if (!value) {
120          *keyExistsAndHasValidFormat = false;
121          return 0;
122      }
123      typeID = CFGetTypeID(value);
124      if (typeID == CFStringGetTypeID()) {
125          SInt32 charIndex = 0;
126          SInt32 intVal;
127          CFStringInlineBuffer buf;
128          Boolean success;
129          CFStringInitInlineBuffer((CFStringRef)value, &buf, CFRangeMake(0, CFStringGetLength((CFStringRef)value)));
130          success = __CFStringScanInteger(&buf, NULL, &charIndex, false, &intVal);
131          *keyExistsAndHasValidFormat = (success && charIndex == CFStringGetLength((CFStringRef)value));
132          result = (*keyExistsAndHasValidFormat) ? intVal : 0;
133      } else if (typeID == CFNumberGetTypeID()) {
134          *keyExistsAndHasValidFormat = !CFNumberIsFloatType((CFNumberRef)value);
135          if (*keyExistsAndHasValidFormat) {
136              CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &result);
137          } else {
138              result = 0;
139          }
140      } else {
141          // Unknown type
142          result = 0;
143          *keyExistsAndHasValidFormat = false;
144      }
145      CFRelease(value);
146      return result;
147  }
148  
149  Boolean CFPreferencesGetAppBooleanValue(CFStringRef key, CFStringRef appName, Boolean *keyExistsAndHasValidFormat) {
150      CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
151      CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
152      return CFPreferencesAppBooleanValue(key, appName, keyExistsAndHasValidFormat);
153  }
154  
155  CFIndex CFPreferencesGetAppIntegerValue(CFStringRef key, CFStringRef appName, Boolean *keyExistsAndHasValidFormat) {
156      CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
157      CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
158      return CFPreferencesAppIntegerValue(key, appName, keyExistsAndHasValidFormat);
159  }
160  
161  void CFPreferencesSetAppValue(CFStringRef key, CFTypeRef value, CFStringRef appName) {
162      _CFApplicationPreferences *standardPrefs;
163      CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
164      CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
165  
166      standardPrefs = _CFStandardApplicationPreferences(appName);
167      if (standardPrefs) {
168          if (value) _CFApplicationPreferencesSet(standardPrefs, key, value);
169          else _CFApplicationPreferencesRemove(standardPrefs, key);
170      }
171  }
172  
173  
174  static CFLock_t __CFApplicationPreferencesLock = CFLockInit; // Locks access to __CFStandardUserPreferences
175  static CFMutableDictionaryRef __CFStandardUserPreferences = NULL; // Mutable dictionary; keys are app names, values are _CFApplicationPreferences 
176  
177  Boolean CFPreferencesAppSynchronize(CFStringRef appName) {
178      _CFApplicationPreferences *standardPrefs;
179      Boolean result;
180      CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
181      
182      // Do not call _CFStandardApplicationPreferences(), as we do not want to create the preferences only to synchronize
183      __CFLock(&__CFApplicationPreferencesLock);
184      if (__CFStandardUserPreferences)  {
185          standardPrefs = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName);
186      } else {
187          standardPrefs = NULL;
188      }
189  
190      result = standardPrefs ? _CFApplicationPreferencesSynchronizeNoLock(standardPrefs) : _CFSynchronizeDomainCache();
191      __CFUnlock(&__CFApplicationPreferencesLock);
192      return result;
193  }
194  
195  void CFPreferencesFlushCaches(void) {
196      CFAllocatorRef alloc = __CFPreferencesAllocator();
197      __CFLock(&__CFApplicationPreferencesLock);
198      if (__CFStandardUserPreferences)  {
199          _CFApplicationPreferences **prefsArray, *prefsBuf[32];
200          CFIndex idx, count = CFDictionaryGetCount(__CFStandardUserPreferences);
201          if (count < 32) {
202              prefsArray = prefsBuf;
203          } else {
204              prefsArray = (_CFApplicationPreferences **)CFAllocatorAllocate(alloc, count * sizeof(_CFApplicationPreferences *), 0);
205          }
206          CFDictionaryGetKeysAndValues(__CFStandardUserPreferences, NULL, (const void **)prefsArray);
207  
208          __CFUnlock(&__CFApplicationPreferencesLock);
209          // DeallocateApplicationPreferences needs the lock
210          for (idx = 0; idx < count; idx ++) {
211              _CFApplicationPreferences *appPrefs = prefsArray[idx];
212              _CFApplicationPreferencesSynchronize(appPrefs);
213              _CFDeallocateApplicationPreferences(appPrefs);
214          }
215          __CFLock(&__CFApplicationPreferencesLock);
216  
217          CFRelease(__CFStandardUserPreferences);
218          __CFStandardUserPreferences = NULL;
219          if(prefsArray != prefsBuf) CFAllocatorDeallocate(alloc, prefsArray);
220      }
221      __CFUnlock(&__CFApplicationPreferencesLock);
222      _CFPreferencesPurgeDomainCache();
223  }
224  
225  // quick message to indicate that the given domain has changed, and we should go through and invalidate any dictReps that involve this domain.
226  void _CFApplicationPreferencesDomainHasChanged(CFPreferencesDomainRef changedDomain) {
227      CFAllocatorRef alloc = __CFPreferencesAllocator();
228      __CFLock(&__CFApplicationPreferencesLock);
229      if(__CFStandardUserPreferences) {  // only grovel over the prefs if there's something there to grovel
230          _CFApplicationPreferences **prefsArray, *prefsBuf[32];
231          CFIndex idx, count = CFDictionaryGetCount(__CFStandardUserPreferences);
232          if(count < 32) {
233              prefsArray = prefsBuf;
234          } else {
235              prefsArray = (_CFApplicationPreferences **)CFAllocatorAllocate(alloc, count * sizeof(_CFApplicationPreferences *), 0);
236          }
237          CFDictionaryGetKeysAndValues(__CFStandardUserPreferences, NULL, (const void **)prefsArray);
238          // For this operation, giving up the lock is the last thing we want to do, so use the modified flavor of _CFApplicationPreferencesContainsDomain
239          for(idx = 0; idx < count; idx++) {
240              _CFApplicationPreferences *appPrefs = prefsArray[idx];
241              if(_CFApplicationPreferencesContainsDomainNoLock(appPrefs, changedDomain)) {
242                  updateDictRep(appPrefs);
243              }
244          }
245          if(prefsArray != prefsBuf) CFAllocatorDeallocate(alloc, prefsArray);
246      }
247      __CFUnlock(&__CFApplicationPreferencesLock);
248  }
249  
250  
251  // Begin ported code from NSUserDefaults.m
252  
253  
254  static void updateDictRep(_CFApplicationPreferences *self) {
255      if (self->_dictRep) {
256          CFRelease(self->_dictRep);
257          self->_dictRep = NULL;
258      }
259  }
260  
261  static void __addKeysAndValues(const void *key, const void *value, void *context) {
262      CFDictionarySetValue((CFMutableDictionaryRef)context, key, value);
263  }
264  
265  static CFMutableDictionaryRef computeDictRep(_CFApplicationPreferences *self, Boolean skipC0C0A) {
266      CFAllocatorRef alloc = __CFPreferencesAllocator();
267      CFMutableArrayRef searchList = self->_search;
268      CFIndex idx;
269      CFIndex cnt = CFArrayGetCount(searchList);
270      CFDictionaryRef subdomainDict;
271      CFMutableDictionaryRef dictRep;
272      
273      dictRep = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
274      _CFDictionarySetCapacity(dictRep, 260);	// avoid lots of rehashing
275      
276      // For each subdomain triplet in the domain, iterate over dictionaries, adding them if necessary to the dictRep
277      for (idx = cnt; idx--;) {
278          CFPreferencesDomainRef domain = (CFPreferencesDomainRef)CFArrayGetValueAtIndex(searchList, idx);
279  
280          if (!domain) continue;
281  
282          subdomainDict = _CFPreferencesDomainDeepCopyDictionary(domain);
283          if (subdomainDict) {
284              CFDictionaryApplyFunction(subdomainDict, __addKeysAndValues, dictRep);
285              CFRelease(subdomainDict);
286          }
287      }
288      return dictRep;
289  }
290  
291  CFTypeRef _CFApplicationPreferencesSearchDownToDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef stopper, CFStringRef key) {
292      return NULL;
293  }
294  
295  
296  void _CFApplicationPreferencesUpdate(_CFApplicationPreferences *self) {
297      __CFLock(&__CFApplicationPreferencesLock);
298      updateDictRep(self);
299      __CFUnlock(&__CFApplicationPreferencesLock);
300  }
301  
302  CF_EXPORT CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self);
303  
304  CF_PRIVATE CFDictionaryRef __CFApplicationPreferencesCopyCurrentState(void) {
305      _CFApplicationPreferences *self = _CFStandardApplicationPreferences(kCFPreferencesCurrentApplication);
306      CFDictionaryRef result = _CFApplicationPreferencesCopyRepresentation(self);
307      return result;
308  }
309  
310  // CACHING here - we will only return a value as current as the last time computeDictRep() was called
311  static CFTypeRef _CFApplicationPreferencesCreateValueForKey2(_CFApplicationPreferences *self, CFStringRef defaultName) {
312      CFTypeRef result;
313      __CFLock(&__CFApplicationPreferencesLock);
314      if (!self->_dictRep) {
315          self->_dictRep = computeDictRep(self, true);
316      }
317      result = (self->_dictRep) ? (CFTypeRef )CFDictionaryGetValue(self->_dictRep, defaultName) : NULL;
318      if (result) {
319          CFRetain(result);
320      }
321      __CFUnlock(&__CFApplicationPreferencesLock);
322      return result;
323  }
324  
325  
326  void _CFApplicationPreferencesSet(_CFApplicationPreferences *self, CFStringRef defaultName, CFTypeRef value) {
327      CFPreferencesDomainRef applicationDomain;
328  
329      __CFLock(&__CFApplicationPreferencesLock);
330      applicationDomain = _CFPreferencesStandardDomain(self->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
331      if(applicationDomain) {
332          _CFPreferencesDomainSet(applicationDomain, defaultName, value);
333          if (CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), applicationDomain)) {
334              // Expensive; can't we just check the relevant value throughout the appropriate sets of domains? -- REW, 7/19/99
335              updateDictRep(self);
336          }
337      }
338      __CFUnlock(&__CFApplicationPreferencesLock);
339  }
340  
341  void _CFApplicationPreferencesRemove(_CFApplicationPreferences *self, CFStringRef defaultName) {
342      CFPreferencesDomainRef appDomain;
343  
344      __CFLock(&__CFApplicationPreferencesLock);
345      appDomain = _CFPreferencesStandardDomain(self->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
346      if(appDomain) {
347          _CFPreferencesDomainSet(appDomain, defaultName, NULL);
348          if (CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), appDomain)) {
349              // If key exists, it will be in the _dictRep (but possibly overridden)
350              updateDictRep(self);
351          }
352      }
353      __CFUnlock(&__CFApplicationPreferencesLock);
354  }
355  
356  static Boolean _CFApplicationPreferencesSynchronizeNoLock(_CFApplicationPreferences *self) {
357      Boolean success = _CFSynchronizeDomainCache();
358      updateDictRep(self);
359      return success;
360  }
361  
362  Boolean _CFApplicationPreferencesSynchronize(_CFApplicationPreferences *self) {
363      Boolean result;
364      __CFLock(&__CFApplicationPreferencesLock);
365      result = _CFApplicationPreferencesSynchronizeNoLock(self);
366      __CFUnlock(&__CFApplicationPreferencesLock);
367      return result;
368  }
369  
370  // appName should not be kCFPreferencesCurrentApplication going in to this call
371  _CFApplicationPreferences *_CFApplicationPreferencesCreateWithUser(CFStringRef userName, CFStringRef appName) {
372      CFAllocatorRef alloc = __CFPreferencesAllocator();
373      _CFApplicationPreferences *self = (_CFApplicationPreferences*)CFAllocatorAllocate(alloc, sizeof(_CFApplicationPreferences), 0);
374      if (self) {
375          self->_dictRep = NULL;
376          self->_appName = (CFStringRef)CFRetain(appName);
377          self->_search = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
378          if (!self->_search) {
379              CFAllocatorDeallocate(alloc, self);
380              CFRelease(appName);
381              self = NULL;
382          }
383      }
384      return self;
385  }
386  
387  // Do NOT release the domain after adding it to the array; domain_expression should not return a retained object  -- REW, 8/26/99 
388  #define ADD_DOMAIN(domain_expression) domain = domain_expression; if (domain) {CFArrayAppendValue(search, domain);}
389  void _CFApplicationPreferencesSetStandardSearchList(_CFApplicationPreferences *appPreferences) {
390      /* Here is how the domains end up in priority order in a search list.  Only a subset of these are setup by default.
391  	argument domain
392  	this app, this user, managed
393  	this app, any user, managed
394          this app, this user, this host
395          this app, this user, any host (AppDomain)
396  	suiteN, this user, this host
397  	suiteN, this user, any host
398          ...
399  	suite0, this user, this host
400  	suite0, this user, any host
401          any app, this user, this host
402          any app, this user, any host (GlobalDomain)
403          NSUserDefaults backwards-compat ICU domain
404          this app, any user, this host
405          this app, any user, any host
406  	suiteN, any user, this host
407  	suiteN, any user, any host
408          ...
409  	suite0, any user, this host
410  	suite0, any user, any host
411          any app, any user, this host
412          any app, any user, any host
413  	registration domain
414      */
415      CFPreferencesDomainRef domain;
416      CFMutableArrayRef search = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
417      if (!search) {
418          // couldn't allocate memory!
419          return;
420      }
421  
422      ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost));
423      ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost));
424      ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost));
425      ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost));
426      ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost));
427      ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesAnyUser, kCFPreferencesAnyHost));
428      ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesCurrentHost));
429      ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost));
430  
431      _CFApplicationPreferencesSetSearchList(appPreferences, search);
432      CFRelease(search);
433  }
434  #undef ADD_DOMAIN
435  
436  
437  CF_PRIVATE _CFApplicationPreferences *_CFStandardApplicationPreferences(CFStringRef appName) {
438      _CFApplicationPreferences *appPreferences;
439  //    CFAssert(appName != kCFPreferencesAnyApplication, __kCFLogAssertion, "Cannot use any of the CFPreferences...App... functions with an appName of kCFPreferencesAnyApplication");
440      __CFLock(&__CFApplicationPreferencesLock);
441      if (!__CFStandardUserPreferences)  {
442          __CFStandardUserPreferences = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, & kCFTypeDictionaryKeyCallBacks, NULL);
443      }
444      if (!__CFStandardUserPreferences) {
445          // Couldn't create
446          __CFUnlock(&__CFApplicationPreferencesLock);
447          return NULL;
448      }
449      if ((appPreferences = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName)) == NULL ) {
450          appPreferences = _CFApplicationPreferencesCreateWithUser(kCFPreferencesCurrentUser, appName);
451          CFDictionarySetValue(__CFStandardUserPreferences, appName, appPreferences);
452          __CFUnlock(&__CFApplicationPreferencesLock);
453          _CFApplicationPreferencesSetStandardSearchList(appPreferences);
454      } else {
455          __CFUnlock(&__CFApplicationPreferencesLock);
456      }
457      return appPreferences;
458  }
459  
460  // Exclusively for Foundation's use
461  void _CFApplicationPreferencesSetCacheForApp(_CFApplicationPreferences *appPrefs, CFStringRef appName) {
462      __CFLock(&__CFApplicationPreferencesLock);
463      if (!__CFStandardUserPreferences) {
464          __CFStandardUserPreferences = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
465          CFDictionarySetValue(__CFStandardUserPreferences, appName, appPrefs);
466          __CFUnlock(&__CFApplicationPreferencesLock);
467      } else {
468          _CFApplicationPreferences *oldPrefs = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName);
469          CFDictionarySetValue(__CFStandardUserPreferences, appName, appPrefs);
470          __CFUnlock(&__CFApplicationPreferencesLock);
471          if (oldPrefs) {
472              _CFDeallocateApplicationPreferences(oldPrefs);
473          }
474      }
475  }
476  
477  
478  void _CFDeallocateApplicationPreferences(_CFApplicationPreferences *self) {
479      CFAllocatorRef alloc = __CFPreferencesAllocator();
480      _CFApplicationPreferences *cachedPrefs = NULL;
481      __CFLock(&__CFApplicationPreferencesLock);
482  
483      // Get us out of the cache before destroying!
484      if (__CFStandardUserPreferences)  {
485          cachedPrefs = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, self->_appName);
486      }
487      if (cachedPrefs == self) {
488          CFDictionaryRemoveValue(__CFStandardUserPreferences, self->_appName);
489      }
490      
491      if (self->_dictRep) CFRelease(self->_dictRep);
492      CFRelease(self->_search);
493      CFRelease(self->_appName);
494      CFAllocatorDeallocate(alloc, self);
495      __CFUnlock(&__CFApplicationPreferencesLock);
496  }
497  
498  
499  CF_EXPORT
500  CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self) {
501      CFDictionaryRef dict;
502      __CFLock(&__CFApplicationPreferencesLock);
503      if (!self->_dictRep) {
504          self->_dictRep = computeDictRep(self, true);
505      }
506      if (self->_dictRep) {
507          CFRetain(self->_dictRep);
508      }
509      dict = self->_dictRep;
510      __CFUnlock(&__CFApplicationPreferencesLock);
511      return dict;
512  }
513  
514  static void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList) {
515      CFIndex idx, count;
516      __CFLock(&__CFApplicationPreferencesLock);
517      CFArrayRemoveAllValues(self->_search);
518      count = CFArrayGetCount(newSearchList);
519      for (idx = 0; idx < count; idx ++) {
520          CFArrayAppendValue(self->_search, CFArrayGetValueAtIndex(newSearchList, idx));
521      }
522      updateDictRep(self);
523      __CFUnlock(&__CFApplicationPreferencesLock);
524  }
525  
526  void CFPreferencesAddSuitePreferencesToApp(CFStringRef appName, CFStringRef suiteName) {
527      _CFApplicationPreferences *appPrefs;
528      
529      appPrefs = _CFStandardApplicationPreferences(appName);
530      _CFApplicationPreferencesAddSuitePreferences(appPrefs, suiteName);
531  }
532  
533  void _CFApplicationPreferencesAddSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName) {
534      CFPreferencesDomainRef domain; 
535      CFIndex idx;
536      CFRange range;
537  
538      // Find where to insert the new suite
539      __CFLock(&__CFApplicationPreferencesLock);
540      domain = _CFPreferencesStandardDomain(appPrefs->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
541      range.location = 0;
542      range.length = CFArrayGetCount(appPrefs->_search);
543      idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
544      __CFUnlock(&__CFApplicationPreferencesLock);
545      idx ++; // We want just below the app domain.  Coincidentally, this gives us the top of the list if the app domain has been removed.
546      domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
547      if (domain) {
548          __CFLock(&__CFApplicationPreferencesLock);
549          CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
550          __CFUnlock(&__CFApplicationPreferencesLock);
551          range.length ++;
552      }
553      domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
554      if (domain) {
555          __CFLock(&__CFApplicationPreferencesLock);
556          CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
557          __CFUnlock(&__CFApplicationPreferencesLock);
558          range.length ++;
559      }
560  
561      // Now the AnyUser domains
562      domain = _CFPreferencesStandardDomain(appPrefs->_appName, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
563      idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
564      if (idx == kCFNotFound) {
565          // Someone blew away the app domain. For the any user case, we look for right below the global domain
566          domain = _CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
567          idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
568          if (idx == kCFNotFound) {
569              // Try the "any host" choice
570              domain = _CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
571              idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
572              if (idx == kCFNotFound) {
573                  // We give up; put the new domains at the bottom
574                  idx = CFArrayGetCount(appPrefs->_search) - 1;
575              }
576          }
577      }
578      idx ++;
579      domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
580      if (domain) {
581          __CFLock(&__CFApplicationPreferencesLock);
582          CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
583          __CFUnlock(&__CFApplicationPreferencesLock);
584      }
585      domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
586      if (domain) {
587          __CFLock(&__CFApplicationPreferencesLock);
588          CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
589          __CFUnlock(&__CFApplicationPreferencesLock);
590      }
591      __CFLock(&__CFApplicationPreferencesLock);
592      updateDictRep(appPrefs);
593      __CFUnlock(&__CFApplicationPreferencesLock);
594  }
595  
596  void CFPreferencesRemoveSuitePreferencesFromApp(CFStringRef appName, CFStringRef suiteName) {
597      _CFApplicationPreferences *appPrefs;
598  
599      appPrefs = _CFStandardApplicationPreferences(appName);
600      
601      _CFApplicationPreferencesRemoveSuitePreferences(appPrefs, suiteName);
602  }
603  
604  void _CFApplicationPreferencesRemoveSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName) {
605      CFPreferencesDomainRef domain;
606  
607      __CFLock(&__CFApplicationPreferencesLock);
608      domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
609      __CFUnlock(&__CFApplicationPreferencesLock);
610      if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
611  
612      __CFLock(&__CFApplicationPreferencesLock);
613      domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
614      __CFUnlock(&__CFApplicationPreferencesLock);
615      if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
616  
617      __CFLock(&__CFApplicationPreferencesLock);
618      domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
619      __CFUnlock(&__CFApplicationPreferencesLock);
620      if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
621  
622      __CFLock(&__CFApplicationPreferencesLock);
623      domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
624      __CFUnlock(&__CFApplicationPreferencesLock);
625      if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
626  }
627  
628  void _CFApplicationPreferencesAddDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain, Boolean addAtTop) {
629      __CFLock(&__CFApplicationPreferencesLock);
630      if (addAtTop) {
631          CFArrayInsertValueAtIndex(self->_search, 0, domain);
632      } else {
633          CFArrayAppendValue(self->_search, domain);
634      }
635      updateDictRep(self);
636      __CFUnlock(&__CFApplicationPreferencesLock);
637  }
638  
639  Boolean _CFApplicationPreferencesContainsDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) {
640      Boolean result;
641  
642      if (!domain) {
643          return false;
644      }
645  
646      __CFLock(&__CFApplicationPreferencesLock);
647      result = CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), domain);
648      __CFUnlock(&__CFApplicationPreferencesLock);
649      return result;
650  }
651  
652  Boolean _CFApplicationPreferencesContainsDomainNoLock(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) {
653      Boolean result;
654      result = CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), domain);
655      return result;
656  }
657  
658  void _CFApplicationPreferencesRemoveDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) {
659      CFIndex idx;
660      CFRange range;
661      __CFLock(&__CFApplicationPreferencesLock);
662      range.location = 0;
663      range.length = CFArrayGetCount(self->_search);
664      while ((idx = CFArrayGetFirstIndexOfValue(self->_search, range, domain)) != kCFNotFound) {
665          CFArrayRemoveValueAtIndex(self->_search, idx);
666          range.location = idx;
667          range.length  = range.length - idx - 1;
668      }
669      updateDictRep(self);
670      __CFUnlock(&__CFApplicationPreferencesLock);
671  }