2 * Copyright (c) 2010 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-2009, Apple Inc. All rights reserved.
26 Responsibility: Doug Davidson
29 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
30 #define READ_DIRECTORIES 1
31 #elif DEPLOYMENT_TARGET_WINDOWS
32 #define READ_DIRECTORIES 0
34 #error Unknown or unspecified DEPLOYMENT_TARGET
37 #define READ_DIRECTORIES_CACHE_CAPACITY 128
39 #include "CFBundle_Internal.h"
40 #include <CoreFoundation/CFURLAccess.h>
41 #include <CoreFoundation/CFPropertyList.h>
42 #include <CoreFoundation/CFByteOrder.h>
43 #include <CoreFoundation/CFNumber.h>
44 #include <CoreFoundation/CFLocale.h>
45 #include <CoreFoundation/CFPreferences.h>
47 #include "CFInternal.h"
48 #include <CoreFoundation/CFPriv.h>
54 #if DEPLOYMENT_TARGET_MACOSX
56 #elif DEPLOYMENT_TARGET_EMBEDDED
58 #elif DEPLOYMENT_TARGET_WINDOWS
60 #error Unknown or unspecified DEPLOYMENT_TARGET
65 #endif /* READ_DIRECTORIES */
69 // All new-style bundles will have these extensions.
70 CF_INLINE CFStringRef
_CFGetPlatformName(void) {
71 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
72 return _CFBundleMacOSXPlatformName
;
73 #elif DEPLOYMENT_TARGET_WINDOWS
74 return _CFBundleWindowsPlatformName
;
75 #elif DEPLOYMENT_TARGET_SOLARIS
76 return _CFBundleSolarisPlatformName
;
77 #elif DEPLOYMENT_TARGET_HPUX
78 return _CFBundleHPUXPlatformName
;
79 #elif DEPLOYMENT_TARGET_LINUX
80 return _CFBundleLinuxPlatformName
;
81 #elif DEPLOYMENT_TARGET_FREEBSD
82 return _CFBundleFreeBSDPlatformName
;
84 #error Unknown or unspecified DEPLOYMENT_TARGET
88 CF_INLINE CFStringRef
_CFGetAlternatePlatformName(void) {
89 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
90 return _CFBundleAlternateMacOSXPlatformName
;
91 #elif DEPLOYMENT_TARGET_WINDOWS
94 #error Unknown or unspecified DEPLOYMENT_TARGET
98 static CFSpinLock_t CFBundleResourceGlobalDataLock
= CFSpinLockInit
;
99 static UniChar
*_AppSupportUniChars1
= NULL
;
100 static CFIndex _AppSupportLen1
= 0;
101 static UniChar
*_AppSupportUniChars2
= NULL
;
102 static CFIndex _AppSupportLen2
= 0;
103 static UniChar
*_ResourcesUniChars
= NULL
;
104 static CFIndex _ResourcesLen
= 0;
105 static UniChar
*_PlatformUniChars
= NULL
;
106 static CFIndex _PlatformLen
= 0;
107 static UniChar
*_AlternatePlatformUniChars
= NULL
;
108 static CFIndex _AlternatePlatformLen
= 0;
109 static UniChar
*_LprojUniChars
= NULL
;
110 static CFIndex _LprojLen
= 0;
111 static UniChar
*_GlobalResourcesUniChars
= NULL
;
112 static CFIndex _GlobalResourcesLen
= 0;
113 static UniChar
*_InfoExtensionUniChars
= NULL
;
114 static CFIndex _InfoExtensionLen
= 0;
116 static void _CFBundleInitStaticUniCharBuffers(void) {
117 CFStringRef appSupportStr1
= _CFBundleSupportFilesDirectoryName1
;
118 CFStringRef appSupportStr2
= _CFBundleSupportFilesDirectoryName2
;
119 CFStringRef resourcesStr
= _CFBundleResourcesDirectoryName
;
120 CFStringRef platformStr
= _CFGetPlatformName();
121 CFStringRef alternatePlatformStr
= _CFGetAlternatePlatformName();
122 CFStringRef lprojStr
= _CFBundleLprojExtension
;
123 CFStringRef globalResourcesStr
= _CFBundleNonLocalizedResourcesDirectoryName
;
124 CFStringRef infoExtensionStr
= _CFBundleInfoExtension
;
126 CFAllocatorRef alloc
= __CFGetDefaultAllocator();
128 _AppSupportLen1
= CFStringGetLength(appSupportStr1
);
129 _AppSupportLen2
= CFStringGetLength(appSupportStr2
);
130 _ResourcesLen
= CFStringGetLength(resourcesStr
);
131 _PlatformLen
= CFStringGetLength(platformStr
);
132 _AlternatePlatformLen
= CFStringGetLength(alternatePlatformStr
);
133 _LprojLen
= CFStringGetLength(lprojStr
);
134 _GlobalResourcesLen
= CFStringGetLength(globalResourcesStr
);
135 _InfoExtensionLen
= CFStringGetLength(infoExtensionStr
);
137 _AppSupportUniChars1
= (UniChar
*)CFAllocatorAllocate(alloc
, sizeof(UniChar
) * (_AppSupportLen1
+ _AppSupportLen2
+ _ResourcesLen
+ _PlatformLen
+ _AlternatePlatformLen
+ _LprojLen
+ _GlobalResourcesLen
+ _InfoExtensionLen
), 0);
138 _AppSupportUniChars2
= _AppSupportUniChars1
+ _AppSupportLen1
;
139 _ResourcesUniChars
= _AppSupportUniChars2
+ _AppSupportLen2
;
140 _PlatformUniChars
= _ResourcesUniChars
+ _ResourcesLen
;
141 _AlternatePlatformUniChars
= _PlatformUniChars
+ _PlatformLen
;
142 _LprojUniChars
= _AlternatePlatformUniChars
+ _AlternatePlatformLen
;
143 _GlobalResourcesUniChars
= _LprojUniChars
+ _LprojLen
;
144 _InfoExtensionUniChars
= _GlobalResourcesUniChars
+ _GlobalResourcesLen
;
146 if (_AppSupportLen1
> 0) CFStringGetCharacters(appSupportStr1
, CFRangeMake(0, _AppSupportLen1
), _AppSupportUniChars1
);
147 if (_AppSupportLen2
> 0) CFStringGetCharacters(appSupportStr2
, CFRangeMake(0, _AppSupportLen2
), _AppSupportUniChars2
);
148 if (_ResourcesLen
> 0) CFStringGetCharacters(resourcesStr
, CFRangeMake(0, _ResourcesLen
), _ResourcesUniChars
);
149 if (_PlatformLen
> 0) CFStringGetCharacters(platformStr
, CFRangeMake(0, _PlatformLen
), _PlatformUniChars
);
150 if (_AlternatePlatformLen
> 0) CFStringGetCharacters(alternatePlatformStr
, CFRangeMake(0, _AlternatePlatformLen
), _AlternatePlatformUniChars
);
151 if (_LprojLen
> 0) CFStringGetCharacters(lprojStr
, CFRangeMake(0, _LprojLen
), _LprojUniChars
);
152 if (_GlobalResourcesLen
> 0) CFStringGetCharacters(globalResourcesStr
, CFRangeMake(0, _GlobalResourcesLen
), _GlobalResourcesUniChars
);
153 if (_InfoExtensionLen
> 0) CFStringGetCharacters(infoExtensionStr
, CFRangeMake(0, _InfoExtensionLen
), _InfoExtensionUniChars
);
156 CF_INLINE
void _CFEnsureStaticBuffersInited(void) {
157 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
158 if (!_AppSupportUniChars1
) _CFBundleInitStaticUniCharBuffers();
159 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
164 static CFMutableDictionaryRef contentsCache
= NULL
;
165 static CFMutableDictionaryRef directoryContentsCache
= NULL
;
166 static CFMutableDictionaryRef unknownContentsCache
= NULL
;
169 _CFBundleAllContents
= 0,
170 _CFBundleDirectoryContents
= 1,
171 _CFBundleUnknownContents
= 2
172 } _CFBundleDirectoryContentsType
;
174 static CFArrayRef
_CFBundleCopyDirectoryContentsAtPath(CFStringRef path
, _CFBundleDirectoryContentsType contentsType
) {
175 CFArrayRef result
= NULL
;
177 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
178 if (contentsType
== _CFBundleUnknownContents
) {
179 if (unknownContentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(unknownContentsCache
, path
);
180 } else if (contentsType
== _CFBundleDirectoryContents
) {
181 if (directoryContentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(directoryContentsCache
, path
);
183 if (contentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(contentsCache
, path
);
185 if (result
) CFRetain(result
);
186 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
189 Boolean tryToOpen
= false, allDots
= true;
190 char cpathBuff
[CFMaxPathSize
];
191 CFIndex cpathLen
= 0, idx
, lastSlashIdx
= 0;
194 CFMutableArrayRef contents
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
), directoryContents
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
), unknownContents
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
195 CFStringRef dirName
, name
;
199 if (CFStringGetFileSystemRepresentation(path
, cpathBuff
, CFMaxPathSize
)) {
201 cpathLen
= strlen(cpathBuff
);
203 // First see whether we already know that the directory doesn't exist
204 for (idx
= cpathLen
; lastSlashIdx
== 0 && idx
-- > 0;) {
205 if (cpathBuff
[idx
] == '/') lastSlashIdx
= idx
;
206 else if (cpathBuff
[idx
] != '.') allDots
= false;
208 if (lastSlashIdx
> 0 && lastSlashIdx
+ 1 < cpathLen
&& !allDots
) {
209 cpathBuff
[lastSlashIdx
] = '\0';
210 dirName
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, cpathBuff
);
212 name
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, cpathBuff
+ lastSlashIdx
+ 1);
214 // ??? we might like to use directoryContentsCache rather than contentsCache here, but we cannot unless we resolve DT_LNKs below
215 CFArrayRef dirDirContents
= NULL
;
217 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
218 if (contentsCache
) dirDirContents
= (CFArrayRef
)CFDictionaryGetValue(contentsCache
, dirName
);
219 if (dirDirContents
) {
220 Boolean foundIt
= false;
221 CFIndex dirDirIdx
, dirDirLength
= CFArrayGetCount(dirDirContents
);
222 for (dirDirIdx
= 0; !foundIt
&& dirDirIdx
< dirDirLength
; dirDirIdx
++) if (kCFCompareEqualTo
== CFStringCompare(name
, CFArrayGetValueAtIndex(dirDirContents
, dirDirIdx
), kCFCompareCaseInsensitive
)) foundIt
= true;
223 if (!foundIt
) tryToOpen
= false;
225 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
230 cpathBuff
[lastSlashIdx
] = '/';
233 if (tryToOpen
&& stat(cpathBuff
, &statBuf
) == 0 && (statBuf
.st_mode
& S_IFMT
) == S_IFDIR
&& (dirp
= opendir(cpathBuff
))) {
234 while ((dent
= readdir(dirp
))) {
235 CFIndex nameLen
= strlen(dent
->d_name
);
236 if (0 == nameLen
|| 0 == dent
->d_fileno
|| ('.' == dent
->d_name
[0] && (1 == nameLen
|| (2 == nameLen
&& '.' == dent
->d_name
[1]) || '_' == dent
->d_name
[1]))) continue;
237 name
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, dent
->d_name
);
239 // ??? should we follow links for DT_LNK? unless we do, results are approximate, but for performance reasons we do not
240 // ??? likewise for DT_UNKNOWN
241 // ??? the utility of distinguishing directories from other contents is somewhat doubtful anyway
242 CFArrayAppendValue(contents
, name
);
243 if (dent
->d_type
== DT_DIR
) {
244 CFArrayAppendValue(directoryContents
, name
);
245 } else if (dent
->d_type
== DT_UNKNOWN
) {
246 CFArrayAppendValue(unknownContents
, name
);
251 (void)closedir(dirp
);
254 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
255 if (!contentsCache
) contentsCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, READ_DIRECTORIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
256 if (READ_DIRECTORIES_CACHE_CAPACITY
<= CFDictionaryGetCount(contentsCache
)) CFDictionaryRemoveAllValues(contentsCache
);
257 CFDictionaryAddValue(contentsCache
, path
, contents
);
259 if (!directoryContentsCache
) directoryContentsCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, READ_DIRECTORIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
260 if (READ_DIRECTORIES_CACHE_CAPACITY
<= CFDictionaryGetCount(directoryContentsCache
)) CFDictionaryRemoveAllValues(directoryContentsCache
);
261 CFDictionaryAddValue(directoryContentsCache
, path
, directoryContents
);
263 if (!unknownContentsCache
) unknownContentsCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, READ_DIRECTORIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
264 if (READ_DIRECTORIES_CACHE_CAPACITY
<= CFDictionaryGetCount(unknownContentsCache
)) CFDictionaryRemoveAllValues(unknownContentsCache
);
265 CFDictionaryAddValue(unknownContentsCache
, path
, unknownContents
);
267 if (contentsType
== _CFBundleUnknownContents
) {
268 result
= CFRetain(unknownContents
);
269 } else if (contentsType
== _CFBundleDirectoryContents
) {
270 result
= CFRetain(directoryContents
);
272 result
= CFRetain(contents
);
276 CFRelease(directoryContents
);
277 CFRelease(unknownContents
);
278 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
283 static void _CFBundleFlushContentsCaches(void) {
284 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
285 if (contentsCache
) CFDictionaryRemoveAllValues(contentsCache
);
286 if (directoryContentsCache
) CFDictionaryRemoveAllValues(directoryContentsCache
);
287 if (unknownContentsCache
) CFDictionaryRemoveAllValues(unknownContentsCache
);
288 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
291 static void _CFBundleFlushContentsCacheForPath(CFMutableDictionaryRef cache
, CFStringRef path
) {
292 CFStringRef keys
[READ_DIRECTORIES_CACHE_CAPACITY
];
293 unsigned i
, count
= CFDictionaryGetCount(cache
);
294 if (count
<= READ_DIRECTORIES_CACHE_CAPACITY
) {
295 CFDictionaryGetKeysAndValues(cache
, (const void **)keys
, NULL
);
296 for (i
= 0; i
< count
; i
++) {
297 if (CFStringFindWithOptions(keys
[i
], path
, CFRangeMake(0, CFStringGetLength(keys
[i
])), kCFCompareAnchored
|kCFCompareCaseInsensitive
, NULL
)) CFDictionaryRemoveValue(cache
, keys
[i
]);
302 static void _CFBundleFlushContentsCachesForPath(CFStringRef path
) {
303 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
304 if (contentsCache
) _CFBundleFlushContentsCacheForPath(contentsCache
, path
);
305 if (directoryContentsCache
) _CFBundleFlushContentsCacheForPath(directoryContentsCache
, path
);
306 if (unknownContentsCache
) _CFBundleFlushContentsCacheForPath(unknownContentsCache
, path
);
307 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
310 #endif /* READ_DIRECTORIES */
312 CF_EXPORT
void _CFBundleFlushCachesForURL(CFURLRef url
) {
314 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
315 CFStringRef path
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
316 _CFBundleFlushContentsCachesForPath(path
);
318 CFRelease(absoluteURL
);
319 #endif /* READ_DIRECTORIES */
322 CF_EXPORT
void _CFBundleFlushCaches(void) {
324 _CFBundleFlushContentsCaches();
325 #endif /* READ_DIRECTORIES */
328 __private_extern__ Boolean
_CFIsResourceAtURL(CFURLRef url
, Boolean
*isDir
) {
331 if (_CFGetFileProperties(kCFAllocatorSystemDefault
, url
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) {
332 if (isDir
) *isDir
= ((exists
&& ((mode
& S_IFMT
) == S_IFDIR
)) ? true : false);
333 return (exists
&& (mode
& 0444));
339 __private_extern__ Boolean
_CFIsResourceAtPath(CFStringRef path
, Boolean
*isDir
) {
340 Boolean result
= false;
341 CFURLRef url
= CFURLCreateWithFileSystemPath(CFGetAllocator(path
), path
, PLATFORM_PATH_STYLE
, false);
343 result
= _CFIsResourceAtURL(url
, isDir
);
350 static CFArrayRef
_CFCopyTypesForSearchBundleDirectory(CFAllocatorRef alloc
, UniChar
*pathUniChars
, CFIndex pathLen
, UniChar
*nameUniChars
, CFIndex nameLen
, CFArrayRef resTypes
, CFMutableStringRef cheapStr
, CFMutableStringRef tmpString
, uint8_t version
) {
351 CFMutableArrayRef result
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
353 CFRange contentsRange
, resultRange
= CFRangeMake(0, 0);
354 CFIndex dirPathLen
= pathLen
, numResTypes
= CFArrayGetCount(resTypes
), i
, j
;
356 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, dirPathLen
, dirPathLen
);
357 CFStringReplaceAll(cheapStr
, tmpString
);
358 //fprintf(stderr, "looking in ");CFShow(cheapStr);
359 contents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, _CFBundleAllContents
);
360 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
362 CFStringSetExternalCharactersNoCopy(tmpString
, nameUniChars
, nameLen
, nameLen
);
363 CFStringReplaceAll(cheapStr
, tmpString
);
364 for (i
= 0; i
< contentsRange
.length
; i
++) {
365 CFStringRef content
= CFArrayGetValueAtIndex(contents
, i
);
366 if (CFStringHasPrefix(content
, cheapStr
)) {
367 //fprintf(stderr, "found ");CFShow(content);
368 for (j
= 0; j
< numResTypes
; j
++) {
369 CFStringRef resType
= CFArrayGetValueAtIndex(resTypes
, j
);
370 if (!CFArrayContainsValue(result
, resultRange
, resType
) && CFStringHasSuffix(content
, resType
)) {
371 CFArrayAppendValue(result
, resType
);
372 resultRange
.length
= CFArrayGetCount(result
);
377 //fprintf(stderr, "result ");CFShow(result);
381 #endif /* READ_DIRECTORIES */
383 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
) {
384 // pathUniChars is the full path to the directory we are searching.
385 // nameUniChars is what we are looking for.
386 // typeUniChars is the type we are looking for.
387 // platformUniChars is the platform name.
388 // cheapStr is available for our use for whatever we want.
389 // URLs for found resources get added to result.
390 CFIndex savedPathLen
;
391 Boolean appendSucceeded
= true, platformGenericFound
= false, platformSpecificFound
= false, platformGenericIsDir
= false, platformSpecificIsDir
= false;
393 Boolean platformGenericIsUnknown
= false, platformSpecificIsUnknown
= false;
395 CFStringRef platformGenericStr
= NULL
;
398 CFIndex dirPathLen
= pathLen
;
399 CFArrayRef contents
, directoryContents
, unknownContents
;
400 CFRange contentsRange
, directoryContentsRange
, unknownContentsRange
;
402 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, dirPathLen
, dirPathLen
);
403 CFStringReplaceAll(cheapStr
, tmpString
);
404 //fprintf(stderr, "looking in ");CFShow(cheapStr);
405 contents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, _CFBundleAllContents
);
406 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
407 directoryContents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, _CFBundleDirectoryContents
);
408 directoryContentsRange
= CFRangeMake(0, CFArrayGetCount(directoryContents
));
409 unknownContents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, _CFBundleUnknownContents
);
410 unknownContentsRange
= CFRangeMake(0, CFArrayGetCount(unknownContents
));
411 #endif /* READ_DIRECTORIES */
413 if (nameLen
> 0) appendSucceeded
= _CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, nameUniChars
, nameLen
);
414 savedPathLen
= pathLen
;
415 if (appendSucceeded
&& typeLen
> 0) appendSucceeded
= _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
416 if (appendSucceeded
) {
418 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ dirPathLen
+ 1, pathLen
- dirPathLen
- 1, pathLen
- dirPathLen
- 1);
419 CFStringReplaceAll(cheapStr
, tmpString
);
420 platformGenericFound
= CFArrayContainsValue(contents
, contentsRange
, cheapStr
);
421 platformGenericIsDir
= CFArrayContainsValue(directoryContents
, directoryContentsRange
, cheapStr
);
422 platformGenericIsUnknown
= CFArrayContainsValue(unknownContents
, unknownContentsRange
, cheapStr
);
423 //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformGenericFound) fprintf(stderr, "found it\n"); if (platformGenericIsDir) fprintf(stderr, "a directory\n");
424 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
425 CFStringReplaceAll(cheapStr
, tmpString
);
426 if (platformGenericFound
&& platformGenericIsUnknown
) {
427 (void)_CFIsResourceAtPath(cheapStr
, &platformGenericIsDir
);
428 //if (platformGenericIsDir) fprintf(stderr, "a directory after all\n"); else fprintf(stderr, "not a directory after all\n");
430 #else /* READ_DIRECTORIES */
431 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
432 CFStringReplaceAll(cheapStr
, tmpString
);
433 platformGenericFound
= _CFIsResourceAtPath(cheapStr
, &platformGenericIsDir
);
434 #endif /* READ_DIRECTORIES */
437 // Check for platform specific.
438 if (platformGenericFound
) {
439 platformGenericStr
= (CFStringRef
)CFStringCreateCopy(alloc
, cheapStr
);
440 if (!platformSpecificFound
&& (_PlatformLen
> 0)) {
441 pathLen
= savedPathLen
;
442 pathUniChars
[pathLen
++] = (UniChar
)'-';
443 memmove(pathUniChars
+ pathLen
, _PlatformUniChars
, _PlatformLen
* sizeof(UniChar
));
444 pathLen
+= _PlatformLen
;
445 if (appendSucceeded
&& typeLen
> 0) appendSucceeded
= _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
446 if (appendSucceeded
) {
448 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ dirPathLen
+ 1, pathLen
- dirPathLen
- 1, pathLen
- dirPathLen
- 1);
449 CFStringReplaceAll(cheapStr
, tmpString
);
450 platformSpecificFound
= CFArrayContainsValue(contents
, contentsRange
, cheapStr
);
451 platformSpecificIsDir
= CFArrayContainsValue(directoryContents
, directoryContentsRange
, cheapStr
);
452 platformSpecificIsUnknown
= CFArrayContainsValue(unknownContents
, unknownContentsRange
, cheapStr
);
453 //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformSpecificFound) fprintf(stderr, "found it\n"); if (platformSpecificIsDir) fprintf(stderr, "a directory\n");
454 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
455 CFStringReplaceAll(cheapStr
, tmpString
);
456 if (platformSpecificFound
&& platformSpecificIsUnknown
) {
457 (void)_CFIsResourceAtPath(cheapStr
, &platformSpecificIsDir
);
458 //if (platformSpecificIsDir) fprintf(stderr, "a directory after all\n"); else fprintf(stderr, "not a directory after all\n");
460 #else /* READ_DIRECTORIES */
461 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
462 CFStringReplaceAll(cheapStr
, tmpString
);
463 platformSpecificFound
= _CFIsResourceAtPath(cheapStr
, &platformSpecificIsDir
);
464 #endif /* READ_DIRECTORIES */
468 if (platformSpecificFound
) {
469 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, platformSpecificIsDir
);
470 CFArrayAppendValue(result
, url
);
472 } else if (platformGenericFound
) {
473 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, platformGenericStr
? platformGenericStr
: cheapStr
, PLATFORM_PATH_STYLE
, platformGenericIsDir
);
474 CFArrayAppendValue(result
, url
);
477 if (platformGenericStr
) CFRelease(platformGenericStr
);
480 CFRelease(directoryContents
);
481 CFRelease(unknownContents
);
482 #endif /* READ_DIRECTORIES */
485 static void _CFFindBundleResourcesInRawDir(CFAllocatorRef alloc
, UniChar
*workingUniChars
, CFIndex workingLen
, UniChar
*nameUniChars
, CFIndex nameLen
, CFArrayRef resTypes
, CFIndex limit
, uint8_t version
, CFMutableStringRef cheapStr
, CFMutableStringRef tmpString
, CFMutableArrayRef result
) {
487 // If we have a resName, just call the search API. We may have to loop over the resTypes.
489 _CFSearchBundleDirectory(alloc
, result
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, NULL
, 0, cheapStr
, tmpString
, version
);
491 CFArrayRef subResTypes
= resTypes
;
492 Boolean releaseSubResTypes
= false;
493 CFIndex i
, c
= CFArrayGetCount(resTypes
);
496 // this is an optimization we employ when searching for large numbers of types, if the directory contents are available
497 // we scan the directory contents and restrict the list of resTypes to the types that might actually occur with the specified name
498 subResTypes
= _CFCopyTypesForSearchBundleDirectory(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, cheapStr
, tmpString
, version
);
499 c
= CFArrayGetCount(subResTypes
);
500 releaseSubResTypes
= true;
502 #endif /* READ_DIRECTORIES */
503 for (i
= 0; i
< c
; i
++) {
504 CFStringRef curType
= (CFStringRef
)CFArrayGetValueAtIndex(subResTypes
, i
);
505 CFIndex typeLen
= CFStringGetLength(curType
);
506 STACK_BUFFER_DECL(UniChar
, typeChars
, typeLen
);
507 CFStringGetCharacters(curType
, CFRangeMake(0, typeLen
), typeChars
);
508 _CFSearchBundleDirectory(alloc
, result
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, typeChars
, typeLen
, cheapStr
, tmpString
, version
);
509 if (limit
<= CFArrayGetCount(result
)) break;
511 if (releaseSubResTypes
) CFRelease(subResTypes
);
514 // If we have no resName, do it by hand. We may have to loop over the resTypes.
515 char cpathBuff
[CFMaxPathSize
];
517 CFMutableArrayRef children
;
519 CFStringSetExternalCharactersNoCopy(tmpString
, workingUniChars
, workingLen
, workingLen
);
520 if (!CFStringGetFileSystemRepresentation(tmpString
, cpathBuff
, CFMaxPathSize
)) return;
521 cpathLen
= strlen(cpathBuff
);
524 // ??? should this use _CFBundleCopyDirectoryContentsAtPath?
525 children
= _CFContentsOfDirectory(alloc
, cpathBuff
, NULL
, NULL
, NULL
);
527 CFIndex childIndex
, childCount
= CFArrayGetCount(children
);
528 for (childIndex
= 0; childIndex
< childCount
; childIndex
++) CFArrayAppendValue(result
, CFArrayGetValueAtIndex(children
, childIndex
));
532 CFIndex i
, c
= CFArrayGetCount(resTypes
);
533 for (i
= 0; i
< c
; i
++) {
534 CFStringRef curType
= (CFStringRef
)CFArrayGetValueAtIndex(resTypes
, i
);
536 // ??? should this use _CFBundleCopyDirectoryContentsAtPath?
537 children
= _CFContentsOfDirectory(alloc
, cpathBuff
, NULL
, NULL
, curType
);
539 CFIndex childIndex
, childCount
= CFArrayGetCount(children
);
540 for (childIndex
= 0; childIndex
< childCount
; childIndex
++) CFArrayAppendValue(result
, CFArrayGetValueAtIndex(children
, childIndex
));
543 if (limit
<= CFArrayGetCount(result
)) break;
549 static void _CFFindBundleResourcesInResourcesDir(CFAllocatorRef alloc
, UniChar
*workingUniChars
, CFIndex workingLen
, UniChar
*subDirUniChars
, CFIndex subDirLen
, CFArrayRef searchLanguages
, UniChar
*nameUniChars
, CFIndex nameLen
, CFArrayRef resTypes
, CFIndex limit
, uint8_t version
, CFMutableStringRef cheapStr
, CFMutableStringRef tmpString
, CFMutableArrayRef result
) {
550 CFIndex savedWorkingLen
= workingLen
;
552 // Look directly in the directory specified in workingUniChars. as if it is a Resources directory.
554 // Add the non-localized resource directory.
555 Boolean appendSucceeded
= _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _GlobalResourcesUniChars
, _GlobalResourcesLen
);
556 if (appendSucceeded
&& subDirLen
> 0) appendSucceeded
= _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
);
557 if (appendSucceeded
) _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
558 // Strip the non-localized resource directory.
559 workingLen
= savedWorkingLen
;
561 if (CFArrayGetCount(result
) < limit
) {
562 Boolean appendSucceeded
= true;
563 if (subDirLen
> 0) appendSucceeded
= _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
);
564 if (appendSucceeded
) _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
567 // Now search the local resources.
568 workingLen
= savedWorkingLen
;
569 if (CFArrayGetCount(result
) < limit
) {
571 CFIndex langCount
= (searchLanguages
? CFArrayGetCount(searchLanguages
) : 0);
572 CFStringRef curLangStr
;
574 // MF:??? OK to hard-wire this length?
575 UniChar curLangUniChars
[255];
576 CFIndex numResults
= CFArrayGetCount(result
);
578 for (langIndex
= 0; langIndex
< langCount
; langIndex
++) {
579 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(searchLanguages
, langIndex
);
580 curLangLen
= CFStringGetLength(curLangStr
);
581 if (curLangLen
> 255) curLangLen
= 255;
582 CFStringGetCharacters(curLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
583 savedWorkingLen
= workingLen
;
584 if (!_CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
)) {
585 workingLen
= savedWorkingLen
;
588 if (!_CFAppendPathExtension(workingUniChars
, &workingLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
589 workingLen
= savedWorkingLen
;
593 if (!_CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
)) {
594 workingLen
= savedWorkingLen
;
598 _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
600 // Back off this lproj component
601 workingLen
= savedWorkingLen
;
602 if (CFArrayGetCount(result
) != numResults
) {
603 // We found resources in a language we already searched. Don't look any farther.
604 // We also don't need to check the limit, since if the count changed at all, we are bailing.
611 extern void _CFStrSetDesiredCapacity(CFMutableStringRef str
, CFIndex len
);
613 CFArrayRef
_CFFindBundleResources(CFBundleRef bundle
, CFURLRef bundleURL
, CFStringRef subDirName
, CFArrayRef searchLanguages
, CFStringRef resName
, CFArrayRef resTypes
, CFIndex limit
, uint8_t version
) {
614 CFAllocatorRef alloc
= (bundle
? CFGetAllocator(bundle
) : (CFAllocatorRef
)CFRetain(__CFGetDefaultAllocator()));
615 CFMutableArrayRef result
;
616 UniChar
*workingUniChars
, *nameUniChars
, *subDirUniChars
;
618 CFIndex subDirLen
= (subDirName
? CFStringGetLength(subDirName
) : 0);
619 CFIndex workingLen
, savedWorkingLen
;
620 CFURLRef absoluteURL
;
621 CFStringRef bundlePath
;
622 CFMutableStringRef cheapStr
, tmpString
;
623 char buff
[CFMaxPathSize
];
625 result
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
627 CFStringRef newResName
= NULL
;
628 if (CFStringGetFileSystemRepresentation(resName
, buff
, CFMaxPathSize
)) newResName
= CFStringCreateWithFileSystemRepresentation(alloc
, buff
);
629 resName
= newResName
? newResName
: (CFStringRef
)CFRetain(resName
);
630 nameLen
= CFStringGetLength(resName
);
633 // Init the one-time-only unichar buffers.
634 _CFEnsureStaticBuffersInited();
636 // Build UniChar buffers for some of the string pieces we need.
637 // One malloc will do.
638 nameUniChars
= (UniChar
*)CFAllocatorAllocate(alloc
, sizeof(UniChar
) * (nameLen
+ subDirLen
+ CFMaxPathSize
), 0);
640 subDirUniChars
= nameUniChars
+ nameLen
;
641 workingUniChars
= subDirUniChars
+ subDirLen
;
643 if (nameLen
> 0) CFStringGetCharacters(resName
, CFRangeMake(0, nameLen
), nameUniChars
);
644 if (subDirLen
> 0) CFStringGetCharacters(subDirName
, CFRangeMake(0, subDirLen
), subDirUniChars
);
645 // Build a UniChar buffer with the absolute path to the bundle's resources directory.
646 // If no URL was passed, we get it from the bundle.
647 bundleURL
= (bundleURL
? (CFURLRef
)CFRetain(bundleURL
) : CFBundleCopyBundleURL(bundle
));
648 absoluteURL
= CFURLCopyAbsoluteURL(bundleURL
);
649 bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
650 if ((workingLen
= CFStringGetLength(bundlePath
)) > 0) CFStringGetCharacters(bundlePath
, CFRangeMake(0, workingLen
), workingUniChars
);
651 savedWorkingLen
= workingLen
;
653 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _AppSupportUniChars1
, _AppSupportLen1
);
654 } else if (2 == version
) {
655 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _AppSupportUniChars2
, _AppSupportLen2
);
657 if (0 == version
|| 1 == version
|| 2 == version
) _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _ResourcesUniChars
, _ResourcesLen
);
659 // both of these used for temp string operations, for slightly different purposes, where each type is appropriate
660 cheapStr
= CFStringCreateMutable(alloc
, 0);
661 _CFStrSetDesiredCapacity(cheapStr
, CFMaxPathSize
);
662 tmpString
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, kCFAllocatorNull
);
664 _CFFindBundleResourcesInResourcesDir(alloc
, workingUniChars
, workingLen
, subDirUniChars
, subDirLen
, searchLanguages
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
666 // drd: This unfortunate hack is still necessary because of installer packages and Spotlight importers
667 if (CFArrayGetCount(result
) == 0 && (0 == version
|| (2 == version
&& bundlePath
&& CFEqual(CFSTR("/Library/Spotlight"), bundlePath
)))) {
668 // Try looking directly in the bundle path
669 workingLen
= savedWorkingLen
;
670 _CFFindBundleResourcesInResourcesDir(alloc
, workingUniChars
, workingLen
, subDirUniChars
, subDirLen
, searchLanguages
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
673 CFRelease(absoluteURL
);
674 CFRelease(bundlePath
);
675 CFRelease(bundleURL
);
677 CFRelease(tmpString
);
678 CFAllocatorDeallocate(alloc
, nameUniChars
);
680 if (resName
) CFRelease(resName
);
681 if (!bundle
) CFRelease(alloc
);
685 CF_EXPORT CFURLRef
CFBundleCopyResourceURL(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
) {
686 CFURLRef result
= NULL
;
687 CFArrayRef languages
= _CFBundleGetLanguageSearchList(bundle
), types
= NULL
, array
;
688 if (resourceType
) types
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
689 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, resourceName
, types
, 1, _CFBundleLayoutVersion(bundle
));
690 if (types
) CFRelease(types
);
692 if (CFArrayGetCount(array
) > 0) result
= (CFURLRef
)CFRetain(CFArrayGetValueAtIndex(array
, 0));
698 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfType(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
) {
699 CFArrayRef languages
= _CFBundleGetLanguageSearchList(bundle
), types
= NULL
, array
;
700 if (resourceType
) types
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
701 // MF:!!! Better "limit" than 1,000,000?
702 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, NULL
, types
, 1000000, _CFBundleLayoutVersion(bundle
));
703 if (types
) CFRelease(types
);
708 CF_EXPORT CFURLRef
_CFBundleCopyResourceURLForLanguage(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef language
) {
709 return CFBundleCopyResourceURLForLocalization(bundle
, resourceName
, resourceType
, subDirName
, language
);
712 CF_EXPORT CFURLRef
CFBundleCopyResourceURLForLocalization(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef localizationName
) {
713 CFURLRef result
= NULL
;
714 CFArrayRef languages
= NULL
, types
= NULL
, array
;
716 if (localizationName
) languages
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&localizationName
, 1, &kCFTypeArrayCallBacks
);
717 if (resourceType
) types
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
718 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, resourceName
, types
, 1, _CFBundleLayoutVersion(bundle
));
720 if (CFArrayGetCount(array
) > 0) result
= (CFURLRef
)CFRetain(CFArrayGetValueAtIndex(array
, 0));
723 if (types
) CFRelease(types
);
724 if (languages
) CFRelease(languages
);
728 CF_EXPORT CFArrayRef
_CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef language
) {
729 return CFBundleCopyResourceURLsOfTypeForLocalization(bundle
, resourceType
, subDirName
, language
);
732 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef localizationName
) {
733 CFArrayRef languages
= NULL
, types
= NULL
, array
;
735 if (localizationName
) languages
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&localizationName
, 1, &kCFTypeArrayCallBacks
);
736 if (resourceType
) types
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
737 // MF:!!! Better "limit" than 1,000,000?
738 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, NULL
, types
, 1000000, _CFBundleLayoutVersion(bundle
));
739 if (types
) CFRelease(types
);
740 if (languages
) CFRelease(languages
);
744 CF_EXPORT CFStringRef
CFBundleCopyLocalizedString(CFBundleRef bundle
, CFStringRef key
, CFStringRef value
, CFStringRef tableName
) {
745 CFStringRef result
= NULL
;
746 CFDictionaryRef stringTable
= NULL
;
747 static CFSpinLock_t CFBundleLocalizedStringLock
= CFSpinLockInit
;
749 if (!key
) return (value
? (CFStringRef
)CFRetain(value
) : (CFStringRef
)CFRetain(CFSTR("")));
751 if (!tableName
|| CFEqual(tableName
, CFSTR(""))) tableName
= _CFBundleDefaultStringTableName
;
753 __CFSpinLock(&CFBundleLocalizedStringLock
);
754 if (__CFBundleGetResourceData(bundle
)->_stringTableCache
) {
755 stringTable
= (CFDictionaryRef
)CFDictionaryGetValue(__CFBundleGetResourceData(bundle
)->_stringTableCache
, tableName
);
756 if (stringTable
) CFRetain(stringTable
);
758 __CFSpinUnlock(&CFBundleLocalizedStringLock
);
761 // Go load the table.
762 CFURLRef tableURL
= CFBundleCopyResourceURL(bundle
, tableName
, _CFBundleStringTableType
, NULL
);
764 CFStringRef nameForSharing
= NULL
;
766 CFDataRef tableData
= NULL
;
769 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle
), tableURL
, &tableData
, NULL
, NULL
, &errCode
)) {
770 stringTable
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(CFGetAllocator(bundle
), tableData
, kCFPropertyListImmutable
, &errStr
);
775 if (stringTable
&& CFDictionaryGetTypeID() != CFGetTypeID(stringTable
)) {
776 CFRelease(stringTable
);
779 CFRelease(tableData
);
782 if (nameForSharing
) CFRelease(nameForSharing
);
785 if (!stringTable
) stringTable
= CFDictionaryCreate(CFGetAllocator(bundle
), NULL
, NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
787 if (!CFStringHasSuffix(tableName
, CFSTR(".nocache")) || !_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard
)) {
788 __CFSpinLock(&CFBundleLocalizedStringLock
);
789 if (!__CFBundleGetResourceData(bundle
)->_stringTableCache
) __CFBundleGetResourceData(bundle
)->_stringTableCache
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
790 CFDictionarySetValue(__CFBundleGetResourceData(bundle
)->_stringTableCache
, tableName
, stringTable
);
791 __CFSpinUnlock(&CFBundleLocalizedStringLock
);
795 result
= (CFStringRef
)CFDictionaryGetValue(stringTable
, key
);
797 static int capitalize
= -1;
799 result
= (CFStringRef
)CFRetain(key
);
800 } else if (CFEqual(value
, CFSTR(""))) {
801 result
= (CFStringRef
)CFRetain(key
);
803 result
= (CFStringRef
)CFRetain(value
);
805 if (capitalize
!= 0) {
806 if (capitalize
!= 0) {
807 CFMutableStringRef capitalizedResult
= CFStringCreateMutableCopy(CFGetAllocator(bundle
), 0, result
);
808 CFLog(__kCFLogBundle
, CFSTR("Localizable string \"%@\" not found in strings table \"%@\" of bundle %@."), key
, tableName
, bundle
);
809 CFStringUppercase(capitalizedResult
, NULL
);
811 result
= capitalizedResult
;
817 CFRelease(stringTable
);
821 CF_EXPORT CFURLRef
CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
) {
822 CFURLRef result
= NULL
;
823 unsigned char buff
[CFMaxPathSize
];
824 CFURLRef newURL
= NULL
;
826 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
828 newURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
, strlen((char *)buff
), true);
829 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
830 if (_CFBundleCouldBeBundle(newURL
)) {
832 CFArrayRef languages
= _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault
, newURL
, &version
), types
= NULL
, array
;
833 if (resourceType
) types
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
834 array
= _CFFindBundleResources(NULL
, newURL
, subDirName
, languages
, resourceName
, types
, 1, version
);
835 if (types
) CFRelease(types
);
836 if (languages
) CFRelease(languages
);
838 if (CFArrayGetCount(array
) > 0) result
= (CFURLRef
)CFRetain(CFArrayGetValueAtIndex(array
, 0));
842 if (newURL
) CFRelease(newURL
);
846 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleURL
, CFStringRef resourceType
, CFStringRef subDirName
) {
847 CFArrayRef array
= NULL
;
848 unsigned char buff
[CFMaxPathSize
];
849 CFURLRef newURL
= NULL
;
851 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
853 newURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
, strlen((char *)buff
), true);
854 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
855 if (_CFBundleCouldBeBundle(newURL
)) {
857 CFArrayRef languages
= _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault
, newURL
, &version
), types
= NULL
;
858 if (resourceType
) types
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
859 // MF:!!! Better "limit" than 1,000,000?
860 array
= _CFFindBundleResources(NULL
, newURL
, subDirName
, languages
, NULL
, types
, 1000000, version
);
861 if (types
) CFRelease(types
);
862 if (languages
) CFRelease(languages
);
864 if (newURL
) CFRelease(newURL
);
868 // string, with groups of 6 characters being 1 element in the array of locale abbreviations
869 const char * __CFBundleLocaleAbbreviationsArray
=
870 "en_US\0" "fr_FR\0" "en_GB\0" "de_DE\0" "it_IT\0" "nl_NL\0" "nl_BE\0" "sv_SE\0"
871 "es_ES\0" "da_DK\0" "pt_PT\0" "fr_CA\0" "nb_NO\0" "he_IL\0" "ja_JP\0" "en_AU\0"
872 "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"
873 "tr_TR\0" "hr_HR\0" "nl_NL\0" "nl_BE\0" "en_CA\0" "en_CA\0" "pt_PT\0" "nb_NO\0"
874 "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"
875 "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"
876 "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"
877 "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"
878 "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"
879 "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"
880 "en_CA\0" "ga_IE\0" "en_CA\0" "dz_BT\0" "hy_AM\0" "ka_GE\0" "es_XL\0" "es_ES\0"
881 "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"
882 "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"
883 "mr_IN\0" "bo\0\0\0\0" "ne_NP\0" "kl\0\0\0\0" "en_IE\0";
885 #define NUM_LOCALE_ABBREVIATIONS 109
886 #define LOCALE_ABBREVIATION_LENGTH 6
888 static const char * const __CFBundleLanguageNamesArray
[] = {
889 "English", "French", "German", "Italian", "Dutch", "Swedish", "Spanish", "Danish",
890 "Portuguese", "Norwegian", "Hebrew", "Japanese", "Arabic", "Finnish", "Greek", "Icelandic",
891 "Maltese", "Turkish", "Croatian", "Chinese", "Urdu", "Hindi", "Thai", "Korean",
892 "Lithuanian", "Polish", "Hungarian", "Estonian", "Latvian", "Sami", "Faroese", "Farsi",
893 "Russian", "Chinese", "Dutch", "Irish", "Albanian", "Romanian", "Czech", "Slovak",
894 "Slovenian", "Yiddish", "Serbian", "Macedonian", "Bulgarian", "Ukrainian", "Byelorussian", "Uzbek",
895 "Kazakh", "Azerbaijani", "Azerbaijani", "Armenian", "Georgian", "Moldavian", "Kirghiz", "Tajiki",
896 "Turkmen", "Mongolian", "Mongolian", "Pashto", "Kurdish", "Kashmiri", "Sindhi", "Tibetan",
897 "Nepali", "Sanskrit", "Marathi", "Bengali", "Assamese", "Gujarati", "Punjabi", "Oriya",
898 "Malayalam", "Kannada", "Tamil", "Telugu", "Sinhalese", "Burmese", "Khmer", "Lao",
899 "Vietnamese", "Indonesian", "Tagalog", "Malay", "Malay", "Amharic", "Tigrinya", "Oromo",
900 "Somali", "Swahili", "Kinyarwanda", "Rundi", "Nyanja", "Malagasy", "Esperanto", "",
901 "", "", "", "", "", "", "", "",
902 "", "", "", "", "", "", "", "",
903 "", "", "", "", "", "", "", "",
904 "", "", "", "", "", "", "", "",
905 "Welsh", "Basque", "Catalan", "Latin", "Quechua", "Guarani", "Aymara", "Tatar",
906 "Uighur", "Dzongkha", "Javanese", "Sundanese", "Galician", "Afrikaans", "Breton", "Inuktitut",
907 "Scottish", "Manx", "Irish", "Tongan", "Greek", "Greenlandic", "Azerbaijani", "Nynorsk"
910 #define NUM_LANGUAGE_NAMES 152
911 #define LANGUAGE_NAME_LENGTH 13
913 // string, with groups of 3 characters being 1 element in the array of abbreviations
914 const char * __CFBundleLanguageAbbreviationsArray
=
915 "en\0" "fr\0" "de\0" "it\0" "nl\0" "sv\0" "es\0" "da\0"
916 "pt\0" "nb\0" "he\0" "ja\0" "ar\0" "fi\0" "el\0" "is\0"
917 "mt\0" "tr\0" "hr\0" "zh\0" "ur\0" "hi\0" "th\0" "ko\0"
918 "lt\0" "pl\0" "hu\0" "et\0" "lv\0" "se\0" "fo\0" "fa\0"
919 "ru\0" "zh\0" "nl\0" "ga\0" "sq\0" "ro\0" "cs\0" "sk\0"
920 "sl\0" "yi\0" "sr\0" "mk\0" "bg\0" "uk\0" "be\0" "uz\0"
921 "kk\0" "az\0" "az\0" "hy\0" "ka\0" "mo\0" "ky\0" "tg\0"
922 "tk\0" "mn\0" "mn\0" "ps\0" "ku\0" "ks\0" "sd\0" "bo\0"
923 "ne\0" "sa\0" "mr\0" "bn\0" "as\0" "gu\0" "pa\0" "or\0"
924 "ml\0" "kn\0" "ta\0" "te\0" "si\0" "my\0" "km\0" "lo\0"
925 "vi\0" "id\0" "tl\0" "ms\0" "ms\0" "am\0" "ti\0" "om\0"
926 "so\0" "sw\0" "rw\0" "rn\0" "\0\0\0" "mg\0" "eo\0" "\0\0\0"
927 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
928 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
929 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
930 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
931 "cy\0" "eu\0" "ca\0" "la\0" "qu\0" "gn\0" "ay\0" "tt\0"
932 "ug\0" "dz\0" "jv\0" "su\0" "gl\0" "af\0" "br\0" "iu\0"
933 "gd\0" "gv\0" "ga\0" "to\0" "el\0" "kl\0" "az\0" "nn\0";
935 #define NUM_LANGUAGE_ABBREVIATIONS 152
936 #define LANGUAGE_ABBREVIATION_LENGTH 3
938 #if defined(__CONSTANT_CFSTRINGS__)
940 // These are not necessarily common localizations per se, but localizations for which the full language name is still in common use.
941 // These are used to provide a fast path for it (other localizations usually use the abbreviation, which is even faster).
942 static CFStringRef
const __CFBundleCommonLanguageNamesArray
[] = {CFSTR("English"), CFSTR("French"), CFSTR("German"), CFSTR("Italian"), CFSTR("Dutch"), CFSTR("Spanish"), CFSTR("Japanese")};
943 static CFStringRef
const __CFBundleCommonLanguageAbbreviationsArray
[] = {CFSTR("en"), CFSTR("fr"), CFSTR("de"), CFSTR("it"), CFSTR("nl"), CFSTR("es"), CFSTR("ja")};
945 #define NUM_COMMON_LANGUAGE_NAMES 7
947 #endif /* __CONSTANT_CFSTRINGS__ */
949 static const SInt32 __CFBundleScriptCodesArray
[] = {
950 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 6, 0,
951 0, 0, 0, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 0, 4,
952 7, 25, 0, 0, 0, 0, 29, 29, 0, 5, 7, 7, 7, 7, 7, 7,
953 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
954 9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
955 30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
956 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
957 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
958 0, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 0, 28,
959 0, 0, 0, 0, 6, 0, 0, 0
962 static const CFStringEncoding __CFBundleStringEncodingsArray
[] = {
963 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 6, 37,
964 0, 35, 36, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 37, 0x8C,
965 7, 25, 0, 39, 0, 38, 29, 29, 36, 5, 7, 7, 7, 0x98, 7, 7,
966 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
967 9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
968 30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
969 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
970 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
971 39, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 39, 0xEC,
972 39, 39, 40, 0, 6, 0, 0, 0
975 static SInt32
_CFBundleGetLanguageCodeForLocalization(CFStringRef localizationName
) {
976 SInt32 result
= -1, i
;
978 CFIndex length
= CFStringGetLength(localizationName
);
979 if (length
>= LANGUAGE_ABBREVIATION_LENGTH
- 1 && length
<= 255 && CFStringGetCString(localizationName
, buff
, 255, kCFStringEncodingASCII
)) {
981 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_NAMES
; i
++) {
982 if (0 == strcmp(buff
, __CFBundleLanguageNamesArray
[i
])) result
= i
;
984 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
985 if (-1 == result
&& (length
== LANGUAGE_ABBREVIATION_LENGTH
- 1 || !isalpha(buff
[LANGUAGE_ABBREVIATION_LENGTH
- 1]))) {
986 buff
[LANGUAGE_ABBREVIATION_LENGTH
- 1] = '\0';
987 if ('n' == buff
[0] && 'o' == buff
[1]) result
= 9; // hack for Norwegian
988 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_ABBREVIATIONS
* LANGUAGE_ABBREVIATION_LENGTH
; i
+= LANGUAGE_ABBREVIATION_LENGTH
) {
989 if (buff
[0] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 0) && buff
[1] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 1)) result
= i
/ LANGUAGE_ABBREVIATION_LENGTH
;
996 static CFStringRef
_CFBundleCopyLanguageAbbreviationForLanguageCode(SInt32 languageCode
) {
997 CFStringRef result
= NULL
;
998 if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_ABBREVIATIONS
) {
999 const char *languageAbbreviation
= __CFBundleLanguageAbbreviationsArray
+ languageCode
* LANGUAGE_ABBREVIATION_LENGTH
;
1000 if (languageAbbreviation
&& *languageAbbreviation
!= '\0') result
= CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault
, languageAbbreviation
, kCFStringEncodingASCII
, kCFAllocatorNull
);
1005 CF_INLINE CFStringRef
_CFBundleCopyLanguageNameForLanguageCode(SInt32 languageCode
) {
1006 CFStringRef result
= NULL
;
1007 if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_NAMES
) {
1008 const char *languageName
= __CFBundleLanguageNamesArray
[languageCode
];
1009 if (languageName
&& *languageName
!= '\0') result
= CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault
, languageName
, kCFStringEncodingASCII
, kCFAllocatorNull
);
1014 CF_INLINE CFStringRef
_CFBundleCopyLanguageAbbreviationForLocalization(CFStringRef localizationName
) {
1015 CFStringRef result
= NULL
;
1016 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1017 if (languageCode
>= 0) {
1018 result
= _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode
);
1020 CFIndex length
= CFStringGetLength(localizationName
);
1021 if (length
== LANGUAGE_ABBREVIATION_LENGTH
- 1 || (length
> LANGUAGE_ABBREVIATION_LENGTH
- 1 && CFStringGetCharacterAtIndex(localizationName
, LANGUAGE_ABBREVIATION_LENGTH
- 1) == '_')) {
1022 result
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, localizationName
, CFRangeMake(0, LANGUAGE_ABBREVIATION_LENGTH
- 1));
1028 CF_INLINE CFStringRef
_CFBundleCopyModifiedLocalization(CFStringRef localizationName
) {
1029 CFMutableStringRef result
= NULL
;
1030 CFIndex length
= CFStringGetLength(localizationName
);
1032 UniChar c
= CFStringGetCharacterAtIndex(localizationName
, 2);
1033 if ('-' == c
|| '_' == c
) {
1034 result
= CFStringCreateMutableCopy(kCFAllocatorSystemDefault
, length
, localizationName
);
1035 CFStringReplace(result
, CFRangeMake(2, 1), ('-' == c
) ? CFSTR("_") : CFSTR("-"));
1041 CF_INLINE CFStringRef
_CFBundleCopyLanguageNameForLocalization(CFStringRef localizationName
) {
1042 CFStringRef result
= NULL
;
1043 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1044 if (languageCode
>= 0) {
1045 result
= _CFBundleCopyLanguageNameForLanguageCode(languageCode
);
1047 result
= (CFStringRef
)CFStringCreateCopy(kCFAllocatorSystemDefault
, localizationName
);
1052 static SInt32
_CFBundleGetLanguageCodeForRegionCode(SInt32 regionCode
) {
1053 SInt32 result
= -1, i
;
1054 if (52 == regionCode
) { // hack for mixed-up Chinese language codes
1056 } else if (0 <= regionCode
&& regionCode
< NUM_LOCALE_ABBREVIATIONS
) {
1057 const char *localeAbbreviation
= __CFBundleLocaleAbbreviationsArray
+ regionCode
* LOCALE_ABBREVIATION_LENGTH
;
1058 if (localeAbbreviation
&& *localeAbbreviation
!= '\0') {
1059 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_ABBREVIATIONS
* LANGUAGE_ABBREVIATION_LENGTH
; i
+= LANGUAGE_ABBREVIATION_LENGTH
) {
1060 if (localeAbbreviation
[0] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 0) && localeAbbreviation
[1] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 1)) result
= i
/ LANGUAGE_ABBREVIATION_LENGTH
;
1067 static SInt32
_CFBundleGetRegionCodeForLanguageCode(SInt32 languageCode
) {
1068 SInt32 result
= -1, i
;
1069 if (19 == languageCode
) { // hack for mixed-up Chinese language codes
1071 } else if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_ABBREVIATIONS
) {
1072 const char *languageAbbreviation
= __CFBundleLanguageAbbreviationsArray
+ languageCode
* LANGUAGE_ABBREVIATION_LENGTH
;
1073 if (languageAbbreviation
&& *languageAbbreviation
!= '\0') {
1074 for (i
= 0; -1 == result
&& i
< NUM_LOCALE_ABBREVIATIONS
* LOCALE_ABBREVIATION_LENGTH
; i
+= LOCALE_ABBREVIATION_LENGTH
) {
1075 if (*(__CFBundleLocaleAbbreviationsArray
+ i
+ 0) == languageAbbreviation
[0] && *(__CFBundleLocaleAbbreviationsArray
+ i
+ 1) == languageAbbreviation
[1]) result
= i
/ LOCALE_ABBREVIATION_LENGTH
;
1079 if (25 == result
) result
= 68;
1080 if (28 == result
) result
= 82;
1084 static SInt32
_CFBundleGetRegionCodeForLocalization(CFStringRef localizationName
) {
1085 SInt32 result
= -1, i
;
1086 char buff
[LOCALE_ABBREVIATION_LENGTH
];
1087 CFIndex length
= CFStringGetLength(localizationName
);
1088 if (length
>= LANGUAGE_ABBREVIATION_LENGTH
- 1 && length
<= LOCALE_ABBREVIATION_LENGTH
- 1 && CFStringGetCString(localizationName
, buff
, LOCALE_ABBREVIATION_LENGTH
, kCFStringEncodingASCII
)) {
1089 buff
[LOCALE_ABBREVIATION_LENGTH
- 1] = '\0';
1090 for (i
= 0; -1 == result
&& i
< NUM_LOCALE_ABBREVIATIONS
* LOCALE_ABBREVIATION_LENGTH
; i
+= LOCALE_ABBREVIATION_LENGTH
) {
1091 if (0 == strcmp(buff
, __CFBundleLocaleAbbreviationsArray
+ i
)) result
= i
/ LOCALE_ABBREVIATION_LENGTH
;
1094 if (25 == result
) result
= 68;
1095 if (28 == result
) result
= 82;
1096 if (37 == result
) result
= 0;
1098 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1099 result
= _CFBundleGetRegionCodeForLanguageCode(languageCode
);
1104 static CFStringRef
_CFBundleCopyLocaleAbbreviationForRegionCode(SInt32 regionCode
) {
1105 CFStringRef result
= NULL
;
1106 if (0 <= regionCode
&& regionCode
< NUM_LOCALE_ABBREVIATIONS
) {
1107 const char *localeAbbreviation
= __CFBundleLocaleAbbreviationsArray
+ regionCode
* LOCALE_ABBREVIATION_LENGTH
;
1108 if (localeAbbreviation
&& *localeAbbreviation
!= '\0') {
1109 result
= CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault
, localeAbbreviation
, kCFStringEncodingASCII
, kCFAllocatorNull
);
1115 Boolean
CFBundleGetLocalizationInfoForLocalization(CFStringRef localizationName
, SInt32
*languageCode
, SInt32
*regionCode
, SInt32
*scriptCode
, CFStringEncoding
*stringEncoding
) {
1116 Boolean retval
= false;
1117 SInt32 language
= -1, region
= -1, script
= 0;
1118 CFStringEncoding encoding
= kCFStringEncodingMacRoman
;
1119 if (!localizationName
) {
1120 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1121 CFArrayRef languages
= NULL
;
1123 languages
= _CFBundleGetLanguageSearchList(mainBundle
);
1124 if (languages
) CFRetain(languages
);
1126 if (!languages
) languages
= _CFBundleCopyUserLanguages(false);
1127 if (languages
&& CFArrayGetCount(languages
) > 0) localizationName
= (CFStringRef
)CFArrayGetValueAtIndex(languages
, 0);
1129 if (localizationName
) {
1130 LangCode langCode
= -1;
1131 RegionCode regCode
= -1;
1132 ScriptCode scrCode
= 0;
1133 CFStringEncoding enc
= kCFStringEncodingMacRoman
;
1134 retval
= CFLocaleGetLanguageRegionEncodingForLocaleIdentifier(localizationName
, &langCode
, ®Code
, &scrCode
, &enc
);
1136 language
= langCode
;
1143 if (localizationName
) {
1144 language
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1145 region
= _CFBundleGetRegionCodeForLocalization(localizationName
);
1147 _CFBundleGetLanguageAndRegionCodes(&language
, ®ion
);
1149 if ((language
< 0 || language
> (int)(sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
))) && region
!= -1) language
= _CFBundleGetLanguageCodeForRegionCode(region
);
1150 if (region
== -1 && language
!= -1) region
= _CFBundleGetRegionCodeForLanguageCode(language
);
1151 if (language
>= 0 && language
< (int)(sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
))) {
1152 script
= __CFBundleScriptCodesArray
[language
];
1154 if (language
>= 0 && language
< (int)(sizeof(__CFBundleStringEncodingsArray
)/sizeof(CFStringEncoding
))) {
1155 encoding
= __CFBundleStringEncodingsArray
[language
];
1157 retval
= (language
!= -1 || region
!= -1);
1159 if (languageCode
) *languageCode
= language
;
1160 if (regionCode
) *regionCode
= region
;
1161 if (scriptCode
) *scriptCode
= script
;
1162 if (stringEncoding
) *stringEncoding
= encoding
;
1166 CFStringRef
CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode
, SInt32 regionCode
, SInt32 scriptCode
, CFStringEncoding stringEncoding
) {
1167 CFStringRef localizationName
= NULL
;
1168 if (!localizationName
) localizationName
= _CFBundleCopyLocaleAbbreviationForRegionCode(regionCode
);
1169 #if DEPLOYMENT_TARGET_MACOSX
1170 if (!localizationName
&& 0 <= languageCode
&& languageCode
< SHRT_MAX
) localizationName
= CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes(kCFAllocatorSystemDefault
, (LangCode
)languageCode
, (RegionCode
)-1);
1172 if (!localizationName
) localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode
);
1173 if (!localizationName
) {
1174 SInt32 language
= -1, scriptLanguage
= -1, encodingLanguage
= -1;
1176 for (i
= 0; language
== -1 && i
< (sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
)); i
++) {
1177 if (__CFBundleScriptCodesArray
[i
] == scriptCode
&& __CFBundleStringEncodingsArray
[i
] == stringEncoding
) language
= i
;
1179 for (i
= 0; scriptLanguage
== -1 && i
< (sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
)); i
++) {
1180 if (__CFBundleScriptCodesArray
[i
] == scriptCode
) scriptLanguage
= i
;
1182 for (i
= 0; encodingLanguage
== -1 && i
< (sizeof(__CFBundleStringEncodingsArray
)/sizeof(CFStringEncoding
)); i
++) {
1183 if (__CFBundleStringEncodingsArray
[i
] == stringEncoding
) encodingLanguage
= i
;
1185 localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(language
);
1186 if (!localizationName
) localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(encodingLanguage
);
1187 if (!localizationName
) localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(scriptLanguage
);
1189 return localizationName
;
1192 extern void *__CFAppleLanguages
;
1194 #if DEPLOYMENT_TARGET_WINDOWS
1196 extern CFStringRef
copyLocaleLanguageName(void);
1197 extern CFStringRef
copyLocaleCountryName(void);
1199 static CFArrayRef
copyWindowsLanguagePrefsArray() {
1201 CFStringRef locales
[4];
1202 CFStringRef languageName
= copyLocaleLanguageName(), countryName
= copyLocaleCountryName();
1203 if (!languageName
) languageName
= CFSTR("en");
1204 if (!countryName
) countryName
= CFSTR("");
1205 CFIndex i
, localesCount
= 0;
1206 if (CFStringGetLength(countryName
) > 0) locales
[localesCount
++] = CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@_%@"), languageName
, countryName
);
1207 if (CFStringGetLength(languageName
) != 0) {
1208 // special-case for zh since we don't have a generic zh localization
1209 if (CFStringCompare(languageName
, CFSTR("zh"), kCFCompareCaseInsensitive
) != 0) {
1210 locales
[localesCount
++] = CFStringCreateCopy(kCFAllocatorSystemDefault
, languageName
);//languageName;
1212 CFStringRef moreSpecificLanguageName
;
1214 // See http://intrigue-build.apple.com/changeset/14948 for the details on the change. Copied below is the snippet of the code change.
1215 // According to http://www.microsoft.com/globaldev/reference/win2k/setup/lcid.mspx, the locales that use
1216 // 126 // simplified chinese are CN (PRC) and SG (Singapore). The rest use traditional chinese.
1217 // 127 languageName = (countryName == TEXT("CN") || countryName == TEXT("SG")) ? TEXT("zh_CN") : TEXT("zh_TW");
1219 // Compare for CN or SG
1220 if (CFStringCompare(countryName
, CFSTR("CN"), kCFCompareCaseInsensitive
) == 0 || CFStringCompare(countryName
, CFSTR("SG"), kCFCompareCaseInsensitive
) == 0) {
1221 moreSpecificLanguageName
= CFSTR("zh_CN");
1223 moreSpecificLanguageName
= CFSTR("zh_TW");
1225 locales
[localesCount
++] = CFStringCreateCopy(kCFAllocatorSystemDefault
, moreSpecificLanguageName
);
1227 // Don't need this now
1228 if (languageName
) CFRelease(languageName
);
1229 if (countryName
) CFRelease(countryName
);
1231 if (localesCount
== 0) locales
[localesCount
++] = CFStringCreateCopy(kCFAllocatorSystemDefault
, CFSTR("en"));
1232 result
= CFArrayCreate(kCFAllocatorDefault
, (const void **)locales
, localesCount
, &kCFTypeArrayCallBacks
);
1233 for (i
= 0; i
< localesCount
; i
++) CFRelease(locales
[i
]);
1237 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1239 #error Unknown or unspecified DEPLOYMENT_TARGET
1242 static CFArrayRef _CFBundleUserLanguages
= NULL
;
1244 __private_extern__ CFArrayRef
_CFBundleCopyUserLanguages(Boolean useBackstops
) {
1245 CFArrayRef result
= NULL
;
1246 static Boolean didit
= false;
1247 CFArrayRef preferencesArray
= NULL
;
1248 // This is a temporary solution, until the argument domain is moved down into CFPreferences
1249 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
1251 if (__CFAppleLanguages
) {
1253 CFIndex length
= strlen((const char *)__CFAppleLanguages
);
1255 data
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, (const UInt8
*)__CFAppleLanguages
, length
, kCFAllocatorNull
);
1257 _CFBundleUserLanguages
= (CFArrayRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, data
, kCFPropertyListImmutable
, NULL
);
1262 if (!_CFBundleUserLanguages
&& preferencesArray
) _CFBundleUserLanguages
= (CFArrayRef
)CFRetain(preferencesArray
);
1263 Boolean useEnglishAsBackstop
= true;
1264 // could perhaps read out of LANG environment variable
1265 if (useEnglishAsBackstop
&& !_CFBundleUserLanguages
) {
1266 CFStringRef english
= CFSTR("en");
1267 _CFBundleUserLanguages
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&english
, 1, &kCFTypeArrayCallBacks
);
1269 if (_CFBundleUserLanguages
&& CFGetTypeID(_CFBundleUserLanguages
) != CFArrayGetTypeID()) {
1270 CFRelease(_CFBundleUserLanguages
);
1271 _CFBundleUserLanguages
= NULL
;
1275 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
1276 if (preferencesArray
) CFRelease(preferencesArray
);
1277 if (!result
&& _CFBundleUserLanguages
) result
= (CFArrayRef
)CFRetain(_CFBundleUserLanguages
);
1281 CF_EXPORT
void _CFBundleGetLanguageAndRegionCodes(SInt32
*languageCode
, SInt32
*regionCode
) {
1282 // an attempt to answer the question, "what language are we running in?"
1283 // note that the question cannot be answered fully since it may depend on the bundle
1284 SInt32 language
= -1, region
= -1;
1285 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1286 CFArrayRef languages
= NULL
;
1288 languages
= _CFBundleGetLanguageSearchList(mainBundle
);
1289 if (languages
) CFRetain(languages
);
1291 if (!languages
) languages
= _CFBundleCopyUserLanguages(false);
1292 if (languages
&& CFArrayGetCount(languages
) > 0) {
1293 CFStringRef localizationName
= (CFStringRef
)CFArrayGetValueAtIndex(languages
, 0);
1294 Boolean retval
= false;
1295 LangCode langCode
= -1;
1296 RegionCode regCode
= -1;
1297 retval
= CFLocaleGetLanguageRegionEncodingForLocaleIdentifier(localizationName
, &langCode
, ®Code
, NULL
, NULL
);
1299 language
= langCode
;
1303 language
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1304 region
= _CFBundleGetRegionCodeForLocalization(localizationName
);
1310 if (language
== -1 && region
!= -1) language
= _CFBundleGetLanguageCodeForRegionCode(region
);
1311 if (region
== -1 && language
!= -1) region
= _CFBundleGetRegionCodeForLanguageCode(language
);
1312 if (languages
) CFRelease(languages
);
1313 if (languageCode
) *languageCode
= language
;
1314 if (regionCode
) *regionCode
= region
;
1318 static Boolean
_CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc
, UniChar
*pathUniChars
, CFIndex pathLen
, uint8_t version
, CFDictionaryRef infoDict
, CFStringRef curLangStr
, CFMutableArrayRef lprojNames
, Boolean fallBackToLanguage
) {
1319 CFIndex curLangLen
= CFStringGetLength(curLangStr
), savedPathLen
;
1320 UniChar curLangUniChars
[255];
1321 CFStringRef altLangStr
= NULL
, modifiedLangStr
= NULL
, languageAbbreviation
= NULL
, languageName
= NULL
, canonicalLanguageIdentifier
= NULL
, canonicalLanguageAbbreviation
= NULL
;
1322 CFMutableDictionaryRef canonicalLanguageIdentifiers
= NULL
, predefinedCanonicalLanguageIdentifiers
= NULL
;
1323 Boolean foundOne
= false, specifiesScript
= false;
1324 CFArrayRef predefinedLocalizations
= NULL
;
1325 CFRange predefinedLocalizationsRange
;
1326 CFMutableStringRef cheapStr
, tmpString
;
1327 #if READ_DIRECTORIES
1328 CFArrayRef contents
;
1329 CFRange contentsRange
;
1330 #else /* READ_DIRECTORIES */
1331 Boolean isDir
= false;
1332 #endif /* READ_DIRECTORIES */
1334 // both of these used for temp string operations, for slightly
1335 // different purposes, where each type is appropriate
1336 cheapStr
= CFStringCreateMutable(alloc
, 0);
1337 _CFStrSetDesiredCapacity(cheapStr
, CFMaxPathSize
);
1338 tmpString
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, kCFAllocatorNull
);
1340 #if READ_DIRECTORIES
1341 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1342 CFStringReplaceAll(cheapStr
, tmpString
);
1343 contents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, _CFBundleAllContents
);
1344 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
1345 #endif /* READ_DIRECTORIES */
1348 predefinedLocalizations
= (CFArrayRef
)CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
1349 if (predefinedLocalizations
&& CFGetTypeID(predefinedLocalizations
) != CFArrayGetTypeID()) {
1350 predefinedLocalizations
= NULL
;
1351 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleLocalizationsKey
);
1354 predefinedLocalizationsRange
= CFRangeMake(0, predefinedLocalizations
? CFArrayGetCount(predefinedLocalizations
) : 0);
1356 if (curLangLen
> 255) curLangLen
= 255;
1357 CFStringGetCharacters(curLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1358 savedPathLen
= pathLen
;
1359 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1360 #if READ_DIRECTORIES
1361 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1362 CFStringReplaceAll(cheapStr
, tmpString
);
1363 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, curLangStr
)) || (version
!= 4 && CFArrayContainsValue(contents
, contentsRange
, cheapStr
))) {
1364 #else /* READ_DIRECTORIES */
1365 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1366 CFStringReplaceAll(cheapStr
, tmpString
);
1367 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, curLangStr
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1368 #endif /* READ_DIRECTORIES */
1369 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), curLangStr
)) CFArrayAppendValue(lprojNames
, curLangStr
);
1371 if (CFStringGetLength(curLangStr
) <= 2) {
1372 CFRelease(cheapStr
);
1373 CFRelease(tmpString
);
1374 #if READ_DIRECTORIES
1375 CFRelease(contents
);
1376 #endif /* READ_DIRECTORIES */
1381 #if defined(__CONSTANT_CFSTRINGS__)
1384 for (idx
= 0; !altLangStr
&& idx
< NUM_COMMON_LANGUAGE_NAMES
; idx
++) {
1385 if (CFEqual(curLangStr
, __CFBundleCommonLanguageAbbreviationsArray
[idx
])) altLangStr
= __CFBundleCommonLanguageNamesArray
[idx
];
1386 else if (CFEqual(curLangStr
, __CFBundleCommonLanguageNamesArray
[idx
])) altLangStr
= __CFBundleCommonLanguageAbbreviationsArray
[idx
];
1389 #endif /* __CONSTANT_CFSTRINGS__ */
1390 if (foundOne
&& altLangStr
) {
1391 CFRelease(cheapStr
);
1392 CFRelease(tmpString
);
1393 #if READ_DIRECTORIES
1394 CFRelease(contents
);
1395 #endif /* READ_DIRECTORIES */
1399 curLangLen
= CFStringGetLength(altLangStr
);
1400 if (curLangLen
> 255) curLangLen
= 255;
1401 CFStringGetCharacters(altLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1402 pathLen
= savedPathLen
;
1403 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1404 #if READ_DIRECTORIES
1405 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1406 CFStringReplaceAll(cheapStr
, tmpString
);
1407 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, altLangStr
)) || (version
!= 4 && CFArrayContainsValue(contents
, contentsRange
, cheapStr
))) {
1408 #else /* READ_DIRECTORIES */
1409 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1410 CFStringReplaceAll(cheapStr
, tmpString
);
1411 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, altLangStr
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1412 #endif /* READ_DIRECTORIES */
1413 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), altLangStr
)) CFArrayAppendValue(lprojNames
, altLangStr
);
1415 CFRelease(cheapStr
);
1416 CFRelease(tmpString
);
1417 #if READ_DIRECTORIES
1418 CFRelease(contents
);
1419 #endif /* READ_DIRECTORIES */
1424 #if READ_DIRECTORIES
1425 if (!foundOne
&& (!predefinedLocalizations
|| CFArrayGetCount(predefinedLocalizations
) == 0)) {
1426 Boolean hasLocalizations
= false;
1428 for (idx
= 0; !hasLocalizations
&& idx
< contentsRange
.length
; idx
++) {
1429 CFStringRef name
= CFArrayGetValueAtIndex(contents
, idx
);
1430 if (CFStringHasSuffix(name
, _CFBundleLprojExtensionWithDot
)) hasLocalizations
= true;
1432 if (!hasLocalizations
) {
1433 CFRelease(cheapStr
);
1434 CFRelease(tmpString
);
1435 CFRelease(contents
);
1439 #endif /* READ_DIRECTORIES */
1440 if (!altLangStr
&& (modifiedLangStr
= _CFBundleCopyModifiedLocalization(curLangStr
))) {
1441 curLangLen
= CFStringGetLength(modifiedLangStr
);
1442 if (curLangLen
> 255) curLangLen
= 255;
1443 CFStringGetCharacters(modifiedLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1444 pathLen
= savedPathLen
;
1445 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1446 #if READ_DIRECTORIES
1447 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1448 CFStringReplaceAll(cheapStr
, tmpString
);
1449 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, modifiedLangStr
)) || (version
!= 4 && CFArrayContainsValue(contents
, contentsRange
, cheapStr
))) {
1450 #else /* READ_DIRECTORIES */
1451 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1452 CFStringReplaceAll(cheapStr
, tmpString
);
1453 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, modifiedLangStr
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1454 #endif /* READ_DIRECTORIES */
1455 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), modifiedLangStr
)) CFArrayAppendValue(lprojNames
, modifiedLangStr
);
1460 if (!specifiesScript
&& (foundOne
|| fallBackToLanguage
) && !altLangStr
&& (languageAbbreviation
= _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageAbbreviation
)) {
1461 curLangLen
= CFStringGetLength(languageAbbreviation
);
1462 if (curLangLen
> 255) curLangLen
= 255;
1463 CFStringGetCharacters(languageAbbreviation
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1464 pathLen
= savedPathLen
;
1465 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1466 #if READ_DIRECTORIES
1467 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1468 CFStringReplaceAll(cheapStr
, tmpString
);
1469 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageAbbreviation
)) || (version
!= 4 && CFArrayContainsValue(contents
, contentsRange
, cheapStr
))) {
1470 #else /* READ_DIRECTORIES */
1471 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1472 CFStringReplaceAll(cheapStr
, tmpString
);
1473 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageAbbreviation
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1474 #endif /* READ_DIRECTORIES */
1475 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageAbbreviation
)) CFArrayAppendValue(lprojNames
, languageAbbreviation
);
1480 if (!specifiesScript
&& (foundOne
|| fallBackToLanguage
) && !altLangStr
&& (languageName
= _CFBundleCopyLanguageNameForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageName
)) {
1481 curLangLen
= CFStringGetLength(languageName
);
1482 if (curLangLen
> 255) curLangLen
= 255;
1483 CFStringGetCharacters(languageName
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1484 pathLen
= savedPathLen
;
1485 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1486 #if READ_DIRECTORIES
1487 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1488 CFStringReplaceAll(cheapStr
, tmpString
);
1489 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageName
)) || (version
!= 4 && CFArrayContainsValue(contents
, contentsRange
, cheapStr
))) {
1490 #else /* READ_DIRECTORIES */
1491 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1492 CFStringReplaceAll(cheapStr
, tmpString
);
1493 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageName
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1494 #endif /* READ_DIRECTORIES */
1495 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageName
)) CFArrayAppendValue(lprojNames
, languageName
);
1500 if (modifiedLangStr
) CFRelease(modifiedLangStr
);
1501 if (languageAbbreviation
) CFRelease(languageAbbreviation
);
1502 if (languageName
) CFRelease(languageName
);
1503 if (canonicalLanguageIdentifier
) CFRelease(canonicalLanguageIdentifier
);
1504 if (canonicalLanguageIdentifiers
) CFRelease(canonicalLanguageIdentifiers
);
1505 if (predefinedCanonicalLanguageIdentifiers
) CFRelease(predefinedCanonicalLanguageIdentifiers
);
1506 if (canonicalLanguageAbbreviation
) CFRelease(canonicalLanguageAbbreviation
);
1507 CFRelease(cheapStr
);
1508 CFRelease(tmpString
);
1509 #if READ_DIRECTORIES
1510 CFRelease(contents
);
1511 #endif /* READ_DIRECTORIES */
1515 static Boolean
CFBundleAllowMixedLocalizations(void) {
1516 static Boolean allowMixed
= false, examinedMain
= false;
1517 if (!examinedMain
) {
1518 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1519 CFDictionaryRef infoDict
= mainBundle
? CFBundleGetInfoDictionary(mainBundle
) : NULL
;
1520 CFTypeRef allowMixedValue
= infoDict
? CFDictionaryGetValue(infoDict
, _kCFBundleAllowMixedLocalizationsKey
) : NULL
;
1521 if (allowMixedValue
) {
1522 CFTypeID typeID
= CFGetTypeID(allowMixedValue
);
1523 if (typeID
== CFBooleanGetTypeID()) {
1524 allowMixed
= CFBooleanGetValue((CFBooleanRef
)allowMixedValue
);
1525 } else if (typeID
== CFStringGetTypeID()) {
1526 allowMixed
= (CFStringCompare((CFStringRef
)allowMixedValue
, CFSTR("true"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
|| CFStringCompare((CFStringRef
)allowMixedValue
, CFSTR("YES"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1527 } else if (typeID
== CFNumberGetTypeID()) {
1529 if (CFNumberGetValue((CFNumberRef
)allowMixedValue
, kCFNumberSInt32Type
, &val
)) allowMixed
= (val
!= 0);
1532 examinedMain
= true;
1537 static Boolean
_CFBundleLocalizationsHaveCommonPrefix(CFStringRef loc1
, CFStringRef loc2
) {
1538 Boolean result
= false;
1539 CFIndex length1
= CFStringGetLength(loc1
), length2
= CFStringGetLength(loc2
), idx
;
1540 if (length1
> 3 && length2
> 3) {
1541 for (idx
= 0; idx
< length1
&& idx
< length2
; idx
++) {
1542 UniChar c1
= CFStringGetCharacterAtIndex(loc1
, idx
), c2
= CFStringGetCharacterAtIndex(loc2
, idx
);
1543 if (idx
>= 2 && (c1
== '-' || c1
== '_') && (c2
== '-' || c2
== '_')) {
1546 } else if (c1
!= c2
) {
1554 __private_extern__
void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
, CFDictionaryRef infoDict
, CFMutableArrayRef lprojNames
, CFStringRef devLang
) {
1555 // This function will add zero, one or two elements to the lprojNames array.
1556 // 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.
1557 // 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.
1558 CFURLRef resourcesURL
= _CFBundleCopyResourcesDirectoryURLInDirectory(alloc
, bundleURL
, version
);
1559 CFURLRef absoluteURL
;
1560 CFIndex idx
, startIdx
;
1562 CFStringRef resourcesPath
;
1563 UniChar pathUniChars
[CFMaxPathSize
];
1565 CFStringRef curLangStr
, nextLangStr
;
1566 Boolean foundOne
= false;
1567 CFArrayRef userLanguages
;
1569 // Init the one-time-only unichar buffers.
1570 _CFEnsureStaticBuffersInited();
1572 // Get the path to the resources and extract into a buffer.
1573 absoluteURL
= CFURLCopyAbsoluteURL(resourcesURL
);
1574 resourcesPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1575 CFRelease(absoluteURL
);
1576 pathLen
= CFStringGetLength(resourcesPath
);
1577 if (pathLen
> CFMaxPathSize
) pathLen
= CFMaxPathSize
;
1578 CFStringGetCharacters(resourcesPath
, CFRangeMake(0, pathLen
), pathUniChars
);
1579 CFRelease(resourcesURL
);
1580 CFRelease(resourcesPath
);
1582 // First check the main bundle.
1583 if (!CFBundleAllowMixedLocalizations()) {
1584 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1586 CFURLRef mainBundleURL
= CFBundleCopyBundleURL(mainBundle
);
1587 if (mainBundleURL
) {
1588 if (!CFEqual(bundleURL
, mainBundleURL
)) {
1589 // If there is a main bundle, and it isn't this one, try to use the language it prefers.
1590 CFArrayRef mainBundleLangs
= _CFBundleGetLanguageSearchList(mainBundle
);
1591 if (mainBundleLangs
&& (CFArrayGetCount(mainBundleLangs
) > 0)) {
1592 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(mainBundleLangs
, 0);
1593 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
, true);
1596 CFRelease(mainBundleURL
);
1602 // If we didn't find the main bundle's preferred language, look at the users' prefs again and find the best one.
1603 userLanguages
= _CFBundleCopyUserLanguages(true);
1604 count
= (userLanguages
? CFArrayGetCount(userLanguages
) : 0);
1605 for (idx
= 0, startIdx
= -1; !foundOne
&& idx
< count
; idx
++) {
1606 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(userLanguages
, idx
);
1607 nextLangStr
= (idx
+ 1 < count
) ? (CFStringRef
)CFArrayGetValueAtIndex(userLanguages
, idx
+ 1) : NULL
;
1608 if (nextLangStr
&& _CFBundleLocalizationsHaveCommonPrefix(curLangStr
, nextLangStr
)) {
1609 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
, false);
1610 if (startIdx
< 0) startIdx
= idx
;
1611 } else if (startIdx
>= 0 && startIdx
<= idx
) {
1612 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
, false);
1613 for (; !foundOne
&& startIdx
<= idx
; startIdx
++) {
1614 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(userLanguages
, startIdx
);
1615 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
, true);
1619 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
, true);
1623 // use development region and U.S. English as backstops
1624 if (!foundOne
&& devLang
) foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, devLang
, lprojNames
, true);
1625 if (!foundOne
) foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, CFSTR("en_US"), lprojNames
, true);
1626 if (userLanguages
) CFRelease(userLanguages
);
1630 static Boolean
_CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array
, CFStringRef curLangStr
, CFMutableArrayRef lprojNames
, Boolean fallBackToLanguage
) {
1631 Boolean foundOne
= false, specifiesScript
= false;
1632 CFRange range
= CFRangeMake(0, CFArrayGetCount(array
));
1633 CFStringRef altLangStr
= NULL
, modifiedLangStr
= NULL
, languageAbbreviation
= NULL
, languageName
= NULL
, canonicalLanguageIdentifier
= NULL
, canonicalLanguageAbbreviation
= NULL
;
1634 CFMutableDictionaryRef canonicalLanguageIdentifiers
= NULL
;
1636 if (range
.length
== 0) return foundOne
;
1637 if (CFArrayContainsValue(array
, range
, curLangStr
)) {
1638 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), curLangStr
)) CFArrayAppendValue(lprojNames
, curLangStr
);
1640 if (range
.length
== 1 || CFStringGetLength(curLangStr
) <= 2) return foundOne
;
1642 if (range
.length
== 1 && CFArrayContainsValue(array
, range
, CFSTR("default"))) return foundOne
;
1643 #if defined(__CONSTANT_CFSTRINGS__)
1646 for (idx
= 0; !altLangStr
&& idx
< NUM_COMMON_LANGUAGE_NAMES
; idx
++) {
1647 if (CFEqual(curLangStr
, __CFBundleCommonLanguageAbbreviationsArray
[idx
])) altLangStr
= __CFBundleCommonLanguageNamesArray
[idx
];
1648 else if (CFEqual(curLangStr
, __CFBundleCommonLanguageNamesArray
[idx
])) altLangStr
= __CFBundleCommonLanguageAbbreviationsArray
[idx
];
1651 #endif /* __CONSTANT_CFSTRINGS__ */
1652 if (foundOne
&& altLangStr
) return foundOne
;
1653 if (altLangStr
&& CFArrayContainsValue(array
, range
, altLangStr
)) {
1654 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), altLangStr
)) CFArrayAppendValue(lprojNames
, altLangStr
);
1658 if (!altLangStr
&& (modifiedLangStr
= _CFBundleCopyModifiedLocalization(curLangStr
))) {
1659 if (CFArrayContainsValue(array
, range
, modifiedLangStr
)) {
1660 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), modifiedLangStr
)) CFArrayAppendValue(lprojNames
, modifiedLangStr
);
1664 if (!specifiesScript
&& (foundOne
|| fallBackToLanguage
) && !altLangStr
&& (languageAbbreviation
= _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageAbbreviation
)) {
1665 if (CFArrayContainsValue(array
, range
, languageAbbreviation
)) {
1666 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageAbbreviation
)) CFArrayAppendValue(lprojNames
, languageAbbreviation
);
1670 if (!specifiesScript
&& (foundOne
|| fallBackToLanguage
) && !altLangStr
&& (languageName
= _CFBundleCopyLanguageNameForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageName
)) {
1671 if (CFArrayContainsValue(array
, range
, languageName
)) {
1672 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageName
)) CFArrayAppendValue(lprojNames
, languageName
);
1676 if (modifiedLangStr
) CFRelease(modifiedLangStr
);
1677 if (languageAbbreviation
) CFRelease(languageAbbreviation
);
1678 if (languageName
) CFRelease(languageName
);
1679 if (canonicalLanguageIdentifier
) CFRelease(canonicalLanguageIdentifier
);
1680 if (canonicalLanguageIdentifiers
) CFRelease(canonicalLanguageIdentifiers
);
1681 if (canonicalLanguageAbbreviation
) CFRelease(canonicalLanguageAbbreviation
);
1685 static CFArrayRef
_CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray
, CFArrayRef prefArray
, Boolean considerMain
) {
1686 CFMutableArrayRef lprojNames
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1687 Boolean foundOne
= false, releasePrefArray
= false;
1688 CFIndex idx
, count
, startIdx
;
1690 if (considerMain
&& !CFBundleAllowMixedLocalizations()) {
1691 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1693 // If there is a main bundle, try to use the language it prefers.
1694 CFArrayRef mainBundleLangs
= _CFBundleGetLanguageSearchList(mainBundle
);
1695 if (mainBundleLangs
&& (CFArrayGetCount(mainBundleLangs
) > 0)) foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, (CFStringRef
)CFArrayGetValueAtIndex(mainBundleLangs
, 0), lprojNames
, true);
1700 CFStringRef curLangStr
, nextLangStr
;
1702 prefArray
= _CFBundleCopyUserLanguages(true);
1703 if (prefArray
) releasePrefArray
= true;
1705 count
= (prefArray
? CFArrayGetCount(prefArray
) : 0);
1706 for (idx
= 0, startIdx
= -1; !foundOne
&& idx
< count
; idx
++) {
1707 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(prefArray
, idx
);
1708 nextLangStr
= (idx
+ 1 < count
) ? (CFStringRef
)CFArrayGetValueAtIndex(prefArray
, idx
+ 1) : NULL
;
1709 if (nextLangStr
&& _CFBundleLocalizationsHaveCommonPrefix(curLangStr
, nextLangStr
)) {
1710 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, curLangStr
, lprojNames
, false);
1711 if (startIdx
< 0) startIdx
= idx
;
1712 } else if (startIdx
>= 0 && startIdx
<= idx
) {
1713 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, curLangStr
, lprojNames
, false);
1714 for (; !foundOne
&& startIdx
<= idx
; startIdx
++) {
1715 curLangStr
= (CFStringRef
)CFArrayGetValueAtIndex(prefArray
, startIdx
);
1716 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, curLangStr
, lprojNames
, true);
1720 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, curLangStr
, lprojNames
, true);
1724 // use U.S. English as backstop
1725 if (!foundOne
) foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, CFSTR("en_US"), lprojNames
, true);
1726 // use random entry as backstop
1727 if (!foundOne
&& CFArrayGetCount(locArray
) > 0) foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, (CFStringRef
)CFArrayGetValueAtIndex(locArray
, 0), lprojNames
, true);
1729 if (CFArrayGetCount(lprojNames
) == 0) {
1730 // Total backstop behavior to avoid having an empty array.
1731 CFArrayAppendValue(lprojNames
, CFSTR("en"));
1733 if (releasePrefArray
) {
1734 CFRelease(prefArray
);
1739 CF_EXPORT CFArrayRef
CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray
, CFArrayRef prefArray
) {
1740 return _CFBundleCopyLocalizationsForPreferences(locArray
, prefArray
, false);
1743 CF_EXPORT CFArrayRef
CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locArray
) {
1744 return _CFBundleCopyLocalizationsForPreferences(locArray
, NULL
, true);
1747 __private_extern__ CFArrayRef
_CFBundleCopyLanguageSearchListInDirectory(CFAllocatorRef alloc
, CFURLRef url
, uint8_t *version
) {
1748 CFMutableArrayRef langs
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
1749 uint8_t localVersion
= 0;
1750 CFDictionaryRef infoDict
= _CFBundleCopyInfoDictionaryInDirectory(alloc
, url
, &localVersion
);
1751 CFStringRef devLang
= NULL
;
1752 if (infoDict
) devLang
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1753 if (devLang
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) devLang
= NULL
;
1755 _CFBundleAddPreferredLprojNamesInDirectory(alloc
, url
, localVersion
, infoDict
, langs
, devLang
);
1757 if (devLang
&& CFArrayGetFirstIndexOfValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), devLang
) < 0) CFArrayAppendValue(langs
, devLang
);
1759 // Total backstop behavior to avoid having an empty array.
1760 if (CFArrayGetCount(langs
) == 0) CFArrayAppendValue(langs
, CFSTR("en"));
1762 if (infoDict
) CFRelease(infoDict
);
1763 if (version
) *version
= localVersion
;
1767 CF_EXPORT Boolean
_CFBundleURLLooksLikeBundle(CFURLRef url
) {
1768 Boolean result
= false;
1769 CFBundleRef bundle
= _CFBundleCreateIfLooksLikeBundle(kCFAllocatorSystemDefault
, url
);
1777 // Note that subDirName is expected to be the string for a URL
1778 CF_INLINE Boolean
_CFBundleURLHasSubDir(CFURLRef url
, CFStringRef subDirName
) {
1779 Boolean isDir
= false, result
= false;
1780 CFURLRef dirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, subDirName
, url
);
1782 if (_CFIsResourceAtURL(dirURL
, &isDir
) && isDir
) result
= true;
1788 __private_extern__ Boolean
_CFBundleURLLooksLikeBundleVersion(CFURLRef url
, uint8_t *version
) {
1789 // check for existence of "Resources" or "Contents" or "Support Files"
1790 // but check for the most likely one first
1791 // version 0: old-style "Resources" bundles
1792 // version 1: obsolete "Support Files" bundles
1793 // version 2: modern "Contents" bundles
1794 // version 3: none of the above (see below)
1795 // version 4: not a bundle (for main bundle only)
1796 uint8_t localVersion
= 3;
1797 #if READ_DIRECTORIES
1798 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
1799 CFStringRef directoryPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1800 CFArrayRef contents
= _CFBundleCopyDirectoryContentsAtPath(directoryPath
, _CFBundleAllContents
);
1801 CFRange contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
1802 if (CFStringHasSuffix(CFURLGetString(url
), CFSTR(".framework/"))) {
1803 if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleResourcesDirectoryName
)) localVersion
= 0;
1804 else if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleSupportFilesDirectoryName2
)) localVersion
= 2;
1805 else if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleSupportFilesDirectoryName1
)) localVersion
= 1;
1807 if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleSupportFilesDirectoryName2
)) localVersion
= 2;
1808 else if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleResourcesDirectoryName
)) localVersion
= 0;
1809 else if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleSupportFilesDirectoryName1
)) localVersion
= 1;
1811 CFRelease(contents
);
1812 CFRelease(directoryPath
);
1813 CFRelease(absoluteURL
);
1814 #endif /* READ_DIRECTORIES */
1815 if (localVersion
== 3) {
1816 #if DEPLOYMENT_TARGET_EMBEDDED
1817 #elif DEPLOYMENT_TARGET_MACOSX
1818 if (CFStringHasSuffix(CFURLGetString(url
), CFSTR(".framework/"))) {
1819 if (_CFBundleURLHasSubDir(url
, _CFBundleResourcesURLFromBase0
)) localVersion
= 0;
1820 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase2
)) localVersion
= 2;
1821 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase1
)) localVersion
= 1;
1823 if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase2
)) localVersion
= 2;
1824 else if (_CFBundleURLHasSubDir(url
, _CFBundleResourcesURLFromBase0
)) localVersion
= 0;
1825 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase1
)) localVersion
= 1;
1827 #elif DEPLOYMENT_TARGET_WINDOWS
1828 if (CFStringHasSuffix(CFURLGetString(url
), CFSTR(".framework\\"))) {
1829 if (_CFBundleURLHasSubDir(url
, _CFBundleResourcesURLFromBase0
)) localVersion
= 0;
1830 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase2
)) localVersion
= 2;
1831 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase1
)) localVersion
= 1;
1833 if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase2
)) localVersion
= 2;
1834 else if (_CFBundleURLHasSubDir(url
, _CFBundleResourcesURLFromBase0
)) localVersion
= 0;
1835 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase1
)) localVersion
= 1;
1838 #error Unknown or unspecified DEPLOYMENT_TARGET
1841 if (version
) *version
= localVersion
;
1842 return (localVersion
!= 3);
1845 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc
, CFURLRef url
, uint8_t *version
) {
1846 CFDictionaryRef dict
= NULL
;
1847 unsigned char buff
[CFMaxPathSize
];
1848 uint8_t localVersion
= 0;
1850 if (CFURLGetFileSystemRepresentation(url
, true, buff
, CFMaxPathSize
)) {
1851 CFURLRef newURL
= CFURLCreateFromFileSystemRepresentation(alloc
, buff
, strlen((char *)buff
), true);
1852 if (!newURL
) newURL
= (CFURLRef
)CFRetain(url
);
1854 // version 3 is for flattened pseudo-bundles with no Contents, Support Files, or Resources directories
1855 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) localVersion
= 3;
1857 dict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(alloc
, newURL
, localVersion
);
1860 if (version
) *version
= localVersion
;
1864 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc
, CFURLRef url
, uint8_t version
) {
1865 CFDictionaryRef result
= NULL
;
1867 CFURLRef infoURL
= NULL
, rawInfoURL
= NULL
;
1868 CFDataRef infoData
= NULL
;
1869 UniChar buff
[CFMaxPathSize
];
1871 CFMutableStringRef cheapStr
;
1872 CFStringRef infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension0
, infoURLFromBase
= _CFBundleInfoURLFromBase0
;
1873 Boolean tryPlatformSpecific
= true, tryGlobal
= true;
1874 #if READ_DIRECTORIES
1875 CFURLRef directoryURL
= NULL
, absoluteURL
;
1876 CFStringRef directoryPath
;
1877 CFArrayRef contents
= NULL
;
1878 CFRange contentsRange
= CFRangeMake(0, 0);
1879 #endif /* READ_DIRECTORIES */
1881 _CFEnsureStaticBuffersInited();
1884 #if READ_DIRECTORIES
1885 directoryURL
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase0
, url
);
1886 #endif /* READ_DIRECTORIES */
1887 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension0
;
1888 infoURLFromBase
= _CFBundleInfoURLFromBase0
;
1889 } else if (1 == version
) {
1890 #if READ_DIRECTORIES
1891 directoryURL
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase1
, url
);
1892 #endif /* READ_DIRECTORIES */
1893 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension1
;
1894 infoURLFromBase
= _CFBundleInfoURLFromBase1
;
1895 } else if (2 == version
) {
1896 #if READ_DIRECTORIES
1897 directoryURL
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase2
, url
);
1898 #endif /* READ_DIRECTORIES */
1899 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension2
;
1900 infoURLFromBase
= _CFBundleInfoURLFromBase2
;
1901 } else if (3 == version
) {
1902 CFStringRef path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
1903 // this test is necessary to exclude the case where a bundle is spuriously created from the innards of another bundle
1905 if (!(CFStringHasSuffix(path
, _CFBundleSupportFilesDirectoryName1
) || CFStringHasSuffix(path
, _CFBundleSupportFilesDirectoryName2
) || CFStringHasSuffix(path
, _CFBundleResourcesDirectoryName
))) {
1906 #if READ_DIRECTORIES
1907 directoryURL
= CFRetain(url
);
1908 #endif /* READ_DIRECTORIES */
1909 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension3
;
1910 infoURLFromBase
= _CFBundleInfoURLFromBase3
;
1915 #if READ_DIRECTORIES
1917 absoluteURL
= CFURLCopyAbsoluteURL(directoryURL
);
1918 directoryPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1919 contents
= _CFBundleCopyDirectoryContentsAtPath(directoryPath
, _CFBundleAllContents
);
1920 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
1921 CFRelease(directoryPath
);
1922 CFRelease(absoluteURL
);
1923 CFRelease(directoryURL
);
1925 #endif /* READ_DIRECTORIES */
1927 len
= CFStringGetLength(infoURLFromBaseNoExtension
);
1928 CFStringGetCharacters(infoURLFromBaseNoExtension
, CFRangeMake(0, len
), buff
);
1929 buff
[len
++] = (UniChar
)'-';
1930 memmove(buff
+ len
, _PlatformUniChars
, _PlatformLen
* sizeof(UniChar
));
1931 len
+= _PlatformLen
;
1932 _CFAppendPathExtension(buff
, &len
, CFMaxPathSize
, _InfoExtensionUniChars
, _InfoExtensionLen
);
1933 cheapStr
= CFStringCreateMutable(alloc
, 0);
1934 CFStringAppendCharacters(cheapStr
, buff
, len
);
1935 infoURL
= CFURLCreateWithString(alloc
, cheapStr
, url
);
1936 #if READ_DIRECTORIES
1938 CFIndex resourcesLen
, idx
;
1939 for (resourcesLen
= len
; resourcesLen
> 0; resourcesLen
--) if (buff
[resourcesLen
- 1] == '/') break;
1940 CFStringDelete(cheapStr
, CFRangeMake(0, CFStringGetLength(cheapStr
)));
1941 CFStringAppendCharacters(cheapStr
, buff
+ resourcesLen
, len
- resourcesLen
);
1942 for (tryPlatformSpecific
= false, idx
= 0; !tryPlatformSpecific
&& idx
< contentsRange
.length
; idx
++) {
1943 // Need to do this case-insensitive to accommodate Palm
1944 if (kCFCompareEqualTo
== CFStringCompare(cheapStr
, CFArrayGetValueAtIndex(contents
, idx
), kCFCompareCaseInsensitive
)) tryPlatformSpecific
= true;
1947 #endif /* READ_DIRECTORIES */
1948 if (tryPlatformSpecific
) CFURLCreateDataAndPropertiesFromResource(alloc
, infoURL
, &infoData
, NULL
, NULL
, NULL
);
1949 //fprintf(stderr, "looking for ");CFShow(infoURL);fprintf(stderr, infoData ? "found it\n" : (tryPlatformSpecific ? "missed it\n" : "skipped it\n"));
1950 CFRelease(cheapStr
);
1952 // Check for global Info.plist
1954 infoURL
= CFURLCreateWithString(alloc
, infoURLFromBase
, url
);
1955 #if READ_DIRECTORIES
1958 for (tryGlobal
= false, idx
= 0; !tryGlobal
&& idx
< contentsRange
.length
; idx
++) {
1959 // Need to do this case-insensitive to accommodate Palm
1960 if (kCFCompareEqualTo
== CFStringCompare(_CFBundleInfoFileName
, CFArrayGetValueAtIndex(contents
, idx
), kCFCompareCaseInsensitive
)) tryGlobal
= true;
1963 #endif /* READ_DIRECTORIES */
1964 if (tryGlobal
) CFURLCreateDataAndPropertiesFromResource(alloc
, infoURL
, &infoData
, NULL
, NULL
, NULL
);
1965 //fprintf(stderr, "looking for ");CFShow(infoURL);fprintf(stderr, infoData ? "found it\n" : (tryGlobal ? "missed it\n" : "skipped it\n"));
1969 result
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(alloc
, infoData
, kCFPropertyListMutableContainers
, NULL
);
1971 if (CFDictionaryGetTypeID() == CFGetTypeID(result
)) {
1972 CFDictionarySetValue((CFMutableDictionaryRef
)result
, _kCFBundleInfoPlistURLKey
, infoURL
);
1978 if (!result
) rawInfoURL
= infoURL
;
1979 CFRelease(infoData
);
1982 result
= CFDictionaryCreateMutable(alloc
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1983 if (rawInfoURL
) CFDictionarySetValue((CFMutableDictionaryRef
)result
, _kCFBundleRawInfoPlistURLKey
, rawInfoURL
);
1987 #if READ_DIRECTORIES
1988 if (contents
) CFRelease(contents
);
1989 #endif /* READ_DIRECTORIES */
1994 static Boolean
_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorRef alloc
, CFURLRef url
, CFDictionaryRef infoDict
, UInt32
*packageType
, UInt32
*packageCreator
) {
1995 Boolean retVal
= false, hasType
= false, hasCreator
= false, releaseInfoDict
= false;
1997 CFDataRef pkgInfoData
= NULL
;
1999 // Check for a "real" new bundle
2000 tempURL
= CFURLCreateWithString(alloc
, _CFBundlePkgInfoURLFromBase2
, url
);
2001 CFURLCreateDataAndPropertiesFromResource(alloc
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
2004 tempURL
= CFURLCreateWithString(alloc
, _CFBundlePkgInfoURLFromBase1
, url
);
2005 CFURLCreateDataAndPropertiesFromResource(alloc
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
2009 // Check for a "pseudo" new bundle
2010 tempURL
= CFURLCreateWithString(alloc
, _CFBundlePseudoPkgInfoURLFromBase
, url
);
2011 CFURLCreateDataAndPropertiesFromResource(alloc
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
2015 // 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.
2016 // 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.
2017 // 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.
2019 if (pkgInfoData
&& CFDataGetLength(pkgInfoData
) >= (int)(sizeof(UInt32
) * 2)) {
2020 UInt32
*pkgInfo
= (UInt32
*)CFDataGetBytePtr(pkgInfoData
);
2021 if (packageType
) *packageType
= CFSwapInt32BigToHost(pkgInfo
[0]);
2022 if (packageCreator
) *packageCreator
= CFSwapInt32BigToHost(pkgInfo
[1]);
2023 retVal
= hasType
= hasCreator
= true;
2025 if (pkgInfoData
) CFRelease(pkgInfoData
);
2028 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(alloc
, url
, NULL
);
2029 releaseInfoDict
= true;
2032 CFStringRef typeString
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundlePackageTypeKey
), creatorString
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleSignatureKey
);
2034 CFIndex usedBufLen
= 0;
2035 if (typeString
&& CFGetTypeID(typeString
) == CFStringGetTypeID() && CFStringGetLength(typeString
) == 4 && 4 == CFStringGetBytes(typeString
, CFRangeMake(0, 4), kCFStringEncodingMacRoman
, 0, false, (UInt8
*)&tmp
, 4, &usedBufLen
) && 4 == usedBufLen
) {
2036 if (packageType
) *packageType
= CFSwapInt32BigToHost(tmp
);
2037 retVal
= hasType
= true;
2039 if (creatorString
&& CFGetTypeID(creatorString
) == CFStringGetTypeID() && CFStringGetLength(creatorString
) == 4 && 4 == CFStringGetBytes(creatorString
, CFRangeMake(0, 4), kCFStringEncodingMacRoman
, 0, false, (UInt8
*)&tmp
, 4, &usedBufLen
) && 4 == usedBufLen
) {
2040 if (packageCreator
) *packageCreator
= CFSwapInt32BigToHost(tmp
);
2041 retVal
= hasCreator
= true;
2043 if (releaseInfoDict
) CFRelease(infoDict
);
2046 if (!hasType
|| !hasCreator
) {
2047 // If this looks like a bundle then manufacture the type and creator.
2048 if (retVal
|| _CFBundleURLLooksLikeBundle(url
)) {
2049 if (packageCreator
&& !hasCreator
) *packageCreator
= 0x3f3f3f3f; // '????'
2050 if (packageType
&& !hasType
) {
2052 UniChar buff
[CFMaxPathSize
];
2053 CFIndex strLen
, startOfExtension
;
2054 CFURLRef absoluteURL
;
2056 // Detect "app", "debug", "profile", or "framework" extensions
2057 absoluteURL
= CFURLCopyAbsoluteURL(url
);
2058 urlStr
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
2059 CFRelease(absoluteURL
);
2060 strLen
= CFStringGetLength(urlStr
);
2061 if (strLen
> CFMaxPathSize
) strLen
= CFMaxPathSize
;
2062 CFStringGetCharacters(urlStr
, CFRangeMake(0, strLen
), buff
);
2064 startOfExtension
= _CFStartOfPathExtension(buff
, strLen
);
2065 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
)'/')) {
2067 *packageType
= 0x4150504c; // 'APPL'
2068 } 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
)'/')) {
2069 // This is an app (debug version)
2070 *packageType
= 0x4150504c; // 'APPL'
2071 } 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
)'/')) {
2072 // This is an app (profile version)
2073 *packageType
= 0x4150504c; // 'APPL'
2074 } 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
)'/')) {
2075 // This is a service
2076 *packageType
= 0x4150504c; // 'APPL'
2077 } 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
)'/')) {
2078 // This is a framework
2079 *packageType
= 0x464d574b; // 'FMWK'
2081 // Default to BNDL for generic bundle
2082 *packageType
= 0x424e444c; // 'BNDL'
2091 CF_EXPORT Boolean
_CFBundleGetPackageInfoInDirectory(CFAllocatorRef alloc
, CFURLRef url
, UInt32
*packageType
, UInt32
*packageCreator
) {
2092 return _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(alloc
, url
, NULL
, packageType
, packageCreator
);
2095 CF_EXPORT
void CFBundleGetPackageInfo(CFBundleRef bundle
, UInt32
*packageType
, UInt32
*packageCreator
) {
2096 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
);
2097 if (!_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFGetAllocator(bundle
), bundleURL
, CFBundleGetInfoDictionary(bundle
), packageType
, packageCreator
)) {
2098 if (packageType
) *packageType
= 0x424e444c; // 'BNDL'
2099 if (packageCreator
) *packageCreator
= 0x3f3f3f3f; // '????'
2101 if (bundleURL
) CFRelease(bundleURL
);
2104 CF_EXPORT Boolean
CFBundleGetPackageInfoInDirectory(CFURLRef url
, UInt32
*packageType
, UInt32
*packageCreator
) {
2105 return _CFBundleGetPackageInfoInDirectory(kCFAllocatorSystemDefault
, url
, packageType
, packageCreator
);
2108 static void _CFBundleCheckSupportedPlatform(CFMutableArrayRef mutableArray
, UniChar
*buff
, CFIndex startLen
, CFStringRef platformName
, CFStringRef platformIdentifier
) {
2109 CFIndex buffLen
= startLen
, platformLen
= CFStringGetLength(platformName
), extLen
= CFStringGetLength(_CFBundleInfoExtension
);
2110 CFMutableStringRef str
;
2112 if (buffLen
+ platformLen
+ extLen
< CFMaxPathSize
) {
2113 CFStringGetCharacters(platformName
, CFRangeMake(0, platformLen
), buff
+ buffLen
);
2114 buffLen
+= platformLen
;
2115 buff
[buffLen
++] = (UniChar
)'.';
2116 CFStringGetCharacters(_CFBundleInfoExtension
, CFRangeMake(0, extLen
), buff
+ buffLen
);
2118 str
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
2119 CFStringAppendCharacters(str
, buff
, buffLen
);
2120 if (_CFIsResourceAtPath(str
, &isDir
) && !isDir
&& CFArrayGetFirstIndexOfValue(mutableArray
, CFRangeMake(0, CFArrayGetCount(mutableArray
)), platformIdentifier
) < 0) CFArrayAppendValue(mutableArray
, platformIdentifier
);
2125 CF_EXPORT CFArrayRef
_CFBundleGetSupportedPlatforms(CFBundleRef bundle
) {
2126 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
2127 CFArrayRef platformArray
= infoDict
? (CFArrayRef
)CFDictionaryGetValue(infoDict
, _kCFBundleSupportedPlatformsKey
) : NULL
;
2128 if (platformArray
&& CFGetTypeID(platformArray
) != CFArrayGetTypeID()) {
2129 platformArray
= NULL
;
2130 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleSupportedPlatformsKey
);
2132 if (!platformArray
) {
2133 CFURLRef infoPlistURL
= infoDict
? (CFURLRef
)CFDictionaryGetValue(infoDict
, _kCFBundleInfoPlistURLKey
) : NULL
, absoluteURL
;
2134 CFStringRef infoPlistPath
;
2135 UniChar buff
[CFMaxPathSize
];
2136 CFIndex buffLen
, infoLen
= CFStringGetLength(_CFBundleInfoURLFromBaseNoExtension3
), startLen
, extLen
= CFStringGetLength(_CFBundleInfoExtension
);
2138 CFMutableArrayRef mutableArray
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2139 absoluteURL
= CFURLCopyAbsoluteURL(infoPlistURL
);
2140 infoPlistPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
2141 CFRelease(absoluteURL
);
2142 buffLen
= CFStringGetLength(infoPlistPath
);
2143 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
2144 CFStringGetCharacters(infoPlistPath
, CFRangeMake(0, buffLen
), buff
);
2145 CFRelease(infoPlistPath
);
2147 buffLen
= _CFStartOfLastPathComponent(buff
, buffLen
);
2148 if (buffLen
> 0 && buffLen
+ infoLen
+ extLen
< CFMaxPathSize
) {
2149 CFStringGetCharacters(_CFBundleInfoURLFromBaseNoExtension3
, CFRangeMake(0, infoLen
), buff
+ buffLen
);
2151 buff
[buffLen
++] = (UniChar
)'-';
2153 _CFBundleCheckSupportedPlatform(mutableArray
, buff
, startLen
, CFSTR("macos"), CFSTR("MacOS"));
2154 _CFBundleCheckSupportedPlatform(mutableArray
, buff
, startLen
, CFSTR("macosx"), CFSTR("MacOS"));
2155 _CFBundleCheckSupportedPlatform(mutableArray
, buff
, startLen
, CFSTR("iphoneos"), CFSTR("iPhoneOS"));
2156 _CFBundleCheckSupportedPlatform(mutableArray
, buff
, startLen
, CFSTR("windows"), CFSTR("Windows"));
2159 if (CFArrayGetCount(mutableArray
) > 0) {
2160 platformArray
= (CFArrayRef
)mutableArray
;
2161 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleSupportedPlatformsKey
, platformArray
);
2163 CFRelease(mutableArray
);
2166 return platformArray
;
2169 CF_EXPORT CFStringRef
_CFBundleGetCurrentPlatform(void) {
2170 #if DEPLOYMENT_TARGET_MACOSX
2171 return CFSTR("MacOS");
2172 #elif DEPLOYMENT_TARGET_EMBEDDED
2173 return CFSTR("iPhoneOS");
2174 #elif DEPLOYMENT_TARGET_WINDOWS
2175 return CFSTR("Windows");
2176 #elif DEPLOYMENT_TARGET_SOLARIS
2177 return CFSTR("Solaris");
2178 #elif DEPLOYMENT_TARGET_HPUX
2179 return CFSTR("HPUX");
2180 #elif DEPLOYMENT_TARGET_LINUX
2181 return CFSTR("Linux");
2182 #elif DEPLOYMENT_TARGET_FREEBSD
2183 return CFSTR("FreeBSD");
2185 #error Unknown or unspecified DEPLOYMENT_TARGET
2189 __private_extern__ CFStringRef
_CFBundleGetPlatformExecutablesSubdirectoryName(void) {
2190 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2191 return CFSTR("MacOS");
2192 #elif DEPLOYMENT_TARGET_WINDOWS
2193 return CFSTR("Windows");
2194 #elif DEPLOYMENT_TARGET_SOLARIS
2195 return CFSTR("Solaris");
2196 #elif DEPLOYMENT_TARGET_HPUX
2197 return CFSTR("HPUX");
2198 #elif DEPLOYMENT_TARGET_LINUX
2199 return CFSTR("Linux");
2200 #elif DEPLOYMENT_TARGET_FREEBSD
2201 return CFSTR("FreeBSD");
2203 #error Unknown or unspecified DEPLOYMENT_TARGET
2207 __private_extern__ CFStringRef
_CFBundleGetAlternatePlatformExecutablesSubdirectoryName(void) {
2208 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2209 return CFSTR("Mac OS X");
2210 #elif DEPLOYMENT_TARGET_WINDOWS
2211 return CFSTR("WinNT");
2212 #elif DEPLOYMENT_TARGET_SOLARIS
2213 return CFSTR("Solaris");
2214 #elif DEPLOYMENT_TARGET_HPUX
2215 return CFSTR("HP-UX");
2216 #elif DEPLOYMENT_TARGET_LINUX
2217 return CFSTR("Linux");
2218 #elif DEPLOYMENT_TARGET_FREEBSD
2219 return CFSTR("FreeBSD");
2221 #error Unknown or unspecified DEPLOYMENT_TARGET
2225 __private_extern__ CFStringRef
_CFBundleGetOtherPlatformExecutablesSubdirectoryName(void) {
2226 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2227 return CFSTR("MacOSClassic");
2228 #elif DEPLOYMENT_TARGET_WINDOWS
2229 return CFSTR("Other");
2230 #elif DEPLOYMENT_TARGET_HPUX
2231 return CFSTR("Other");
2232 #elif DEPLOYMENT_TARGET_SOLARIS
2233 return CFSTR("Other");
2234 #elif DEPLOYMENT_TARGET_LINUX
2235 return CFSTR("Other");
2236 #elif DEPLOYMENT_TARGET_FREEBSD
2237 return CFSTR("Other");
2239 #error Unknown or unspecified DEPLOYMENT_TARGET
2243 __private_extern__ CFStringRef
_CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(void) {
2244 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2245 return CFSTR("Mac OS 8");
2246 #elif DEPLOYMENT_TARGET_WINDOWS
2247 return CFSTR("Other");
2248 #elif DEPLOYMENT_TARGET_HPUX
2249 return CFSTR("Other");
2250 #elif DEPLOYMENT_TARGET_SOLARIS
2251 return CFSTR("Other");
2252 #elif DEPLOYMENT_TARGET_LINUX
2253 return CFSTR("Other");
2254 #elif DEPLOYMENT_TARGET_FREEBSD
2255 return CFSTR("Other");
2257 #error Unknown or unspecified DEPLOYMENT_TARGET
2261 __private_extern__ CFArrayRef
_CFBundleCopyBundleRegionsArray(CFBundleRef bundle
) {
2262 return CFBundleCopyBundleLocalizations(bundle
);
2265 CF_EXPORT CFArrayRef
CFBundleCopyBundleLocalizations(CFBundleRef bundle
) {
2266 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
2267 CFURLRef resourcesURL
= CFBundleCopyResourcesDirectoryURL(bundle
);
2268 #if READ_DIRECTORIES
2269 CFURLRef absoluteURL
;
2270 CFStringRef directoryPath
;
2271 CFArrayRef contents
;
2272 CFRange contentsRange
;
2274 #else /* READ_DIRECTORIES */
2275 CFArrayRef urls
= ((_CFBundleLayoutVersion(bundle
) != 4) ? _CFContentsOfDirectory(CFGetAllocator(bundle
), NULL
, NULL
, resourcesURL
, _CFBundleLprojExtension
) : NULL
);
2276 #endif /* READ_DIRECTORIES */
2277 CFArrayRef predefinedLocalizations
= NULL
;
2278 CFMutableArrayRef result
= NULL
;
2281 predefinedLocalizations
= (CFArrayRef
)CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
2282 if (predefinedLocalizations
&& CFGetTypeID(predefinedLocalizations
) != CFArrayGetTypeID()) {
2283 predefinedLocalizations
= NULL
;
2284 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleLocalizationsKey
);
2286 if (predefinedLocalizations
) {
2287 CFIndex i
, c
= CFArrayGetCount(predefinedLocalizations
);
2288 if (c
> 0 && !result
) result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2289 for (i
= 0; i
< c
; i
++) CFArrayAppendValue(result
, CFArrayGetValueAtIndex(predefinedLocalizations
, i
));
2293 #if READ_DIRECTORIES
2295 absoluteURL
= CFURLCopyAbsoluteURL(resourcesURL
);
2296 directoryPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
2297 contents
= _CFBundleCopyDirectoryContentsAtPath(directoryPath
, _CFBundleAllContents
);
2298 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
2299 for (idx
= 0; idx
< contentsRange
.length
; idx
++) {
2300 CFStringRef name
= CFArrayGetValueAtIndex(contents
, idx
);
2301 if (CFStringHasSuffix(name
, _CFBundleLprojExtensionWithDot
)) {
2302 CFStringRef localization
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, name
, CFRangeMake(0, CFStringGetLength(name
) - 6));
2303 if (!result
) result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2304 CFArrayAppendValue(result
, localization
);
2305 CFRelease(localization
);
2308 CFRelease(contents
);
2309 CFRelease(directoryPath
);
2310 CFRelease(absoluteURL
);
2312 #else /* READ_DIRECTORIES */
2314 CFIndex i
, c
= CFArrayGetCount(urls
);
2315 CFURLRef curURL
, curAbsoluteURL
;
2316 CFStringRef curStr
, regionStr
;
2317 UniChar buff
[CFMaxPathSize
];
2318 CFIndex strLen
, startOfLastPathComponent
, regionLen
;
2320 if (c
> 0 && !result
) result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2321 for (i
= 0; i
< c
; i
++) {
2322 curURL
= (CFURLRef
)CFArrayGetValueAtIndex(urls
, i
);
2323 curAbsoluteURL
= CFURLCopyAbsoluteURL(curURL
);
2324 curStr
= CFURLCopyFileSystemPath(curAbsoluteURL
, PLATFORM_PATH_STYLE
);
2325 CFRelease(curAbsoluteURL
);
2326 strLen
= CFStringGetLength(curStr
);
2327 if (strLen
> CFMaxPathSize
) strLen
= CFMaxPathSize
;
2328 CFStringGetCharacters(curStr
, CFRangeMake(0, strLen
), buff
);
2330 startOfLastPathComponent
= _CFStartOfLastPathComponent(buff
, strLen
);
2331 regionLen
= _CFLengthAfterDeletingPathExtension(&(buff
[startOfLastPathComponent
]), strLen
- startOfLastPathComponent
);
2332 regionStr
= CFStringCreateWithCharacters(CFGetAllocator(bundle
), &(buff
[startOfLastPathComponent
]), regionLen
);
2333 CFArrayAppendValue(result
, regionStr
);
2334 CFRelease(regionStr
);
2339 #endif /* READ_DIRECTORIES */
2342 CFStringRef developmentLocalization
= CFBundleGetDevelopmentRegion(bundle
);
2343 if (developmentLocalization
) {
2344 result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2345 CFArrayAppendValue(result
, developmentLocalization
);
2348 if (resourcesURL
) CFRelease(resourcesURL
);
2353 CF_EXPORT CFDictionaryRef
CFBundleCopyInfoDictionaryForURL(CFURLRef url
) {
2354 CFDictionaryRef result
= NULL
;
2355 Boolean isDir
= false;
2356 if (_CFIsResourceAtURL(url
, &isDir
)) {
2358 result
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault
, url
, NULL
);
2360 result
= _CFBundleCopyInfoDictionaryInExecutable(url
);
2366 CFArrayRef
CFBundleCopyExecutableArchitecturesForURL(CFURLRef url
) {
2367 CFArrayRef result
= NULL
;
2368 CFBundleRef bundle
= CFBundleCreate(kCFAllocatorSystemDefault
, url
);
2370 result
= CFBundleCopyExecutableArchitectures(bundle
);
2373 result
= _CFBundleCopyArchitecturesForExecutable(url
);
2378 CFArrayRef
CFBundleCopyLocalizationsForURL(CFURLRef url
) {
2379 CFArrayRef result
= NULL
;
2380 CFBundleRef bundle
= CFBundleCreate(kCFAllocatorSystemDefault
, url
);
2381 CFStringRef devLang
= NULL
;
2383 result
= CFBundleCopyBundleLocalizations(bundle
);
2386 CFDictionaryRef infoDict
= _CFBundleCopyInfoDictionaryInExecutable(url
);
2388 CFArrayRef predefinedLocalizations
= (CFArrayRef
)CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
2389 if (predefinedLocalizations
&& CFGetTypeID(predefinedLocalizations
) == CFArrayGetTypeID()) result
= (CFArrayRef
)CFRetain(predefinedLocalizations
);
2391 devLang
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
2392 if (devLang
&& (CFGetTypeID(devLang
) == CFStringGetTypeID() && CFStringGetLength(devLang
) > 0)) result
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&devLang
, 1, &kCFTypeArrayCallBacks
);
2394 CFRelease(infoDict
);