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