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 }