]> git.saurik.com Git - apple/cf.git/blame - CFApplicationPreferences.c
CF-550.19.tar.gz
[apple/cf.git] / CFApplicationPreferences.c
CommitLineData
d8925383 1/*
e588f561 2 * Copyright (c) 2010 Apple Inc. All rights reserved.
d8925383
A
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 */
f64f9b69 23
d8925383 24/* CFApplicationPreferences.c
cf7d2af9 25 Copyright (c) 1998-2009, Apple Inc. All rights reserved.
d8925383
A
26 Responsibility: Chris Parker
27*/
28
29#include <CoreFoundation/CFPreferences.h>
30#include "CFInternal.h"
31#include <CoreFoundation/CFUniChar.h>
32#include <CoreFoundation/CFNumber.h>
bd5b749c
A
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>
cf7d2af9 38#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
bd5b749c
A
39#include <unistd.h>
40#endif
0ae65c4b 41
d8925383
A
42static Boolean _CFApplicationPreferencesSynchronizeNoLock(_CFApplicationPreferences *self);
43void _CFPreferencesDomainSetMultiple(CFPreferencesDomainRef domain, CFDictionaryRef dict);
44static void updateDictRep(_CFApplicationPreferences *self);
bd5b749c 45static void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList);
d8925383 46Boolean _CFApplicationPreferencesContainsDomainNoLock(_CFApplicationPreferences *self, CFPreferencesDomainRef domain);
bd5b749c 47static CFTypeRef _CFApplicationPreferencesCreateValueForKey2(_CFApplicationPreferences *self, CFStringRef defaultName);
d8925383
A
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);
bd5b749c 57 return standardPrefs ? _CFApplicationPreferencesCreateValueForKey2(standardPrefs, key) : NULL;
d8925383
A
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()) {
bd5b749c 77 if (CFStringCompare((CFStringRef)value, CFSTR("true"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare((CFStringRef)value, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
d8925383
A
78 *keyExistsAndHasValidFormat = true;
79 result = true;
bd5b749c 80 } else if (CFStringCompare((CFStringRef)value, CFSTR("false"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare((CFStringRef)value, CFSTR("NO"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
d8925383
A
81 *keyExistsAndHasValidFormat = true;
82 result = false;
83 } else {
84 *keyExistsAndHasValidFormat = false;
85 result = false;
86 }
87 } else if (typeID == CFNumberGetTypeID()) {
bd5b749c 88 if (CFNumberIsFloatType((CFNumberRef)value)) {
d8925383
A
89 *keyExistsAndHasValidFormat = false;
90 result = false;
91 } else {
92 int i;
93 *keyExistsAndHasValidFormat = true;
bd5b749c 94 CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &i);
d8925383
A
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__private_extern__ 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()) {
bd5b749c 127 SInt32 charIndex = 0;
d8925383
A
128 SInt32 intVal;
129 CFStringInlineBuffer buf;
130 Boolean success;
bd5b749c 131 CFStringInitInlineBuffer((CFStringRef)value, &buf, CFRangeMake(0, CFStringGetLength((CFStringRef)value)));
d8925383 132 success = __CFStringScanInteger(&buf, NULL, &charIndex, false, &intVal);
bd5b749c 133 *keyExistsAndHasValidFormat = (success && charIndex == CFStringGetLength((CFStringRef)value));
d8925383
A
134 result = (*keyExistsAndHasValidFormat) ? intVal : 0;
135 } else if (typeID == CFNumberGetTypeID()) {
bd5b749c 136 *keyExistsAndHasValidFormat = !CFNumberIsFloatType((CFNumberRef)value);
d8925383 137 if (*keyExistsAndHasValidFormat) {
bd5b749c 138 CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &result);
d8925383
A
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
bd5b749c 176static CFSpinLock_t __CFApplicationPreferencesLock = CFSpinLockInit; // Locks access to __CFStandardUserPreferences
d8925383
A
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__);
d8925383
A
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 {
bd5b749c 206 prefsArray = (_CFApplicationPreferences **)CFAllocatorAllocate(alloc, count * sizeof(_CFApplicationPreferences *), 0);
d8925383
A
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;
bd5b749c 221 if(prefsArray != prefsBuf) CFAllocatorDeallocate(alloc, prefsArray);
d8925383
A
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 {
bd5b749c 237 prefsArray = (_CFApplicationPreferences **)CFAllocatorAllocate(alloc, count * sizeof(_CFApplicationPreferences *), 0);
d8925383
A
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
d8925383
A
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) {
bd5b749c 264 CFDictionarySetValue((CFMutableDictionaryRef)context, key, value);
d8925383
A
265}
266
bd5b749c 267static CFMutableDictionaryRef computeDictRep(_CFApplicationPreferences *self, Boolean skipC0C0A) {
d8925383
A
268 CFAllocatorRef alloc = __CFPreferencesAllocator();
269 CFMutableArrayRef searchList = self->_search;
270 CFIndex idx;
271 CFIndex cnt = CFArrayGetCount(searchList);
272 CFDictionaryRef subdomainDict;
bd5b749c 273 CFMutableDictionaryRef dictRep;
d8925383 274
bd5b749c
A
275 dictRep = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
276 _CFDictionarySetCapacity(dictRep, 260); // avoid lots of rehashing
d8925383
A
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);
bd5b749c
A
285 if (subdomainDict) {
286 CFDictionaryApplyFunction(subdomainDict, __addKeysAndValues, dictRep);
d8925383
A
287 CFRelease(subdomainDict);
288 }
d8925383 289 }
bd5b749c 290 return dictRep;
d8925383
A
291}
292
293CFTypeRef _CFApplicationPreferencesSearchDownToDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef stopper, CFStringRef key) {
bd5b749c 294 return NULL;
d8925383
A
295}
296
297
298void _CFApplicationPreferencesUpdate(_CFApplicationPreferences *self) {
299 __CFSpinLock(&__CFApplicationPreferencesLock);
300 updateDictRep(self);
301 __CFSpinUnlock(&__CFApplicationPreferencesLock);
302}
303
bd5b749c
A
304CF_EXPORT CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self);
305
d8925383 306__private_extern__ CFDictionaryRef __CFApplicationPreferencesCopyCurrentState(void) {
d8925383 307 _CFApplicationPreferences *self = _CFStandardApplicationPreferences(kCFPreferencesCurrentApplication);
bd5b749c 308 CFDictionaryRef result = _CFApplicationPreferencesCopyRepresentation(self);
d8925383
A
309 return result;
310}
311
312// CACHING here - we will only return a value as current as the last time computeDictRep() was called
bd5b749c 313static CFTypeRef _CFApplicationPreferencesCreateValueForKey2(_CFApplicationPreferences *self, CFStringRef defaultName) {
d8925383
A
314 CFTypeRef result;
315 __CFSpinLock(&__CFApplicationPreferencesLock);
316 if (!self->_dictRep) {
bd5b749c 317 self->_dictRep = computeDictRep(self, true);
d8925383
A
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
bd5b749c 327
d8925383
A
328void _CFApplicationPreferencesSet(_CFApplicationPreferences *self, CFStringRef defaultName, CFTypeRef value) {
329 CFPreferencesDomainRef applicationDomain;
bd5b749c 330
d8925383
A
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);
d8925383
A
341}
342
343void _CFApplicationPreferencesRemove(_CFApplicationPreferences *self, CFStringRef defaultName) {
344 CFPreferencesDomainRef appDomain;
bd5b749c 345
d8925383
A
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();
bd5b749c 360 updateDictRep(self);
d8925383
A
361 return success;
362}
363
364Boolean _CFApplicationPreferencesSynchronize(_CFApplicationPreferences *self) {
365 Boolean result;
d8925383
A
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();
bd5b749c 375 _CFApplicationPreferences *self = (_CFApplicationPreferences*)CFAllocatorAllocate(alloc, sizeof(_CFApplicationPreferences), 0);
d8925383
A
376 if (self) {
377 self->_dictRep = NULL;
bd5b749c 378 self->_appName = (CFStringRef)CFRetain(appName);
d8925383
A
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) {
bd5b749c
A
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
d8925383
A
416 */
417 CFPreferencesDomainRef domain;
bd5b749c 418 CFMutableArrayRef search = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
d8925383
A
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));
bd5b749c 426 ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost));
d8925383
A
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__private_extern__ _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) {
bd5b749c 444 __CFStandardUserPreferences = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, & kCFTypeDictionaryKeyCallBacks, NULL);
d8925383
A
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) {
bd5b749c 466 __CFStandardUserPreferences = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
d8925383
A
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
bd5b749c
A
500
501CF_EXPORT
502CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self) {
d8925383
A
503 CFDictionaryRef dict;
504 __CFSpinLock(&__CFApplicationPreferencesLock);
505 if (!self->_dictRep) {
bd5b749c 506 self->_dictRep = computeDictRep(self, true);
d8925383 507 }
bd5b749c 508 if (self->_dictRep) {
d8925383
A
509 CFRetain(self->_dictRep);
510 }
511 dict = self->_dictRep;
512 __CFSpinUnlock(&__CFApplicationPreferencesLock);
513 return dict;
514}
515
bd5b749c 516static void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList) {
d8925383
A
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) {
bd5b749c 567 // Someone blew away the app domain. For the any user case, we look for right below the global domain
d8925383
A
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;
bd5b749c
A
643
644 if (!domain) {
645 return false;
646 }
647
d8925383
A
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}