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