1/* 2 * Copyright (c) 2014 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-2013, 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 42static Boolean _CFApplicationPreferencesSynchronizeNoLock(_CFApplicationPreferences *self); 43void _CFPreferencesDomainSetMultiple(CFPreferencesDomainRef domain, CFDictionaryRef dict); 44static void updateDictRep(_CFApplicationPreferences *self); 45static void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList); 46Boolean _CFApplicationPreferencesContainsDomainNoLock(_CFApplicationPreferences *self, CFPreferencesDomainRef domain); 47static 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 51CFPropertyListRef 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 60CF_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 109CF_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 151Boolean 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 157CFIndex 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 163void 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 176static CFSpinLock_t __CFApplicationPreferencesLock = CFSpinLockInit; // Locks access to __CFStandardUserPreferences 177static CFMutableDictionaryRef __CFStandardUserPreferences = NULL; // Mutable dictionary; keys are app names, values are _CFApplicationPreferences 178 179Boolean 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 __CFSpinLock(&__CFApplicationPreferencesLock); 186 if (__CFStandardUserPreferences) { 187 standardPrefs = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName); 188 } else { 189 standardPrefs = NULL; 190 } 191 192 result = standardPrefs ? _CFApplicationPreferencesSynchronizeNoLock(standardPrefs) : _CFSynchronizeDomainCache(); 193 __CFSpinUnlock(&__CFApplicationPreferencesLock); 194 return result; 195} 196 197void CFPreferencesFlushCaches(void) { 198 CFAllocatorRef alloc = __CFPreferencesAllocator(); 199 __CFSpinLock(&__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 __CFSpinUnlock(&__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 __CFSpinLock(&__CFApplicationPreferencesLock); 218 219 CFRelease(__CFStandardUserPreferences); 220 __CFStandardUserPreferences = NULL; 221 if(prefsArray != prefsBuf) CFAllocatorDeallocate(alloc, prefsArray); 222 } 223 __CFSpinUnlock(&__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. 228void _CFApplicationPreferencesDomainHasChanged(CFPreferencesDomainRef changedDomain) { 229 CFAllocatorRef alloc = __CFPreferencesAllocator(); 230 __CFSpinLock(&__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 __CFSpinUnlock(&__CFApplicationPreferencesLock); 250} 251 252 253// Begin ported code from NSUserDefaults.m 254 255 256static void updateDictRep(_CFApplicationPreferences *self) { 257 if (self->_dictRep) { 258 CFRelease(self->_dictRep); 259 self->_dictRep = NULL; 260 } 261} 262 263static void __addKeysAndValues(const void *key, const void *value, void *context) { 264 CFDictionarySetValue((CFMutableDictionaryRef)context, key, value); 265} 266 267static 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 293CFTypeRef _CFApplicationPreferencesSearchDownToDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef stopper, CFStringRef key) { 294 return NULL; 295} 296 297 298void _CFApplicationPreferencesUpdate(_CFApplicationPreferences *self) { 299 __CFSpinLock(&__CFApplicationPreferencesLock); 300 updateDictRep(self); 301 __CFSpinUnlock(&__CFApplicationPreferencesLock); 302} 303 304CF_EXPORT CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self); 305 306CF_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 313static CFTypeRef _CFApplicationPreferencesCreateValueForKey2(_CFApplicationPreferences *self, CFStringRef defaultName) { 314 CFTypeRef result; 315 __CFSpinLock(&__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 __CFSpinUnlock(&__CFApplicationPreferencesLock); 324 return result; 325} 326 327 328void _CFApplicationPreferencesSet(_CFApplicationPreferences *self, CFStringRef defaultName, CFTypeRef value) { 329 CFPreferencesDomainRef applicationDomain; 330 331 __CFSpinLock(&__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 __CFSpinUnlock(&__CFApplicationPreferencesLock); 341} 342 343void _CFApplicationPreferencesRemove(_CFApplicationPreferences *self, CFStringRef defaultName) { 344 CFPreferencesDomainRef appDomain; 345 346 __CFSpinLock(&__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 __CFSpinUnlock(&__CFApplicationPreferencesLock); 356} 357 358static Boolean _CFApplicationPreferencesSynchronizeNoLock(_CFApplicationPreferences *self) { 359 Boolean success = _CFSynchronizeDomainCache(); 360 updateDictRep(self); 361 return success; 362} 363 364Boolean _CFApplicationPreferencesSynchronize(_CFApplicationPreferences *self) { 365 Boolean result; 366 __CFSpinLock(&__CFApplicationPreferencesLock); 367 result = _CFApplicationPreferencesSynchronizeNoLock(self); 368 __CFSpinUnlock(&__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);} 391void _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 439CF_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 __CFSpinLock(&__CFApplicationPreferencesLock); 443 if (!__CFStandardUserPreferences) { 444 __CFStandardUserPreferences = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, & kCFTypeDictionaryKeyCallBacks, NULL); 445 } 446 if (!__CFStandardUserPreferences) { 447 // Couldn't create 448 __CFSpinUnlock(&__CFApplicationPreferencesLock); 449 return NULL; 450 } 451 if ((appPreferences = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName)) == NULL ) { 452 appPreferences = _CFApplicationPreferencesCreateWithUser(kCFPreferencesCurrentUser, appName); 453 CFDictionarySetValue(__CFStandardUserPreferences, appName, appPreferences); 454 __CFSpinUnlock(&__CFApplicationPreferencesLock); 455 _CFApplicationPreferencesSetStandardSearchList(appPreferences); 456 } else { 457 __CFSpinUnlock(&__CFApplicationPreferencesLock); 458 } 459 return appPreferences; 460} 461 462// Exclusively for Foundation's use 463void _CFApplicationPreferencesSetCacheForApp(_CFApplicationPreferences *appPrefs, CFStringRef appName) { 464 __CFSpinLock(&__CFApplicationPreferencesLock); 465 if (!__CFStandardUserPreferences) { 466 __CFStandardUserPreferences = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); 467 CFDictionarySetValue(__CFStandardUserPreferences, appName, appPrefs); 468 __CFSpinUnlock(&__CFApplicationPreferencesLock); 469 } else { 470 _CFApplicationPreferences *oldPrefs = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName); 471 CFDictionarySetValue(__CFStandardUserPreferences, appName, appPrefs); 472 __CFSpinUnlock(&__CFApplicationPreferencesLock); 473 if (oldPrefs) { 474 _CFDeallocateApplicationPreferences(oldPrefs); 475 } 476 } 477} 478 479 480void _CFDeallocateApplicationPreferences(_CFApplicationPreferences *self) { 481 CFAllocatorRef alloc = __CFPreferencesAllocator(); 482 _CFApplicationPreferences *cachedPrefs = NULL; 483 __CFSpinLock(&__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 __CFSpinUnlock(&__CFApplicationPreferencesLock); 498} 499 500 501CF_EXPORT 502CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self) { 503 CFDictionaryRef dict; 504 __CFSpinLock(&__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 __CFSpinUnlock(&__CFApplicationPreferencesLock); 513 return dict; 514} 515 516static void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList) { 517 CFIndex idx, count; 518 __CFSpinLock(&__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 __CFSpinUnlock(&__CFApplicationPreferencesLock); 526} 527 528void CFPreferencesAddSuitePreferencesToApp(CFStringRef appName, CFStringRef suiteName) { 529 _CFApplicationPreferences *appPrefs; 530 531 appPrefs = _CFStandardApplicationPreferences(appName); 532 _CFApplicationPreferencesAddSuitePreferences(appPrefs, suiteName); 533} 534 535void _CFApplicationPreferencesAddSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName) { 536 CFPreferencesDomainRef domain; 537 CFIndex idx; 538 CFRange range; 539 540 // Find where to insert the new suite 541 __CFSpinLock(&__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 __CFSpinUnlock(&__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 __CFSpinLock(&__CFApplicationPreferencesLock); 551 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain); 552 __CFSpinUnlock(&__CFApplicationPreferencesLock); 553 range.length ++; 554 } 555 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); 556 if (domain) { 557 __CFSpinLock(&__CFApplicationPreferencesLock); 558 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain); 559 __CFSpinUnlock(&__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 __CFSpinLock(&__CFApplicationPreferencesLock); 584 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain); 585 __CFSpinUnlock(&__CFApplicationPreferencesLock); 586 } 587 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); 588 if (domain) { 589 __CFSpinLock(&__CFApplicationPreferencesLock); 590 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain); 591 __CFSpinUnlock(&__CFApplicationPreferencesLock); 592 } 593 __CFSpinLock(&__CFApplicationPreferencesLock); 594 updateDictRep(appPrefs); 595 __CFSpinUnlock(&__CFApplicationPreferencesLock); 596} 597 598void CFPreferencesRemoveSuitePreferencesFromApp(CFStringRef appName, CFStringRef suiteName) { 599 _CFApplicationPreferences *appPrefs; 600 601 appPrefs = _CFStandardApplicationPreferences(appName); 602 603 _CFApplicationPreferencesRemoveSuitePreferences(appPrefs, suiteName); 604} 605 606void _CFApplicationPreferencesRemoveSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName) { 607 CFPreferencesDomainRef domain; 608 609 __CFSpinLock(&__CFApplicationPreferencesLock); 610 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 611 __CFSpinUnlock(&__CFApplicationPreferencesLock); 612 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain); 613 614 __CFSpinLock(&__CFApplicationPreferencesLock); 615 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); 616 __CFSpinUnlock(&__CFApplicationPreferencesLock); 617 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain); 618 619 __CFSpinLock(&__CFApplicationPreferencesLock); 620 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesAnyHost); 621 __CFSpinUnlock(&__CFApplicationPreferencesLock); 622 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain); 623 624 __CFSpinLock(&__CFApplicationPreferencesLock); 625 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); 626 __CFSpinUnlock(&__CFApplicationPreferencesLock); 627 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain); 628} 629 630void _CFApplicationPreferencesAddDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain, Boolean addAtTop) { 631 __CFSpinLock(&__CFApplicationPreferencesLock); 632 if (addAtTop) { 633 CFArrayInsertValueAtIndex(self->_search, 0, domain); 634 } else { 635 CFArrayAppendValue(self->_search, domain); 636 } 637 updateDictRep(self); 638 __CFSpinUnlock(&__CFApplicationPreferencesLock); 639} 640 641Boolean _CFApplicationPreferencesContainsDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) { 642 Boolean result; 643 644 if (!domain) { 645 return false; 646 } 647 648 __CFSpinLock(&__CFApplicationPreferencesLock); 649 result = CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), domain); 650 __CFSpinUnlock(&__CFApplicationPreferencesLock); 651 return result; 652} 653 654Boolean _CFApplicationPreferencesContainsDomainNoLock(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) { 655 Boolean result; 656 result = CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), domain); 657 return result; 658} 659 660void _CFApplicationPreferencesRemoveDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) { 661 CFIndex idx; 662 CFRange range; 663 __CFSpinLock(&__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 __CFSpinUnlock(&__CFApplicationPreferencesLock); 673} 674