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