2 * Copyright (c) 2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 /* CFBundle_Resources.c
25 Copyright (c) 1999-2011, Apple Inc. All rights reserved.
26 Responsibility: David Smith
29 #if DEPLOYMENT_TARGET_MACOSX
30 #define READ_DIRECTORIES 1
31 #elif DEPLOYMENT_TARGET_EMBEDDED
32 #define READ_DIRECTORIES 1
33 #elif DEPLOYMENT_TARGET_WINDOWS
34 #define READ_DIRECTORIES 0
36 #error Unknown or unspecified DEPLOYMENT_TARGET
39 #define READ_DIRECTORIES_CACHE_CAPACITY 128
41 #include "CFBundle_Internal.h"
42 #include <CoreFoundation/CFURLAccess.h>
43 #include <CoreFoundation/CFPropertyList.h>
44 #include <CoreFoundation/CFByteOrder.h>
45 #include <CoreFoundation/CFNumber.h>
46 #include <CoreFoundation/CFLocale.h>
47 #include <CoreFoundation/CFPreferences.h>
49 #include "CFInternal.h"
50 #include <CoreFoundation/CFPriv.h>
56 #include <sys/types.h>
57 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
58 #include <sys/sysctl.h>
61 #if DEPLOYMENT_TARGET_MACOSX
63 #elif DEPLOYMENT_TARGET_EMBEDDED
65 #elif DEPLOYMENT_TARGET_WINDOWS
67 #error Unknown or unspecified DEPLOYMENT_TARGET
72 #endif /* READ_DIRECTORIES */
74 CF_EXPORT
bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict
, const void *key
, const void **actualkey
);
77 static inline Boolean
_CFBundleSortedArrayContains(CFArrayRef arr
, CFStringRef target
) {
78 CFRange arrRange
= CFRangeMake(0, CFArrayGetCount(arr
));
79 CFIndex itemIdx
= CFArrayBSearchValues(arr
, arrRange
, target
, (CFComparatorFunction
)CFStringCompare
, NULL
);
80 return itemIdx
< arrRange
.length
&& CFEqual(CFArrayGetValueAtIndex(arr
, itemIdx
), target
);
83 // The following strings are initialized 'later' (i.e., not at static initialization time) because static init time is too early for CFSTR to work, on Windows
84 // This is here to make sure it gets updated when _CFGetPlatformName does
85 #define _CFBundleNumberOfPlatforms 7
86 static CFStringRef _CFBundleSupportedPlatforms
[_CFBundleNumberOfPlatforms
] = { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
87 static const char *_CFBundleSupportedPlatformStrings
[_CFBundleNumberOfPlatforms
] = { "iphoneos", "macos", "windows", "linux", "freebsd", "solaris", "hpux" };
89 // This is here to make sure it gets updated when _CFGetProductName does
90 #define _CFBundleNumberOfProducts 3
91 static CFStringRef _CFBundleSupportedProducts
[_CFBundleNumberOfProducts
] = { NULL
, NULL
, NULL
};
92 static const char *_CFBundleSupportedProductStrings
[_CFBundleNumberOfProducts
] = { "iphone", "ipod", "ipad" };
94 #define _CFBundleNumberOfiPhoneOSPlatformProducts 3
95 static CFStringRef _CFBundleSupportediPhoneOSPlatformProducts
[_CFBundleNumberOfiPhoneOSPlatformProducts
] = { NULL
, NULL
, NULL
};
96 static const char *_CFBundleSupportediPhoneOSPlatformProductStrings
[_CFBundleNumberOfiPhoneOSPlatformProducts
] = { "iphone", "ipod", "ipad" };
98 void _CFBundleResourcesInitialize() {
99 for (unsigned int i
= 0; i
< _CFBundleNumberOfPlatforms
; i
++) _CFBundleSupportedPlatforms
[i
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, _CFBundleSupportedPlatformStrings
[i
], kCFStringEncodingUTF8
);
101 for (unsigned int i
= 0; i
< _CFBundleNumberOfProducts
; i
++) _CFBundleSupportedProducts
[i
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, _CFBundleSupportedProductStrings
[i
], kCFStringEncodingUTF8
);
103 for (unsigned int i
= 0; i
< _CFBundleNumberOfiPhoneOSPlatformProducts
; i
++) _CFBundleSupportediPhoneOSPlatformProducts
[i
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, _CFBundleSupportediPhoneOSPlatformProductStrings
[i
], kCFStringEncodingUTF8
);
106 static CFStringRef platform
= NULL
;
108 void _CFSetProductName(CFStringRef str
) {
109 if (str
) CFRetain(str
);
111 // Note that the previous value is leaked, which is fine normally
112 // because the initial values would tend to be the constant strings
113 // below. That is required for thread-safety value due to the Get
114 // function [not being Copy]. It is also fine because people
115 // shouldn't be screwing around with this value casually.
118 CFStringRef
_CFGetProductName(void) {
119 #if DEPLOYMENT_TARGET_EMBEDDED
122 memset(buffer
, 0, sizeof(buffer
));
123 size_t buflen
= sizeof(buffer
);
124 int ret
= sysctlbyname("hw.machine", buffer
, &buflen
, NULL
, 0);
125 if (0 == ret
|| (-1 == ret
&& ENOMEM
== errno
)) {
126 if (6 <= buflen
&& 0 == memcmp(buffer
, "iPhone", 6)) {
127 platform
= CFSTR("iphone");
128 } else if (4 <= buflen
&& 0 == memcmp(buffer
, "iPod", 4)) {
129 platform
= CFSTR("ipod");
130 } else if (4 <= buflen
&& 0 == memcmp(buffer
, "iPad", 4)) {
131 platform
= CFSTR("ipad");
133 const char *env
= __CFgetenv("IPHONE_SIMULATOR_DEVICE");
135 if (0 == strcmp(env
, "iPhone")) {
136 platform
= CFSTR("iphone");
137 } else if (0 == strcmp(env
, "iPad")) {
138 platform
= CFSTR("ipad");
140 // fallback, unrecognized IPHONE_SIMULATOR_DEVICE
143 // fallback, unrecognized hw.machine and no IPHONE_SIMULATOR_DEVICE
147 if (!platform
) platform
= CFSTR("iphone"); // fallback
154 // All new-style bundles will have these extensions.
155 __private_extern__ CFStringRef
_CFGetPlatformName(void) {
156 #if DEPLOYMENT_TARGET_MACOSX
157 return _CFBundleMacOSXPlatformName
;
158 #elif DEPLOYMENT_TARGET_EMBEDDED
159 return _CFBundleiPhoneOSPlatformName
;
160 #elif DEPLOYMENT_TARGET_WINDOWS
161 return _CFBundleWindowsPlatformName
;
162 #elif DEPLOYMENT_TARGET_SOLARIS
163 return _CFBundleSolarisPlatformName
;
164 #elif DEPLOYMENT_TARGET_HPUX
165 return _CFBundleHPUXPlatformName
;
166 #elif DEPLOYMENT_TARGET_LINUX
167 return _CFBundleLinuxPlatformName
;
168 #elif DEPLOYMENT_TARGET_FREEBSD
169 return _CFBundleFreeBSDPlatformName
;
171 #error Unknown or unspecified DEPLOYMENT_TARGET
175 __private_extern__ CFStringRef
_CFGetAlternatePlatformName(void) {
176 #if DEPLOYMENT_TARGET_MACOSX
177 return _CFBundleAlternateMacOSXPlatformName
;
178 #elif DEPLOYMENT_TARGET_EMBEDDED
179 return _CFBundleMacOSXPlatformName
;
180 #elif DEPLOYMENT_TARGET_WINDOWS
183 #error Unknown or unspecified DEPLOYMENT_TARGET
187 static CFSpinLock_t CFBundleResourceGlobalDataLock
= CFSpinLockInit
;
188 static UniChar
*_AppSupportUniChars1
= NULL
;
189 static CFIndex _AppSupportLen1
= 0;
190 static UniChar
*_AppSupportUniChars2
= NULL
;
191 static CFIndex _AppSupportLen2
= 0;
192 static UniChar
*_ResourcesUniChars
= NULL
;
193 static CFIndex _ResourcesLen
= 0;
194 static UniChar
*_PlatformUniChars
= NULL
;
195 static CFIndex _PlatformLen
= 0;
196 static UniChar
*_AlternatePlatformUniChars
= NULL
;
197 static CFIndex _AlternatePlatformLen
= 0;
198 static UniChar
*_LprojUniChars
= NULL
;
199 static CFIndex _LprojLen
= 0;
200 static UniChar
*_GlobalResourcesUniChars
= NULL
;
201 static CFIndex _GlobalResourcesLen
= 0;
202 static UniChar
*_InfoExtensionUniChars
= NULL
;
203 static CFIndex _InfoExtensionLen
= 0;
205 static UniChar _ResourceSuffix3
[32];
206 static CFIndex _ResourceSuffix3Len
= 0;
207 static UniChar _ResourceSuffix2
[16];
208 static CFIndex _ResourceSuffix2Len
= 0;
209 static UniChar _ResourceSuffix1
[16];
210 static CFIndex _ResourceSuffix1Len
= 0;
212 static void _CFBundleInitStaticUniCharBuffers(void) {
213 CFStringRef appSupportStr1
= _CFBundleSupportFilesDirectoryName1
;
214 CFStringRef appSupportStr2
= _CFBundleSupportFilesDirectoryName2
;
215 CFStringRef resourcesStr
= _CFBundleResourcesDirectoryName
;
216 CFStringRef platformStr
= _CFGetPlatformName();
217 CFStringRef alternatePlatformStr
= _CFGetAlternatePlatformName();
218 CFStringRef lprojStr
= _CFBundleLprojExtension
;
219 CFStringRef globalResourcesStr
= _CFBundleNonLocalizedResourcesDirectoryName
;
220 CFStringRef infoExtensionStr
= _CFBundleInfoExtension
;
222 _AppSupportLen1
= CFStringGetLength(appSupportStr1
);
223 _AppSupportLen2
= CFStringGetLength(appSupportStr2
);
224 _ResourcesLen
= CFStringGetLength(resourcesStr
);
225 _PlatformLen
= CFStringGetLength(platformStr
);
226 _AlternatePlatformLen
= CFStringGetLength(alternatePlatformStr
);
227 _LprojLen
= CFStringGetLength(lprojStr
);
228 _GlobalResourcesLen
= CFStringGetLength(globalResourcesStr
);
229 _InfoExtensionLen
= CFStringGetLength(infoExtensionStr
);
231 _AppSupportUniChars1
= (UniChar
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(UniChar
) * (_AppSupportLen1
+ _AppSupportLen2
+ _ResourcesLen
+ _PlatformLen
+ _AlternatePlatformLen
+ _LprojLen
+ _GlobalResourcesLen
+ _InfoExtensionLen
), 0);
232 _AppSupportUniChars2
= _AppSupportUniChars1
+ _AppSupportLen1
;
233 _ResourcesUniChars
= _AppSupportUniChars2
+ _AppSupportLen2
;
234 _PlatformUniChars
= _ResourcesUniChars
+ _ResourcesLen
;
235 _AlternatePlatformUniChars
= _PlatformUniChars
+ _PlatformLen
;
236 _LprojUniChars
= _AlternatePlatformUniChars
+ _AlternatePlatformLen
;
237 _GlobalResourcesUniChars
= _LprojUniChars
+ _LprojLen
;
238 _InfoExtensionUniChars
= _GlobalResourcesUniChars
+ _GlobalResourcesLen
;
240 if (_AppSupportLen1
> 0) CFStringGetCharacters(appSupportStr1
, CFRangeMake(0, _AppSupportLen1
), _AppSupportUniChars1
);
241 if (_AppSupportLen2
> 0) CFStringGetCharacters(appSupportStr2
, CFRangeMake(0, _AppSupportLen2
), _AppSupportUniChars2
);
242 if (_ResourcesLen
> 0) CFStringGetCharacters(resourcesStr
, CFRangeMake(0, _ResourcesLen
), _ResourcesUniChars
);
243 if (_PlatformLen
> 0) CFStringGetCharacters(platformStr
, CFRangeMake(0, _PlatformLen
), _PlatformUniChars
);
244 if (_AlternatePlatformLen
> 0) CFStringGetCharacters(alternatePlatformStr
, CFRangeMake(0, _AlternatePlatformLen
), _AlternatePlatformUniChars
);
245 if (_LprojLen
> 0) CFStringGetCharacters(lprojStr
, CFRangeMake(0, _LprojLen
), _LprojUniChars
);
246 if (_GlobalResourcesLen
> 0) CFStringGetCharacters(globalResourcesStr
, CFRangeMake(0, _GlobalResourcesLen
), _GlobalResourcesUniChars
);
247 if (_InfoExtensionLen
> 0) CFStringGetCharacters(infoExtensionStr
, CFRangeMake(0, _InfoExtensionLen
), _InfoExtensionUniChars
);
249 _ResourceSuffix1Len
= CFStringGetLength(platformStr
);
250 if (_ResourceSuffix1Len
> 0) _ResourceSuffix1
[0] = '-';
251 if (_ResourceSuffix1Len
> 0) CFStringGetCharacters(platformStr
, CFRangeMake(0, _ResourceSuffix1Len
), _ResourceSuffix1
+ 1);
252 if (_ResourceSuffix1Len
> 0) _ResourceSuffix1Len
++;
253 CFStringRef productStr
= _CFGetProductName();
254 if (CFEqual(productStr
, CFSTR("ipod"))) { // For now, for resource lookups, hide ipod distinction and make it look for iphone resources
255 productStr
= CFSTR("iphone");
257 _ResourceSuffix2Len
= CFStringGetLength(productStr
);
258 if (_ResourceSuffix2Len
> 0) _ResourceSuffix2
[0] = '~';
259 if (_ResourceSuffix2Len
> 0) CFStringGetCharacters(productStr
, CFRangeMake(0, _ResourceSuffix2Len
), _ResourceSuffix2
+ 1);
260 if (_ResourceSuffix2Len
> 0) _ResourceSuffix2Len
++;
261 if (_ResourceSuffix1Len
> 1 && _ResourceSuffix2Len
> 1) {
262 _ResourceSuffix3Len
= _ResourceSuffix1Len
+ _ResourceSuffix2Len
;
263 memmove(_ResourceSuffix3
, _ResourceSuffix1
, sizeof(UniChar
) * _ResourceSuffix1Len
);
264 memmove(_ResourceSuffix3
+ _ResourceSuffix1Len
, _ResourceSuffix2
, sizeof(UniChar
) * _ResourceSuffix2Len
);
268 CF_INLINE
void _CFEnsureStaticBuffersInited(void) {
269 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
270 if (!_AppSupportUniChars1
) _CFBundleInitStaticUniCharBuffers();
271 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
276 static CFMutableDictionaryRef contentsCache
= NULL
;
277 static CFMutableDictionaryRef directoryContentsCache
= NULL
;
278 static CFMutableDictionaryRef unknownContentsCache
= NULL
;
281 _CFBundleAllContents
= 0,
282 _CFBundleDirectoryContents
= 1,
283 _CFBundleUnknownContents
= 2
284 } _CFBundleDirectoryContentsType
;
286 extern void _CFArraySortValues(CFMutableArrayRef array
, CFComparatorFunction comparator
, void *context
);
288 static CFArrayRef
_CFBundleCopySortedDirectoryContentsAtPath(CFStringRef path
, _CFBundleDirectoryContentsType contentsType
) {
289 CFArrayRef result
= NULL
;
291 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
292 if (contentsType
== _CFBundleUnknownContents
) {
293 if (unknownContentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(unknownContentsCache
, path
);
294 } else if (contentsType
== _CFBundleDirectoryContents
) {
295 if (directoryContentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(directoryContentsCache
, path
);
297 if (contentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(contentsCache
, path
);
299 if (result
) CFRetain(result
);
300 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
303 Boolean tryToOpen
= false, allDots
= true;
304 char cpathBuff
[CFMaxPathSize
];
305 CFIndex cpathLen
= 0, idx
, lastSlashIdx
= 0;
308 CFMutableArrayRef contents
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
), directoryContents
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
), unknownContents
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
309 CFStringRef dirName
, name
;
312 if (CFStringGetFileSystemRepresentation(path
, cpathBuff
, CFMaxPathSize
)) {
314 cpathLen
= strlen(cpathBuff
);
316 // First see whether we already know that the directory doesn't exist
317 for (idx
= cpathLen
; lastSlashIdx
== 0 && idx
-- > 0;) {
318 if (cpathBuff
[idx
] == '/') lastSlashIdx
= idx
;
319 else if (cpathBuff
[idx
] != '.') allDots
= false;
321 if (lastSlashIdx
> 0 && lastSlashIdx
+ 1 < cpathLen
&& !allDots
) {
322 cpathBuff
[lastSlashIdx
] = '\0';
323 dirName
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, cpathBuff
);
325 name
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, cpathBuff
+ lastSlashIdx
+ 1);
327 // ??? we might like to use directoryContentsCache rather than contentsCache here, but we cannot unless we resolve DT_LNKs below
328 CFArrayRef dirDirContents
= NULL
;
330 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
331 if (contentsCache
) dirDirContents
= (CFArrayRef
)CFDictionaryGetValue(contentsCache
, dirName
);
332 if (dirDirContents
) {
333 Boolean foundIt
= false;
334 CFIndex dirDirIdx
, dirDirLength
= CFArrayGetCount(dirDirContents
);
335 for (dirDirIdx
= 0; !foundIt
&& dirDirIdx
< dirDirLength
; dirDirIdx
++) if (kCFCompareEqualTo
== CFStringCompare(name
, CFArrayGetValueAtIndex(dirDirContents
, dirDirIdx
), kCFCompareCaseInsensitive
)) foundIt
= true;
336 if (!foundIt
) tryToOpen
= false;
338 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
343 cpathBuff
[lastSlashIdx
] = '/';
346 if (tryToOpen
&& (dirp
= opendir(cpathBuff
))) {
347 while ((dent
= readdir(dirp
))) {
348 CFIndex nameLen
= dent
->d_namlen
;
349 if (0 == nameLen
|| 0 == dent
->d_fileno
|| ('.' == dent
->d_name
[0] && (1 == nameLen
|| (2 == nameLen
&& '.' == dent
->d_name
[1]) || '_' == dent
->d_name
[1]))) continue;
350 name
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, dent
->d_name
);
352 // ??? should we follow links for DT_LNK? unless we do, results are approximate, but for performance reasons we do not
353 // ??? likewise for DT_UNKNOWN
354 // ??? the utility of distinguishing directories from other contents is somewhat doubtful anyway
355 CFArrayAppendValue(contents
, name
);
356 if (dent
->d_type
== DT_DIR
) {
357 CFArrayAppendValue(directoryContents
, name
);
358 } else if (dent
->d_type
== DT_UNKNOWN
) {
359 CFArrayAppendValue(unknownContents
, name
);
364 (void)closedir(dirp
);
367 _CFArraySortValues(contents
, (CFComparatorFunction
)CFStringCompare
, NULL
);
368 _CFArraySortValues(directoryContents
, (CFComparatorFunction
)CFStringCompare
, NULL
);
369 _CFArraySortValues(unknownContents
, (CFComparatorFunction
)CFStringCompare
, NULL
);
371 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
372 if (!contentsCache
) contentsCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, READ_DIRECTORIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
373 if (READ_DIRECTORIES_CACHE_CAPACITY
<= CFDictionaryGetCount(contentsCache
)) CFDictionaryRemoveAllValues(contentsCache
);
374 CFDictionaryAddValue(contentsCache
, path
, contents
);
376 if (!directoryContentsCache
) directoryContentsCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, READ_DIRECTORIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
377 if (READ_DIRECTORIES_CACHE_CAPACITY
<= CFDictionaryGetCount(directoryContentsCache
)) CFDictionaryRemoveAllValues(directoryContentsCache
);
378 CFDictionaryAddValue(directoryContentsCache
, path
, directoryContents
);
380 if (!unknownContentsCache
) unknownContentsCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, READ_DIRECTORIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
381 if (READ_DIRECTORIES_CACHE_CAPACITY
<= CFDictionaryGetCount(unknownContentsCache
)) CFDictionaryRemoveAllValues(unknownContentsCache
);
382 CFDictionaryAddValue(unknownContentsCache
, path
, unknownContents
);
384 if (contentsType
== _CFBundleUnknownContents
) {
385 result
= CFRetain(unknownContents
);
386 } else if (contentsType
== _CFBundleDirectoryContents
) {
387 result
= CFRetain(directoryContents
);
389 result
= CFRetain(contents
);
393 CFRelease(directoryContents
);
394 CFRelease(unknownContents
);
395 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
400 static void _CFBundleFlushContentsCaches(void) {
401 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
402 if (contentsCache
) CFDictionaryRemoveAllValues(contentsCache
);
403 if (directoryContentsCache
) CFDictionaryRemoveAllValues(directoryContentsCache
);
404 if (unknownContentsCache
) CFDictionaryRemoveAllValues(unknownContentsCache
);
405 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
408 static void _CFBundleFlushContentsCacheForPath(CFMutableDictionaryRef cache
, CFStringRef path
) {
409 CFStringRef keys
[READ_DIRECTORIES_CACHE_CAPACITY
];
410 unsigned i
, count
= CFDictionaryGetCount(cache
);
411 if (count
<= READ_DIRECTORIES_CACHE_CAPACITY
) {
412 CFDictionaryGetKeysAndValues(cache
, (const void **)keys
, NULL
);
413 for (i
= 0; i
< count
; i
++) {
414 if (CFStringFindWithOptions(keys
[i
], path
, CFRangeMake(0, CFStringGetLength(keys
[i
])), kCFCompareAnchored
|kCFCompareCaseInsensitive
, NULL
)) CFDictionaryRemoveValue(cache
, keys
[i
]);
419 static void _CFBundleFlushContentsCachesForPath(CFStringRef path
) {
420 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
421 if (contentsCache
) _CFBundleFlushContentsCacheForPath(contentsCache
, path
);
422 if (directoryContentsCache
) _CFBundleFlushContentsCacheForPath(directoryContentsCache
, path
);
423 if (unknownContentsCache
) _CFBundleFlushContentsCacheForPath(unknownContentsCache
, path
);
424 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
427 #endif /* READ_DIRECTORIES */
429 CF_EXPORT
void _CFBundleFlushCachesForURL(CFURLRef url
) {
431 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
432 CFStringRef path
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
433 _CFBundleFlushContentsCachesForPath(path
);
435 CFRelease(absoluteURL
);
436 #endif /* READ_DIRECTORIES */
439 CF_EXPORT
void _CFBundleFlushCaches(void) {
441 _CFBundleFlushContentsCaches();
442 #endif /* READ_DIRECTORIES */
445 static inline Boolean
_CFIsResourceCommon(char *path
, Boolean
*isDir
) {
448 if (_CFGetPathProperties(kCFAllocatorSystemDefault
, path
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) {
449 if (isDir
) *isDir
= ((exists
&& ((mode
& S_IFMT
) == S_IFDIR
)) ? true : false);
450 return (exists
&& (mode
& 0444));
455 __private_extern__ Boolean
_CFIsResourceAtURL(CFURLRef url
, Boolean
*isDir
) {
456 char path
[CFMaxPathSize
];
457 if (!CFURLGetFileSystemRepresentation(url
, true, (uint8_t *)path
, CFMaxPathLength
)) return false;
459 return _CFIsResourceCommon(path
, isDir
);
462 __private_extern__ Boolean
_CFIsResourceAtPath(CFStringRef path
, Boolean
*isDir
) {
463 char pathBuf
[CFMaxPathSize
];
464 if (!CFStringGetFileSystemRepresentation(path
, pathBuf
, CFMaxPathSize
)) return false;
466 return _CFIsResourceCommon(pathBuf
, isDir
);
470 static CFArrayRef
_CFCopyTypesForSearchBundleDirectory(CFAllocatorRef alloc
, UniChar
*pathUniChars
, CFIndex pathLen
, UniChar
*nameUniChars
, CFIndex nameLen
, CFArrayRef resTypes
, CFMutableStringRef cheapStr
, CFMutableStringRef tmpString
, uint8_t version
) {
471 CFMutableArrayRef result
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
473 CFRange contentsRange
, resultRange
= CFRangeMake(0, 0);
474 CFIndex dirPathLen
= pathLen
, numResTypes
= CFArrayGetCount(resTypes
), i
, j
;
476 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, dirPathLen
, dirPathLen
);
477 CFStringReplaceAll(cheapStr
, tmpString
);
478 //fprintf(stderr, "looking in ");CFShow(cheapStr);
479 contents
= _CFBundleCopySortedDirectoryContentsAtPath(cheapStr
, _CFBundleAllContents
);
480 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
482 CFStringSetExternalCharactersNoCopy(tmpString
, nameUniChars
, nameLen
, nameLen
);
483 CFStringReplaceAll(cheapStr
, tmpString
);
484 for (i
= 0; i
< contentsRange
.length
; i
++) {
485 CFStringRef content
= CFArrayGetValueAtIndex(contents
, i
);
486 if (CFStringHasPrefix(content
, cheapStr
)) {
487 //fprintf(stderr, "found ");CFShow(content);
488 for (j
= 0; j
< numResTypes
; j
++) {
489 CFStringRef resType
= CFArrayGetValueAtIndex(resTypes
, j
);
490 if (!CFArrayContainsValue(result
, resultRange
, resType
) && CFStringHasSuffix(content
, resType
)) {
491 CFArrayAppendValue(result
, resType
);
492 resultRange
.length
= CFArrayGetCount(result
);
497 //fprintf(stderr, "result ");CFShow(result);
501 #endif /* READ_DIRECTORIES */
503 #if DEPLOYMENT_TARGET_EMBEDDED
504 static void _CFSearchBundleDirectory2(CFAllocatorRef alloc
, CFMutableArrayRef result
, UniChar
*pathUniChars
, CFIndex pathLen
, UniChar
*nameUniChars
, CFIndex nameLen
, UniChar
*typeUniChars
, CFIndex typeLen
, CFMutableStringRef cheapStr
, CFMutableStringRef tmpString
, uint8_t version
) {
505 // pathUniChars is the full path to the directory we are searching.
506 // nameUniChars is what we are looking for.
507 // typeUniChars is the type we are looking for.
508 // platformUniChars is the platform name.
509 // cheapStr is available for our use for whatever we want.
510 // URLs for found resources get added to result.
512 Boolean appendSucceeded
= true;
513 if (nameLen
> 0) appendSucceeded
= _CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, nameUniChars
, nameLen
);
514 if (! appendSucceeded
) return;
515 CFIndex savedPathLen
= pathLen
;
518 // NAME-PLATFORM~PRODUCT.TYPE (disabled for now)
520 // NAME-PLATFORM.TYPE (disabled for now)
524 appendSucceeded
= (pathLen
+ _ResourceSuffix3Len
< CFMaxPathSize
);
525 if (appendSucceeded
) {
526 memmove(pathUniChars
+ pathLen
, _ResourceSuffix3
, _ResourceSuffix3Len
* sizeof(UniChar
));
527 pathLen
+= _ResourceSuffix3Len
;
529 if (appendSucceeded
&& typeLen
> 0) appendSucceeded
= _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
530 if (appendSucceeded
) {
531 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
532 CFStringReplaceAll(cheapStr
, tmpString
);
533 Boolean Found
= false, IsDir
= false;
534 Found
= _CFIsResourceAtPath(cheapStr
, &IsDir
);
536 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, IsDir
);
537 CFArrayAppendValue(result
, url
);
544 pathLen
= savedPathLen
;
545 appendSucceeded
= (pathLen
+ _ResourceSuffix2Len
< CFMaxPathSize
);
546 if (appendSucceeded
) {
547 memmove(pathUniChars
+ pathLen
, _ResourceSuffix2
, _ResourceSuffix2Len
* sizeof(UniChar
));
548 pathLen
+= _ResourceSuffix2Len
;
550 if (appendSucceeded
&& typeLen
> 0) appendSucceeded
= _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
551 if (appendSucceeded
) {
552 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
553 CFStringReplaceAll(cheapStr
, tmpString
);
554 Boolean Found
= false, IsDir
= false;
555 Found
= _CFIsResourceAtPath(cheapStr
, &IsDir
);
557 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, IsDir
);
558 CFArrayAppendValue(result
, url
);
565 pathLen
= savedPathLen
;
566 appendSucceeded
= (pathLen
+ _ResourceSuffix1Len
< CFMaxPathSize
);
567 if (appendSucceeded
) {
568 memmove(pathUniChars
+ pathLen
, _ResourceSuffix1
, _ResourceSuffix1Len
* sizeof(UniChar
));
569 pathLen
+= _ResourceSuffix1Len
;
571 if (appendSucceeded
&& typeLen
> 0) appendSucceeded
= _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
572 if (appendSucceeded
) {
573 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
574 CFStringReplaceAll(cheapStr
, tmpString
);
575 Boolean Found
= false, IsDir
= false;
576 Found
= _CFIsResourceAtPath(cheapStr
, &IsDir
);
578 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, IsDir
);
579 CFArrayAppendValue(result
, url
);
586 pathLen
= savedPathLen
;
587 appendSucceeded
= true;
588 if (appendSucceeded
&& typeLen
> 0) appendSucceeded
= _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
589 if (appendSucceeded
) {
590 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
591 CFStringReplaceAll(cheapStr
, tmpString
);
592 Boolean Found
= false, IsDir
= false;
593 Found
= _CFIsResourceAtPath(cheapStr
, &IsDir
);
595 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, IsDir
);
596 CFArrayAppendValue(result
, url
);
604 static void _CFSearchBundleDirectory(CFAllocatorRef alloc
, CFMutableArrayRef result
, UniChar
*pathUniChars
, CFIndex pathLen
, UniChar
*nameUniChars
, CFIndex nameLen
, UniChar
*typeUniChars
, CFIndex typeLen
, CFMutableStringRef cheapStr
, CFMutableStringRef tmpString
, uint8_t version
) {
606 #if DEPLOYMENT_TARGET_EMBEDDED
607 _CFSearchBundleDirectory2(alloc
, result
, pathUniChars
, pathLen
, nameUniChars
, nameLen
, typeUniChars
, typeLen
, cheapStr
, tmpString
, version
);
609 // pathUniChars is the full path to the directory we are searching.
610 // nameUniChars is what we are looking for.
611 // typeUniChars is the type we are looking for.
612 // platformUniChars is the platform name.
613 // cheapStr is available for our use for whatever we want.
614 // URLs for found resources get added to result.
615 CFIndex savedPathLen
;
616 Boolean appendSucceeded
= true, platformGenericFound
= false, platformSpecificFound
= false, platformGenericIsDir
= false, platformSpecificIsDir
= false;
618 Boolean platformGenericIsUnknown
= false, platformSpecificIsUnknown
= false;
620 CFStringRef platformGenericStr
= NULL
;
623 CFIndex dirPathLen
= pathLen
;
624 CFArrayRef contents
, directoryContents
, unknownContents
;
625 CFRange contentsRange
, directoryContentsRange
, unknownContentsRange
;
627 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, dirPathLen
, dirPathLen
);
628 CFStringReplaceAll(cheapStr
, tmpString
);
629 //fprintf(stderr, "looking in ");CFShow(cheapStr);
630 contents
= _CFBundleCopySortedDirectoryContentsAtPath(cheapStr
, _CFBundleAllContents
);
631 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
632 directoryContents
= _CFBundleCopySortedDirectoryContentsAtPath(cheapStr
, _CFBundleDirectoryContents
);
633 directoryContentsRange
= CFRangeMake(0, CFArrayGetCount(directoryContents
));
634 unknownContents
= _CFBundleCopySortedDirectoryContentsAtPath(cheapStr
, _CFBundleUnknownContents
);
635 unknownContentsRange
= CFRangeMake(0, CFArrayGetCount(unknownContents
));
636 #endif /* READ_DIRECTORIES */
638 if (nameLen
> 0) appendSucceeded
= _CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, nameUniChars
, nameLen
);
639 savedPathLen
= pathLen
;
640 if (appendSucceeded
&& typeLen
> 0) appendSucceeded
= _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
641 if (appendSucceeded
) {
643 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ dirPathLen
+ 1, pathLen
- dirPathLen
- 1, pathLen
- dirPathLen
- 1);
644 CFStringReplaceAll(cheapStr
, tmpString
);
645 platformGenericFound
= _CFBundleSortedArrayContains(contents
, cheapStr
);
646 platformGenericIsDir
= _CFBundleSortedArrayContains(directoryContents
, cheapStr
);
647 platformGenericIsUnknown
= _CFBundleSortedArrayContains(unknownContents
, cheapStr
);
648 //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformGenericFound) fprintf(stderr, "found it\n"); if (platformGenericIsDir) fprintf(stderr, "a directory\n");
649 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
650 CFStringReplaceAll(cheapStr
, tmpString
);
651 if (platformGenericFound
&& platformGenericIsUnknown
) {
652 (void)_CFIsResourceAtPath(cheapStr
, &platformGenericIsDir
);
653 //if (platformGenericIsDir) fprintf(stderr, "a directory after all\n"); else fprintf(stderr, "not a directory after all\n");
655 #else /* READ_DIRECTORIES */
656 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
657 CFStringReplaceAll(cheapStr
, tmpString
);
658 platformGenericFound
= _CFIsResourceAtPath(cheapStr
, &platformGenericIsDir
);
659 #endif /* READ_DIRECTORIES */
662 // Check for platform specific.
663 if (platformGenericFound
) {
664 platformGenericStr
= (CFStringRef
)CFStringCreateCopy(kCFAllocatorSystemDefault
, cheapStr
);
665 if (!platformSpecificFound
&& (_PlatformLen
> 0)) {
666 pathLen
= savedPathLen
;
667 pathUniChars
[pathLen
++] = (UniChar
)'-';
668 memmove(pathUniChars
+ pathLen
, _PlatformUniChars
, _PlatformLen
* sizeof(UniChar
));
669 pathLen
+= _PlatformLen
;
670 if (appendSucceeded
&& typeLen
> 0) appendSucceeded
= _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
671 if (appendSucceeded
) {
673 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ dirPathLen
+ 1, pathLen
- dirPathLen
- 1, pathLen
- dirPathLen
- 1);
674 CFStringReplaceAll(cheapStr
, tmpString
);
675 platformSpecificFound
= _CFBundleSortedArrayContains(contents
, cheapStr
);
676 platformSpecificIsDir
= _CFBundleSortedArrayContains(directoryContents
, cheapStr
);
677 platformSpecificIsUnknown
= _CFBundleSortedArrayContains(unknownContents
, cheapStr
);
678 //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformSpecificFound) fprintf(stderr, "found it\n"); if (platformSpecificIsDir) fprintf(stderr, "a directory\n");
679 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
680 CFStringReplaceAll(cheapStr
, tmpString
);
681 if (platformSpecificFound
&& platformSpecificIsUnknown
) {
682 (void)_CFIsResourceAtPath(cheapStr
, &platformSpecificIsDir
);
683 //if (platformSpecificIsDir) fprintf(stderr, "a directory after all\n"); else fprintf(stderr, "not a directory after all\n");
685 #else /* READ_DIRECTORIES */
686 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
687 CFStringReplaceAll(cheapStr
, tmpString
);
688 platformSpecificFound
= _CFIsResourceAtPath(cheapStr
, &platformSpecificIsDir
);
689 #endif /* READ_DIRECTORIES */
693 if (platformSpecificFound
) {
694 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, platformSpecificIsDir
);
695 CFArrayAppendValue(result
, url
);
697 } else if (platformGenericFound
) {
698 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, platformGenericStr
? platformGenericStr
: cheapStr
, PLATFORM_PATH_STYLE
, platformGenericIsDir
);
699 CFArrayAppendValue(result
, url
);
702 if (platformGenericStr
) CFRelease(platformGenericStr
);
705 CFRelease(directoryContents
);
706 CFRelease(unknownContents
);
707 #endif /* READ_DIRECTORIES */
712 static void _CFSearchBundleDirectoryWithPredicate(CFAllocatorRef alloc
, CFMutableArrayRef result
, UniChar
*pathUniChars
, CFIndex dirPathLen
, Boolean (^predicate
)(CFStringRef filename
, Boolean
*stop
), CFMutableStringRef cheapStr
, CFMutableStringRef tmpString
, Boolean
*stopLooking
, uint8_t version
) {
714 // pathUniChars is the full path to the directory we are searching.
715 // platformUniChars is the platform name.
716 // predicate is a block that evaluates a given filename to see if it's a match.
717 // cheapStr is available for our use for whatever we want.
718 // URLs for found resources get added to result.
720 // get the contents of the directory
721 CFArrayRef contents
, directoryContents
, unknownContents
;
722 CFRange contentsRange
;
724 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, dirPathLen
, dirPathLen
);
725 CFStringReplaceAll(cheapStr
, tmpString
);
727 if (!_CFAppendTrailingPathSlash(pathUniChars
, &dirPathLen
, CFMaxPathSize
)) {
731 //fprintf(stderr, "looking in ");CFShow(cheapStr);
732 contents
= _CFBundleCopySortedDirectoryContentsAtPath(cheapStr
, _CFBundleAllContents
);
733 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
734 directoryContents
= _CFBundleCopySortedDirectoryContentsAtPath(cheapStr
, _CFBundleDirectoryContents
);
735 unknownContents
= _CFBundleCopySortedDirectoryContentsAtPath(cheapStr
, _CFBundleUnknownContents
);
737 // scan directory contents for matches against predicate
738 for (int i
= 0; i
< contentsRange
.length
; i
++) {
739 CFStringRef candidateFilename
= CFArrayGetValueAtIndex(contents
, i
);
740 if (predicate(candidateFilename
, stopLooking
)) {
741 // we want this resource, though possibly a platform specific version of it
742 // unpack candidateFilename string into pathUniChars after verifying that we have enough space in the buffer
743 CFIndex candidateFilenameLength
= CFStringGetLength(candidateFilename
);
744 if ((dirPathLen
+ candidateFilenameLength
< CFMaxPathSize
)) {
745 CFStringGetCharacters(candidateFilename
, CFRangeMake(0, candidateFilenameLength
), pathUniChars
+ dirPathLen
);
747 // is there a platform specific version available? if so update pathUniChars to contain it and candidateFilenameLength to describe its length.
748 static const int platformSeparatorLen
= 1; // the length of '-', as appears in foo-macos.tiff. sugar to make the following easier to read.
749 if (_PlatformLen
&& (dirPathLen
+ candidateFilenameLength
+ platformSeparatorLen
+ _PlatformLen
< CFMaxPathSize
)) {
750 CFIndex candidateFilenameWithoutExtensionLen
= _CFLengthAfterDeletingPathExtension(pathUniChars
+ dirPathLen
, candidateFilenameLength
);
751 CFIndex extensionLen
= candidateFilenameLength
- candidateFilenameWithoutExtensionLen
;
752 // shift the extension over to make space for the platform
753 memmove(pathUniChars
+ dirPathLen
+ candidateFilenameWithoutExtensionLen
+ platformSeparatorLen
+ _PlatformLen
, pathUniChars
+ dirPathLen
+ candidateFilenameWithoutExtensionLen
, extensionLen
* sizeof(UniChar
));
754 // write the platform into the middle of the string
755 pathUniChars
[dirPathLen
+ candidateFilenameWithoutExtensionLen
] = (UniChar
)'-';
756 memcpy(pathUniChars
+ dirPathLen
+ candidateFilenameWithoutExtensionLen
+ platformSeparatorLen
, _PlatformUniChars
, _PlatformLen
* sizeof(UniChar
));
757 // pack it up as a CFStringRef
758 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ dirPathLen
, candidateFilenameLength
+ platformSeparatorLen
+ _PlatformLen
, candidateFilenameLength
+ _PlatformLen
);
759 CFStringReplaceAll(cheapStr
, tmpString
);
760 // is the platform specialized version there?
761 if (_CFBundleSortedArrayContains(contents
, cheapStr
)) {
762 // woo. update the candidateFilenameLength. we'll update the candidateFilename too for consistency, but we don't actually use it again.
763 // the pathUniChars now contains the full path to the file
764 candidateFilename
= cheapStr
;
765 candidateFilenameLength
= candidateFilenameLength
+ _PlatformLen
+ platformSeparatorLen
;
767 // nope, no platform specific resource. Put the pathUniChars back how they were before, without the platform.
768 memmove(pathUniChars
+ dirPathLen
+ candidateFilenameWithoutExtensionLen
, pathUniChars
+ dirPathLen
+ candidateFilenameWithoutExtensionLen
+ platformSeparatorLen
+ _PlatformLen
, extensionLen
* sizeof(UniChar
));
772 // get the full path into cheapStr
773 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, dirPathLen
+ candidateFilenameLength
, dirPathLen
+ candidateFilenameLength
);
774 CFStringReplaceAll(cheapStr
, tmpString
);
776 // is the resource a directory? we need to know so that we can avoid file access when making a URL.
778 if (_CFBundleSortedArrayContains(directoryContents
, cheapStr
)) {
780 } else if (_CFBundleSortedArrayContains(unknownContents
, cheapStr
)) {
781 _CFIsResourceAtPath(cheapStr
, &isDir
);
784 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, isDir
);
785 CFArrayAppendValue(result
, url
);
790 if (*stopLooking
) break;
794 CFRelease(directoryContents
);
795 CFRelease(unknownContents
);
799 static void _CFFindBundleResourcesInRawDir(CFAllocatorRef alloc
, UniChar
*workingUniChars
, CFIndex workingLen
, UniChar
*nameUniChars
, CFIndex nameLen
, CFArrayRef resTypes
, CFIndex limit
, Boolean
*stopLooking
, Boolean (^predicate
)(CFStringRef filename
, Boolean
*stop
), uint8_t version
, CFMutableStringRef cheapStr
, CFMutableStringRef tmpString
, CFMutableArrayRef result
) {
802 _CFSearchBundleDirectoryWithPredicate(alloc
, result
, workingUniChars
, workingLen
, predicate
, cheapStr
, tmpString
, stopLooking
, version
);
805 CFLog(kCFLogLevelCritical
, CFSTR("_CFFindBundleResourcesInRawDir: predicate blocks are not supported on this platform"));
810 // If we have a resName, just call the search API. We may have to loop over the resTypes.
812 _CFSearchBundleDirectory(alloc
, result
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, NULL
, 0, cheapStr
, tmpString
, version
);
814 CFArrayRef subResTypes
= resTypes
;
815 Boolean releaseSubResTypes
= false;
816 CFIndex i
, c
= CFArrayGetCount(resTypes
);
819 // this is an optimization we employ when searching for large numbers of types, if the directory contents are available
820 // we scan the directory contents and restrict the list of resTypes to the types that might actually occur with the specified name
821 subResTypes
= _CFCopyTypesForSearchBundleDirectory(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, cheapStr
, tmpString
, version
);
822 c
= CFArrayGetCount(subResTypes
);
823 releaseSubResTypes
= true;
825 #endif /* READ_DIRECTORIES */
826 for (i
= 0; i
< c
; i
++) {
827 CFStringRef curType
= (CFStringRef
)CFArrayGetValueAtIndex(subResTypes
, i
);
828 CFIndex typeLen
= CFStringGetLength(curType
);
829 STACK_BUFFER_DECL(UniChar
, typeChars
, typeLen
);
830 CFStringGetCharacters(curType
, CFRangeMake(0, typeLen
), typeChars
);
831 _CFSearchBundleDirectory(alloc
, result
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, typeChars
, typeLen
, cheapStr
, tmpString
, version
);
832 if (limit
<= CFArrayGetCount(result
)) break;
834 if (releaseSubResTypes
) CFRelease(subResTypes
);
837 // If we have no resName, do it by hand. We may have to loop over the resTypes.
838 char cpathBuff
[CFMaxPathSize
];
840 CFMutableArrayRef children
;
842 CFStringSetExternalCharactersNoCopy(tmpString
, workingUniChars
, workingLen
, workingLen
);
843 if (!CFStringGetFileSystemRepresentation(tmpString
, cpathBuff
, CFMaxPathSize
)) return;
844 cpathLen
= strlen(cpathBuff
);
847 // ??? should this use _CFBundleCopyDirectoryContentsAtPath?
848 children
= _CFContentsOfDirectory(alloc
, cpathBuff
, NULL
, NULL
, NULL
);
850 CFIndex childIndex
, childCount
= CFArrayGetCount(children
);
851 for (childIndex
= 0; childIndex
< childCount
; childIndex
++) CFArrayAppendValue(result
, CFArrayGetValueAtIndex(children
, childIndex
));
855 CFIndex i
, c
= CFArrayGetCount(resTypes
);
856 for (i
= 0; i
< c
; i
++) {
857 CFStringRef curType
= (CFStringRef
)CFArrayGetValueAtIndex(resTypes
, i
);
859 // ??? should this use _CFBundleCopyDirectoryContentsAtPath?
860 children
= _CFContentsOfDirectory(alloc
, cpathBuff
, NULL
, NULL
, curType
);
862 CFIndex childIndex
, childCount
= CFArrayGetCount(children
);
863 for (childIndex
= 0; childIndex
< childCount
; childIndex
++) CFArrayAppendValue(result
, CFArrayGetValueAtIndex(children
, childIndex
));
866 if (limit
<= CFArrayGetCount(result
)) break;
872 static void _CFFindBundleResourcesInResourcesDir(CFAllocatorRef alloc
, UniChar
*workingUniChars
, CFIndex workingLen
, UniChar
*subDirUniChars
, CFIndex subDirLen
, CFArrayRef searchLanguages
, UniChar
*nameUniChars
, CFIndex nameLen
, CFArrayRef resTypes
, CFIndex limit
, Boolean (^predicate
)(CFStringRef filename
, Boolean
*stop
), uint8_t version
, CFMutableStringRef cheapStr
, CFMutableStringRef tmpString
, CFMutableArrayRef result
) {
873 CFIndex savedWorkingLen
= workingLen
;
874 Boolean stopLooking
= false; // for predicate based-queries, we set stopLooking instead of using a limit
875 // Look directly in the directory specified in workingUniChars. as if it is a Resources directory.
877 // Add the non-localized resource directory.
878 Boolean appendSucceeded
= _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _GlobalResourcesUniChars
, _GlobalResourcesLen
);
879 if (appendSucceeded
&& subDirLen
> 0) appendSucceeded
= _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
);
880 if (appendSucceeded
) _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, &stopLooking
, predicate
, version
, cheapStr
, tmpString
, result
);
881 // Strip the non-localized resource directory.
882 workingLen
= savedWorkingLen
;
884 if (CFArrayGetCount(result
) < limit
&& !stopLooking
) {
885 Boolean appendSucceeded
= true;
886 if (subDirLen
> 0) appendSucceeded
= _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
);
887 if (appendSucceeded
) _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, &stopLooking
, predicate
, version
, cheapStr
, tmpString
, result
);
890 // Now search the local resources.
891 workingLen
= savedWorkingLen
;
892 if (CFArrayGetCount(result
) < limit
&& !stopLooking
) {
893 CFIndex langCount
= (searchLanguages
? CFArrayGetCount(searchLanguages
) : 0);
894 // MF:??? OK to hard-wire this length?
895 UniChar curLangUniChars
[255];
896 CFIndex numResults
= CFArrayGetCount(result
);
898 for (CFIndex langIndex
= 0; langIndex
< langCount
; langIndex
++) {
899 CFStringRef curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(searchLanguages
, langIndex
);
900 CFIndex curLangLen
= CFStringGetLength(curLangStr
);
901 if (curLangLen
> 255) curLangLen
= 255;
902 CFStringGetCharacters(curLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
903 savedWorkingLen
= workingLen
;
904 if (!_CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
)) {
905 workingLen
= savedWorkingLen
;
908 if (!_CFAppendPathExtension(workingUniChars
, &workingLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
909 workingLen
= savedWorkingLen
;
913 if (!_CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
)) {
914 workingLen
= savedWorkingLen
;
918 _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, &stopLooking
, predicate
, version
, cheapStr
, tmpString
, result
);
920 // Back off this lproj component
921 workingLen
= savedWorkingLen
;
922 if (CFArrayGetCount(result
) != numResults
) {
923 // We found resources in a language we already searched. Don't look any farther.
924 // We also don't need to check the limit, since if the count changed at all, we are bailing.
931 extern void _CFStrSetDesiredCapacity(CFMutableStringRef str
, CFIndex len
);
933 CFArrayRef
_CFFindBundleResources(CFBundleRef bundle
, CFURLRef bundleURL
, CFStringRef subDirName
, CFArrayRef searchLanguages
, CFStringRef resName
, CFArrayRef resTypes
, CFIndex limit
, Boolean (^predicate
)(CFStringRef filename
, Boolean
*stop
), uint8_t version
) {
934 CFMutableArrayRef result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
936 // Build an absolute path to the base directory.
937 // If no URL was passed, we get it from the bundle.
938 CFURLRef baseURL
= bundleURL
? (CFURLRef
)CFRetain(bundleURL
) : (bundle
? CFBundleCopyBundleURL(bundle
) : NULL
);
939 CFURLRef absoluteURL
= baseURL
? CFURLCopyAbsoluteURL(baseURL
) : NULL
;
940 CFStringRef basePath
= absoluteURL
? CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
) : NULL
;
941 if (absoluteURL
) CFRelease(absoluteURL
);
942 if (baseURL
) CFRelease(baseURL
);
943 baseURL
= absoluteURL
= bundleURL
= NULL
;
945 // bundle and bundleURL arguments are not used any further
947 if (!basePath
) return result
;
950 UniChar
*workingUniChars
, *nameUniChars
, *subDirUniChars
;
952 CFIndex workingLen
, savedWorkingLen
;
953 CFMutableStringRef cheapStr
, tmpString
;
956 char buff
[CFMaxPathSize
];
957 CFStringRef newResName
= NULL
;
958 if (CFStringGetFileSystemRepresentation(resName
, buff
, CFMaxPathSize
)) newResName
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
959 resName
= newResName
? newResName
: (CFStringRef
)CFRetain(resName
);
960 nameLen
= CFStringGetLength(resName
);
963 // Init the one-time-only unichar buffers.
964 _CFEnsureStaticBuffersInited();
966 // Build UniChar buffers for some of the string pieces we need.
967 CFIndex subDirLen
= (subDirName
? CFStringGetLength(subDirName
) : 0);
968 nameUniChars
= (UniChar
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(UniChar
) * (nameLen
+ subDirLen
+ CFMaxPathSize
), 0);
970 subDirUniChars
= nameUniChars
+ nameLen
;
971 workingUniChars
= subDirUniChars
+ subDirLen
;
973 if (nameLen
> 0) CFStringGetCharacters(resName
, CFRangeMake(0, nameLen
), nameUniChars
);
974 if (subDirLen
> 0) CFStringGetCharacters(subDirName
, CFRangeMake(0, subDirLen
), subDirUniChars
);
976 if ((workingLen
= CFStringGetLength(basePath
)) > 0) CFStringGetCharacters(basePath
, CFRangeMake(0, workingLen
), workingUniChars
);
977 savedWorkingLen
= workingLen
;
979 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _AppSupportUniChars1
, _AppSupportLen1
);
980 } else if (2 == version
) {
981 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _AppSupportUniChars2
, _AppSupportLen2
);
983 if (0 == version
|| 1 == version
|| 2 == version
) _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _ResourcesUniChars
, _ResourcesLen
);
985 // both of these used for temp string operations, for slightly different purposes, where each type is appropriate
986 cheapStr
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
987 _CFStrSetDesiredCapacity(cheapStr
, CFMaxPathSize
);
988 tmpString
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, kCFAllocatorNull
);
990 _CFFindBundleResourcesInResourcesDir(kCFAllocatorSystemDefault
, workingUniChars
, workingLen
, subDirUniChars
, subDirLen
, searchLanguages
, nameUniChars
, nameLen
, resTypes
, limit
, predicate
, version
, cheapStr
, tmpString
, result
);
992 // drd: This unfortunate hack is still necessary because of installer packages and Spotlight importers
993 if (CFArrayGetCount(result
) == 0 && (0 == version
|| (2 == version
&& CFEqual(CFSTR("/Library/Spotlight"), basePath
)))) {
994 // Try looking directly in the bundle path
995 workingLen
= savedWorkingLen
;
996 _CFFindBundleResourcesInResourcesDir(kCFAllocatorSystemDefault
, workingUniChars
, workingLen
, subDirUniChars
, subDirLen
, searchLanguages
, nameUniChars
, nameLen
, resTypes
, limit
, predicate
, version
, cheapStr
, tmpString
, result
);
1000 CFRelease(tmpString
);
1001 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, nameUniChars
);
1003 if (resName
) CFRelease(resName
);
1004 if (basePath
) CFRelease(basePath
);
1008 CF_EXPORT CFURLRef
CFBundleCopyResourceURL(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
) {
1011 CFURLRef result
= NULL
;
1012 CFArrayRef languages
= _CFBundleGetLanguageSearchList(bundle
), types
= NULL
, array
;
1013 if (resourceType
) types
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
1014 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, resourceName
, types
, 1, NULL
, _CFBundleLayoutVersion(bundle
));
1015 if (types
) CFRelease(types
);
1017 if (CFArrayGetCount(array
) > 0) result
= (CFURLRef
)CFRetain(CFArrayGetValueAtIndex(array
, 0));
1023 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfType(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
) {
1024 CFArrayRef languages
= _CFBundleGetLanguageSearchList(bundle
), types
= NULL
, array
;
1025 if (resourceType
) types
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
1026 // MF:!!! Better "limit" than 1,000,000?
1027 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, NULL
, types
, 1000000, NULL
, _CFBundleLayoutVersion(bundle
));
1028 if (types
) CFRelease(types
);
1033 CF_EXPORT CFURLRef
_CFBundleCopyResourceURLForLanguage(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef language
) {
1034 return CFBundleCopyResourceURLForLocalization(bundle
, resourceName
, resourceType
, subDirName
, language
);
1037 CF_EXPORT CFURLRef
CFBundleCopyResourceURLForLocalization(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef localizationName
) {
1038 CFURLRef result
= NULL
;
1039 CFArrayRef languages
= NULL
, types
= NULL
, array
;
1041 if (localizationName
) languages
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&localizationName
, 1, &kCFTypeArrayCallBacks
);
1042 if (resourceType
) types
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
1043 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, resourceName
, types
, 1, NULL
, _CFBundleLayoutVersion(bundle
));
1045 if (CFArrayGetCount(array
) > 0) result
= (CFURLRef
)CFRetain(CFArrayGetValueAtIndex(array
, 0));
1048 if (types
) CFRelease(types
);
1049 if (languages
) CFRelease(languages
);
1053 CF_EXPORT CFArrayRef
_CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef language
) {
1054 return CFBundleCopyResourceURLsOfTypeForLocalization(bundle
, resourceType
, subDirName
, language
);
1057 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef localizationName
) {
1058 CFArrayRef languages
= NULL
, types
= NULL
, array
;
1060 if (localizationName
) languages
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&localizationName
, 1, &kCFTypeArrayCallBacks
);
1061 if (resourceType
) types
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
1062 // MF:!!! Better "limit" than 1,000,000?
1063 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, NULL
, types
, 1000000, NULL
, _CFBundleLayoutVersion(bundle
));
1064 if (types
) CFRelease(types
);
1065 if (languages
) CFRelease(languages
);
1070 CF_EXPORT CFStringRef
CFBundleCopyLocalizedString(CFBundleRef bundle
, CFStringRef key
, CFStringRef value
, CFStringRef tableName
) {
1071 CFStringRef result
= NULL
;
1072 CFDictionaryRef stringTable
= NULL
;
1073 static CFSpinLock_t CFBundleLocalizedStringLock
= CFSpinLockInit
;
1075 if (!key
) return (value
? (CFStringRef
)CFRetain(value
) : (CFStringRef
)CFRetain(CFSTR("")));
1077 if (!tableName
|| CFEqual(tableName
, CFSTR(""))) tableName
= _CFBundleDefaultStringTableName
;
1079 __CFSpinLock(&CFBundleLocalizedStringLock
);
1080 if (__CFBundleGetResourceData(bundle
)->_stringTableCache
) {
1081 stringTable
= (CFDictionaryRef
)CFDictionaryGetValue(__CFBundleGetResourceData(bundle
)->_stringTableCache
, tableName
);
1082 if (stringTable
) CFRetain(stringTable
);
1084 __CFSpinUnlock(&CFBundleLocalizedStringLock
);
1087 // Go load the table.
1088 CFURLRef tableURL
= CFBundleCopyResourceURL(bundle
, tableName
, _CFBundleStringTableType
, NULL
);
1090 CFStringRef nameForSharing
= NULL
;
1092 CFDataRef tableData
= NULL
;
1095 if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault
, tableURL
, &tableData
, NULL
, NULL
, &errCode
)) {
1096 stringTable
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(CFGetAllocator(bundle
), tableData
, kCFPropertyListImmutable
, &errStr
);
1101 if (stringTable
&& CFDictionaryGetTypeID() != CFGetTypeID(stringTable
)) {
1102 CFRelease(stringTable
);
1105 CFRelease(tableData
);
1109 if (nameForSharing
) CFRelease(nameForSharing
);
1110 if (tableURL
) CFRelease(tableURL
);
1112 if (!stringTable
) stringTable
= CFDictionaryCreate(CFGetAllocator(bundle
), NULL
, NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1114 if (!CFStringHasSuffix(tableName
, CFSTR(".nocache")) || !_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard
)) {
1115 __CFSpinLock(&CFBundleLocalizedStringLock
);
1116 if (!__CFBundleGetResourceData(bundle
)->_stringTableCache
) __CFBundleGetResourceData(bundle
)->_stringTableCache
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1117 CFDictionarySetValue(__CFBundleGetResourceData(bundle
)->_stringTableCache
, tableName
, stringTable
);
1118 __CFSpinUnlock(&CFBundleLocalizedStringLock
);
1122 result
= (CFStringRef
)CFDictionaryGetValue(stringTable
, key
);
1124 static int capitalize
= -1;
1126 result
= (CFStringRef
)CFRetain(key
);
1127 } else if (CFEqual(value
, CFSTR(""))) {
1128 result
= (CFStringRef
)CFRetain(key
);
1130 result
= (CFStringRef
)CFRetain(value
);
1132 if (capitalize
!= 0) {
1133 if (capitalize
!= 0) {
1134 CFMutableStringRef capitalizedResult
= CFStringCreateMutableCopy(kCFAllocatorSystemDefault
, 0, result
);
1135 CFLog(__kCFLogBundle
, CFSTR("Localizable string \"%@\" not found in strings table \"%@\" of bundle %@."), key
, tableName
, bundle
);
1136 CFStringUppercase(capitalizedResult
, NULL
);
1138 result
= capitalizedResult
;
1144 CFRelease(stringTable
);
1148 CF_EXPORT CFURLRef
CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
) {
1149 CFURLRef result
= NULL
;
1150 unsigned char buff
[CFMaxPathSize
];
1151 CFURLRef newURL
= NULL
;
1153 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
1155 newURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
, strlen((char *)buff
), true);
1156 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
1157 if (_CFBundleCouldBeBundle(newURL
)) {
1158 uint8_t version
= 0;
1159 CFArrayRef languages
= _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault
, newURL
, &version
), types
= NULL
, array
;
1160 if (resourceType
) types
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
1161 array
= _CFFindBundleResources(NULL
, newURL
, subDirName
, languages
, resourceName
, types
, 1, NULL
, version
);
1162 if (types
) CFRelease(types
);
1163 if (languages
) CFRelease(languages
);
1165 if (CFArrayGetCount(array
) > 0) result
= (CFURLRef
)CFRetain(CFArrayGetValueAtIndex(array
, 0));
1169 if (newURL
) CFRelease(newURL
);
1173 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleURL
, CFStringRef resourceType
, CFStringRef subDirName
) {
1174 CFArrayRef array
= NULL
;
1175 unsigned char buff
[CFMaxPathSize
];
1176 CFURLRef newURL
= NULL
;
1178 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
1180 newURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
, strlen((char *)buff
), true);
1181 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
1182 if (_CFBundleCouldBeBundle(newURL
)) {
1183 uint8_t version
= 0;
1184 CFArrayRef languages
= _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault
, newURL
, &version
), types
= NULL
;
1185 if (resourceType
) types
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
1186 // MF:!!! Better "limit" than 1,000,000?
1187 array
= _CFFindBundleResources(NULL
, newURL
, subDirName
, languages
, NULL
, types
, 1000000, NULL
, version
);
1188 if (types
) CFRelease(types
);
1189 if (languages
) CFRelease(languages
);
1191 if (newURL
) CFRelease(newURL
);
1195 // string, with groups of 6 characters being 1 element in the array of locale abbreviations
1196 const char * __CFBundleLocaleAbbreviationsArray
=
1197 "en_US\0" "fr_FR\0" "en_GB\0" "de_DE\0" "it_IT\0" "nl_NL\0" "nl_BE\0" "sv_SE\0"
1198 "es_ES\0" "da_DK\0" "pt_PT\0" "fr_CA\0" "nb_NO\0" "he_IL\0" "ja_JP\0" "en_AU\0"
1199 "ar\0\0\0\0" "fi_FI\0" "fr_CH\0" "de_CH\0" "el_GR\0" "is_IS\0" "mt_MT\0" "el_CY\0"
1200 "tr_TR\0" "hr_HR\0" "nl_NL\0" "nl_BE\0" "en_CA\0" "en_CA\0" "pt_PT\0" "nb_NO\0"
1201 "da_DK\0" "hi_IN\0" "ur_PK\0" "tr_TR\0" "it_CH\0" "en\0\0\0\0" "\0\0\0\0\0\0" "ro_RO\0"
1202 "grc\0\0\0" "lt_LT\0" "pl_PL\0" "hu_HU\0" "et_EE\0" "lv_LV\0" "se\0\0\0\0" "fo_FO\0"
1203 "fa_IR\0" "ru_RU\0" "ga_IE\0" "ko_KR\0" "zh_CN\0" "zh_TW\0" "th_TH\0" "\0\0\0\0\0\0"
1204 "cs_CZ\0" "sk_SK\0" "\0\0\0\0\0\0" "hu_HU\0" "bn\0\0\0\0" "be_BY\0" "uk_UA\0" "\0\0\0\0\0\0"
1205 "el_GR\0" "sr_CS\0" "sl_SI\0" "mk_MK\0" "hr_HR\0" "\0\0\0\0\0\0" "de_DE\0" "pt_BR\0"
1206 "bg_BG\0" "ca_ES\0" "\0\0\0\0\0\0" "gd\0\0\0\0" "gv\0\0\0\0" "br\0\0\0\0" "iu_CA\0" "cy\0\0\0\0"
1207 "en_CA\0" "ga_IE\0" "en_CA\0" "dz_BT\0" "hy_AM\0" "ka_GE\0" "es_XL\0" "es_ES\0"
1208 "to_TO\0" "pl_PL\0" "ca_ES\0" "fr\0\0\0\0" "de_AT\0" "es_XL\0" "gu_IN\0" "pa\0\0\0\0"
1209 "ur_IN\0" "vi_VN\0" "fr_BE\0" "uz_UZ\0" "en_SG\0" "nn_NO\0" "af_ZA\0" "eo\0\0\0\0"
1210 "mr_IN\0" "bo\0\0\0\0" "ne_NP\0" "kl\0\0\0\0" "en_IE\0";
1212 #define NUM_LOCALE_ABBREVIATIONS 109
1213 #define LOCALE_ABBREVIATION_LENGTH 6
1215 static const char * const __CFBundleLanguageNamesArray
[] = {
1216 "English", "French", "German", "Italian", "Dutch", "Swedish", "Spanish", "Danish",
1217 "Portuguese", "Norwegian", "Hebrew", "Japanese", "Arabic", "Finnish", "Greek", "Icelandic",
1218 "Maltese", "Turkish", "Croatian", "Chinese", "Urdu", "Hindi", "Thai", "Korean",
1219 "Lithuanian", "Polish", "Hungarian", "Estonian", "Latvian", "Sami", "Faroese", "Farsi",
1220 "Russian", "Chinese", "Dutch", "Irish", "Albanian", "Romanian", "Czech", "Slovak",
1221 "Slovenian", "Yiddish", "Serbian", "Macedonian", "Bulgarian", "Ukrainian", "Byelorussian", "Uzbek",
1222 "Kazakh", "Azerbaijani", "Azerbaijani", "Armenian", "Georgian", "Moldavian", "Kirghiz", "Tajiki",
1223 "Turkmen", "Mongolian", "Mongolian", "Pashto", "Kurdish", "Kashmiri", "Sindhi", "Tibetan",
1224 "Nepali", "Sanskrit", "Marathi", "Bengali", "Assamese", "Gujarati", "Punjabi", "Oriya",
1225 "Malayalam", "Kannada", "Tamil", "Telugu", "Sinhalese", "Burmese", "Khmer", "Lao",
1226 "Vietnamese", "Indonesian", "Tagalog", "Malay", "Malay", "Amharic", "Tigrinya", "Oromo",
1227 "Somali", "Swahili", "Kinyarwanda", "Rundi", "Nyanja", "Malagasy", "Esperanto", "",
1228 "", "", "", "", "", "", "", "",
1229 "", "", "", "", "", "", "", "",
1230 "", "", "", "", "", "", "", "",
1231 "", "", "", "", "", "", "", "",
1232 "Welsh", "Basque", "Catalan", "Latin", "Quechua", "Guarani", "Aymara", "Tatar",
1233 "Uighur", "Dzongkha", "Javanese", "Sundanese", "Galician", "Afrikaans", "Breton", "Inuktitut",
1234 "Scottish", "Manx", "Irish", "Tongan", "Greek", "Greenlandic", "Azerbaijani", "Nynorsk"
1237 #define NUM_LANGUAGE_NAMES 152
1238 #define LANGUAGE_NAME_LENGTH 13
1240 // string, with groups of 3 characters being 1 element in the array of abbreviations
1241 const char * __CFBundleLanguageAbbreviationsArray
=
1242 "en\0" "fr\0" "de\0" "it\0" "nl\0" "sv\0" "es\0" "da\0"
1243 "pt\0" "nb\0" "he\0" "ja\0" "ar\0" "fi\0" "el\0" "is\0"
1244 "mt\0" "tr\0" "hr\0" "zh\0" "ur\0" "hi\0" "th\0" "ko\0"
1245 "lt\0" "pl\0" "hu\0" "et\0" "lv\0" "se\0" "fo\0" "fa\0"
1246 "ru\0" "zh\0" "nl\0" "ga\0" "sq\0" "ro\0" "cs\0" "sk\0"
1247 "sl\0" "yi\0" "sr\0" "mk\0" "bg\0" "uk\0" "be\0" "uz\0"
1248 "kk\0" "az\0" "az\0" "hy\0" "ka\0" "mo\0" "ky\0" "tg\0"
1249 "tk\0" "mn\0" "mn\0" "ps\0" "ku\0" "ks\0" "sd\0" "bo\0"
1250 "ne\0" "sa\0" "mr\0" "bn\0" "as\0" "gu\0" "pa\0" "or\0"
1251 "ml\0" "kn\0" "ta\0" "te\0" "si\0" "my\0" "km\0" "lo\0"
1252 "vi\0" "id\0" "tl\0" "ms\0" "ms\0" "am\0" "ti\0" "om\0"
1253 "so\0" "sw\0" "rw\0" "rn\0" "\0\0\0" "mg\0" "eo\0" "\0\0\0"
1254 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
1255 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
1256 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
1257 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
1258 "cy\0" "eu\0" "ca\0" "la\0" "qu\0" "gn\0" "ay\0" "tt\0"
1259 "ug\0" "dz\0" "jv\0" "su\0" "gl\0" "af\0" "br\0" "iu\0"
1260 "gd\0" "gv\0" "ga\0" "to\0" "el\0" "kl\0" "az\0" "nn\0";
1262 #define NUM_LANGUAGE_ABBREVIATIONS 152
1263 #define LANGUAGE_ABBREVIATION_LENGTH 3
1265 #if defined(__CONSTANT_CFSTRINGS__)
1267 // These are not necessarily common localizations per se, but localizations for which the full language name is still in common use.
1268 // These are used to provide a fast path for it (other localizations usually use the abbreviation, which is even faster).
1269 static CFStringRef
const __CFBundleCommonLanguageNamesArray
[] = {CFSTR("English"), CFSTR("French"), CFSTR("German"), CFSTR("Italian"), CFSTR("Dutch"), CFSTR("Spanish"), CFSTR("Japanese")};
1270 static CFStringRef
const __CFBundleCommonLanguageAbbreviationsArray
[] = {CFSTR("en"), CFSTR("fr"), CFSTR("de"), CFSTR("it"), CFSTR("nl"), CFSTR("es"), CFSTR("ja")};
1272 #define NUM_COMMON_LANGUAGE_NAMES 7
1274 #endif /* __CONSTANT_CFSTRINGS__ */
1276 static const SInt32 __CFBundleScriptCodesArray
[] = {
1277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 6, 0,
1278 0, 0, 0, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 0, 4,
1279 7, 25, 0, 0, 0, 0, 29, 29, 0, 5, 7, 7, 7, 7, 7, 7,
1280 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
1281 9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
1282 30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
1283 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1284 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1285 0, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 0, 28,
1286 0, 0, 0, 0, 6, 0, 0, 0
1289 static const CFStringEncoding __CFBundleStringEncodingsArray
[] = {
1290 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 6, 37,
1291 0, 35, 36, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 37, 0x8C,
1292 7, 25, 0, 39, 0, 38, 29, 29, 36, 5, 7, 7, 7, 0x98, 7, 7,
1293 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
1294 9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
1295 30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
1296 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1297 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1298 39, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 39, 0xEC,
1299 39, 39, 40, 0, 6, 0, 0, 0
1302 static SInt32
_CFBundleGetLanguageCodeForLocalization(CFStringRef localizationName
) {
1303 SInt32 result
= -1, i
;
1305 CFIndex length
= CFStringGetLength(localizationName
);
1306 if (length
>= LANGUAGE_ABBREVIATION_LENGTH
- 1 && length
<= 255 && CFStringGetCString(localizationName
, buff
, 255, kCFStringEncodingASCII
)) {
1308 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_NAMES
; i
++) {
1309 if (0 == strcmp(buff
, __CFBundleLanguageNamesArray
[i
])) result
= i
;
1311 if (0 == strcmp(buff
, "zh_TW") || 0 == strcmp(buff
, "zh-Hant")) result
= 19; else if (0 == strcmp(buff
, "zh_CN") || 0 == strcmp(buff
, "zh-Hans")) result
= 33; // hack for mixed-up Chinese language codes
1312 if (-1 == result
&& (length
== LANGUAGE_ABBREVIATION_LENGTH
- 1 || !isalpha(buff
[LANGUAGE_ABBREVIATION_LENGTH
- 1]))) {
1313 buff
[LANGUAGE_ABBREVIATION_LENGTH
- 1] = '\0';
1314 if ('n' == buff
[0] && 'o' == buff
[1]) result
= 9; // hack for Norwegian
1315 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_ABBREVIATIONS
* LANGUAGE_ABBREVIATION_LENGTH
; i
+= LANGUAGE_ABBREVIATION_LENGTH
) {
1316 if (buff
[0] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 0) && buff
[1] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 1)) result
= i
/ LANGUAGE_ABBREVIATION_LENGTH
;
1323 static CFStringRef
_CFBundleCopyLanguageAbbreviationForLanguageCode(SInt32 languageCode
) {
1324 CFStringRef result
= NULL
;
1325 if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_ABBREVIATIONS
) {
1326 const char *languageAbbreviation
= __CFBundleLanguageAbbreviationsArray
+ languageCode
* LANGUAGE_ABBREVIATION_LENGTH
;
1327 if (languageAbbreviation
&& *languageAbbreviation
!= '\0') result
= CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault
, languageAbbreviation
, kCFStringEncodingASCII
, kCFAllocatorNull
);
1332 CF_INLINE CFStringRef
_CFBundleCopyLanguageNameForLanguageCode(SInt32 languageCode
) {
1333 CFStringRef result
= NULL
;
1334 if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_NAMES
) {
1335 const char *languageName
= __CFBundleLanguageNamesArray
[languageCode
];
1336 if (languageName
&& *languageName
!= '\0') result
= CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault
, languageName
, kCFStringEncodingASCII
, kCFAllocatorNull
);
1341 CF_INLINE CFStringRef
_CFBundleCopyLanguageAbbreviationForLocalization(CFStringRef localizationName
) {
1342 CFStringRef result
= NULL
;
1343 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1344 if (languageCode
>= 0) {
1345 result
= _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode
);
1347 CFIndex length
= CFStringGetLength(localizationName
);
1348 if (length
== LANGUAGE_ABBREVIATION_LENGTH
- 1 || (length
> LANGUAGE_ABBREVIATION_LENGTH
- 1 && CFStringGetCharacterAtIndex(localizationName
, LANGUAGE_ABBREVIATION_LENGTH
- 1) == '_')) {
1349 result
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, localizationName
, CFRangeMake(0, LANGUAGE_ABBREVIATION_LENGTH
- 1));
1355 CF_INLINE CFStringRef
_CFBundleCopyModifiedLocalization(CFStringRef localizationName
) {
1356 CFMutableStringRef result
= NULL
;
1357 CFIndex length
= CFStringGetLength(localizationName
);
1359 UniChar c
= CFStringGetCharacterAtIndex(localizationName
, 2);
1360 if ('-' == c
|| '_' == c
) {
1361 result
= CFStringCreateMutableCopy(kCFAllocatorSystemDefault
, length
, localizationName
);
1362 CFStringReplace(result
, CFRangeMake(2, 1), ('-' == c
) ? CFSTR("_") : CFSTR("-"));
1368 CF_INLINE CFStringRef
_CFBundleCopyLanguageNameForLocalization(CFStringRef localizationName
) {
1369 CFStringRef result
= NULL
;
1370 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1371 if (languageCode
>= 0) {
1372 result
= _CFBundleCopyLanguageNameForLanguageCode(languageCode
);
1374 result
= (CFStringRef
)CFStringCreateCopy(kCFAllocatorSystemDefault
, localizationName
);
1379 static SInt32
_CFBundleGetLanguageCodeForRegionCode(SInt32 regionCode
) {
1380 SInt32 result
= -1, i
;
1381 if (52 == regionCode
) { // hack for mixed-up Chinese language codes
1383 } else if (0 <= regionCode
&& regionCode
< NUM_LOCALE_ABBREVIATIONS
) {
1384 const char *localeAbbreviation
= __CFBundleLocaleAbbreviationsArray
+ regionCode
* LOCALE_ABBREVIATION_LENGTH
;
1385 if (localeAbbreviation
&& *localeAbbreviation
!= '\0') {
1386 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_ABBREVIATIONS
* LANGUAGE_ABBREVIATION_LENGTH
; i
+= LANGUAGE_ABBREVIATION_LENGTH
) {
1387 if (localeAbbreviation
[0] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 0) && localeAbbreviation
[1] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 1)) result
= i
/ LANGUAGE_ABBREVIATION_LENGTH
;
1394 static SInt32
_CFBundleGetRegionCodeForLanguageCode(SInt32 languageCode
) {
1395 SInt32 result
= -1, i
;
1396 if (19 == languageCode
) { // hack for mixed-up Chinese language codes
1398 } else if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_ABBREVIATIONS
) {
1399 const char *languageAbbreviation
= __CFBundleLanguageAbbreviationsArray
+ languageCode
* LANGUAGE_ABBREVIATION_LENGTH
;
1400 if (languageAbbreviation
&& *languageAbbreviation
!= '\0') {
1401 for (i
= 0; -1 == result
&& i
< NUM_LOCALE_ABBREVIATIONS
* LOCALE_ABBREVIATION_LENGTH
; i
+= LOCALE_ABBREVIATION_LENGTH
) {
1402 if (*(__CFBundleLocaleAbbreviationsArray
+ i
+ 0) == languageAbbreviation
[0] && *(__CFBundleLocaleAbbreviationsArray
+ i
+ 1) == languageAbbreviation
[1]) result
= i
/ LOCALE_ABBREVIATION_LENGTH
;
1406 if (25 == result
) result
= 68;
1407 if (28 == result
) result
= 82;
1411 static SInt32
_CFBundleGetRegionCodeForLocalization(CFStringRef localizationName
) {
1412 SInt32 result
= -1, i
;
1413 char buff
[LOCALE_ABBREVIATION_LENGTH
];
1414 CFIndex length
= CFStringGetLength(localizationName
);
1415 if (length
>= LANGUAGE_ABBREVIATION_LENGTH
- 1 && length
<= LOCALE_ABBREVIATION_LENGTH
- 1 && CFStringGetCString(localizationName
, buff
, LOCALE_ABBREVIATION_LENGTH
, kCFStringEncodingASCII
)) {
1416 buff
[LOCALE_ABBREVIATION_LENGTH
- 1] = '\0';
1417 for (i
= 0; -1 == result
&& i
< NUM_LOCALE_ABBREVIATIONS
* LOCALE_ABBREVIATION_LENGTH
; i
+= LOCALE_ABBREVIATION_LENGTH
) {
1418 if (0 == strcmp(buff
, __CFBundleLocaleAbbreviationsArray
+ i
)) result
= i
/ LOCALE_ABBREVIATION_LENGTH
;
1421 if (25 == result
) result
= 68;
1422 if (28 == result
) result
= 82;
1423 if (37 == result
) result
= 0;
1425 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1426 result
= _CFBundleGetRegionCodeForLanguageCode(languageCode
);
1431 static CFStringRef
_CFBundleCopyLocaleAbbreviationForRegionCode(SInt32 regionCode
) {
1432 CFStringRef result
= NULL
;
1433 if (0 <= regionCode
&& regionCode
< NUM_LOCALE_ABBREVIATIONS
) {
1434 const char *localeAbbreviation
= __CFBundleLocaleAbbreviationsArray
+ regionCode
* LOCALE_ABBREVIATION_LENGTH
;
1435 if (localeAbbreviation
&& *localeAbbreviation
!= '\0') {
1436 result
= CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault
, localeAbbreviation
, kCFStringEncodingASCII
, kCFAllocatorNull
);
1442 Boolean
CFBundleGetLocalizationInfoForLocalization(CFStringRef localizationName
, SInt32
*languageCode
, SInt32
*regionCode
, SInt32
*scriptCode
, CFStringEncoding
*stringEncoding
) {
1443 Boolean retval
= false;
1444 SInt32 language
= -1, region
= -1, script
= 0;
1445 CFStringEncoding encoding
= kCFStringEncodingMacRoman
;
1446 if (!localizationName
) {
1447 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1448 CFArrayRef languages
= NULL
;
1450 languages
= _CFBundleGetLanguageSearchList(mainBundle
);
1451 if (languages
) CFRetain(languages
);
1453 if (!languages
) languages
= _CFBundleCopyUserLanguages(false);
1454 if (languages
&& CFArrayGetCount(languages
) > 0) localizationName
= (CFStringRef
)CFArrayGetValueAtIndex(languages
, 0);
1456 if (localizationName
) {
1457 LangCode langCode
= -1;
1458 RegionCode regCode
= -1;
1459 ScriptCode scrCode
= 0;
1460 CFStringEncoding enc
= kCFStringEncodingMacRoman
;
1461 retval
= CFLocaleGetLanguageRegionEncodingForLocaleIdentifier(localizationName
, &langCode
, ®Code
, &scrCode
, &enc
);
1463 language
= langCode
;
1470 if (localizationName
) {
1471 language
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1472 region
= _CFBundleGetRegionCodeForLocalization(localizationName
);
1474 _CFBundleGetLanguageAndRegionCodes(&language
, ®ion
);
1476 if ((language
< 0 || language
> (int)(sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
))) && region
!= -1) language
= _CFBundleGetLanguageCodeForRegionCode(region
);
1477 if (region
== -1 && language
!= -1) region
= _CFBundleGetRegionCodeForLanguageCode(language
);
1478 if (language
>= 0 && language
< (int)(sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
))) {
1479 script
= __CFBundleScriptCodesArray
[language
];
1481 if (language
>= 0 && language
< (int)(sizeof(__CFBundleStringEncodingsArray
)/sizeof(CFStringEncoding
))) {
1482 encoding
= __CFBundleStringEncodingsArray
[language
];
1484 retval
= (language
!= -1 || region
!= -1);
1486 if (languageCode
) *languageCode
= language
;
1487 if (regionCode
) *regionCode
= region
;
1488 if (scriptCode
) *scriptCode
= script
;
1489 if (stringEncoding
) *stringEncoding
= encoding
;
1493 CFStringRef
CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode
, SInt32 regionCode
, SInt32 scriptCode
, CFStringEncoding stringEncoding
) {
1494 CFStringRef localizationName
= NULL
;
1495 if (!localizationName
) localizationName
= _CFBundleCopyLocaleAbbreviationForRegionCode(regionCode
);
1496 #if DEPLOYMENT_TARGET_MACOSX
1497 if (!localizationName
&& 0 <= languageCode
&& languageCode
< SHRT_MAX
) localizationName
= CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes(kCFAllocatorSystemDefault
, (LangCode
)languageCode
, (RegionCode
)-1);
1499 if (!localizationName
) localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode
);
1500 if (!localizationName
) {
1501 SInt32 language
= -1, scriptLanguage
= -1, encodingLanguage
= -1;
1503 for (i
= 0; language
== -1 && i
< (sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
)); i
++) {
1504 if (__CFBundleScriptCodesArray
[i
] == scriptCode
&& __CFBundleStringEncodingsArray
[i
] == stringEncoding
) language
= i
;
1506 for (i
= 0; scriptLanguage
== -1 && i
< (sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
)); i
++) {
1507 if (__CFBundleScriptCodesArray
[i
] == scriptCode
) scriptLanguage
= i
;
1509 for (i
= 0; encodingLanguage
== -1 && i
< (sizeof(__CFBundleStringEncodingsArray
)/sizeof(CFStringEncoding
)); i
++) {
1510 if (__CFBundleStringEncodingsArray
[i
] == stringEncoding
) encodingLanguage
= i
;
1512 localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(language
);
1513 if (!localizationName
) localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(encodingLanguage
);
1514 if (!localizationName
) localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(scriptLanguage
);
1516 return localizationName
;
1519 extern void *__CFAppleLanguages
;
1521 #if DEPLOYMENT_TARGET_WINDOWS
1523 extern CFStringRef
copyLocaleLanguageName(void);
1524 extern CFStringRef
copyLocaleCountryName(void);
1526 static CFArrayRef
copyWindowsLanguagePrefsArray() {
1528 CFStringRef locales
[4];
1529 CFStringRef languageName
= copyLocaleLanguageName(), countryName
= copyLocaleCountryName();
1530 if (!languageName
) languageName
= CFSTR("en");
1531 if (!countryName
) countryName
= CFSTR("");
1532 CFIndex i
, localesCount
= 0;
1533 if (CFStringGetLength(countryName
) > 0) locales
[localesCount
++] = CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@_%@"), languageName
, countryName
);
1534 if (CFStringGetLength(languageName
) != 0) {
1535 // special-case for zh since we don't have a generic zh localization
1536 if (CFStringCompare(languageName
, CFSTR("zh"), kCFCompareCaseInsensitive
) != 0) {
1537 locales
[localesCount
++] = CFStringCreateCopy(kCFAllocatorSystemDefault
, languageName
);//languageName;
1539 CFStringRef moreSpecificLanguageName
;
1541 // See http://intrigue-build.apple.com/changeset/14948 for the details on the change. Copied below is the snippet of the code change.
1542 // According to http://www.microsoft.com/globaldev/reference/win2k/setup/lcid.mspx, the locales that use
1543 // 126 // simplified chinese are CN (PRC) and SG (Singapore). The rest use traditional chinese.
1544 // 127 languageName = (countryName == TEXT("CN") || countryName == TEXT("SG")) ? TEXT("zh_CN") : TEXT("zh_TW");
1546 // Compare for CN or SG
1547 if (CFStringCompare(countryName
, CFSTR("CN"), kCFCompareCaseInsensitive
) == 0 || CFStringCompare(countryName
, CFSTR("SG"), kCFCompareCaseInsensitive
) == 0) {
1548 moreSpecificLanguageName
= CFSTR("zh_CN");
1550 moreSpecificLanguageName
= CFSTR("zh_TW");
1552 locales
[localesCount
++] = CFStringCreateCopy(kCFAllocatorSystemDefault
, moreSpecificLanguageName
);
1554 // Don't need this now
1555 if (languageName
) CFRelease(languageName
);
1556 if (countryName
) CFRelease(countryName
);
1558 if (localesCount
== 0) locales
[localesCount
++] = CFStringCreateCopy(kCFAllocatorSystemDefault
, CFSTR("en"));
1559 result
= CFArrayCreate(kCFAllocatorDefault
, (const void **)locales
, localesCount
, &kCFTypeArrayCallBacks
);
1560 for (i
= 0; i
< localesCount
; i
++) CFRelease(locales
[i
]);
1564 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1566 #error Unknown or unspecified DEPLOYMENT_TARGET
1569 static CFArrayRef _CFBundleUserLanguages
= NULL
;
1571 __private_extern__ CFArrayRef
_CFBundleCopyUserLanguages(Boolean useBackstops
) {
1572 CFArrayRef result
= NULL
;
1573 static Boolean didit
= false;
1574 CFArrayRef preferencesArray
= NULL
;
1575 // This is a temporary solution, until the argument domain is moved down into CFPreferences
1576 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
1578 if (__CFAppleLanguages
) {
1580 CFIndex length
= strlen((const char *)__CFAppleLanguages
);
1582 data
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, (const UInt8
*)__CFAppleLanguages
, length
, kCFAllocatorNull
);
1584 _CFBundleUserLanguages
= (CFArrayRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, data
, kCFPropertyListImmutable
, NULL
);
1589 if (!_CFBundleUserLanguages
&& preferencesArray
) _CFBundleUserLanguages
= (CFArrayRef
)CFRetain(preferencesArray
);
1590 Boolean useEnglishAsBackstop
= true;
1591 // could perhaps read out of LANG environment variable
1592 if (useEnglishAsBackstop
&& !_CFBundleUserLanguages
) {
1593 CFStringRef english
= CFSTR("en");
1594 _CFBundleUserLanguages
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&english
, 1, &kCFTypeArrayCallBacks
);
1596 if (_CFBundleUserLanguages
&& CFGetTypeID(_CFBundleUserLanguages
) != CFArrayGetTypeID()) {
1597 CFRelease(_CFBundleUserLanguages
);
1598 _CFBundleUserLanguages
= NULL
;
1602 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
1603 if (preferencesArray
) CFRelease(preferencesArray
);
1604 if (!result
&& _CFBundleUserLanguages
) result
= (CFArrayRef
)CFRetain(_CFBundleUserLanguages
);
1608 CF_EXPORT
void _CFBundleGetLanguageAndRegionCodes(SInt32
*languageCode
, SInt32
*regionCode
) {
1609 // an attempt to answer the question, "what language are we running in?"
1610 // note that the question cannot be answered fully since it may depend on the bundle
1611 SInt32 language
= -1, region
= -1;
1612 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1613 CFArrayRef languages
= NULL
;
1615 languages
= _CFBundleGetLanguageSearchList(mainBundle
);
1616 if (languages
) CFRetain(languages
);
1618 if (!languages
) languages
= _CFBundleCopyUserLanguages(false);
1619 if (languages
&& CFArrayGetCount(languages
) > 0) {
1620 CFStringRef localizationName
= (CFStringRef
)CFArrayGetValueAtIndex(languages
, 0);
1621 Boolean retval
= false;
1622 LangCode langCode
= -1;
1623 RegionCode regCode
= -1;
1624 retval
= CFLocaleGetLanguageRegionEncodingForLocaleIdentifier(localizationName
, &langCode
, ®Code
, NULL
, NULL
);
1626 language
= langCode
;
1630 language
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1631 region
= _CFBundleGetRegionCodeForLocalization(localizationName
);
1637 if (language
== -1 && region
!= -1) language
= _CFBundleGetLanguageCodeForRegionCode(region
);
1638 if (region
== -1 && language
!= -1) region
= _CFBundleGetRegionCodeForLanguageCode(language
);
1639 if (languages
) CFRelease(languages
);
1640 if (languageCode
) *languageCode
= language
;
1641 if (regionCode
) *regionCode
= region
;
1645 static Boolean
_CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc
, UniChar
*pathUniChars
, CFIndex pathLen
, uint8_t version
, CFDictionaryRef infoDict
, CFStringRef curLangStr
, CFMutableArrayRef lprojNames
, Boolean fallBackToLanguage
) {
1646 CFIndex curLangLen
= CFStringGetLength(curLangStr
), savedPathLen
;
1647 UniChar curLangUniChars
[255];
1648 CFStringRef altLangStr
= NULL
, modifiedLangStr
= NULL
, languageAbbreviation
= NULL
, languageName
= NULL
, canonicalLanguageIdentifier
= NULL
, canonicalLanguageAbbreviation
= NULL
;
1649 CFMutableDictionaryRef canonicalLanguageIdentifiers
= NULL
, predefinedCanonicalLanguageIdentifiers
= NULL
;
1650 Boolean foundOne
= false, specifiesScript
= false;
1651 CFArrayRef predefinedLocalizations
= NULL
;
1652 CFRange predefinedLocalizationsRange
;
1653 CFMutableStringRef cheapStr
, tmpString
;
1654 #if READ_DIRECTORIES
1655 CFArrayRef contents
;
1656 CFRange contentsRange
;
1657 #else /* READ_DIRECTORIES */
1658 Boolean isDir
= false;
1659 #endif /* READ_DIRECTORIES */
1661 // both of these used for temp string operations, for slightly
1662 // different purposes, where each type is appropriate
1663 cheapStr
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
1664 _CFStrSetDesiredCapacity(cheapStr
, CFMaxPathSize
);
1665 tmpString
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, kCFAllocatorNull
);
1667 #if READ_DIRECTORIES
1668 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1669 CFStringReplaceAll(cheapStr
, tmpString
);
1670 contents
= _CFBundleCopySortedDirectoryContentsAtPath(cheapStr
, _CFBundleAllContents
);
1671 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
1672 #endif /* READ_DIRECTORIES */
1675 predefinedLocalizations
= (CFArrayRef
)CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
1676 if (predefinedLocalizations
&& CFGetTypeID(predefinedLocalizations
) != CFArrayGetTypeID()) {
1677 predefinedLocalizations
= NULL
;
1678 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleLocalizationsKey
);
1681 predefinedLocalizationsRange
= CFRangeMake(0, predefinedLocalizations
? CFArrayGetCount(predefinedLocalizations
) : 0);
1683 if (curLangLen
> 255) curLangLen
= 255;
1684 CFStringGetCharacters(curLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1685 savedPathLen
= pathLen
;
1686 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1687 #if READ_DIRECTORIES
1688 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1689 CFStringReplaceAll(cheapStr
, tmpString
);
1690 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, curLangStr
)) || (version
!= 4 && _CFBundleSortedArrayContains(contents
, cheapStr
))) {
1691 #else /* READ_DIRECTORIES */
1692 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1693 CFStringReplaceAll(cheapStr
, tmpString
);
1694 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, curLangStr
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1695 #endif /* READ_DIRECTORIES */
1696 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), curLangStr
)) CFArrayAppendValue(lprojNames
, curLangStr
);
1698 if (CFStringGetLength(curLangStr
) <= 2) {
1699 CFRelease(cheapStr
);
1700 CFRelease(tmpString
);
1701 #if READ_DIRECTORIES
1702 CFRelease(contents
);
1703 #endif /* READ_DIRECTORIES */
1708 #if defined(__CONSTANT_CFSTRINGS__)
1711 for (idx
= 0; !altLangStr
&& idx
< NUM_COMMON_LANGUAGE_NAMES
; idx
++) {
1712 if (CFEqual(curLangStr
, __CFBundleCommonLanguageAbbreviationsArray
[idx
])) altLangStr
= __CFBundleCommonLanguageNamesArray
[idx
];
1713 else if (CFEqual(curLangStr
, __CFBundleCommonLanguageNamesArray
[idx
])) altLangStr
= __CFBundleCommonLanguageAbbreviationsArray
[idx
];
1716 #endif /* __CONSTANT_CFSTRINGS__ */
1717 if (foundOne
&& altLangStr
) {
1718 CFRelease(cheapStr
);
1719 CFRelease(tmpString
);
1720 #if READ_DIRECTORIES
1721 CFRelease(contents
);
1722 #endif /* READ_DIRECTORIES */
1726 curLangLen
= CFStringGetLength(altLangStr
);
1727 if (curLangLen
> 255) curLangLen
= 255;
1728 CFStringGetCharacters(altLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1729 pathLen
= savedPathLen
;
1730 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1731 #if READ_DIRECTORIES
1732 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1733 CFStringReplaceAll(cheapStr
, tmpString
);
1734 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, altLangStr
)) || (version
!= 4 && _CFBundleSortedArrayContains(contents
, cheapStr
))) {
1735 #else /* READ_DIRECTORIES */
1736 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1737 CFStringReplaceAll(cheapStr
, tmpString
);
1738 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, altLangStr
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1739 #endif /* READ_DIRECTORIES */
1740 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), altLangStr
)) CFArrayAppendValue(lprojNames
, altLangStr
);
1742 CFRelease(cheapStr
);
1743 CFRelease(tmpString
);
1744 #if READ_DIRECTORIES
1745 CFRelease(contents
);
1746 #endif /* READ_DIRECTORIES */
1751 #if READ_DIRECTORIES
1752 if (!foundOne
&& (!predefinedLocalizations
|| CFArrayGetCount(predefinedLocalizations
) == 0)) {
1753 Boolean hasLocalizations
= false;
1755 for (idx
= 0; !hasLocalizations
&& idx
< contentsRange
.length
; idx
++) {
1756 CFStringRef name
= CFArrayGetValueAtIndex(contents
, idx
);
1757 if (CFStringHasSuffix(name
, _CFBundleLprojExtensionWithDot
)) hasLocalizations
= true;
1759 if (!hasLocalizations
) {
1760 CFRelease(cheapStr
);
1761 CFRelease(tmpString
);
1762 CFRelease(contents
);
1766 #endif /* READ_DIRECTORIES */
1767 if (!altLangStr
&& (modifiedLangStr
= _CFBundleCopyModifiedLocalization(curLangStr
))) {
1768 curLangLen
= CFStringGetLength(modifiedLangStr
);
1769 if (curLangLen
> 255) curLangLen
= 255;
1770 CFStringGetCharacters(modifiedLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1771 pathLen
= savedPathLen
;
1772 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1773 #if READ_DIRECTORIES
1774 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1775 CFStringReplaceAll(cheapStr
, tmpString
);
1776 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, modifiedLangStr
)) || (version
!= 4 && _CFBundleSortedArrayContains(contents
, cheapStr
))) {
1777 #else /* READ_DIRECTORIES */
1778 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1779 CFStringReplaceAll(cheapStr
, tmpString
);
1780 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, modifiedLangStr
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1781 #endif /* READ_DIRECTORIES */
1782 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), modifiedLangStr
)) CFArrayAppendValue(lprojNames
, modifiedLangStr
);
1787 if (!specifiesScript
&& (foundOne
|| fallBackToLanguage
) && !altLangStr
&& (languageAbbreviation
= _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageAbbreviation
)) {
1788 curLangLen
= CFStringGetLength(languageAbbreviation
);
1789 if (curLangLen
> 255) curLangLen
= 255;
1790 CFStringGetCharacters(languageAbbreviation
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1791 pathLen
= savedPathLen
;
1792 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1793 #if READ_DIRECTORIES
1794 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1795 CFStringReplaceAll(cheapStr
, tmpString
);
1796 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageAbbreviation
)) || (version
!= 4 && _CFBundleSortedArrayContains(contents
, cheapStr
))) {
1797 #else /* READ_DIRECTORIES */
1798 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1799 CFStringReplaceAll(cheapStr
, tmpString
);
1800 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageAbbreviation
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1801 #endif /* READ_DIRECTORIES */
1802 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageAbbreviation
)) CFArrayAppendValue(lprojNames
, languageAbbreviation
);
1807 if (!specifiesScript
&& (foundOne
|| fallBackToLanguage
) && !altLangStr
&& (languageName
= _CFBundleCopyLanguageNameForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageName
)) {
1808 curLangLen
= CFStringGetLength(languageName
);
1809 if (curLangLen
> 255) curLangLen
= 255;
1810 CFStringGetCharacters(languageName
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1811 pathLen
= savedPathLen
;
1812 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1813 #if READ_DIRECTORIES
1814 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1815 CFStringReplaceAll(cheapStr
, tmpString
);
1816 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageName
)) || (version
!= 4 && _CFBundleSortedArrayContains(contents
, cheapStr
))) {
1817 #else /* READ_DIRECTORIES */
1818 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1819 CFStringReplaceAll(cheapStr
, tmpString
);
1820 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageName
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1821 #endif /* READ_DIRECTORIES */
1822 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageName
)) CFArrayAppendValue(lprojNames
, languageName
);
1827 if (modifiedLangStr
) CFRelease(modifiedLangStr
);
1828 if (languageAbbreviation
) CFRelease(languageAbbreviation
);
1829 if (languageName
) CFRelease(languageName
);
1830 if (canonicalLanguageIdentifier
) CFRelease(canonicalLanguageIdentifier
);
1831 if (canonicalLanguageIdentifiers
) CFRelease(canonicalLanguageIdentifiers
);
1832 if (predefinedCanonicalLanguageIdentifiers
) CFRelease(predefinedCanonicalLanguageIdentifiers
);
1833 if (canonicalLanguageAbbreviation
) CFRelease(canonicalLanguageAbbreviation
);
1834 CFRelease(cheapStr
);
1835 CFRelease(tmpString
);
1836 #if READ_DIRECTORIES
1837 CFRelease(contents
);
1838 #endif /* READ_DIRECTORIES */
1842 static Boolean
CFBundleAllowMixedLocalizations(void) {
1843 static Boolean allowMixed
= false, examinedMain
= false;
1844 if (!examinedMain
) {
1845 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1846 CFDictionaryRef infoDict
= mainBundle
? CFBundleGetInfoDictionary(mainBundle
) : NULL
;
1847 CFTypeRef allowMixedValue
= infoDict
? CFDictionaryGetValue(infoDict
, _kCFBundleAllowMixedLocalizationsKey
) : NULL
;
1848 if (allowMixedValue
) {
1849 CFTypeID typeID
= CFGetTypeID(allowMixedValue
);
1850 if (typeID
== CFBooleanGetTypeID()) {
1851 allowMixed
= CFBooleanGetValue((CFBooleanRef
)allowMixedValue
);
1852 } else if (typeID
== CFStringGetTypeID()) {
1853 allowMixed
= (CFStringCompare((CFStringRef
)allowMixedValue
, CFSTR("true"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
|| CFStringCompare((CFStringRef
)allowMixedValue
, CFSTR("YES"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1854 } else if (typeID
== CFNumberGetTypeID()) {
1856 if (CFNumberGetValue((CFNumberRef
)allowMixedValue
, kCFNumberSInt32Type
, &val
)) allowMixed
= (val
!= 0);
1859 examinedMain
= true;
1864 static Boolean
_CFBundleLocalizationsHaveCommonPrefix(CFStringRef loc1
, CFStringRef loc2
) {
1865 Boolean result
= false;
1866 CFIndex length1
= CFStringGetLength(loc1
), length2
= CFStringGetLength(loc2
), idx
;
1867 if (length1
> 3 && length2
> 3) {
1868 for (idx
= 0; idx
< length1
&& idx
< length2
; idx
++) {
1869 UniChar c1
= CFStringGetCharacterAtIndex(loc1
, idx
), c2
= CFStringGetCharacterAtIndex(loc2
, idx
);
1870 if (idx
>= 2 && (c1
== '-' || c1
== '_') && (c2
== '-' || c2
== '_')) {
1873 } else if (c1
!= c2
) {
1881 __private_extern__
void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
, CFDictionaryRef infoDict
, CFMutableArrayRef lprojNames
, CFStringRef devLang
) {
1882 // This function will add zero, one or two elements to the lprojNames array.
1883 // It examines the users preferred language list and the lproj directories inside the bundle directory. It picks the lproj directory that is highest on the users list.
1884 // The users list can contain region names (like "en_US" for US English). In this case, if the region lproj exists, it will be added, and, if the region's associated language lproj exists that will be added.
1885 CFURLRef resourcesURL
= _CFBundleCopyResourcesDirectoryURLInDirectory(bundleURL
, version
);
1886 CFURLRef absoluteURL
;
1887 CFIndex idx
, startIdx
;
1889 CFStringRef resourcesPath
;
1890 UniChar pathUniChars
[CFMaxPathSize
];
1892 CFStringRef curLangStr
, nextLangStr
;
1893 Boolean foundOne
= false;
1894 CFArrayRef userLanguages
;
1896 // Init the one-time-only unichar buffers.
1897 _CFEnsureStaticBuffersInited();
1899 // Get the path to the resources and extract into a buffer.
1900 absoluteURL
= CFURLCopyAbsoluteURL(resourcesURL
);
1901 resourcesPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1902 CFRelease(absoluteURL
);
1903 pathLen
= CFStringGetLength(resourcesPath
);
1904 if (pathLen
> CFMaxPathSize
) pathLen
= CFMaxPathSize
;
1905 CFStringGetCharacters(resourcesPath
, CFRangeMake(0, pathLen
), pathUniChars
);
1906 CFRelease(resourcesURL
);
1907 CFRelease(resourcesPath
);
1909 // First check the main bundle.
1910 if (!CFBundleAllowMixedLocalizations()) {
1911 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1913 CFURLRef mainBundleURL
= CFBundleCopyBundleURL(mainBundle
);
1914 if (mainBundleURL
) {
1915 if (!CFEqual(bundleURL
, mainBundleURL
)) {
1916 // If there is a main bundle, and it isn't this one, try to use the language it prefers.
1917 CFArrayRef mainBundleLangs
= _CFBundleGetLanguageSearchList(mainBundle
);
1918 if (mainBundleLangs
&& (CFArrayGetCount(mainBundleLangs
) > 0)) {
1919 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(mainBundleLangs
, 0);
1920 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
, true);
1923 CFRelease(mainBundleURL
);
1929 // If we didn't find the main bundle's preferred language, look at the users' prefs again and find the best one.
1930 userLanguages
= _CFBundleCopyUserLanguages(true);
1931 count
= (userLanguages
? CFArrayGetCount(userLanguages
) : 0);
1932 for (idx
= 0, startIdx
= -1; !foundOne
&& idx
< count
; idx
++) {
1933 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(userLanguages
, idx
);
1934 nextLangStr
= (idx
+ 1 < count
) ? (CFStringRef
)CFArrayGetValueAtIndex(userLanguages
, idx
+ 1) : NULL
;
1935 if (nextLangStr
&& _CFBundleLocalizationsHaveCommonPrefix(curLangStr
, nextLangStr
)) {
1936 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
, false);
1937 if (startIdx
< 0) startIdx
= idx
;
1938 } else if (startIdx
>= 0 && startIdx
<= idx
) {
1939 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
, false);
1940 for (; !foundOne
&& startIdx
<= idx
; startIdx
++) {
1941 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(userLanguages
, startIdx
);
1942 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
, true);
1946 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
, true);
1950 // use development region and U.S. English as backstops
1951 if (!foundOne
&& devLang
) foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault
, pathUniChars
, pathLen
, version
, infoDict
, devLang
, lprojNames
, true);
1952 if (!foundOne
) foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault
, pathUniChars
, pathLen
, version
, infoDict
, CFSTR("en_US"), lprojNames
, true);
1953 if (userLanguages
) CFRelease(userLanguages
);
1957 static Boolean
_CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array
, CFStringRef curLangStr
, CFMutableArrayRef lprojNames
, Boolean fallBackToLanguage
) {
1958 Boolean foundOne
= false, specifiesScript
= false;
1959 CFRange range
= CFRangeMake(0, CFArrayGetCount(array
));
1960 CFStringRef altLangStr
= NULL
, modifiedLangStr
= NULL
, languageAbbreviation
= NULL
, languageName
= NULL
, canonicalLanguageIdentifier
= NULL
, canonicalLanguageAbbreviation
= NULL
;
1961 CFMutableDictionaryRef canonicalLanguageIdentifiers
= NULL
;
1963 if (range
.length
== 0) return foundOne
;
1964 if (CFArrayContainsValue(array
, range
, curLangStr
)) {
1965 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), curLangStr
)) CFArrayAppendValue(lprojNames
, curLangStr
);
1967 if (range
.length
== 1 || CFStringGetLength(curLangStr
) <= 2) return foundOne
;
1969 if (range
.length
== 1 && CFArrayContainsValue(array
, range
, CFSTR("default"))) return foundOne
;
1970 #if defined(__CONSTANT_CFSTRINGS__)
1973 for (idx
= 0; !altLangStr
&& idx
< NUM_COMMON_LANGUAGE_NAMES
; idx
++) {
1974 if (CFEqual(curLangStr
, __CFBundleCommonLanguageAbbreviationsArray
[idx
])) altLangStr
= __CFBundleCommonLanguageNamesArray
[idx
];
1975 else if (CFEqual(curLangStr
, __CFBundleCommonLanguageNamesArray
[idx
])) altLangStr
= __CFBundleCommonLanguageAbbreviationsArray
[idx
];
1978 #endif /* __CONSTANT_CFSTRINGS__ */
1979 if (foundOne
&& altLangStr
) return foundOne
;
1980 if (altLangStr
&& CFArrayContainsValue(array
, range
, altLangStr
)) {
1981 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), altLangStr
)) CFArrayAppendValue(lprojNames
, altLangStr
);
1985 if (!altLangStr
&& (modifiedLangStr
= _CFBundleCopyModifiedLocalization(curLangStr
))) {
1986 if (CFArrayContainsValue(array
, range
, modifiedLangStr
)) {
1987 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), modifiedLangStr
)) CFArrayAppendValue(lprojNames
, modifiedLangStr
);
1991 if (!specifiesScript
&& (foundOne
|| fallBackToLanguage
) && !altLangStr
&& (languageAbbreviation
= _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageAbbreviation
)) {
1992 if (CFArrayContainsValue(array
, range
, languageAbbreviation
)) {
1993 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageAbbreviation
)) CFArrayAppendValue(lprojNames
, languageAbbreviation
);
1997 if (!specifiesScript
&& (foundOne
|| fallBackToLanguage
) && !altLangStr
&& (languageName
= _CFBundleCopyLanguageNameForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageName
)) {
1998 if (CFArrayContainsValue(array
, range
, languageName
)) {
1999 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageName
)) CFArrayAppendValue(lprojNames
, languageName
);
2003 if (modifiedLangStr
) CFRelease(modifiedLangStr
);
2004 if (languageAbbreviation
) CFRelease(languageAbbreviation
);
2005 if (languageName
) CFRelease(languageName
);
2006 if (canonicalLanguageIdentifier
) CFRelease(canonicalLanguageIdentifier
);
2007 if (canonicalLanguageIdentifiers
) CFRelease(canonicalLanguageIdentifiers
);
2008 if (canonicalLanguageAbbreviation
) CFRelease(canonicalLanguageAbbreviation
);
2012 static CFArrayRef
_CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray
, CFArrayRef prefArray
, Boolean considerMain
) {
2013 CFMutableArrayRef lprojNames
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2014 Boolean foundOne
= false, releasePrefArray
= false;
2015 CFIndex idx
, count
, startIdx
;
2017 if (considerMain
&& !CFBundleAllowMixedLocalizations()) {
2018 CFBundleRef mainBundle
= CFBundleGetMainBundle();
2020 // If there is a main bundle, try to use the language it prefers.
2021 CFArrayRef mainBundleLangs
= _CFBundleGetLanguageSearchList(mainBundle
);
2022 if (mainBundleLangs
&& (CFArrayGetCount(mainBundleLangs
) > 0)) foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, (CFStringRef
)CFArrayGetValueAtIndex(mainBundleLangs
, 0), lprojNames
, true);
2027 CFStringRef curLangStr
, nextLangStr
;
2029 prefArray
= _CFBundleCopyUserLanguages(true);
2030 if (prefArray
) releasePrefArray
= true;
2032 count
= (prefArray
? CFArrayGetCount(prefArray
) : 0);
2033 for (idx
= 0, startIdx
= -1; !foundOne
&& idx
< count
; idx
++) {
2034 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(prefArray
, idx
);
2035 nextLangStr
= (idx
+ 1 < count
) ? (CFStringRef
)CFArrayGetValueAtIndex(prefArray
, idx
+ 1) : NULL
;
2036 if (nextLangStr
&& _CFBundleLocalizationsHaveCommonPrefix(curLangStr
, nextLangStr
)) {
2037 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, curLangStr
, lprojNames
, false);
2038 if (startIdx
< 0) startIdx
= idx
;
2039 } else if (startIdx
>= 0 && startIdx
<= idx
) {
2040 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, curLangStr
, lprojNames
, false);
2041 for (; !foundOne
&& startIdx
<= idx
; startIdx
++) {
2042 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(prefArray
, startIdx
);
2043 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, curLangStr
, lprojNames
, true);
2047 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, curLangStr
, lprojNames
, true);
2051 // use U.S. English as backstop
2052 if (!foundOne
) foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, CFSTR("en_US"), lprojNames
, true);
2053 // use random entry as backstop
2054 if (!foundOne
&& CFArrayGetCount(locArray
) > 0) foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, (CFStringRef
)CFArrayGetValueAtIndex(locArray
, 0), lprojNames
, true);
2056 if (CFArrayGetCount(lprojNames
) == 0) {
2057 // Total backstop behavior to avoid having an empty array.
2058 CFArrayAppendValue(lprojNames
, CFSTR("en"));
2060 if (releasePrefArray
) {
2061 CFRelease(prefArray
);
2066 CF_EXPORT CFArrayRef
CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray
, CFArrayRef prefArray
) {
2067 return _CFBundleCopyLocalizationsForPreferences(locArray
, prefArray
, false);
2070 CF_EXPORT CFArrayRef
CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locArray
) {
2071 return _CFBundleCopyLocalizationsForPreferences(locArray
, NULL
, true);
2074 __private_extern__ CFArrayRef
_CFBundleCopyLanguageSearchListInDirectory(CFAllocatorRef alloc
, CFURLRef url
, uint8_t *version
) {
2075 CFMutableArrayRef langs
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
2076 uint8_t localVersion
= 0;
2077 CFDictionaryRef infoDict
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero
, url
, &localVersion
);
2078 CFStringRef devLang
= NULL
;
2079 if (infoDict
) devLang
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
2080 if (devLang
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) devLang
= NULL
;
2082 _CFBundleAddPreferredLprojNamesInDirectory(alloc
, url
, localVersion
, infoDict
, langs
, devLang
);
2084 if (devLang
&& CFArrayGetFirstIndexOfValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), devLang
) < 0) CFArrayAppendValue(langs
, devLang
);
2086 // Total backstop behavior to avoid having an empty array.
2087 if (CFArrayGetCount(langs
) == 0) CFArrayAppendValue(langs
, CFSTR("en"));
2089 if (infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(infoDict
);
2090 if (version
) *version
= localVersion
;
2094 CF_EXPORT Boolean
_CFBundleURLLooksLikeBundle(CFURLRef url
) {
2095 Boolean result
= false;
2096 CFBundleRef bundle
= _CFBundleCreateIfLooksLikeBundle(kCFAllocatorSystemDefault
, url
);
2104 // Note that subDirName is expected to be the string for a URL
2105 CF_INLINE Boolean
_CFBundleURLHasSubDir(CFURLRef url
, CFStringRef subDirName
) {
2106 Boolean isDir
= false, result
= false;
2107 CFURLRef dirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, subDirName
, url
);
2109 if (_CFIsResourceAtURL(dirURL
, &isDir
) && isDir
) result
= true;
2115 __private_extern__ Boolean
_CFBundleURLLooksLikeBundleVersion(CFURLRef url
, uint8_t *version
) {
2116 // check for existence of "Resources" or "Contents" or "Support Files"
2117 // but check for the most likely one first
2118 // version 0: old-style "Resources" bundles
2119 // version 1: obsolete "Support Files" bundles
2120 // version 2: modern "Contents" bundles
2121 // version 3: none of the above (see below)
2122 // version 4: not a bundle (for main bundle only)
2123 uint8_t localVersion
= 3;
2124 #if READ_DIRECTORIES
2125 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
2126 CFStringRef directoryPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
2127 CFArrayRef contents
= _CFBundleCopySortedDirectoryContentsAtPath(directoryPath
, _CFBundleAllContents
);
2128 if (CFStringHasSuffix(CFURLGetString(url
), CFSTR(".framework/"))) {
2129 if (_CFBundleSortedArrayContains(contents
, _CFBundleResourcesDirectoryName
)) localVersion
= 0;
2130 else if (_CFBundleSortedArrayContains(contents
, _CFBundleSupportFilesDirectoryName2
)) localVersion
= 2;
2131 else if (_CFBundleSortedArrayContains(contents
, _CFBundleSupportFilesDirectoryName1
)) localVersion
= 1;
2133 if (_CFBundleSortedArrayContains(contents
, _CFBundleSupportFilesDirectoryName2
)) localVersion
= 2;
2134 else if (_CFBundleSortedArrayContains(contents
, _CFBundleResourcesDirectoryName
)) localVersion
= 0;
2135 else if (_CFBundleSortedArrayContains(contents
, _CFBundleSupportFilesDirectoryName1
)) localVersion
= 1;
2137 CFRelease(contents
);
2138 CFRelease(directoryPath
);
2139 CFRelease(absoluteURL
);
2140 #endif /* READ_DIRECTORIES */
2141 if (localVersion
== 3) {
2142 #if DEPLOYMENT_TARGET_EMBEDDED
2143 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_WINDOWS
2144 #if DEPLOYMENT_TARGET_WINDOWS
2145 if (CFStringHasSuffix(CFURLGetString(url
), CFSTR(".framework/")) || CFStringHasSuffix(CFURLGetString(url
), CFSTR(".framework\\"))) {
2147 if (CFStringHasSuffix(CFURLGetString(url
), CFSTR(".framework/"))) {
2149 if (_CFBundleURLHasSubDir(url
, _CFBundleResourcesURLFromBase0
)) localVersion
= 0;
2150 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase2
)) localVersion
= 2;
2151 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase1
)) localVersion
= 1;
2153 if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase2
)) localVersion
= 2;
2154 else if (_CFBundleURLHasSubDir(url
, _CFBundleResourcesURLFromBase0
)) localVersion
= 0;
2155 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase1
)) localVersion
= 1;
2159 if (version
) *version
= localVersion
;
2160 return (localVersion
!= 3);
2163 static Boolean
_isValidPlatformSuffix(CFStringRef suffix
) {
2164 for (CFIndex idx
= 0; idx
< _CFBundleNumberOfPlatforms
; idx
++) {
2165 if (CFEqual(suffix
, _CFBundleSupportedPlatforms
[idx
])) return true;
2170 static Boolean
_isValidProductSuffix(CFStringRef suffix
) {
2171 for (CFIndex idx
= 0; idx
< _CFBundleNumberOfProducts
; idx
++) {
2172 if (CFEqual(suffix
, _CFBundleSupportedProducts
[idx
])) return true;
2177 static Boolean
_isValidiPhoneOSPlatformProductSuffix(CFStringRef suffix
) {
2178 for (CFIndex idx
= 0; idx
< _CFBundleNumberOfiPhoneOSPlatformProducts
; idx
++) {
2179 if (CFEqual(suffix
, _CFBundleSupportediPhoneOSPlatformProducts
[idx
])) return true;
2184 static Boolean
_isValidPlatformAndProductSuffixPair(CFStringRef platform
, CFStringRef product
) {
2185 if (!platform
&& !product
) return true;
2187 return _isValidProductSuffix(product
);
2190 return _isValidPlatformSuffix(platform
);
2192 if (CFEqual(platform
, _CFBundleiPhoneOSPlatformName
)) {
2193 return _isValidiPhoneOSPlatformProductSuffix(product
);
2198 static Boolean
_isBlacklistedKey(CFStringRef keyName
) {
2199 #define _CFBundleNumberOfBlacklistedInfoDictionaryKeys 2
2200 static const CFStringRef _CFBundleBlacklistedInfoDictionaryKeys
[_CFBundleNumberOfBlacklistedInfoDictionaryKeys
] = { CFSTR("CFBundleExecutable"), CFSTR("CFBundleIdentifier") };
2202 for (CFIndex idx
= 0; idx
< _CFBundleNumberOfBlacklistedInfoDictionaryKeys
; idx
++) {
2203 if (CFEqual(keyName
, _CFBundleBlacklistedInfoDictionaryKeys
[idx
])) return true;
2208 static Boolean
_isOverrideKey(CFStringRef fullKey
, CFStringRef
*outBaseKey
, CFStringRef
*outPlatformSuffix
, CFStringRef
*outProductSuffix
) {
2212 if (outPlatformSuffix
) {
2213 *outPlatformSuffix
= NULL
;
2215 if (outProductSuffix
) {
2216 *outProductSuffix
= NULL
;
2220 CFRange minusRange
= CFStringFind(fullKey
, CFSTR("-"), kCFCompareBackwards
);
2221 CFRange tildeRange
= CFStringFind(fullKey
, CFSTR("~"), kCFCompareBackwards
);
2222 if (minusRange
.location
== kCFNotFound
&& tildeRange
.location
== kCFNotFound
) return false;
2223 // minus must come before tilde if both are present
2224 if (minusRange
.location
!= kCFNotFound
&& tildeRange
.location
!= kCFNotFound
&& tildeRange
.location
<= minusRange
.location
) return false;
2226 CFIndex strLen
= CFStringGetLength(fullKey
);
2227 CFRange baseKeyRange
= (minusRange
.location
!= kCFNotFound
) ? CFRangeMake(0, minusRange
.location
) : CFRangeMake(0, tildeRange
.location
);
2228 CFRange platformRange
= CFRangeMake(kCFNotFound
, 0);
2229 CFRange productRange
= CFRangeMake(kCFNotFound
, 0);
2230 if (minusRange
.location
!= kCFNotFound
) {
2231 platformRange
.location
= minusRange
.location
+ minusRange
.length
;
2232 platformRange
.length
= ((tildeRange
.location
!= kCFNotFound
) ? tildeRange
.location
: strLen
) - platformRange
.location
;
2234 if (tildeRange
.location
!= kCFNotFound
) {
2235 productRange
.location
= tildeRange
.location
+ tildeRange
.length
;
2236 productRange
.length
= strLen
- productRange
.location
;
2238 if (baseKeyRange
.length
< 1) return false;
2239 if (platformRange
.location
!= kCFNotFound
&& platformRange
.length
< 1) return false;
2240 if (productRange
.location
!= kCFNotFound
&& productRange
.length
< 1) return false;
2242 CFStringRef platform
= (platformRange
.location
!= kCFNotFound
) ? CFStringCreateWithSubstring(kCFAllocatorSystemDefaultGCRefZero
, fullKey
, platformRange
) : NULL
;
2243 CFStringRef product
= (productRange
.location
!= kCFNotFound
) ? CFStringCreateWithSubstring(kCFAllocatorSystemDefaultGCRefZero
, fullKey
, productRange
) : NULL
;
2244 Boolean result
= _isValidPlatformAndProductSuffixPair(platform
, product
);
2248 *outBaseKey
= CFStringCreateWithSubstring(kCFAllocatorSystemDefaultGCRefZero
, fullKey
, baseKeyRange
);
2250 if (outPlatformSuffix
) {
2251 *outPlatformSuffix
= platform
;
2253 if (platform
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(platform
);
2255 if (outProductSuffix
) {
2256 *outProductSuffix
= product
;
2258 if (product
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(product
);
2261 if (platform
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(platform
);
2262 if (product
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(product
);
2267 static Boolean
_isCurrentPlatformAndProduct(CFStringRef platform
, CFStringRef product
) {
2268 if (!platform
&& !product
) return true;
2270 return CFEqual(_CFGetProductName(), product
);
2273 return CFEqual(_CFGetPlatformName(), platform
);
2276 return CFEqual(_CFGetProductName(), product
) && CFEqual(_CFGetPlatformName(), platform
);
2279 static CFArrayRef
_CopySortedOverridesForBaseKey(CFStringRef keyName
, CFDictionaryRef dict
) {
2280 CFMutableArrayRef overrides
= CFArrayCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeArrayCallBacks
);
2281 CFStringRef keyNameWithBoth
= CFStringCreateWithFormat(kCFAllocatorSystemDefaultGCRefZero
, NULL
, CFSTR("%@-%@~%@"), keyName
, _CFGetPlatformName(), _CFGetProductName());
2282 CFStringRef keyNameWithProduct
= CFStringCreateWithFormat(kCFAllocatorSystemDefaultGCRefZero
, NULL
, CFSTR("%@~%@"), keyName
, _CFGetProductName());
2283 CFStringRef keyNameWithPlatform
= CFStringCreateWithFormat(kCFAllocatorSystemDefaultGCRefZero
, NULL
, CFSTR("%@-%@"), keyName
, _CFGetPlatformName());
2285 CFIndex count
= CFDictionaryGetCount(dict
);
2288 CFTypeRef
*keys
= (CFTypeRef
*)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero
, 2 * count
* sizeof(CFTypeRef
), 0);
2289 CFTypeRef
*values
= &(keys
[count
]);
2291 CFDictionaryGetKeysAndValues(dict
, keys
, values
);
2292 for (CFIndex idx
= 0; idx
< count
; idx
++) {
2293 if (CFEqual(keys
[idx
], keyNameWithBoth
)) {
2294 CFArrayAppendValue(overrides
, keys
[idx
]);
2298 for (CFIndex idx
= 0; idx
< count
; idx
++) {
2299 if (CFEqual(keys
[idx
], keyNameWithProduct
)) {
2300 CFArrayAppendValue(overrides
, keys
[idx
]);
2304 for (CFIndex idx
= 0; idx
< count
; idx
++) {
2305 if (CFEqual(keys
[idx
], keyNameWithPlatform
)) {
2306 CFArrayAppendValue(overrides
, keys
[idx
]);
2310 for (CFIndex idx
= 0; idx
< count
; idx
++) {
2311 if (CFEqual(keys
[idx
], keyName
)) {
2312 CFArrayAppendValue(overrides
, keys
[idx
]);
2317 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) {
2318 CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero
, keys
);
2322 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) {
2323 CFRelease(keyNameWithProduct
);
2324 CFRelease(keyNameWithPlatform
);
2325 CFRelease(keyNameWithBoth
);
2331 __private_extern__
void _processInfoDictionary(CFMutableDictionaryRef dict
, CFStringRef platformSuffix
, CFStringRef productSuffix
) {
2332 CFIndex count
= CFDictionaryGetCount(dict
);
2335 CFTypeRef
*keys
= (CFTypeRef
*)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero
, 2 * count
* sizeof(CFTypeRef
), 0);
2336 CFTypeRef
*values
= &(keys
[count
]);
2337 CFMutableArrayRef guard
= CFArrayCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeArrayCallBacks
);
2339 CFDictionaryGetKeysAndValues(dict
, keys
, values
);
2340 for (CFIndex idx
= 0; idx
< count
; idx
++) {
2341 CFStringRef keyPlatformSuffix
, keyProductSuffix
, keyName
;
2342 if (_isOverrideKey((CFStringRef
)keys
[idx
], &keyName
, &keyPlatformSuffix
, &keyProductSuffix
)) {
2343 CFArrayRef keysForBaseKey
= NULL
;
2344 if (_isCurrentPlatformAndProduct(keyPlatformSuffix
, keyProductSuffix
) && !_isBlacklistedKey(keyName
) && CFDictionaryContainsKey(dict
, keys
[idx
])) {
2345 keysForBaseKey
= _CopySortedOverridesForBaseKey(keyName
, dict
);
2346 CFIndex keysForBaseKeyCount
= CFArrayGetCount(keysForBaseKey
);
2348 //make sure the other keys for this base key don't get released out from under us until we're done
2349 CFArrayAppendValue(guard
, keysForBaseKey
);
2351 //the winner for this base key will be sorted to the front, do the override with it
2352 CFTypeRef highestPriorityKey
= CFArrayGetValueAtIndex(keysForBaseKey
, 0);
2353 CFDictionarySetValue(dict
, keyName
, CFDictionaryGetValue(dict
, highestPriorityKey
));
2355 //remove everything except the now-overridden key; this will cause them to fail the CFDictionaryContainsKey(dict, keys[idx]) check in the enclosing if() and not be reprocessed
2356 for (CFIndex presentKeysIdx
= 0; presentKeysIdx
< keysForBaseKeyCount
; presentKeysIdx
++) {
2357 CFStringRef currentKey
= (CFStringRef
)CFArrayGetValueAtIndex(keysForBaseKey
, presentKeysIdx
);
2358 if (!CFEqual(currentKey
, keyName
))
2359 CFDictionaryRemoveValue(dict
, currentKey
);
2362 CFDictionaryRemoveValue(dict
, keys
[idx
]);
2366 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) {
2367 if (keyPlatformSuffix
) CFRelease(keyPlatformSuffix
);
2368 if (keyProductSuffix
) CFRelease(keyProductSuffix
);
2370 if (keysForBaseKey
) CFRelease(keysForBaseKey
);
2375 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) {
2376 CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero
, keys
);
2382 // returns zero-ref dictionary under GC if given kCFAllocatorSystemDefaultGCRefZero
2383 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc
, CFURLRef url
, uint8_t *version
) {
2384 CFDictionaryRef dict
= NULL
;
2385 unsigned char buff
[CFMaxPathSize
];
2386 uint8_t localVersion
= 0;
2388 if (CFURLGetFileSystemRepresentation(url
, true, buff
, CFMaxPathSize
)) {
2389 CFURLRef newURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
, strlen((char *)buff
), true);
2390 if (!newURL
) newURL
= (CFURLRef
)CFRetain(url
);
2392 // version 3 is for flattened pseudo-bundles with no Contents, Support Files, or Resources directories
2393 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) localVersion
= 3;
2395 dict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(alloc
, newURL
, localVersion
);
2398 if (version
) *version
= localVersion
;
2402 // returns zero-ref dictionary under GC if given kCFAllocatorSystemDefaultGCRefZero
2403 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc
, CFURLRef url
, uint8_t version
) {
2404 CFDictionaryRef result
= NULL
;
2406 CFURLRef infoURL
= NULL
, rawInfoURL
= NULL
;
2407 CFDataRef infoData
= NULL
;
2408 UniChar buff
[CFMaxPathSize
];
2410 CFMutableStringRef cheapStr
;
2411 CFStringRef infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension0
, infoURLFromBase
= _CFBundleInfoURLFromBase0
;
2412 Boolean tryPlatformSpecific
= true, tryGlobal
= true;
2413 #if READ_DIRECTORIES
2414 CFURLRef directoryURL
= NULL
, absoluteURL
;
2415 CFStringRef directoryPath
;
2416 CFArrayRef contents
= NULL
;
2417 CFRange contentsRange
= CFRangeMake(0, 0);
2418 #endif /* READ_DIRECTORIES */
2420 _CFEnsureStaticBuffersInited();
2423 #if READ_DIRECTORIES
2424 directoryURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase0
, url
);
2425 #endif /* READ_DIRECTORIES */
2426 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension0
;
2427 infoURLFromBase
= _CFBundleInfoURLFromBase0
;
2428 } else if (1 == version
) {
2429 #if READ_DIRECTORIES
2430 directoryURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleSupportFilesURLFromBase1
, url
);
2431 #endif /* READ_DIRECTORIES */
2432 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension1
;
2433 infoURLFromBase
= _CFBundleInfoURLFromBase1
;
2434 } else if (2 == version
) {
2435 #if READ_DIRECTORIES
2436 directoryURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleSupportFilesURLFromBase2
, url
);
2437 #endif /* READ_DIRECTORIES */
2438 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension2
;
2439 infoURLFromBase
= _CFBundleInfoURLFromBase2
;
2440 } else if (3 == version
) {
2441 CFStringRef path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2442 // this test is necessary to exclude the case where a bundle is spuriously created from the innards of another bundle
2444 if (!(CFStringHasSuffix(path
, _CFBundleSupportFilesDirectoryName1
) || CFStringHasSuffix(path
, _CFBundleSupportFilesDirectoryName2
) || CFStringHasSuffix(path
, _CFBundleResourcesDirectoryName
))) {
2445 #if READ_DIRECTORIES
2446 directoryURL
= CFRetain(url
);
2447 #endif /* READ_DIRECTORIES */
2448 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension3
;
2449 infoURLFromBase
= _CFBundleInfoURLFromBase3
;
2454 #if READ_DIRECTORIES
2456 absoluteURL
= CFURLCopyAbsoluteURL(directoryURL
);
2457 directoryPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
2458 contents
= _CFBundleCopySortedDirectoryContentsAtPath(directoryPath
, _CFBundleAllContents
);
2459 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
2460 CFRelease(directoryPath
);
2461 CFRelease(absoluteURL
);
2462 CFRelease(directoryURL
);
2464 #endif /* READ_DIRECTORIES */
2466 len
= CFStringGetLength(infoURLFromBaseNoExtension
);
2467 CFStringGetCharacters(infoURLFromBaseNoExtension
, CFRangeMake(0, len
), buff
);
2468 buff
[len
++] = (UniChar
)'-';
2469 memmove(buff
+ len
, _PlatformUniChars
, _PlatformLen
* sizeof(UniChar
));
2470 len
+= _PlatformLen
;
2471 _CFAppendPathExtension(buff
, &len
, CFMaxPathSize
, _InfoExtensionUniChars
, _InfoExtensionLen
);
2472 cheapStr
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
2473 CFStringAppendCharacters(cheapStr
, buff
, len
);
2474 infoURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, cheapStr
, url
);
2475 #if READ_DIRECTORIES
2477 CFIndex resourcesLen
, idx
;
2478 for (resourcesLen
= len
; resourcesLen
> 0; resourcesLen
--) if (buff
[resourcesLen
- 1] == '/') break;
2479 CFStringDelete(cheapStr
, CFRangeMake(0, CFStringGetLength(cheapStr
)));
2480 CFStringAppendCharacters(cheapStr
, buff
+ resourcesLen
, len
- resourcesLen
);
2481 for (tryPlatformSpecific
= false, idx
= 0; !tryPlatformSpecific
&& idx
< contentsRange
.length
; idx
++) {
2482 // Need to do this case-insensitive to accommodate Palm
2483 if (kCFCompareEqualTo
== CFStringCompare(cheapStr
, CFArrayGetValueAtIndex(contents
, idx
), kCFCompareCaseInsensitive
)) tryPlatformSpecific
= true;
2486 #endif /* READ_DIRECTORIES */
2487 if (tryPlatformSpecific
) CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault
, infoURL
, &infoData
, NULL
, NULL
, NULL
);
2488 //fprintf(stderr, "looking for ");CFShow(infoURL);fprintf(stderr, infoData ? "found it\n" : (tryPlatformSpecific ? "missed it\n" : "skipped it\n"));
2489 CFRelease(cheapStr
);
2491 // Check for global Info.plist
2493 infoURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, infoURLFromBase
, url
);
2494 #if READ_DIRECTORIES
2497 for (tryGlobal
= false, idx
= 0; !tryGlobal
&& idx
< contentsRange
.length
; idx
++) {
2498 // Need to do this case-insensitive to accommodate Palm
2499 if (kCFCompareEqualTo
== CFStringCompare(_CFBundleInfoFileName
, CFArrayGetValueAtIndex(contents
, idx
), kCFCompareCaseInsensitive
)) tryGlobal
= true;
2502 #endif /* READ_DIRECTORIES */
2503 if (tryGlobal
) CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault
, infoURL
, &infoData
, NULL
, NULL
, NULL
);
2504 //fprintf(stderr, "looking for ");CFShow(infoURL);fprintf(stderr, infoData ? "found it\n" : (tryGlobal ? "missed it\n" : "skipped it\n"));
2508 result
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(alloc
, infoData
, kCFPropertyListMutableContainers
, NULL
);
2510 if (CFDictionaryGetTypeID() == CFGetTypeID(result
)) {
2511 CFDictionarySetValue((CFMutableDictionaryRef
)result
, _kCFBundleInfoPlistURLKey
, infoURL
);
2513 if (!_CFAllocatorIsGCRefZero(alloc
)) CFRelease(result
);
2517 if (!result
) rawInfoURL
= infoURL
;
2518 CFRelease(infoData
);
2521 result
= CFDictionaryCreateMutable(alloc
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2522 if (rawInfoURL
) CFDictionarySetValue((CFMutableDictionaryRef
)result
, _kCFBundleRawInfoPlistURLKey
, rawInfoURL
);
2526 #if READ_DIRECTORIES
2527 if (contents
) CFRelease(contents
);
2528 #endif /* READ_DIRECTORIES */
2530 _processInfoDictionary((CFMutableDictionaryRef
)result
, _CFGetPlatformName(), _CFGetProductName());
2534 static Boolean
_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorRef alloc
, CFURLRef url
, CFDictionaryRef infoDict
, UInt32
*packageType
, UInt32
*packageCreator
) {
2535 Boolean retVal
= false, hasType
= false, hasCreator
= false, releaseInfoDict
= false;
2537 CFDataRef pkgInfoData
= NULL
;
2539 // Check for a "real" new bundle
2540 tempURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundlePkgInfoURLFromBase2
, url
);
2541 CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
2544 tempURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundlePkgInfoURLFromBase1
, url
);
2545 CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
2549 // Check for a "pseudo" new bundle
2550 tempURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundlePseudoPkgInfoURLFromBase
, url
);
2551 CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
2555 // Now, either we have a pkgInfoData or not. If not, then is it because this is a new bundle without one (do we allow this?), or is it dbecause it is an old bundle.
2556 // If we allow new bundles to not have a PkgInfo (because they already have the same data in the Info.plist), then we have to go read the info plist which makes failure expensive.
2557 // drd: So we assume that a new bundle _must_ have a PkgInfo if they have this data at all, otherwise we manufacture it from the extension.
2559 if (pkgInfoData
&& CFDataGetLength(pkgInfoData
) >= (int)(sizeof(UInt32
) * 2)) {
2560 UInt32
*pkgInfo
= (UInt32
*)CFDataGetBytePtr(pkgInfoData
);
2561 if (packageType
) *packageType
= CFSwapInt32BigToHost(pkgInfo
[0]);
2562 if (packageCreator
) *packageCreator
= CFSwapInt32BigToHost(pkgInfo
[1]);
2563 retVal
= hasType
= hasCreator
= true;
2565 if (pkgInfoData
) CFRelease(pkgInfoData
);
2568 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero
, url
, NULL
);
2569 releaseInfoDict
= true;
2572 CFStringRef typeString
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundlePackageTypeKey
), creatorString
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleSignatureKey
);
2574 CFIndex usedBufLen
= 0;
2575 if (typeString
&& CFGetTypeID(typeString
) == CFStringGetTypeID() && CFStringGetLength(typeString
) == 4 && 4 == CFStringGetBytes(typeString
, CFRangeMake(0, 4), kCFStringEncodingMacRoman
, 0, false, (UInt8
*)&tmp
, 4, &usedBufLen
) && 4 == usedBufLen
) {
2576 if (packageType
) *packageType
= CFSwapInt32BigToHost(tmp
);
2577 retVal
= hasType
= true;
2579 if (creatorString
&& CFGetTypeID(creatorString
) == CFStringGetTypeID() && CFStringGetLength(creatorString
) == 4 && 4 == CFStringGetBytes(creatorString
, CFRangeMake(0, 4), kCFStringEncodingMacRoman
, 0, false, (UInt8
*)&tmp
, 4, &usedBufLen
) && 4 == usedBufLen
) {
2580 if (packageCreator
) *packageCreator
= CFSwapInt32BigToHost(tmp
);
2581 retVal
= hasCreator
= true;
2583 if (releaseInfoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(infoDict
);
2586 if (!hasType
|| !hasCreator
) {
2587 // If this looks like a bundle then manufacture the type and creator.
2588 if (retVal
|| _CFBundleURLLooksLikeBundle(url
)) {
2589 if (packageCreator
&& !hasCreator
) *packageCreator
= 0x3f3f3f3f; // '????'
2590 if (packageType
&& !hasType
) {
2592 UniChar buff
[CFMaxPathSize
];
2593 CFIndex strLen
, startOfExtension
;
2594 CFURLRef absoluteURL
;
2596 // Detect "app", "debug", "profile", or "framework" extensions
2597 absoluteURL
= CFURLCopyAbsoluteURL(url
);
2598 urlStr
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
2599 CFRelease(absoluteURL
);
2600 strLen
= CFStringGetLength(urlStr
);
2601 if (strLen
> CFMaxPathSize
) strLen
= CFMaxPathSize
;
2602 CFStringGetCharacters(urlStr
, CFRangeMake(0, strLen
), buff
);
2604 startOfExtension
= _CFStartOfPathExtension(buff
, strLen
);
2605 if ((strLen
- startOfExtension
== 4 || strLen
- startOfExtension
== 5) && buff
[startOfExtension
] == (UniChar
)'.' && buff
[startOfExtension
+1] == (UniChar
)'a' && buff
[startOfExtension
+2] == (UniChar
)'p' && buff
[startOfExtension
+3] == (UniChar
)'p' && (strLen
- startOfExtension
== 4 || buff
[startOfExtension
+4] == (UniChar
)'/')) {
2607 *packageType
= 0x4150504c; // 'APPL'
2608 } else if ((strLen
- startOfExtension
== 6 || strLen
- startOfExtension
== 7) && buff
[startOfExtension
] == (UniChar
)'.' && buff
[startOfExtension
+1] == (UniChar
)'d' && buff
[startOfExtension
+2] == (UniChar
)'e' && buff
[startOfExtension
+3] == (UniChar
)'b' && buff
[startOfExtension
+4] == (UniChar
)'u' && buff
[startOfExtension
+5] == (UniChar
)'g' && (strLen
- startOfExtension
== 6 || buff
[startOfExtension
+6] == (UniChar
)'/')) {
2609 // This is an app (debug version)
2610 *packageType
= 0x4150504c; // 'APPL'
2611 } else if ((strLen
- startOfExtension
== 8 || strLen
- startOfExtension
== 9) && buff
[startOfExtension
] == (UniChar
)'.' && buff
[startOfExtension
+1] == (UniChar
)'p' && buff
[startOfExtension
+2] == (UniChar
)'r' && buff
[startOfExtension
+3] == (UniChar
)'o' && buff
[startOfExtension
+4] == (UniChar
)'f' && buff
[startOfExtension
+5] == (UniChar
)'i' && buff
[startOfExtension
+6] == (UniChar
)'l' && buff
[startOfExtension
+7] == (UniChar
)'e' && (strLen
- startOfExtension
== 8 || buff
[startOfExtension
+8] == (UniChar
)'/')) {
2612 // This is an app (profile version)
2613 *packageType
= 0x4150504c; // 'APPL'
2614 } else if ((strLen
- startOfExtension
== 8 || strLen
- startOfExtension
== 9) && buff
[startOfExtension
] == (UniChar
)'.' && buff
[startOfExtension
+1] == (UniChar
)'s' && buff
[startOfExtension
+2] == (UniChar
)'e' && buff
[startOfExtension
+3] == (UniChar
)'r' && buff
[startOfExtension
+4] == (UniChar
)'v' && buff
[startOfExtension
+5] == (UniChar
)'i' && buff
[startOfExtension
+6] == (UniChar
)'c' && buff
[startOfExtension
+7] == (UniChar
)'e' && (strLen
- startOfExtension
== 8 || buff
[startOfExtension
+8] == (UniChar
)'/')) {
2615 // This is a service
2616 *packageType
= 0x4150504c; // 'APPL'
2617 } else if ((strLen
- startOfExtension
== 10 || strLen
- startOfExtension
== 11) && buff
[startOfExtension
] == (UniChar
)'.' && buff
[startOfExtension
+1] == (UniChar
)'f' && buff
[startOfExtension
+2] == (UniChar
)'r' && buff
[startOfExtension
+3] == (UniChar
)'a' && buff
[startOfExtension
+4] == (UniChar
)'m' && buff
[startOfExtension
+5] == (UniChar
)'e' && buff
[startOfExtension
+6] == (UniChar
)'w' && buff
[startOfExtension
+7] == (UniChar
)'o' && buff
[startOfExtension
+8] == (UniChar
)'r' && buff
[startOfExtension
+9] == (UniChar
)'k' && (strLen
- startOfExtension
== 10 || buff
[startOfExtension
+10] == (UniChar
)'/')) {
2618 // This is a framework
2619 *packageType
= 0x464d574b; // 'FMWK'
2621 // Default to BNDL for generic bundle
2622 *packageType
= 0x424e444c; // 'BNDL'
2631 CF_EXPORT Boolean
_CFBundleGetPackageInfoInDirectory(CFAllocatorRef alloc
, CFURLRef url
, UInt32
*packageType
, UInt32
*packageCreator
) {
2632 return _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(alloc
, url
, NULL
, packageType
, packageCreator
);
2635 CF_EXPORT
void CFBundleGetPackageInfo(CFBundleRef bundle
, UInt32
*packageType
, UInt32
*packageCreator
) {
2636 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
);
2637 if (!_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(kCFAllocatorSystemDefault
, bundleURL
, CFBundleGetInfoDictionary(bundle
), packageType
, packageCreator
)) {
2638 if (packageType
) *packageType
= 0x424e444c; // 'BNDL'
2639 if (packageCreator
) *packageCreator
= 0x3f3f3f3f; // '????'
2641 if (bundleURL
) CFRelease(bundleURL
);
2644 CF_EXPORT Boolean
CFBundleGetPackageInfoInDirectory(CFURLRef url
, UInt32
*packageType
, UInt32
*packageCreator
) {
2645 return _CFBundleGetPackageInfoInDirectory(kCFAllocatorSystemDefault
, url
, packageType
, packageCreator
);
2648 static void _CFBundleCheckSupportedPlatform(CFMutableArrayRef mutableArray
, UniChar
*buff
, CFIndex startLen
, CFStringRef platformName
, CFStringRef platformIdentifier
) {
2649 CFIndex buffLen
= startLen
, platformLen
= CFStringGetLength(platformName
), extLen
= CFStringGetLength(_CFBundleInfoExtension
);
2650 CFMutableStringRef str
;
2652 if (buffLen
+ platformLen
+ extLen
< CFMaxPathSize
) {
2653 CFStringGetCharacters(platformName
, CFRangeMake(0, platformLen
), buff
+ buffLen
);
2654 buffLen
+= platformLen
;
2655 buff
[buffLen
++] = (UniChar
)'.';
2656 CFStringGetCharacters(_CFBundleInfoExtension
, CFRangeMake(0, extLen
), buff
+ buffLen
);
2658 str
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
2659 CFStringAppendCharacters(str
, buff
, buffLen
);
2660 if (_CFIsResourceAtPath(str
, &isDir
) && !isDir
&& CFArrayGetFirstIndexOfValue(mutableArray
, CFRangeMake(0, CFArrayGetCount(mutableArray
)), platformIdentifier
) < 0) CFArrayAppendValue(mutableArray
, platformIdentifier
);
2665 CF_EXPORT CFArrayRef
_CFBundleGetSupportedPlatforms(CFBundleRef bundle
) {
2666 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
2667 CFArrayRef platformArray
= infoDict
? (CFArrayRef
)CFDictionaryGetValue(infoDict
, _kCFBundleSupportedPlatformsKey
) : NULL
;
2668 if (platformArray
&& CFGetTypeID(platformArray
) != CFArrayGetTypeID()) {
2669 platformArray
= NULL
;
2670 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleSupportedPlatformsKey
);
2672 if (!platformArray
) {
2673 CFURLRef infoPlistURL
= infoDict
? (CFURLRef
)CFDictionaryGetValue(infoDict
, _kCFBundleInfoPlistURLKey
) : NULL
, absoluteURL
;
2674 CFStringRef infoPlistPath
;
2675 UniChar buff
[CFMaxPathSize
];
2676 CFIndex buffLen
, infoLen
= CFStringGetLength(_CFBundleInfoURLFromBaseNoExtension3
), startLen
, extLen
= CFStringGetLength(_CFBundleInfoExtension
);
2678 CFMutableArrayRef mutableArray
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2679 absoluteURL
= CFURLCopyAbsoluteURL(infoPlistURL
);
2680 infoPlistPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
2681 CFRelease(absoluteURL
);
2682 buffLen
= CFStringGetLength(infoPlistPath
);
2683 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
2684 CFStringGetCharacters(infoPlistPath
, CFRangeMake(0, buffLen
), buff
);
2685 CFRelease(infoPlistPath
);
2687 buffLen
= _CFStartOfLastPathComponent(buff
, buffLen
);
2688 if (buffLen
> 0 && buffLen
+ infoLen
+ extLen
< CFMaxPathSize
) {
2689 CFStringGetCharacters(_CFBundleInfoURLFromBaseNoExtension3
, CFRangeMake(0, infoLen
), buff
+ buffLen
);
2691 buff
[buffLen
++] = (UniChar
)'-';
2693 _CFBundleCheckSupportedPlatform(mutableArray
, buff
, startLen
, CFSTR("macos"), CFSTR("MacOS"));
2694 _CFBundleCheckSupportedPlatform(mutableArray
, buff
, startLen
, CFSTR("macosx"), CFSTR("MacOS"));
2695 _CFBundleCheckSupportedPlatform(mutableArray
, buff
, startLen
, CFSTR("iphoneos"), CFSTR("iPhoneOS"));
2696 _CFBundleCheckSupportedPlatform(mutableArray
, buff
, startLen
, CFSTR("windows"), CFSTR("Windows"));
2699 if (CFArrayGetCount(mutableArray
) > 0) {
2700 platformArray
= (CFArrayRef
)mutableArray
;
2701 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleSupportedPlatformsKey
, platformArray
);
2703 CFRelease(mutableArray
);
2706 return platformArray
;
2709 CF_EXPORT CFStringRef
_CFBundleGetCurrentPlatform(void) {
2710 #if DEPLOYMENT_TARGET_MACOSX
2711 return CFSTR("MacOS");
2712 #elif DEPLOYMENT_TARGET_EMBEDDED
2713 return CFSTR("iPhoneOS");
2714 #elif DEPLOYMENT_TARGET_WINDOWS
2715 return CFSTR("Windows");
2716 #elif DEPLOYMENT_TARGET_SOLARIS
2717 return CFSTR("Solaris");
2718 #elif DEPLOYMENT_TARGET_HPUX
2719 return CFSTR("HPUX");
2720 #elif DEPLOYMENT_TARGET_LINUX
2721 return CFSTR("Linux");
2722 #elif DEPLOYMENT_TARGET_FREEBSD
2723 return CFSTR("FreeBSD");
2725 #error Unknown or unspecified DEPLOYMENT_TARGET
2729 __private_extern__ CFStringRef
_CFBundleGetPlatformExecutablesSubdirectoryName(void) {
2730 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2731 return CFSTR("MacOS");
2732 #elif DEPLOYMENT_TARGET_WINDOWS
2733 return CFSTR("Windows");
2734 #elif DEPLOYMENT_TARGET_SOLARIS
2735 return CFSTR("Solaris");
2736 #elif DEPLOYMENT_TARGET_HPUX
2737 return CFSTR("HPUX");
2738 #elif DEPLOYMENT_TARGET_LINUX
2739 return CFSTR("Linux");
2740 #elif DEPLOYMENT_TARGET_FREEBSD
2741 return CFSTR("FreeBSD");
2743 #error Unknown or unspecified DEPLOYMENT_TARGET
2747 __private_extern__ CFStringRef
_CFBundleGetAlternatePlatformExecutablesSubdirectoryName(void) {
2748 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2749 return CFSTR("Mac OS X");
2750 #elif DEPLOYMENT_TARGET_WINDOWS
2751 return CFSTR("WinNT");
2752 #elif DEPLOYMENT_TARGET_SOLARIS
2753 return CFSTR("Solaris");
2754 #elif DEPLOYMENT_TARGET_HPUX
2755 return CFSTR("HP-UX");
2756 #elif DEPLOYMENT_TARGET_LINUX
2757 return CFSTR("Linux");
2758 #elif DEPLOYMENT_TARGET_FREEBSD
2759 return CFSTR("FreeBSD");
2761 #error Unknown or unspecified DEPLOYMENT_TARGET
2765 __private_extern__ CFStringRef
_CFBundleGetOtherPlatformExecutablesSubdirectoryName(void) {
2766 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2767 return CFSTR("MacOSClassic");
2768 #elif DEPLOYMENT_TARGET_WINDOWS
2769 return CFSTR("Other");
2770 #elif DEPLOYMENT_TARGET_HPUX
2771 return CFSTR("Other");
2772 #elif DEPLOYMENT_TARGET_SOLARIS
2773 return CFSTR("Other");
2774 #elif DEPLOYMENT_TARGET_LINUX
2775 return CFSTR("Other");
2776 #elif DEPLOYMENT_TARGET_FREEBSD
2777 return CFSTR("Other");
2779 #error Unknown or unspecified DEPLOYMENT_TARGET
2783 __private_extern__ CFStringRef
_CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(void) {
2784 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2785 return CFSTR("Mac OS 8");
2786 #elif DEPLOYMENT_TARGET_WINDOWS
2787 return CFSTR("Other");
2788 #elif DEPLOYMENT_TARGET_HPUX
2789 return CFSTR("Other");
2790 #elif DEPLOYMENT_TARGET_SOLARIS
2791 return CFSTR("Other");
2792 #elif DEPLOYMENT_TARGET_LINUX
2793 return CFSTR("Other");
2794 #elif DEPLOYMENT_TARGET_FREEBSD
2795 return CFSTR("Other");
2797 #error Unknown or unspecified DEPLOYMENT_TARGET
2801 __private_extern__ CFArrayRef
_CFBundleCopyBundleRegionsArray(CFBundleRef bundle
) {
2802 return CFBundleCopyBundleLocalizations(bundle
);
2805 CF_EXPORT CFArrayRef
CFBundleCopyBundleLocalizations(CFBundleRef bundle
) {
2806 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
2807 CFURLRef resourcesURL
= CFBundleCopyResourcesDirectoryURL(bundle
);
2808 #if READ_DIRECTORIES
2809 CFURLRef absoluteURL
;
2810 CFStringRef directoryPath
;
2811 CFArrayRef contents
;
2812 CFRange contentsRange
;
2814 #else /* READ_DIRECTORIES */
2815 CFArrayRef urls
= ((_CFBundleLayoutVersion(bundle
) != 4) ? _CFContentsOfDirectory(CFGetAllocator(bundle
), NULL
, NULL
, resourcesURL
, _CFBundleLprojExtension
) : NULL
);
2816 #endif /* READ_DIRECTORIES */
2817 CFArrayRef predefinedLocalizations
= NULL
;
2818 CFMutableArrayRef result
= NULL
;
2821 predefinedLocalizations
= (CFArrayRef
)CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
2822 if (predefinedLocalizations
&& CFGetTypeID(predefinedLocalizations
) != CFArrayGetTypeID()) {
2823 predefinedLocalizations
= NULL
;
2824 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleLocalizationsKey
);
2826 if (predefinedLocalizations
) {
2827 CFIndex i
, c
= CFArrayGetCount(predefinedLocalizations
);
2828 if (c
> 0 && !result
) result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2829 for (i
= 0; i
< c
; i
++) CFArrayAppendValue(result
, CFArrayGetValueAtIndex(predefinedLocalizations
, i
));
2833 #if READ_DIRECTORIES
2835 absoluteURL
= CFURLCopyAbsoluteURL(resourcesURL
);
2836 directoryPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
2837 contents
= _CFBundleCopySortedDirectoryContentsAtPath(directoryPath
, _CFBundleAllContents
);
2838 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
2839 for (idx
= 0; idx
< contentsRange
.length
; idx
++) {
2840 CFStringRef name
= CFArrayGetValueAtIndex(contents
, idx
);
2841 if (CFStringHasSuffix(name
, _CFBundleLprojExtensionWithDot
)) {
2842 CFStringRef localization
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, name
, CFRangeMake(0, CFStringGetLength(name
) - 6));
2843 if (!result
) result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2844 CFArrayAppendValue(result
, localization
);
2845 CFRelease(localization
);
2848 CFRelease(contents
);
2849 CFRelease(directoryPath
);
2850 CFRelease(absoluteURL
);
2852 #else /* READ_DIRECTORIES */
2854 CFIndex i
, c
= CFArrayGetCount(urls
);
2855 CFURLRef curURL
, curAbsoluteURL
;
2856 CFStringRef curStr
, regionStr
;
2857 UniChar buff
[CFMaxPathSize
];
2858 CFIndex strLen
, startOfLastPathComponent
, regionLen
;
2860 if (c
> 0 && !result
) result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2861 for (i
= 0; i
< c
; i
++) {
2862 curURL
= (CFURLRef
)CFArrayGetValueAtIndex(urls
, i
);
2863 curAbsoluteURL
= CFURLCopyAbsoluteURL(curURL
);
2864 curStr
= CFURLCopyFileSystemPath(curAbsoluteURL
, PLATFORM_PATH_STYLE
);
2865 CFRelease(curAbsoluteURL
);
2866 strLen
= CFStringGetLength(curStr
);
2867 if (strLen
> CFMaxPathSize
) strLen
= CFMaxPathSize
;
2868 CFStringGetCharacters(curStr
, CFRangeMake(0, strLen
), buff
);
2870 startOfLastPathComponent
= _CFStartOfLastPathComponent(buff
, strLen
);
2871 regionLen
= _CFLengthAfterDeletingPathExtension(&(buff
[startOfLastPathComponent
]), strLen
- startOfLastPathComponent
);
2872 regionStr
= CFStringCreateWithCharacters(CFGetAllocator(bundle
), &(buff
[startOfLastPathComponent
]), regionLen
);
2873 CFArrayAppendValue(result
, regionStr
);
2874 CFRelease(regionStr
);
2879 #endif /* READ_DIRECTORIES */
2882 CFStringRef developmentLocalization
= CFBundleGetDevelopmentRegion(bundle
);
2883 if (developmentLocalization
) {
2884 result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2885 CFArrayAppendValue(result
, developmentLocalization
);
2888 if (resourcesURL
) CFRelease(resourcesURL
);
2893 CF_EXPORT CFDictionaryRef
CFBundleCopyInfoDictionaryForURL(CFURLRef url
) {
2894 CFDictionaryRef result
= NULL
;
2895 Boolean isDir
= false;
2896 if (_CFIsResourceAtURL(url
, &isDir
)) {
2898 result
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero
, url
, NULL
);
2900 result
= _CFBundleCopyInfoDictionaryInExecutable(url
); // return zero-ref dictionary under GC
2903 if (result
&& _CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRetain(result
); // conditionally put on a retain for a Copy function
2907 CFArrayRef
CFBundleCopyExecutableArchitecturesForURL(CFURLRef url
) {
2908 CFArrayRef result
= NULL
;
2909 CFBundleRef bundle
= CFBundleCreate(kCFAllocatorSystemDefault
, url
);
2911 result
= CFBundleCopyExecutableArchitectures(bundle
);
2914 result
= _CFBundleCopyArchitecturesForExecutable(url
);
2919 CFArrayRef
CFBundleCopyLocalizationsForURL(CFURLRef url
) {
2920 CFArrayRef result
= NULL
;
2921 CFBundleRef bundle
= CFBundleCreate(kCFAllocatorSystemDefault
, url
);
2922 CFStringRef devLang
= NULL
;
2924 result
= CFBundleCopyBundleLocalizations(bundle
);
2927 CFDictionaryRef infoDict
= _CFBundleCopyInfoDictionaryInExecutable(url
); // return zero-ref dictionary under GC
2929 CFArrayRef predefinedLocalizations
= (CFArrayRef
)CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
2930 if (predefinedLocalizations
&& CFGetTypeID(predefinedLocalizations
) == CFArrayGetTypeID()) result
= (CFArrayRef
)CFRetain(predefinedLocalizations
);
2932 devLang
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
2933 if (devLang
&& (CFGetTypeID(devLang
) == CFStringGetTypeID() && CFStringGetLength(devLang
) > 0)) result
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&devLang
, 1, &kCFTypeArrayCallBacks
);
2935 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(infoDict
);