2 * Copyright (c) 2005 Apple Computer, 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@
23 /* CFBundle_Resources.c
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Doug Davidson
28 #if defined(__MACOS8__) || defined(__WIN32__)
29 #define USE_GETDIRENTRIES 0
31 #define USE_GETDIRENTRIES 1
33 #define GETDIRENTRIES_CACHE_CAPACITY 128
35 #include "CFBundle_Internal.h"
36 #include <CoreFoundation/CFURLAccess.h>
37 #include <CoreFoundation/CFPropertyList.h>
38 #include <CoreFoundation/CFByteOrder.h>
39 #include <CoreFoundation/CFNumber.h>
41 #include "CFInternal.h"
44 /* Unixy & Windows Headers */
54 // All new-style bundles will have these extensions.
55 CF_INLINE CFStringRef
_CFGetPlatformName(void) {
56 // MF:!!! This used to be based on NSInterfaceStyle, not hard-wired by compiler.
57 #if defined(__WIN32__)
58 return _CFBundleWindowsPlatformName
;
59 #elif defined(__MACOS8__)
60 return _CFBundleMacOS8PlatformName
;
61 #elif defined (__MACH__)
62 return _CFBundleMacOSXPlatformName
;
63 #elif defined(__svr4__)
64 return _CFBundleSolarisPlatformName
;
65 #elif defined(__hpux__)
66 return _CFBundleHPUXPlatformName
;
67 #elif defined(__LINUX__)
68 return _CFBundleLinuxPlatformName
;
69 #elif defined(__FREEBSD__)
70 return _CFBundleFreeBSDPlatformName
;
76 CF_INLINE CFStringRef
_CFGetAlternatePlatformName(void) {
77 #if defined (__MACH__)
78 return _CFBundleAlternateMacOSXPlatformName
;
79 #elif defined(__MACOS8__)
80 return _CFBundleAlternateMacOS8PlatformName
;
86 static CFSpinLock_t CFBundleResourceGlobalDataLock
= 0;
87 static UniChar
*_AppSupportUniChars1
= NULL
;
88 static CFIndex _AppSupportLen1
= 0;
89 static UniChar
*_AppSupportUniChars2
= NULL
;
90 static CFIndex _AppSupportLen2
= 0;
91 static UniChar
*_ResourcesUniChars
= NULL
;
92 static CFIndex _ResourcesLen
= 0;
93 static UniChar
*_PlatformUniChars
= NULL
;
94 static CFIndex _PlatformLen
= 0;
95 static UniChar
*_AlternatePlatformUniChars
= NULL
;
96 static CFIndex _AlternatePlatformLen
= 0;
97 static UniChar
*_LprojUniChars
= NULL
;
98 static CFIndex _LprojLen
= 0;
99 static UniChar
*_GlobalResourcesUniChars
= NULL
;
100 static CFIndex _GlobalResourcesLen
= 0;
101 static UniChar
*_InfoExtensionUniChars
= NULL
;
102 static CFIndex _InfoExtensionLen
= 0;
104 static void _CFBundleInitStaticUniCharBuffers(void) {
105 CFStringRef appSupportStr1
= _CFBundleSupportFilesDirectoryName1
;
106 CFStringRef appSupportStr2
= _CFBundleSupportFilesDirectoryName2
;
107 CFStringRef resourcesStr
= _CFBundleResourcesDirectoryName
;
108 CFStringRef platformStr
= _CFGetPlatformName();
109 CFStringRef alternatePlatformStr
= _CFGetAlternatePlatformName();
110 CFStringRef lprojStr
= _CFBundleLprojExtension
;
111 CFStringRef globalResourcesStr
= _CFBundleNonLocalizedResourcesDirectoryName
;
112 CFStringRef infoExtensionStr
= _CFBundleInfoExtension
;
114 CFAllocatorRef alloc
= __CFGetDefaultAllocator();
116 _AppSupportLen1
= CFStringGetLength(appSupportStr1
);
117 _AppSupportLen2
= CFStringGetLength(appSupportStr2
);
118 _ResourcesLen
= CFStringGetLength(resourcesStr
);
119 _PlatformLen
= CFStringGetLength(platformStr
);
120 _AlternatePlatformLen
= CFStringGetLength(alternatePlatformStr
);
121 _LprojLen
= CFStringGetLength(lprojStr
);
122 _GlobalResourcesLen
= CFStringGetLength(globalResourcesStr
);
123 _InfoExtensionLen
= CFStringGetLength(infoExtensionStr
);
125 _AppSupportUniChars1
= CFAllocatorAllocate(alloc
, sizeof(UniChar
) * (_AppSupportLen1
+ _AppSupportLen2
+ _ResourcesLen
+ _PlatformLen
+ _AlternatePlatformLen
+ _LprojLen
+ _GlobalResourcesLen
+ _InfoExtensionLen
), 0);
126 _AppSupportUniChars2
= _AppSupportUniChars1
+ _AppSupportLen1
;
127 _ResourcesUniChars
= _AppSupportUniChars2
+ _AppSupportLen2
;
128 _PlatformUniChars
= _ResourcesUniChars
+ _ResourcesLen
;
129 _AlternatePlatformUniChars
= _PlatformUniChars
+ _PlatformLen
;
130 _LprojUniChars
= _AlternatePlatformUniChars
+ _AlternatePlatformLen
;
131 _GlobalResourcesUniChars
= _LprojUniChars
+ _LprojLen
;
132 _InfoExtensionUniChars
= _GlobalResourcesUniChars
+ _GlobalResourcesLen
;
134 if (_AppSupportLen1
> 0) {
135 CFStringGetCharacters(appSupportStr1
, CFRangeMake(0, _AppSupportLen1
), _AppSupportUniChars1
);
137 if (_AppSupportLen2
> 0) {
138 CFStringGetCharacters(appSupportStr2
, CFRangeMake(0, _AppSupportLen2
), _AppSupportUniChars2
);
140 if (_ResourcesLen
> 0) {
141 CFStringGetCharacters(resourcesStr
, CFRangeMake(0, _ResourcesLen
), _ResourcesUniChars
);
143 if (_PlatformLen
> 0) {
144 CFStringGetCharacters(platformStr
, CFRangeMake(0, _PlatformLen
), _PlatformUniChars
);
146 if (_AlternatePlatformLen
> 0) {
147 CFStringGetCharacters(alternatePlatformStr
, CFRangeMake(0, _AlternatePlatformLen
), _AlternatePlatformUniChars
);
150 CFStringGetCharacters(lprojStr
, CFRangeMake(0, _LprojLen
), _LprojUniChars
);
152 if (_GlobalResourcesLen
> 0) {
153 CFStringGetCharacters(globalResourcesStr
, CFRangeMake(0, _GlobalResourcesLen
), _GlobalResourcesUniChars
);
155 if (_InfoExtensionLen
> 0) {
156 CFStringGetCharacters(infoExtensionStr
, CFRangeMake(0, _InfoExtensionLen
), _InfoExtensionUniChars
);
160 CF_INLINE
void _CFEnsureStaticBuffersInited(void) {
161 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
162 if (_AppSupportUniChars1
== NULL
) {
163 _CFBundleInitStaticUniCharBuffers();
165 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
168 #if USE_GETDIRENTRIES
170 static CFMutableDictionaryRef contentsCache
= NULL
;
171 static CFMutableDictionaryRef directoryContentsCache
= NULL
;
172 static CFMutableDictionaryRef unknownContentsCache
= NULL
;
175 _CFBundleAllContents
= 0,
176 _CFBundleDirectoryContents
= 1,
177 _CFBundleUnknownContents
= 2
178 } _CFBundleDirectoryContentsType
;
180 static CFArrayRef
_CFBundleCopyDirectoryContentsAtPath(CFStringRef path
, _CFBundleDirectoryContentsType contentsType
) {
181 CFArrayRef result
= NULL
;
183 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
184 if (contentsType
== _CFBundleUnknownContents
) {
185 if (unknownContentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(unknownContentsCache
, path
);
186 } else if (contentsType
== _CFBundleDirectoryContents
) {
187 if (directoryContentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(directoryContentsCache
, path
);
189 if (contentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(contentsCache
, path
);
191 if (result
) CFRetain(result
);
192 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
195 Boolean tryToOpen
= true, allDots
= true;
196 char cpathBuff
[CFMaxPathSize
], dirge
[8192];
197 CFIndex cpathLen
= 0, idx
, lastSlashIdx
= 0;
198 int fd
= -1, numread
;
200 CFMutableArrayRef contents
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
), directoryContents
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
), unknownContents
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
201 CFStringRef dirName
, name
;
204 if (_CFStringGetFileSystemRepresentation(path
, cpathBuff
, CFMaxPathSize
)) {
205 cpathLen
= strlen(cpathBuff
);
207 // First see whether we already know that the directory doesn't exist
208 for (idx
= cpathLen
; lastSlashIdx
== 0 && idx
-- > 0;) {
209 if (cpathBuff
[idx
] == '/') lastSlashIdx
= idx
;
210 else if (cpathBuff
[idx
] != '.') allDots
= false;
212 if (lastSlashIdx
> 0 && lastSlashIdx
+ 1 < cpathLen
&& !allDots
) {
213 cpathBuff
[lastSlashIdx
] = '\0';
214 dirName
= CFStringCreateWithCString(NULL
, cpathBuff
, CFStringFileSystemEncoding());
216 name
= CFStringCreateWithCString(NULL
, cpathBuff
+ lastSlashIdx
+ 1, CFStringFileSystemEncoding());
218 // ??? we might like to use directoryContentsCache rather than contentsCache here, but we cannot unless we resolve DT_LNKs below
219 CFArrayRef dirDirContents
= NULL
;
221 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
222 if (contentsCache
) dirDirContents
= (CFArrayRef
)CFDictionaryGetValue(contentsCache
, dirName
);
223 if (dirDirContents
) {
224 Boolean foundIt
= false;
225 CFIndex dirDirIdx
, dirDirLength
= CFArrayGetCount(dirDirContents
);
226 for (dirDirIdx
= 0; !foundIt
&& dirDirIdx
< dirDirLength
; dirDirIdx
++) if (kCFCompareEqualTo
== CFStringCompare(name
, CFArrayGetValueAtIndex(dirDirContents
, dirDirIdx
), kCFCompareCaseInsensitive
)) foundIt
= true;
227 if (!foundIt
) tryToOpen
= false;
229 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
235 cpathBuff
[lastSlashIdx
] = '/';
237 if (tryToOpen
) fd
= open(cpathBuff
, O_RDONLY
, 0777);
239 if (fd
>= 0 && fstat(fd
, &statBuf
) == 0 && (statBuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
240 while ((numread
= getdirentries(fd
, dirge
, sizeof(dirge
), &basep
)) > 0) {
242 for (dent
= (struct dirent
*)dirge
; dent
< (struct dirent
*)(dirge
+ numread
); dent
= (struct dirent
*)((char *)dent
+ dent
->d_reclen
)) {
243 CFIndex nameLen
= strlen(dent
->d_name
);
244 if (0 == dent
->d_fileno
|| (dent
->d_name
[0] == '.' && (nameLen
== 1 || (nameLen
== 2 && dent
->d_name
[1] == '.')))) continue;
245 name
= CFStringCreateWithCString(NULL
, dent
->d_name
, CFStringFileSystemEncoding());
247 // ??? should we follow links for DT_LNK? unless we do, results are approximate, but for performance reasons we do not
248 // ??? likewise for DT_UNKNOWN
249 // ??? the utility of distinguishing directories from other contents is somewhat doubtful anyway
250 CFArrayAppendValue(contents
, name
);
251 if (dent
->d_type
== DT_DIR
) {
252 CFArrayAppendValue(directoryContents
, name
);
253 } else if (dent
->d_type
== DT_UNKNOWN
) {
254 CFArrayAppendValue(unknownContents
, name
);
261 if (fd
>= 0) close(fd
);
263 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
264 if (!contentsCache
) contentsCache
= CFDictionaryCreateMutable(NULL
, GETDIRENTRIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
265 if (GETDIRENTRIES_CACHE_CAPACITY
<= CFDictionaryGetCount(contentsCache
)) CFDictionaryRemoveAllValues(contentsCache
);
266 CFDictionaryAddValue(contentsCache
, path
, contents
);
268 if (!directoryContentsCache
) directoryContentsCache
= CFDictionaryCreateMutable(NULL
, GETDIRENTRIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
269 if (GETDIRENTRIES_CACHE_CAPACITY
<= CFDictionaryGetCount(directoryContentsCache
)) CFDictionaryRemoveAllValues(directoryContentsCache
);
270 CFDictionaryAddValue(directoryContentsCache
, path
, directoryContents
);
272 if (!unknownContentsCache
) unknownContentsCache
= CFDictionaryCreateMutable(NULL
, GETDIRENTRIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
273 if (GETDIRENTRIES_CACHE_CAPACITY
<= CFDictionaryGetCount(unknownContentsCache
)) CFDictionaryRemoveAllValues(unknownContentsCache
);
274 CFDictionaryAddValue(unknownContentsCache
, path
, unknownContents
);
276 if (contentsType
== _CFBundleUnknownContents
) {
277 result
= CFRetain(unknownContents
);
278 } else if (contentsType
== _CFBundleDirectoryContents
) {
279 result
= CFRetain(directoryContents
);
281 result
= CFRetain(contents
);
285 CFRelease(directoryContents
);
286 CFRelease(unknownContents
);
287 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
292 static void _CFBundleFlushContentsCaches(void) {
293 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
294 if (contentsCache
) CFDictionaryRemoveAllValues(contentsCache
);
295 if (directoryContentsCache
) CFDictionaryRemoveAllValues(directoryContentsCache
);
296 if (unknownContentsCache
) CFDictionaryRemoveAllValues(unknownContentsCache
);
297 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
300 static void _CFBundleFlushContentsCacheForPath(CFMutableDictionaryRef cache
, CFStringRef path
) {
301 CFStringRef keys
[GETDIRENTRIES_CACHE_CAPACITY
];
302 unsigned i
, count
= CFDictionaryGetCount(cache
);
303 if (count
<= GETDIRENTRIES_CACHE_CAPACITY
) {
304 CFDictionaryGetKeysAndValues(cache
, (const void **)keys
, NULL
);
305 for (i
= 0; i
< count
; i
++) {
306 if (CFStringFindWithOptions(keys
[i
], path
, CFRangeMake(0, CFStringGetLength(keys
[i
])), kCFCompareAnchored
|kCFCompareCaseInsensitive
, NULL
)) {
307 CFDictionaryRemoveValue(cache
, keys
[i
]);
313 static void _CFBundleFlushContentsCachesForPath(CFStringRef path
) {
314 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
315 if (contentsCache
) _CFBundleFlushContentsCacheForPath(contentsCache
, path
);
316 if (directoryContentsCache
) _CFBundleFlushContentsCacheForPath(directoryContentsCache
, path
);
317 if (unknownContentsCache
) _CFBundleFlushContentsCacheForPath(unknownContentsCache
, path
);
318 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
321 #endif /* USE_GETDIRENTRIES */
323 CF_EXPORT
void _CFBundleFlushCachesForURL(CFURLRef url
) {
324 #if USE_GETDIRENTRIES
325 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
326 CFStringRef path
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
327 _CFBundleFlushContentsCachesForPath(path
);
329 CFRelease(absoluteURL
);
330 #endif /* USE_GETDIRENTRIES */
333 CF_EXPORT
void _CFBundleFlushCaches(void) {
334 #if USE_GETDIRENTRIES
335 _CFBundleFlushContentsCaches();
336 #endif /* USE_GETDIRENTRIES */
339 __private_extern__ Boolean
_CFIsResourceAtURL(CFURLRef url
, Boolean
*isDir
) {
342 if (_CFGetFileProperties(NULL
, url
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) {
344 *isDir
= ((exists
&& ((mode
& S_IFMT
) == S_IFDIR
)) ? true : false);
346 #if defined(__MACOS8__)
349 return (exists
&& (mode
& 0444));
350 #endif /* __MACOS8__ */
356 __private_extern__ Boolean
_CFIsResourceAtPath(CFStringRef path
, Boolean
*isDir
) {
357 Boolean result
= false;
358 CFURLRef url
= CFURLCreateWithFileSystemPath(CFGetAllocator(path
), path
, PLATFORM_PATH_STYLE
, false);
360 result
= _CFIsResourceAtURL(url
, isDir
);
366 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
) {
367 // pathUniChars is the full path to the directory we are searching.
368 // nameUniChars is what we are looking for.
369 // typeUniChars is the type we are looking for.
370 // platformUniChars is the platform name.
371 // cheapStr is available for our use for whatever we want.
372 // URLs for found resources get added to result.
373 CFIndex savedPathLen
;
374 Boolean appendSucceeded
= true, platformGenericFound
= false, platformSpecificFound
= false, platformGenericIsDir
= false, platformSpecificIsDir
= false, platformGenericIsUnknown
= false, platformSpecificIsUnknown
= false;
375 CFStringRef platformGenericStr
= NULL
;
377 #if USE_GETDIRENTRIES
378 CFIndex dirPathLen
= pathLen
;
379 CFArrayRef contents
, directoryContents
, unknownContents
;
380 CFRange contentsRange
, directoryContentsRange
, unknownContentsRange
;
382 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, dirPathLen
, dirPathLen
);
383 CFStringReplaceAll(cheapStr
, tmpString
);
384 //fprintf(stderr, "looking in ");CFShow(cheapStr);
385 contents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, _CFBundleAllContents
);
386 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
387 directoryContents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, _CFBundleDirectoryContents
);
388 directoryContentsRange
= CFRangeMake(0, CFArrayGetCount(directoryContents
));
389 unknownContents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, _CFBundleUnknownContents
);
390 unknownContentsRange
= CFRangeMake(0, CFArrayGetCount(unknownContents
));
393 if (nameLen
> 0) appendSucceeded
= _CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, nameUniChars
, nameLen
);
394 savedPathLen
= pathLen
;
395 if (appendSucceeded
&& typeLen
> 0) appendSucceeded
= _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
396 if (appendSucceeded
) {
397 #if USE_GETDIRENTRIES
398 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ dirPathLen
+ 1, pathLen
- dirPathLen
- 1, pathLen
- dirPathLen
- 1);
399 CFStringReplaceAll(cheapStr
, tmpString
);
400 platformGenericFound
= CFArrayContainsValue(contents
, contentsRange
, cheapStr
);
401 platformGenericIsDir
= CFArrayContainsValue(directoryContents
, directoryContentsRange
, cheapStr
);
402 platformGenericIsUnknown
= CFArrayContainsValue(unknownContents
, unknownContentsRange
, cheapStr
);
403 //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformGenericFound) fprintf(stderr, "found it\n"); if (platformGenericIsDir) fprintf(stderr, "a directory\n");
404 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
405 CFStringReplaceAll(cheapStr
, tmpString
);
406 if (platformGenericFound
&& platformGenericIsUnknown
) {
407 (void)_CFIsResourceAtPath(cheapStr
, &platformGenericIsDir
);
408 //if (platformGenericIsDir) fprintf(stderr, "a directory after all\n"); else fprintf(stderr, "not a directory after all\n");
411 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
412 CFStringReplaceAll(cheapStr
, tmpString
);
413 platformGenericFound
= _CFIsResourceAtPath(cheapStr
, &platformGenericIsDir
);
417 // Check for platform specific.
418 if (platformGenericFound
) {
419 platformGenericStr
= CFStringCreateCopy(alloc
, cheapStr
);
420 if (!platformSpecificFound
&& (_PlatformLen
> 0)) {
421 pathLen
= savedPathLen
;
422 pathUniChars
[pathLen
++] = (UniChar
)'-';
423 memmove(pathUniChars
+ pathLen
, _PlatformUniChars
, _PlatformLen
* sizeof(UniChar
));
424 pathLen
+= _PlatformLen
;
425 if (appendSucceeded
&& typeLen
> 0) appendSucceeded
= _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
426 if (appendSucceeded
) {
427 #if USE_GETDIRENTRIES
428 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ dirPathLen
+ 1, pathLen
- dirPathLen
- 1, pathLen
- dirPathLen
- 1);
429 CFStringReplaceAll(cheapStr
, tmpString
);
430 platformSpecificFound
= CFArrayContainsValue(contents
, contentsRange
, cheapStr
);
431 platformSpecificIsDir
= CFArrayContainsValue(directoryContents
, directoryContentsRange
, cheapStr
);
432 platformSpecificIsUnknown
= CFArrayContainsValue(unknownContents
, unknownContentsRange
, cheapStr
);
433 //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformSpecificFound) fprintf(stderr, "found it\n"); if (platformSpecificIsDir) fprintf(stderr, "a directory\n");
434 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
435 CFStringReplaceAll(cheapStr
, tmpString
);
436 if (platformSpecificFound
&& platformSpecificIsUnknown
) {
437 (void)_CFIsResourceAtPath(cheapStr
, &platformSpecificIsDir
);
438 //if (platformSpecificIsDir) fprintf(stderr, "a directory after all\n"); else fprintf(stderr, "not a directory after all\n");
441 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
442 CFStringReplaceAll(cheapStr
, tmpString
);
443 platformSpecificFound
= _CFIsResourceAtPath(cheapStr
, &platformSpecificIsDir
);
448 if (platformSpecificFound
) {
449 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, platformSpecificIsDir
);
450 CFArrayAppendValue(result
, url
);
452 } else if (platformGenericFound
) {
453 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, ((platformGenericStr
!= NULL
) ? platformGenericStr
: cheapStr
), PLATFORM_PATH_STYLE
, platformGenericIsDir
);
454 CFArrayAppendValue(result
, url
);
457 if (platformGenericStr
!= NULL
) {
458 CFRelease(platformGenericStr
);
460 #if USE_GETDIRENTRIES
462 CFRelease(directoryContents
);
463 CFRelease(unknownContents
);
467 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
) {
470 // If we have a resName, just call the search API. We may have to loop over the resTypes.
472 _CFSearchBundleDirectory(alloc
, result
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, NULL
, 0, cheapStr
, tmpString
, version
);
474 CFIndex i
, c
= CFArrayGetCount(resTypes
);
475 for (i
=0; i
<c
; i
++) {
476 CFStringRef curType
= (CFStringRef
)CFArrayGetValueAtIndex(resTypes
, i
);
477 CFIndex typeLen
= CFStringGetLength(curType
);
478 #if defined(__MACOS8__) || defined(__WIN32__)
479 UniChar
*typeChars
= CFAllocatorAllocate(alloc
, sizeof(UniChar
) * typeLen
, 0);
482 UniChar typeChars
[typeLen
];
483 #endif /* __MACOS8__ */
484 CFStringGetCharacters(curType
, CFRangeMake(0, typeLen
), typeChars
);
485 _CFSearchBundleDirectory(alloc
, result
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, typeChars
, typeLen
, cheapStr
, tmpString
, version
);
486 if (limit
<= CFArrayGetCount(result
)) {
489 #if defined(__MACOS8__) || defined(__WIN32__)
490 CFAllocatorDeallocate(alloc
, typeChars
);
492 #endif /* __MACOS8__ */
496 // If we have no resName, do it by hand. We may have to loop over the resTypes.
497 unsigned char cpathBuff
[CFMaxPathSize
];
499 CFMutableArrayRef children
;
501 CFStringSetExternalCharactersNoCopy(tmpString
, workingUniChars
, workingLen
, workingLen
);
502 if (!_CFStringGetFileSystemRepresentation(tmpString
, cpathBuff
, CFMaxPathSize
)) return;
503 cpathLen
= strlen(cpathBuff
);
506 // ??? should this use _CFBundleCopyDirectoryContentsAtPath?
507 children
= _CFContentsOfDirectory(alloc
, cpathBuff
, NULL
, NULL
, NULL
);
509 CFIndex childIndex
, childCount
= CFArrayGetCount(children
);
510 for (childIndex
= 0; childIndex
< childCount
; childIndex
++) {
511 CFArrayAppendValue(result
, CFArrayGetValueAtIndex(children
, childIndex
));
516 CFIndex i
, c
= CFArrayGetCount(resTypes
);
517 for (i
=0; i
<c
; i
++) {
518 CFStringRef curType
= (CFStringRef
)CFArrayGetValueAtIndex(resTypes
, i
);
520 // ??? should this use _CFBundleCopyDirectoryContentsAtPath?
521 children
= _CFContentsOfDirectory(alloc
, cpathBuff
, NULL
, NULL
, curType
);
523 CFIndex childIndex
, childCount
= CFArrayGetCount(children
);
524 for (childIndex
= 0; childIndex
< childCount
; childIndex
++) {
525 CFArrayAppendValue(result
, CFArrayGetValueAtIndex(children
, childIndex
));
529 if (limit
<= CFArrayGetCount(result
)) {
537 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
) {
538 CFIndex savedWorkingLen
= workingLen
;
540 // Look directly in the directory specified in workingUniChars. as if it is a Resources directory.
542 // Add the non-localized resource directory.
543 Boolean appendSucceeded
= _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _GlobalResourcesUniChars
, _GlobalResourcesLen
);
544 if (appendSucceeded
&& subDirLen
> 0) appendSucceeded
= _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
);
545 if (appendSucceeded
) _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
546 // Strip the non-localized resource directory.
547 workingLen
= savedWorkingLen
;
549 if (CFArrayGetCount(result
) < limit
) {
550 Boolean appendSucceeded
= true;
551 if (subDirLen
> 0) appendSucceeded
= _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
);
552 if (appendSucceeded
) _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
555 // Now search the local resources.
556 workingLen
= savedWorkingLen
;
557 if (CFArrayGetCount(result
) < limit
) {
559 CFIndex langCount
= (searchLanguages
? CFArrayGetCount(searchLanguages
) : 0);
560 CFStringRef curLangStr
;
562 // MF:??? OK to hard-wire this length?
563 UniChar curLangUniChars
[255];
564 CFIndex numResults
= CFArrayGetCount(result
);
566 for (langIndex
= 0; langIndex
< langCount
; langIndex
++) {
567 curLangStr
= CFArrayGetValueAtIndex(searchLanguages
, langIndex
);
568 curLangLen
= CFStringGetLength(curLangStr
);
569 if (curLangLen
> 255) curLangLen
= 255;
570 CFStringGetCharacters(curLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
571 savedWorkingLen
= workingLen
;
572 if (!_CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
)) {
573 workingLen
= savedWorkingLen
;
576 if (!_CFAppendPathExtension(workingUniChars
, &workingLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
577 workingLen
= savedWorkingLen
;
581 if (!_CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
)) {
582 workingLen
= savedWorkingLen
;
586 _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
588 // Back off this lproj component
589 workingLen
= savedWorkingLen
;
590 if (CFArrayGetCount(result
) != numResults
) {
591 // We found resources in a language we already searched. Don't look any farther.
592 // We also don't need to check the limit, since if the count changed at all, we are bailing.
599 extern void _CFStrSetDesiredCapacity(CFMutableStringRef str
, CFIndex len
);
601 CFArrayRef
_CFFindBundleResources(CFBundleRef bundle
, CFURLRef bundleURL
, CFStringRef subDirName
, CFArrayRef searchLanguages
, CFStringRef resName
, CFArrayRef resTypes
, CFIndex limit
, uint8_t version
) {
602 CFAllocatorRef alloc
= ((bundle
!= NULL
) ? CFGetAllocator(bundle
) : CFRetain(__CFGetDefaultAllocator()));
603 CFMutableArrayRef result
;
604 UniChar
*workingUniChars
, *nameUniChars
, *subDirUniChars
;
605 CFIndex nameLen
= (resName
? CFStringGetLength(resName
) : 0);
606 CFIndex subDirLen
= (subDirName
? CFStringGetLength(subDirName
) : 0);
607 CFIndex workingLen
, savedWorkingLen
;
608 CFURLRef absoluteURL
;
609 CFStringRef bundlePath
;
610 CFMutableStringRef cheapStr
, tmpString
;
612 result
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
613 // Init the one-time-only unichar buffers.
614 _CFEnsureStaticBuffersInited();
616 // Build UniChar buffers for some of the string pieces we need.
617 // One malloc will do.
618 nameUniChars
= CFAllocatorAllocate(alloc
, sizeof(UniChar
) * (nameLen
+ subDirLen
+ CFMaxPathSize
), 0);
619 subDirUniChars
= nameUniChars
+ nameLen
;
620 workingUniChars
= subDirUniChars
+ subDirLen
;
623 CFStringGetCharacters(resName
, CFRangeMake(0, nameLen
), nameUniChars
);
626 CFStringGetCharacters(subDirName
, CFRangeMake(0, subDirLen
), subDirUniChars
);
628 // Build a UniChar buffer with the absolute path to the bundle's resources directory.
629 // If no URL was passed, we get it from the bundle.
630 bundleURL
= ((bundleURL
!= NULL
) ? CFRetain(bundleURL
) : CFBundleCopyBundleURL(bundle
));
631 absoluteURL
= CFURLCopyAbsoluteURL(bundleURL
);
632 bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
633 CFRelease(absoluteURL
);
634 if ((workingLen
= CFStringGetLength(bundlePath
)) > 0) {
635 CFStringGetCharacters(bundlePath
, CFRangeMake(0, workingLen
), workingUniChars
);
637 CFRelease(bundlePath
);
638 CFRelease(bundleURL
);
639 savedWorkingLen
= workingLen
;
641 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _AppSupportUniChars1
, _AppSupportLen1
);
642 } else if (2 == version
) {
643 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _AppSupportUniChars2
, _AppSupportLen2
);
645 if (0 == version
|| 1 == version
|| 2 == version
) {
646 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _ResourcesUniChars
, _ResourcesLen
);
649 // both of these used for temp string operations, for slightly
650 // different purposes, where each type is appropriate
651 cheapStr
= CFStringCreateMutable(alloc
, 0);
652 _CFStrSetDesiredCapacity(cheapStr
, CFMaxPathSize
);
653 tmpString
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, kCFAllocatorNull
);
655 _CFFindBundleResourcesInResourcesDir(alloc
, workingUniChars
, workingLen
, subDirUniChars
, subDirLen
, searchLanguages
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
657 // drd: This unfortunate hack is still necessary because of installer packages
658 if (0 == version
&& CFArrayGetCount(result
) == 0) {
659 // Try looking directly in the bundle path
660 workingLen
= savedWorkingLen
;
661 _CFFindBundleResourcesInResourcesDir(alloc
, workingUniChars
, workingLen
, subDirUniChars
, subDirLen
, searchLanguages
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
665 CFRelease(tmpString
);
666 CFAllocatorDeallocate(alloc
, nameUniChars
);
667 if (bundle
== NULL
) {
674 CF_EXPORT CFURLRef
CFBundleCopyResourceURL(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
) {
675 CFURLRef result
= NULL
;
676 CFArrayRef languages
= _CFBundleGetLanguageSearchList(bundle
), types
= NULL
, array
;
677 if (resourceType
) types
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
679 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, resourceName
, types
, 1, _CFBundleLayoutVersion(bundle
));
681 if (types
) CFRelease(types
);
684 if (CFArrayGetCount(array
) > 0) result
= CFRetain(CFArrayGetValueAtIndex(array
, 0));
690 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfType(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
) {
691 CFArrayRef languages
= _CFBundleGetLanguageSearchList(bundle
), types
= NULL
, array
;
692 if (resourceType
) types
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
694 // MF:!!! Better "limit" than 1,000,000?
695 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, NULL
, types
, 1000000, _CFBundleLayoutVersion(bundle
));
697 if (types
) CFRelease(types
);
702 CF_EXPORT CFURLRef
_CFBundleCopyResourceURLForLanguage(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef language
) {return CFBundleCopyResourceURLForLocalization(bundle
, resourceName
, resourceType
, subDirName
, language
);}
704 CF_EXPORT CFURLRef
CFBundleCopyResourceURLForLocalization(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef localizationName
) {
705 CFURLRef result
= NULL
;
706 CFArrayRef languages
= NULL
, types
= NULL
, array
;
708 if (localizationName
) languages
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&localizationName
, 1, &kCFTypeArrayCallBacks
);
709 if (resourceType
) types
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
711 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, resourceName
, types
, 1, _CFBundleLayoutVersion(bundle
));
713 if (CFArrayGetCount(array
) > 0) result
= CFRetain(CFArrayGetValueAtIndex(array
, 0));
717 if (types
) CFRelease(types
);
718 if (languages
) CFRelease(languages
);
723 CF_EXPORT CFArrayRef
_CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef language
) {return CFBundleCopyResourceURLsOfTypeForLocalization(bundle
, resourceType
, subDirName
, language
);}
725 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef localizationName
) {
726 CFArrayRef languages
= NULL
, types
= NULL
, array
;
728 if (localizationName
) languages
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&localizationName
, 1, &kCFTypeArrayCallBacks
);
729 if (resourceType
) types
= CFArrayCreate(CFGetAllocator(bundle
), (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
731 // MF:!!! Better "limit" than 1,000,000?
732 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, NULL
, types
, 1000000, _CFBundleLayoutVersion(bundle
));
734 if (types
) CFRelease(types
);
735 if (languages
) CFRelease(languages
);
740 CF_EXPORT CFStringRef
CFBundleCopyLocalizedString(CFBundleRef bundle
, CFStringRef key
, CFStringRef value
, CFStringRef tableName
) {
741 CFStringRef result
= NULL
;
742 CFDictionaryRef stringTable
= NULL
;
744 if (key
== NULL
) return (value
? CFRetain(value
) : CFRetain(CFSTR("")));
746 if ((tableName
== NULL
) || CFEqual(tableName
, CFSTR(""))) {
747 tableName
= _CFBundleDefaultStringTableName
;
749 if (__CFBundleGetResourceData(bundle
)->_stringTableCache
!= NULL
) {
750 // See if we have the table cached.
751 stringTable
= CFDictionaryGetValue(__CFBundleGetResourceData(bundle
)->_stringTableCache
, tableName
);
753 if (stringTable
== NULL
) {
754 // Go load the table.
755 CFURLRef tableURL
= CFBundleCopyResourceURL(bundle
, tableName
, _CFBundleStringTableType
, NULL
);
757 CFStringRef nameForSharing
= NULL
;
758 if (stringTable
== NULL
) {
759 CFDataRef tableData
= NULL
;
762 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle
), tableURL
, &tableData
, NULL
, NULL
, &errCode
)) {
763 stringTable
= CFPropertyListCreateFromXMLData(CFGetAllocator(bundle
), tableData
, kCFPropertyListImmutable
, &errStr
);
764 if (errStr
!= NULL
) {
768 if (stringTable
&& CFDictionaryGetTypeID() != CFGetTypeID(stringTable
)) {
769 CFRelease(stringTable
);
772 CFRelease(tableData
);
775 if (nameForSharing
) CFRelease(nameForSharing
);
778 if (stringTable
== NULL
) {
779 stringTable
= CFDictionaryCreate(CFGetAllocator(bundle
), NULL
, NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
781 if (__CFBundleGetResourceData(bundle
)->_stringTableCache
== NULL
) {
782 __CFBundleGetResourceData(bundle
)->_stringTableCache
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
784 CFDictionarySetValue(__CFBundleGetResourceData(bundle
)->_stringTableCache
, tableName
, stringTable
);
785 CFRelease(stringTable
);
788 result
= CFDictionaryGetValue(stringTable
, key
);
789 if (result
== NULL
) {
790 static int capitalize
= -1;
792 result
= CFRetain(key
);
793 } else if (CFEqual(value
, CFSTR(""))) {
794 result
= CFRetain(key
);
796 result
= CFRetain(value
);
798 if (capitalize
!= 0) {
799 if (capitalize
!= 0) {
800 CFMutableStringRef capitalizedResult
= CFStringCreateMutableCopy(CFGetAllocator(bundle
), 0, result
);
801 CFLog(__kCFLogBundle
, CFSTR("Localizable string \"%@\" not found in strings table \"%@\" of bundle %@."), key
, tableName
, bundle
);
802 CFStringUppercase(capitalizedResult
, NULL
);
804 result
= capitalizedResult
;
814 CF_EXPORT CFURLRef
CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
) {
815 CFURLRef result
= NULL
;
816 char buff
[CFMaxPathSize
];
817 CFURLRef newURL
= NULL
;
819 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
821 newURL
= CFURLCreateFromFileSystemRepresentation(NULL
, buff
, strlen(buff
), true);
822 if (NULL
== newURL
) {
823 newURL
= CFRetain(bundleURL
);
825 if (_CFBundleCouldBeBundle(newURL
)) {
827 CFArrayRef languages
= _CFBundleCopyLanguageSearchListInDirectory(NULL
, newURL
, &version
), types
= NULL
, array
;
828 if (resourceType
) types
= CFArrayCreate(NULL
, (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
830 array
= _CFFindBundleResources(NULL
, newURL
, subDirName
, languages
, resourceName
, types
, 1, version
);
832 if (types
) CFRelease(types
);
833 if (languages
) CFRelease(languages
);
836 if (CFArrayGetCount(array
) > 0) result
= CFRetain(CFArrayGetValueAtIndex(array
, 0));
840 if (newURL
) CFRelease(newURL
);
844 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleURL
, CFStringRef resourceType
, CFStringRef subDirName
) {
845 CFArrayRef array
= NULL
;
846 char buff
[CFMaxPathSize
];
847 CFURLRef newURL
= NULL
;
849 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
851 newURL
= CFURLCreateFromFileSystemRepresentation(NULL
, buff
, strlen(buff
), true);
852 if (NULL
== newURL
) {
853 newURL
= CFRetain(bundleURL
);
855 if (_CFBundleCouldBeBundle(newURL
)) {
857 CFArrayRef languages
= _CFBundleCopyLanguageSearchListInDirectory(NULL
, newURL
, &version
), types
= NULL
;
858 if (resourceType
) types
= CFArrayCreate(NULL
, (const void **)&resourceType
, 1, &kCFTypeArrayCallBacks
);
860 // MF:!!! Better "limit" than 1,000,000?
861 array
= _CFFindBundleResources(NULL
, newURL
, subDirName
, languages
, NULL
, types
, 1000000, version
);
863 if (types
) CFRelease(types
);
864 if (languages
) CFRelease(languages
);
866 if (newURL
) CFRelease(newURL
);
870 // string, with groups of 6 characters being 1 element in the array of locale abbreviations
871 const char * __CFBundleLocaleAbbreviationsArray
=
872 "en_US\0" "fr_FR\0" "en_GB\0" "de_DE\0" "it_IT\0" "nl_NL\0" "nl_BE\0" "sv_SE\0"
873 "es_ES\0" "da_DK\0" "pt_PT\0" "fr_CA\0" "nb_NO\0" "he_IL\0" "ja_JP\0" "en_AU\0"
874 "ar\0\0\0\0" "fi_FI\0" "fr_CH\0" "de_CH\0" "el_GR\0" "is_IS\0" "mt_MT\0" "\0\0\0\0\0\0"
875 "tr_TR\0" "hr_HR\0" "nl_NL\0" "nl_BE\0" "en_CA\0" "en_CA\0" "pt_PT\0" "nb_NO\0"
876 "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"
877 "el_GR\0" "lt_LT\0" "pl_PL\0" "hu_HU\0" "et_EE\0" "lv_LV\0" "se\0\0\0\0" "fo_FO\0"
878 "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"
879 "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"
880 "el_GR\0" "sr_YU\0" "sl_SI\0" "mk_MK\0" "hr_HR\0" "\0\0\0\0\0\0" "de_DE\0" "pt_BR\0"
881 "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"
882 "en_CA\0" "ga_IE\0" "en_CA\0" "dz_BT\0" "hy_AM\0" "ka_GE\0" "es\0\0\0\0" "es_ES\0"
883 "to_TO\0" "pl_PL\0" "ca_ES\0" "fr\0\0\0\0" "de_AT\0" "es\0\0\0\0" "gu_IN\0" "pa\0\0\0\0"
884 "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"
885 "mr_IN\0" "bo\0\0\0\0" "ne_NP\0" "kl\0\0\0\0" "en_IE\0";
887 #define NUM_LOCALE_ABBREVIATIONS 109
888 #define LOCALE_ABBREVIATION_LENGTH 6
890 static const char * const __CFBundleLanguageNamesArray
[] = {
891 "English", "French", "German", "Italian", "Dutch", "Swedish", "Spanish", "Danish",
892 "Portuguese", "Norwegian", "Hebrew", "Japanese", "Arabic", "Finnish", "Greek", "Icelandic",
893 "Maltese", "Turkish", "Croatian", "Chinese", "Urdu", "Hindi", "Thai", "Korean",
894 "Lithuanian", "Polish", "Hungarian", "Estonian", "Latvian", "Sami", "Faroese", "Farsi",
895 "Russian", "Chinese", "Dutch", "Irish", "Albanian", "Romanian", "Czech", "Slovak",
896 "Slovenian", "Yiddish", "Serbian", "Macedonian", "Bulgarian", "Ukrainian", "Byelorussian", "Uzbek",
897 "Kazakh", "Azerbaijani", "Azerbaijani", "Armenian", "Georgian", "Moldavian", "Kirghiz", "Tajiki",
898 "Turkmen", "Mongolian", "Mongolian", "Pashto", "Kurdish", "Kashmiri", "Sindhi", "Tibetan",
899 "Nepali", "Sanskrit", "Marathi", "Bengali", "Assamese", "Gujarati", "Punjabi", "Oriya",
900 "Malayalam", "Kannada", "Tamil", "Telugu", "Sinhalese", "Burmese", "Khmer", "Lao",
901 "Vietnamese", "Indonesian", "Tagalog", "Malay", "Malay", "Amharic", "Tigrinya", "Oromo",
902 "Somali", "Swahili", "Kinyarwanda", "Rundi", "Nyanja", "Malagasy", "Esperanto", "",
903 "", "", "", "", "", "", "", "",
904 "", "", "", "", "", "", "", "",
905 "", "", "", "", "", "", "", "",
906 "", "", "", "", "", "", "", "",
907 "Welsh", "Basque", "Catalan", "Latin", "Quechua", "Guarani", "Aymara", "Tatar",
908 "Uighur", "Dzongkha", "Javanese", "Sundanese", "Galician", "Afrikaans", "Breton", "Inuktitut",
909 "Scottish", "Manx", "Irish", "Tongan", "Greek", "Greenlandic", "Azerbaijani", "Nynorsk"
912 #define NUM_LANGUAGE_NAMES 152
913 #define LANGUAGE_NAME_LENGTH 13
915 // string, with groups of 3 characters being 1 element in the array of abbreviations
916 const char * __CFBundleLanguageAbbreviationsArray
=
917 "en\0" "fr\0" "de\0" "it\0" "nl\0" "sv\0" "es\0" "da\0"
918 "pt\0" "nb\0" "he\0" "ja\0" "ar\0" "fi\0" "el\0" "is\0"
919 "mt\0" "tr\0" "hr\0" "zh\0" "ur\0" "hi\0" "th\0" "ko\0"
920 "lt\0" "pl\0" "hu\0" "et\0" "lv\0" "se\0" "fo\0" "fa\0"
921 "ru\0" "zh\0" "nl\0" "ga\0" "sq\0" "ro\0" "cs\0" "sk\0"
922 "sl\0" "yi\0" "sr\0" "mk\0" "bg\0" "uk\0" "be\0" "uz\0"
923 "kk\0" "az\0" "az\0" "hy\0" "ka\0" "mo\0" "ky\0" "tg\0"
924 "tk\0" "mn\0" "mn\0" "ps\0" "ku\0" "ks\0" "sd\0" "bo\0"
925 "ne\0" "sa\0" "mr\0" "bn\0" "as\0" "gu\0" "pa\0" "or\0"
926 "ml\0" "kn\0" "ta\0" "te\0" "si\0" "my\0" "km\0" "lo\0"
927 "vi\0" "id\0" "tl\0" "ms\0" "ms\0" "am\0" "ti\0" "om\0"
928 "so\0" "sw\0" "rw\0" "rn\0" "\0\0\0" "mg\0" "eo\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 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
932 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
933 "cy\0" "eu\0" "ca\0" "la\0" "qu\0" "gn\0" "ay\0" "tt\0"
934 "ug\0" "dz\0" "jv\0" "su\0" "gl\0" "af\0" "br\0" "iu\0"
935 "gd\0" "gv\0" "ga\0" "to\0" "el\0" "kl\0" "az\0" "nn\0";
937 #define NUM_LANGUAGE_ABBREVIATIONS 152
938 #define LANGUAGE_ABBREVIATION_LENGTH 3
940 #ifdef __CONSTANT_CFSTRINGS__
942 // These are not necessarily common localizations per se, but localizations for which the full language name is still in common use.
943 // These are used to provide a fast path for it (other localizations usually use the abbreviation, which is even faster).
944 static CFStringRef
const __CFBundleCommonLanguageNamesArray
[] = {CFSTR("English"), CFSTR("French"), CFSTR("German"), CFSTR("Italian"), CFSTR("Dutch"), CFSTR("Spanish"), CFSTR("Japanese")};
945 static CFStringRef
const __CFBundleCommonLanguageAbbreviationsArray
[] = {CFSTR("en"), CFSTR("fr"), CFSTR("de"), CFSTR("it"), CFSTR("nl"), CFSTR("es"), CFSTR("ja")};
947 #define NUM_COMMON_LANGUAGE_NAMES 7
949 #endif // __CONSTANT_CFSTRINGS__
951 static const SInt32 __CFBundleScriptCodesArray
[] = {
952 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 0, 0,
953 0, 0, 0, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 0, 4,
954 7, 25, 0, 0, 0, 0, 29, 29, 0, 5, 7, 7, 7, 7, 7, 7,
955 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
956 9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
957 30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
958 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
959 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
960 0, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 0, 28,
961 0, 0, 0, 0, 6, 0, 0, 0
964 static const CFStringEncoding __CFBundleStringEncodingsArray
[] = {
965 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 6, 37,
966 0, 35, 36, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 37, 0x8C,
967 7, 25, 0, 39, 0, 38, 29, 29, 36, 5, 7, 7, 7, 0x98, 7, 7,
968 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
969 9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
970 30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
971 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
972 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
973 39, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 39, 0xEC,
974 39, 39, 40, 0, 6, 0, 0, 0
977 static SInt32
_CFBundleGetLanguageCodeForLocalization(CFStringRef localizationName
) {
978 SInt32 result
= -1, i
;
980 CFIndex length
= CFStringGetLength(localizationName
);
981 if ((length
>= LANGUAGE_ABBREVIATION_LENGTH
- 1) && (length
<= 255) && CFStringGetCString(localizationName
, buff
, 255, kCFStringEncodingASCII
)) {
983 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_NAMES
; i
++) {
984 if (0 == strcmp(buff
, __CFBundleLanguageNamesArray
[i
])) result
= i
;
986 if ('n' == buff
[0] && 'o' == buff
[1]) result
= 9; // hack for Norwegian
987 else if (0 == strcmp(buff
, "zh_TW") || 0 == strcmp(buff
, "zh-Hant")) result
= 19; // hack for mixed-up Chinese language codes
988 else if (0 == strcmp(buff
, "zh_CN") || 0 == strcmp(buff
, "zh-Hans")) result
= 33;
989 buff
[LANGUAGE_ABBREVIATION_LENGTH
- 1] = '\0';
990 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_ABBREVIATIONS
* LANGUAGE_ABBREVIATION_LENGTH
; i
+= LANGUAGE_ABBREVIATION_LENGTH
) {
991 if (buff
[0] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 0) && buff
[1] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 1)) result
= i
/ LANGUAGE_ABBREVIATION_LENGTH
;
997 static CFStringRef
_CFBundleCopyLanguageAbbreviationForLanguageCode(SInt32 languageCode
) {
998 CFStringRef result
= NULL
;
999 if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_ABBREVIATIONS
) {
1000 const char *languageAbbreviation
= __CFBundleLanguageAbbreviationsArray
+ languageCode
* LANGUAGE_ABBREVIATION_LENGTH
;
1001 if (languageAbbreviation
!= NULL
&& *languageAbbreviation
!= '\0') {
1002 result
= CFStringCreateWithCStringNoCopy(NULL
, languageAbbreviation
, kCFStringEncodingASCII
, kCFAllocatorNull
);
1008 static inline CFStringRef
_CFBundleCopyLanguageNameForLanguageCode(SInt32 languageCode
) {
1009 CFStringRef result
= NULL
;
1010 if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_NAMES
) {
1011 const char *languageName
= __CFBundleLanguageNamesArray
[languageCode
];
1012 if (languageName
!= NULL
&& *languageName
!= '\0') {
1013 result
= CFStringCreateWithCStringNoCopy(NULL
, languageName
, kCFStringEncodingASCII
, kCFAllocatorNull
);
1019 static inline CFStringRef
_CFBundleCopyLanguageAbbreviationForLocalization(CFStringRef localizationName
) {
1020 CFStringRef result
= NULL
;
1021 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1022 if (languageCode
>= 0) {
1023 result
= _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode
);
1025 CFIndex length
= CFStringGetLength(localizationName
);
1026 if (length
== LANGUAGE_ABBREVIATION_LENGTH
- 1 || (length
> LANGUAGE_ABBREVIATION_LENGTH
- 1 && CFStringGetCharacterAtIndex(localizationName
, LANGUAGE_ABBREVIATION_LENGTH
- 1) == '_')) {
1027 result
= CFStringCreateWithSubstring(NULL
, localizationName
, CFRangeMake(0, LANGUAGE_ABBREVIATION_LENGTH
- 1));
1033 static inline CFStringRef
_CFBundleCopyModifiedLocalization(CFStringRef localizationName
) {
1034 CFMutableStringRef result
= NULL
;
1035 CFIndex length
= CFStringGetLength(localizationName
);
1037 UniChar c
= CFStringGetCharacterAtIndex(localizationName
, 2);
1038 if ('-' == c
|| '_' == c
) {
1039 result
= CFStringCreateMutableCopy(NULL
, length
, localizationName
);
1040 CFStringReplace(result
, CFRangeMake(2, 1), ('-' == c
) ? CFSTR("_") : CFSTR("-"));
1046 static inline CFStringRef
_CFBundleCopyLanguageNameForLocalization(CFStringRef localizationName
) {
1047 CFStringRef result
= NULL
;
1048 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1049 if (languageCode
>= 0) {
1050 result
= _CFBundleCopyLanguageNameForLanguageCode(languageCode
);
1052 result
= CFStringCreateCopy(NULL
, localizationName
);
1057 static SInt32
_CFBundleGetLanguageCodeForRegionCode(SInt32 regionCode
) {
1058 SInt32 result
= -1, i
;
1059 if (52 == regionCode
) { // hack for mixed-up Chinese language codes
1061 } else if (0 <= regionCode
&& regionCode
< NUM_LOCALE_ABBREVIATIONS
) {
1062 const char *localeAbbreviation
= __CFBundleLocaleAbbreviationsArray
+ regionCode
* LOCALE_ABBREVIATION_LENGTH
;
1063 if (localeAbbreviation
!= NULL
&& *localeAbbreviation
!= '\0') {
1064 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_ABBREVIATIONS
* LANGUAGE_ABBREVIATION_LENGTH
; i
+= LANGUAGE_ABBREVIATION_LENGTH
) {
1065 if (localeAbbreviation
[0] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 0) && localeAbbreviation
[1] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 1)) result
= i
/ LANGUAGE_ABBREVIATION_LENGTH
;
1072 static SInt32
_CFBundleGetRegionCodeForLanguageCode(SInt32 languageCode
) {
1073 SInt32 result
= -1, i
;
1074 if (19 == languageCode
) { // hack for mixed-up Chinese language codes
1076 } else if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_ABBREVIATIONS
) {
1077 const char *languageAbbreviation
= __CFBundleLanguageAbbreviationsArray
+ languageCode
* LANGUAGE_ABBREVIATION_LENGTH
;
1078 if (languageAbbreviation
!= NULL
&& *languageAbbreviation
!= '\0') {
1079 for (i
= 0; -1 == result
&& i
< NUM_LOCALE_ABBREVIATIONS
* LOCALE_ABBREVIATION_LENGTH
; i
+= LOCALE_ABBREVIATION_LENGTH
) {
1080 if (*(__CFBundleLocaleAbbreviationsArray
+ i
+ 0) == languageAbbreviation
[0] && *(__CFBundleLocaleAbbreviationsArray
+ i
+ 1) == languageAbbreviation
[1]) result
= i
/ LOCALE_ABBREVIATION_LENGTH
;
1087 static SInt32
_CFBundleGetRegionCodeForLocalization(CFStringRef localizationName
) {
1088 SInt32 result
= -1, i
;
1089 char buff
[LOCALE_ABBREVIATION_LENGTH
];
1090 CFIndex length
= CFStringGetLength(localizationName
);
1091 if ((length
>= LANGUAGE_ABBREVIATION_LENGTH
- 1) && (length
<= LOCALE_ABBREVIATION_LENGTH
- 1) && CFStringGetCString(localizationName
, buff
, LOCALE_ABBREVIATION_LENGTH
, kCFStringEncodingASCII
)) {
1092 buff
[LOCALE_ABBREVIATION_LENGTH
- 1] = '\0';
1093 for (i
= 0; -1 == result
&& i
< NUM_LOCALE_ABBREVIATIONS
* LOCALE_ABBREVIATION_LENGTH
; i
+= LOCALE_ABBREVIATION_LENGTH
) {
1094 if (0 == strcmp(buff
, __CFBundleLocaleAbbreviationsArray
+ i
)) result
= i
/ LOCALE_ABBREVIATION_LENGTH
;
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
!= NULL
&& *localeAbbreviation
!= '\0') {
1109 result
= CFStringCreateWithCStringNoCopy(NULL
, localeAbbreviation
, kCFStringEncodingASCII
, kCFAllocatorNull
);
1115 Boolean
CFBundleGetLocalizationInfoForLocalization(CFStringRef localizationName
, SInt32
*languageCode
, SInt32
*regionCode
, SInt32
*scriptCode
, CFStringEncoding
*stringEncoding
) {
1116 SInt32 language
= -1, region
= -1, script
= 0;
1117 CFStringEncoding encoding
= kCFStringEncodingMacRoman
;
1118 if (localizationName
) {
1119 language
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1120 region
= _CFBundleGetRegionCodeForLocalization(localizationName
);
1122 _CFBundleGetLanguageAndRegionCodes(&language
, ®ion
);
1124 if ((language
< 0 || language
> (int)(sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
))) && region
!= -1) language
= _CFBundleGetLanguageCodeForRegionCode(region
);
1125 if (region
== -1 && language
!= -1) region
= _CFBundleGetRegionCodeForLanguageCode(language
);
1126 if (language
>= 0 && language
< (int)(sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
))) {
1127 script
= __CFBundleScriptCodesArray
[language
];
1129 if (language
>= 0 && language
< (int)(sizeof(__CFBundleStringEncodingsArray
)/sizeof(CFStringEncoding
))) {
1130 encoding
= __CFBundleStringEncodingsArray
[language
];
1132 if (languageCode
) *languageCode
= language
;
1133 if (regionCode
) *regionCode
= region
;
1134 if (scriptCode
) *scriptCode
= script
;
1135 if (stringEncoding
) *stringEncoding
= encoding
;
1136 return (language
!= -1 || region
!= -1);
1139 CFStringRef
CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode
, SInt32 regionCode
, SInt32 scriptCode
, CFStringEncoding stringEncoding
) {
1140 CFStringRef localizationName
= NULL
;
1141 if (!localizationName
) {
1142 localizationName
= _CFBundleCopyLocaleAbbreviationForRegionCode(regionCode
);
1144 if (!localizationName
) {
1145 localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode
);
1147 if (!localizationName
) {
1148 SInt32 language
= -1, scriptLanguage
= -1, encodingLanguage
= -1;
1150 for (i
= 0; language
== -1 && i
< (sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
)); i
++) {
1151 if (__CFBundleScriptCodesArray
[i
] == scriptCode
&& __CFBundleStringEncodingsArray
[i
] == stringEncoding
) language
= i
;
1153 for (i
= 0; scriptLanguage
== -1 && i
< (sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
)); i
++) {
1154 if (__CFBundleScriptCodesArray
[i
] == scriptCode
) scriptLanguage
= i
;
1156 for (i
= 0; encodingLanguage
== -1 && i
< (sizeof(__CFBundleStringEncodingsArray
)/sizeof(CFStringEncoding
)); i
++) {
1157 if (__CFBundleStringEncodingsArray
[i
] == stringEncoding
) encodingLanguage
= i
;
1159 localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(language
);
1160 if (!localizationName
) localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(encodingLanguage
);
1161 if (!localizationName
) localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(scriptLanguage
);
1163 return localizationName
;
1166 extern void *__CFAppleLanguages
;
1168 __private_extern__ CFArrayRef
_CFBundleCopyUserLanguages(Boolean useBackstops
) {
1169 CFArrayRef result
= NULL
;
1170 static CFArrayRef userLanguages
= NULL
;
1171 static Boolean didit
= false;
1172 CFArrayRef preferencesArray
= NULL
;
1173 // This is a temporary solution, until the argument domain is moved down into CFPreferences
1174 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
1176 if (__CFAppleLanguages
) {
1178 CFIndex length
= strlen(__CFAppleLanguages
);
1180 data
= CFDataCreateWithBytesNoCopy(NULL
, __CFAppleLanguages
, length
, kCFAllocatorNull
);
1182 __CFSetNastyFile(CFSTR("<plist command-line argument>"));
1183 userLanguages
= CFPropertyListCreateFromXMLData(NULL
, data
, kCFPropertyListImmutable
, NULL
);
1188 if (!userLanguages
&& preferencesArray
) userLanguages
= CFRetain(preferencesArray
);
1189 Boolean useEnglishAsBackstop
= true;
1190 // could perhaps read out of LANG environment variable
1191 if (useEnglishAsBackstop
&& !userLanguages
) {
1192 CFStringRef english
= CFSTR("English");
1193 userLanguages
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&english
, 1, &kCFTypeArrayCallBacks
);
1195 if (userLanguages
&& CFGetTypeID(userLanguages
) != CFArrayGetTypeID()) {
1196 CFRelease(userLanguages
);
1197 userLanguages
= NULL
;
1201 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
1202 if (preferencesArray
) CFRelease(preferencesArray
);
1203 #if defined(__MACOS8__)
1204 if (useBackstops
&& (NULL
== userLanguages
|| 0 == CFArrayGetCount(userLanguages
)) {
1205 // use the system region and language as a backstop on 8
1206 CFMutableArrayRef mutableUserLanguages
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1207 CFStringRef localeAbbreviation
= _CFBundleCopyLocaleAbbreviationForRegionCode(GetScriptManagerVariable(smRegionCode
)), languageAbbreviation
= _CFBundleCopyLanguageAbbreviationForLanguageCode(GetScriptVariable(smSystemScript
, smScriptLang
));
1208 if (localeAbbreviation
) {
1209 CFArrayAppendValue(mutableUserLanguages
, localeAbbreviation
);
1210 CFRelease(localeAbbreviation
);
1212 if (languageAbbreviation
) {
1213 CFArrayAppendValue(mutableUserLanguages
, languageAbbreviation
);
1214 CFRelease(languageAbbreviation
);
1216 result
= (CFArrayRef
)mutableUserLanguages
;
1218 #endif /* __MACOS8__ */
1219 if (!result
&& userLanguages
) result
= CFRetain(userLanguages
);
1223 CF_EXPORT
void _CFBundleGetLanguageAndRegionCodes(SInt32
*languageCode
, SInt32
*regionCode
) {
1224 // an attempt to answer the question, "what language are we running in?"
1225 // note that the question cannot be answered fully since it may depend on the bundle
1226 SInt32 language
= -1, region
= -1;
1227 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1228 CFArrayRef languages
= NULL
;
1229 CFStringRef localizationName
= NULL
;
1231 languages
= _CFBundleGetLanguageSearchList(mainBundle
);
1232 if (languages
) CFRetain(languages
);
1234 if (!languages
) languages
= _CFBundleCopyUserLanguages(false);
1235 if (languages
&& (CFArrayGetCount(languages
) > 0)) {
1236 localizationName
= CFArrayGetValueAtIndex(languages
, 0);
1237 language
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1238 region
= _CFBundleGetRegionCodeForLocalization(localizationName
);
1240 #if defined(__MACOS8__)
1241 language
= GetScriptVariable(smSystemScript
, smScriptLang
);
1242 region
= GetScriptManagerVariable(smRegionCode
);
1246 #endif /* __MACOS8__ */
1248 if (language
== -1 && region
!= -1) language
= _CFBundleGetLanguageCodeForRegionCode(region
);
1249 if (region
== -1 && language
!= -1) region
= _CFBundleGetRegionCodeForLanguageCode(language
);
1250 if (languages
) CFRelease(languages
);
1251 if (languageCode
) *languageCode
= language
;
1252 if (regionCode
) *regionCode
= region
;
1256 static Boolean
_CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc
, UniChar
*pathUniChars
, CFIndex pathLen
, uint8_t version
, CFDictionaryRef infoDict
, CFStringRef curLangStr
, CFMutableArrayRef lprojNames
) {
1257 CFIndex curLangLen
= CFStringGetLength(curLangStr
), savedPathLen
, idx
;
1258 UniChar curLangUniChars
[255];
1259 CFStringRef altLangStr
= NULL
, modifiedLangStr
= NULL
, languageAbbreviation
= NULL
, languageName
= NULL
, canonicalLanguageIdentifier
= NULL
;
1260 CFMutableDictionaryRef canonicalLanguageIdentifiers
= NULL
, predefinedCanonicalLanguageIdentifiers
= NULL
;
1261 Boolean foundOne
= false;
1262 CFArrayRef predefinedLocalizations
= NULL
;
1263 CFRange predefinedLocalizationsRange
;
1264 CFMutableStringRef cheapStr
, tmpString
;
1265 #if USE_GETDIRENTRIES
1266 CFArrayRef contents
;
1267 CFRange contentsRange
;
1269 Boolean isDir
= false;
1272 // both of these used for temp string operations, for slightly
1273 // different purposes, where each type is appropriate
1274 cheapStr
= CFStringCreateMutable(alloc
, 0);
1275 _CFStrSetDesiredCapacity(cheapStr
, CFMaxPathSize
);
1276 tmpString
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, kCFAllocatorNull
);
1278 #if USE_GETDIRENTRIES
1279 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1280 CFStringReplaceAll(cheapStr
, tmpString
);
1281 contents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, _CFBundleAllContents
);
1282 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
1286 predefinedLocalizations
= CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
1287 if (predefinedLocalizations
!= NULL
&& CFGetTypeID(predefinedLocalizations
) != CFArrayGetTypeID()) {
1288 predefinedLocalizations
= NULL
;
1289 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleLocalizationsKey
);
1292 predefinedLocalizationsRange
= CFRangeMake(0, predefinedLocalizations
? CFArrayGetCount(predefinedLocalizations
) : 0);
1294 if (curLangLen
> 255) curLangLen
= 255;
1295 CFStringGetCharacters(curLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1296 savedPathLen
= pathLen
;
1297 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1298 #if USE_GETDIRENTRIES
1299 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1300 CFStringReplaceAll(cheapStr
, tmpString
);
1301 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, curLangStr
)) || (version
!= 4 && CFArrayContainsValue(contents
, contentsRange
, cheapStr
))) {
1303 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1304 CFStringReplaceAll(cheapStr
, tmpString
);
1305 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, curLangStr
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1307 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), curLangStr
)) CFArrayAppendValue(lprojNames
, curLangStr
);
1309 if (CFStringGetLength(curLangStr
) <= 2) {
1310 CFRelease(cheapStr
);
1311 CFRelease(tmpString
);
1312 #if USE_GETDIRENTRIES
1313 CFRelease(contents
);
1319 #ifdef __CONSTANT_CFSTRINGS__
1320 for (idx
= 0; !altLangStr
&& idx
< NUM_COMMON_LANGUAGE_NAMES
; idx
++) {
1321 if (CFEqual(curLangStr
, __CFBundleCommonLanguageAbbreviationsArray
[idx
])) altLangStr
= __CFBundleCommonLanguageNamesArray
[idx
];
1322 else if (CFEqual(curLangStr
, __CFBundleCommonLanguageNamesArray
[idx
])) altLangStr
= __CFBundleCommonLanguageAbbreviationsArray
[idx
];
1324 #endif // __CONSTANT_CFSTRINGS__
1325 if (foundOne
&& altLangStr
) {
1326 CFRelease(cheapStr
);
1327 CFRelease(tmpString
);
1328 #if USE_GETDIRENTRIES
1329 CFRelease(contents
);
1334 curLangLen
= CFStringGetLength(altLangStr
);
1335 if (curLangLen
> 255) curLangLen
= 255;
1336 CFStringGetCharacters(altLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1337 pathLen
= savedPathLen
;
1338 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1339 #if USE_GETDIRENTRIES
1340 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1341 CFStringReplaceAll(cheapStr
, tmpString
);
1342 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, altLangStr
)) || (version
!= 4 && CFArrayContainsValue(contents
, contentsRange
, cheapStr
))) {
1344 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1345 CFStringReplaceAll(cheapStr
, tmpString
);
1346 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, altLangStr
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1348 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), altLangStr
)) CFArrayAppendValue(lprojNames
, altLangStr
);
1350 CFRelease(cheapStr
);
1351 CFRelease(tmpString
);
1352 #if USE_GETDIRENTRIES
1353 CFRelease(contents
);
1359 #if USE_GETDIRENTRIES
1361 Boolean hasLocalizations
= false;
1362 for (idx
= 0; !hasLocalizations
&& idx
< contentsRange
.length
; idx
++) {
1363 CFStringRef name
= CFArrayGetValueAtIndex(contents
, idx
);
1364 if (CFStringHasSuffix(name
, _CFBundleLprojExtensionWithDot
)) hasLocalizations
= true;
1366 if (!hasLocalizations
) {
1367 CFRelease(cheapStr
);
1368 CFRelease(tmpString
);
1369 CFRelease(contents
);
1374 if (!altLangStr
&& (modifiedLangStr
= _CFBundleCopyModifiedLocalization(curLangStr
))) {
1375 curLangLen
= CFStringGetLength(modifiedLangStr
);
1376 if (curLangLen
> 255) curLangLen
= 255;
1377 CFStringGetCharacters(modifiedLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1378 pathLen
= savedPathLen
;
1379 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1380 #if USE_GETDIRENTRIES
1381 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1382 CFStringReplaceAll(cheapStr
, tmpString
);
1383 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, modifiedLangStr
)) || (version
!= 4 && CFArrayContainsValue(contents
, contentsRange
, cheapStr
))) {
1385 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1386 CFStringReplaceAll(cheapStr
, tmpString
);
1387 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, modifiedLangStr
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1389 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), modifiedLangStr
)) CFArrayAppendValue(lprojNames
, modifiedLangStr
);
1394 if (!altLangStr
&& (languageAbbreviation
= _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageAbbreviation
)) {
1395 curLangLen
= CFStringGetLength(languageAbbreviation
);
1396 if (curLangLen
> 255) curLangLen
= 255;
1397 CFStringGetCharacters(languageAbbreviation
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1398 pathLen
= savedPathLen
;
1399 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1400 #if USE_GETDIRENTRIES
1401 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1402 CFStringReplaceAll(cheapStr
, tmpString
);
1403 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageAbbreviation
)) || (version
!= 4 && CFArrayContainsValue(contents
, contentsRange
, cheapStr
))) {
1405 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1406 CFStringReplaceAll(cheapStr
, tmpString
);
1407 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageAbbreviation
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1409 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageAbbreviation
)) CFArrayAppendValue(lprojNames
, languageAbbreviation
);
1414 if (!altLangStr
&& (languageName
= _CFBundleCopyLanguageNameForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageName
)) {
1415 curLangLen
= CFStringGetLength(languageName
);
1416 if (curLangLen
> 255) curLangLen
= 255;
1417 CFStringGetCharacters(languageName
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1418 pathLen
= savedPathLen
;
1419 if (_CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
) && _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
1420 #if USE_GETDIRENTRIES
1421 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1422 CFStringReplaceAll(cheapStr
, tmpString
);
1423 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageName
)) || (version
!= 4 && CFArrayContainsValue(contents
, contentsRange
, cheapStr
))) {
1425 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1426 CFStringReplaceAll(cheapStr
, tmpString
);
1427 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageName
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1429 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageName
)) CFArrayAppendValue(lprojNames
, languageName
);
1434 if (modifiedLangStr
) CFRelease(modifiedLangStr
);
1435 if (languageAbbreviation
) CFRelease(languageAbbreviation
);
1436 if (languageName
) CFRelease(languageName
);
1437 if (canonicalLanguageIdentifier
) CFRelease(canonicalLanguageIdentifier
);
1438 if (canonicalLanguageIdentifiers
) CFRelease(canonicalLanguageIdentifiers
);
1439 if (predefinedCanonicalLanguageIdentifiers
) CFRelease(predefinedCanonicalLanguageIdentifiers
);
1440 CFRelease(cheapStr
);
1441 CFRelease(tmpString
);
1442 #if USE_GETDIRENTRIES
1443 CFRelease(contents
);
1449 static Boolean
CFBundleAllowMixedLocalizations(void) {
1450 static Boolean allowMixed
= false, examinedMain
= false;
1451 if (!examinedMain
) {
1452 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1453 CFDictionaryRef infoDict
= mainBundle
? CFBundleGetInfoDictionary(mainBundle
) : NULL
;
1454 CFTypeRef allowMixedValue
= infoDict
? CFDictionaryGetValue(infoDict
, _kCFBundleAllowMixedLocalizationsKey
) : NULL
;
1455 if (allowMixedValue
) {
1456 CFTypeID typeID
= CFGetTypeID(allowMixedValue
);
1457 if (typeID
== CFBooleanGetTypeID()) {
1458 allowMixed
= CFBooleanGetValue((CFBooleanRef
)allowMixedValue
);
1459 } else if (typeID
== CFStringGetTypeID()) {
1460 allowMixed
= (CFStringCompare((CFStringRef
)allowMixedValue
, CFSTR("true"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
|| CFStringCompare((CFStringRef
)allowMixedValue
, CFSTR("YES"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1461 } else if (typeID
== CFNumberGetTypeID()) {
1463 if (CFNumberGetValue((CFNumberRef
)allowMixedValue
, kCFNumberSInt32Type
, &val
)) allowMixed
= (val
!= 0);
1466 examinedMain
= true;
1471 __private_extern__
void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
, CFDictionaryRef infoDict
, CFMutableArrayRef lprojNames
, CFStringRef devLang
) {
1472 // This function will add zero, one or two elements to the lprojNames array.
1473 // 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.
1474 // 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.
1475 CFURLRef resourcesURL
= _CFBundleCopyResourcesDirectoryURLInDirectory(alloc
, bundleURL
, version
);
1476 CFURLRef absoluteURL
;
1479 CFStringRef resourcesPath
;
1480 UniChar pathUniChars
[CFMaxPathSize
];
1482 CFStringRef curLangStr
;
1483 Boolean foundOne
= false;
1485 CFArrayRef userLanguages
;
1487 // Init the one-time-only unichar buffers.
1488 _CFEnsureStaticBuffersInited();
1490 // Get the path to the resources and extract into a buffer.
1491 absoluteURL
= CFURLCopyAbsoluteURL(resourcesURL
);
1492 resourcesPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1493 CFRelease(absoluteURL
);
1494 pathLen
= CFStringGetLength(resourcesPath
);
1495 if (pathLen
> CFMaxPathSize
) pathLen
= CFMaxPathSize
;
1496 CFStringGetCharacters(resourcesPath
, CFRangeMake(0, pathLen
), pathUniChars
);
1497 CFRelease(resourcesURL
);
1498 CFRelease(resourcesPath
);
1500 // First check the main bundle.
1501 if (!CFBundleAllowMixedLocalizations()) {
1502 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1504 CFURLRef mainBundleURL
= CFBundleCopyBundleURL(mainBundle
);
1505 if (!CFEqual(bundleURL
, mainBundleURL
)) {
1506 // If there is a main bundle, and it isn't this one, try to use the language it prefers.
1507 CFArrayRef mainBundleLangs
= _CFBundleGetLanguageSearchList(mainBundle
);
1508 if (mainBundleLangs
&& (CFArrayGetCount(mainBundleLangs
) > 0)) {
1509 curLangStr
= CFArrayGetValueAtIndex(mainBundleLangs
, 0);
1510 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
);
1513 CFRelease(mainBundleURL
);
1518 // If we didn't find the main bundle's preferred language, look at the users' prefs again and find the best one.
1519 userLanguages
= _CFBundleCopyUserLanguages(true);
1520 count
= (userLanguages
? CFArrayGetCount(userLanguages
) : 0);
1521 for (idx
= 0; !foundOne
&& idx
< count
; idx
++) {
1522 curLangStr
= CFArrayGetValueAtIndex(userLanguages
, idx
);
1523 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
);
1525 // use development region and U.S. English as backstops
1526 if (!foundOne
&& devLang
!= NULL
) {
1527 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, devLang
, lprojNames
);
1530 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, CFSTR("en_US"), lprojNames
);
1532 if (userLanguages
!= NULL
) {
1533 CFRelease(userLanguages
);
1538 static Boolean
_CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array
, CFStringRef curLangStr
, CFMutableArrayRef lprojNames
) {
1539 Boolean foundOne
= false;
1540 CFRange range
= CFRangeMake(0, CFArrayGetCount(array
));
1541 CFStringRef altLangStr
= NULL
, modifiedLangStr
= NULL
, languageAbbreviation
= NULL
, languageName
= NULL
, canonicalLanguageIdentifier
= NULL
;
1542 CFMutableDictionaryRef canonicalLanguageIdentifiers
= NULL
;
1545 if (range
.length
== 0) return foundOne
;
1546 if (CFArrayContainsValue(array
, range
, curLangStr
)) {
1547 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), curLangStr
)) CFArrayAppendValue(lprojNames
, curLangStr
);
1549 if (range
.length
== 1 || CFStringGetLength(curLangStr
) <= 2) return foundOne
;
1551 if (range
.length
== 1 && CFArrayContainsValue(array
, range
, CFSTR("default"))) return foundOne
;
1552 #ifdef __CONSTANT_CFSTRINGS__
1553 for (idx
= 0; !altLangStr
&& idx
< NUM_COMMON_LANGUAGE_NAMES
; idx
++) {
1554 if (CFEqual(curLangStr
, __CFBundleCommonLanguageAbbreviationsArray
[idx
])) altLangStr
= __CFBundleCommonLanguageNamesArray
[idx
];
1555 else if (CFEqual(curLangStr
, __CFBundleCommonLanguageNamesArray
[idx
])) altLangStr
= __CFBundleCommonLanguageAbbreviationsArray
[idx
];
1557 #endif // __CONSTANT_CFSTRINGS__
1558 if (foundOne
&& altLangStr
) return foundOne
;
1559 if (altLangStr
&& CFArrayContainsValue(array
, range
, altLangStr
)) {
1560 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), altLangStr
)) CFArrayAppendValue(lprojNames
, altLangStr
);
1564 if (!altLangStr
&& (modifiedLangStr
= _CFBundleCopyModifiedLocalization(curLangStr
))) {
1565 if (CFArrayContainsValue(array
, range
, modifiedLangStr
)) {
1566 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), modifiedLangStr
)) CFArrayAppendValue(lprojNames
, modifiedLangStr
);
1570 if (!altLangStr
&& (languageAbbreviation
= _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageAbbreviation
)) {
1571 if (CFArrayContainsValue(array
, range
, languageAbbreviation
)) {
1572 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageAbbreviation
)) CFArrayAppendValue(lprojNames
, languageAbbreviation
);
1576 if (!altLangStr
&& (languageName
= _CFBundleCopyLanguageNameForLocalization(curLangStr
)) && !CFEqual(curLangStr
, languageName
)) {
1577 if (CFArrayContainsValue(array
, range
, languageName
)) {
1578 if (!CFArrayContainsValue(lprojNames
, CFRangeMake(0, CFArrayGetCount(lprojNames
)), languageName
)) CFArrayAppendValue(lprojNames
, languageName
);
1582 if (modifiedLangStr
) CFRelease(modifiedLangStr
);
1583 if (languageAbbreviation
) CFRelease(languageAbbreviation
);
1584 if (languageName
) CFRelease(languageName
);
1585 if (canonicalLanguageIdentifier
) CFRelease(canonicalLanguageIdentifier
);
1586 if (canonicalLanguageIdentifiers
) CFRelease(canonicalLanguageIdentifiers
);
1591 static CFArrayRef
_CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray
, CFArrayRef prefArray
, Boolean considerMain
) {
1592 CFMutableArrayRef lprojNames
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1593 Boolean foundOne
= false, releasePrefArray
= false;
1596 if (considerMain
&& !CFBundleAllowMixedLocalizations()) {
1597 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1599 // If there is a main bundle, try to use the language it prefers.
1600 CFArrayRef mainBundleLangs
= _CFBundleGetLanguageSearchList(mainBundle
);
1601 if (mainBundleLangs
&& (CFArrayGetCount(mainBundleLangs
) > 0)) {
1602 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, CFArrayGetValueAtIndex(mainBundleLangs
, 0), lprojNames
);
1608 prefArray
= _CFBundleCopyUserLanguages(true);
1609 if (prefArray
) releasePrefArray
= true;
1611 count
= (prefArray
? CFArrayGetCount(prefArray
) : 0);
1612 for (idx
= 0; !foundOne
&& idx
< count
; idx
++) {
1613 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, CFArrayGetValueAtIndex(prefArray
, idx
), lprojNames
);
1615 // use U.S. English as backstop
1617 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, CFSTR("en_US"), lprojNames
);
1619 // use random entry as backstop
1620 if (!foundOne
&& CFArrayGetCount(lprojNames
) > 0) {
1621 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, CFArrayGetValueAtIndex(locArray
, 0), lprojNames
);
1624 if (CFArrayGetCount(lprojNames
) == 0) {
1625 // Total backstop behavior to avoid having an empty array.
1626 CFArrayAppendValue(lprojNames
, CFSTR("en"));
1628 if (releasePrefArray
) {
1629 CFRelease(prefArray
);
1634 CF_EXPORT CFArrayRef
CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray
, CFArrayRef prefArray
) {return _CFBundleCopyLocalizationsForPreferences(locArray
, prefArray
, false);}
1636 CF_EXPORT CFArrayRef
CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locArray
) {return _CFBundleCopyLocalizationsForPreferences(locArray
, NULL
, true);}
1638 __private_extern__ CFArrayRef
_CFBundleCopyLanguageSearchListInDirectory(CFAllocatorRef alloc
, CFURLRef url
, uint8_t *version
) {
1639 CFMutableArrayRef langs
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
1640 uint8_t localVersion
= 0;
1641 CFDictionaryRef infoDict
= _CFBundleCopyInfoDictionaryInDirectory(alloc
, url
, &localVersion
);
1642 CFStringRef devLang
= NULL
;
1643 if (infoDict
!= NULL
) {
1644 devLang
= CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1646 if (devLang
!= NULL
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) devLang
= NULL
;
1648 _CFBundleAddPreferredLprojNamesInDirectory(alloc
, url
, localVersion
, infoDict
, langs
, devLang
);
1650 if (devLang
!= NULL
&& CFArrayGetFirstIndexOfValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), devLang
) < 0) {
1651 CFArrayAppendValue(langs
, devLang
);
1653 if (CFArrayGetCount(langs
) == 0) {
1654 // Total backstop behavior to avoid having an empty array.
1655 CFArrayAppendValue(langs
, CFSTR("en"));
1657 if (infoDict
!= NULL
) {
1658 CFRelease(infoDict
);
1661 *version
= localVersion
;
1666 CF_EXPORT Boolean
_CFBundleURLLooksLikeBundle(CFURLRef url
) {
1667 Boolean result
= false;
1668 CFBundleRef bundle
= _CFBundleCreateIfLooksLikeBundle(NULL
, url
);
1676 // Note that subDirName is expected to be the string for a URL
1677 CF_INLINE Boolean
_CFBundleURLHasSubDir(CFURLRef url
, CFStringRef subDirName
) {
1679 Boolean isDir
, result
= false;
1681 dirURL
= CFURLCreateWithString(NULL
, subDirName
, url
);
1682 if (dirURL
!= NULL
) {
1683 if (_CFIsResourceAtURL(dirURL
, &isDir
) && isDir
) {
1691 __private_extern__ Boolean
_CFBundleURLLooksLikeBundleVersion(CFURLRef url
, uint8_t *version
) {
1692 // check for existence of "Resources" or "Contents" or "Support Files"
1693 // but check for the most likely one first
1694 // version 0: old-style "Resources" bundles
1695 // version 1: obsolete "Support Files" bundles
1696 // version 2: modern "Contents" bundles
1697 // version 3: none of the above (see below)
1698 // version 4: not a bundle (for main bundle only)
1699 uint8_t localVersion
= 3;
1700 #if USE_GETDIRENTRIES
1701 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
1702 CFStringRef directoryPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1703 CFArrayRef contents
= _CFBundleCopyDirectoryContentsAtPath(directoryPath
, _CFBundleAllContents
);
1704 CFRange contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
1705 if (CFStringHasSuffix(CFURLGetString(url
), CFSTR(".framework/"))) {
1706 if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleResourcesDirectoryName
)) localVersion
= 0;
1707 else if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleSupportFilesDirectoryName2
)) localVersion
= 2;
1708 else if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleSupportFilesDirectoryName1
)) localVersion
= 1;
1710 if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleSupportFilesDirectoryName2
)) localVersion
= 2;
1711 else if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleResourcesDirectoryName
)) localVersion
= 0;
1712 else if (CFArrayContainsValue(contents
, contentsRange
, _CFBundleSupportFilesDirectoryName1
)) localVersion
= 1;
1714 CFRelease(contents
);
1715 CFRelease(directoryPath
);
1716 CFRelease(absoluteURL
);
1718 if (localVersion
== 3) {
1719 if (CFStringHasSuffix(CFURLGetString(url
), CFSTR(".framework/"))) {
1720 if (_CFBundleURLHasSubDir(url
, _CFBundleResourcesURLFromBase0
)) localVersion
= 0;
1721 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase2
)) localVersion
= 2;
1722 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase1
)) localVersion
= 1;
1724 if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase2
)) localVersion
= 2;
1725 else if (_CFBundleURLHasSubDir(url
, _CFBundleResourcesURLFromBase0
)) localVersion
= 0;
1726 else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase1
)) localVersion
= 1;
1729 if (version
) *version
= localVersion
;
1730 return !(localVersion
== 3);
1733 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc
, CFURLRef url
, uint8_t *version
) {
1734 CFDictionaryRef dict
= NULL
;
1735 char buff
[CFMaxPathSize
];
1736 uint8_t localVersion
= 0;
1738 if (CFURLGetFileSystemRepresentation(url
, true, buff
, CFMaxPathSize
)) {
1739 CFURLRef newURL
= CFURLCreateFromFileSystemRepresentation(alloc
, buff
, strlen(buff
), true);
1740 if (NULL
== newURL
) newURL
= CFRetain(url
);
1742 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) {
1743 // version 3 is for flattened pseudo-bundles with no Contents, Support Files, or Resources directories
1746 dict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(alloc
, newURL
, localVersion
);
1749 if (version
) *version
= localVersion
;
1753 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc
, CFURLRef url
, uint8_t version
) {
1754 CFDictionaryRef result
= NULL
;
1756 CFURLRef infoURL
= NULL
;
1757 CFDataRef infoData
= NULL
;
1758 UniChar buff
[CFMaxPathSize
];
1760 CFMutableStringRef cheapStr
;
1761 CFStringRef infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension0
, infoURLFromBase
= _CFBundleInfoURLFromBase0
;
1762 Boolean tryPlatformSpecific
= true, tryGlobal
= true;
1763 #if USE_GETDIRENTRIES
1764 CFURLRef directoryURL
= NULL
, absoluteURL
;
1765 CFStringRef directoryPath
;
1766 CFArrayRef contents
= NULL
;
1767 CFRange contentsRange
= CFRangeMake(0, 0);
1770 _CFEnsureStaticBuffersInited();
1773 #if USE_GETDIRENTRIES
1774 directoryURL
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase0
, url
);
1776 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension0
;
1777 infoURLFromBase
= _CFBundleInfoURLFromBase0
;
1778 } else if (1 == version
) {
1779 #if USE_GETDIRENTRIES
1780 directoryURL
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase1
, url
);
1782 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension1
;
1783 infoURLFromBase
= _CFBundleInfoURLFromBase1
;
1784 } else if (2 == version
) {
1785 #if USE_GETDIRENTRIES
1786 directoryURL
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase2
, url
);
1788 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension2
;
1789 infoURLFromBase
= _CFBundleInfoURLFromBase2
;
1790 } else if (3 == version
) {
1791 CFStringRef posixPath
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
1792 // this test is necessary to exclude the case where a bundle is spuriously created from the innards of another bundle
1794 if (!(CFStringHasSuffix(posixPath
, _CFBundleSupportFilesDirectoryName1
) || CFStringHasSuffix(posixPath
, _CFBundleSupportFilesDirectoryName2
) || CFStringHasSuffix(posixPath
, _CFBundleResourcesDirectoryName
))) {
1795 #if USE_GETDIRENTRIES
1796 directoryURL
= CFRetain(url
);
1798 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension3
;
1799 infoURLFromBase
= _CFBundleInfoURLFromBase3
;
1801 CFRelease(posixPath
);
1804 #if USE_GETDIRENTRIES
1806 absoluteURL
= CFURLCopyAbsoluteURL(directoryURL
);
1807 directoryPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1808 contents
= _CFBundleCopyDirectoryContentsAtPath(directoryPath
, _CFBundleAllContents
);
1809 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
1810 CFRelease(directoryPath
);
1811 CFRelease(absoluteURL
);
1812 CFRelease(directoryURL
);
1816 len
= CFStringGetLength(infoURLFromBaseNoExtension
);
1817 CFStringGetCharacters(infoURLFromBaseNoExtension
, CFRangeMake(0, len
), buff
);
1818 buff
[len
++] = (UniChar
)'-';
1819 memmove(buff
+ len
, _PlatformUniChars
, _PlatformLen
* sizeof(UniChar
));
1820 len
+= _PlatformLen
;
1821 _CFAppendPathExtension(buff
, &len
, CFMaxPathSize
, _InfoExtensionUniChars
, _InfoExtensionLen
);
1822 cheapStr
= CFStringCreateMutable(alloc
, 0);
1823 CFStringAppendCharacters(cheapStr
, buff
, len
);
1824 infoURL
= CFURLCreateWithString(alloc
, cheapStr
, url
);
1825 #if USE_GETDIRENTRIES
1827 CFIndex resourcesLen
, idx
;
1828 for (resourcesLen
= len
; resourcesLen
> 0; resourcesLen
--) if (buff
[resourcesLen
- 1] == '/') break;
1829 CFStringDelete(cheapStr
, CFRangeMake(0, CFStringGetLength(cheapStr
)));
1830 CFStringAppendCharacters(cheapStr
, buff
+ resourcesLen
, len
- resourcesLen
);
1831 for (tryPlatformSpecific
= false, idx
= 0; !tryPlatformSpecific
&& idx
< contentsRange
.length
; idx
++) {
1832 // Need to do this case-insensitive to accommodate Palm
1833 if (kCFCompareEqualTo
== CFStringCompare(cheapStr
, CFArrayGetValueAtIndex(contents
, idx
), kCFCompareCaseInsensitive
)) tryPlatformSpecific
= true;
1837 if (tryPlatformSpecific
) CFURLCreateDataAndPropertiesFromResource(alloc
, infoURL
, &infoData
, NULL
, NULL
, NULL
);
1838 //fprintf(stderr, "looking for ");CFShow(infoURL);fprintf(stderr, infoData ? "found it\n" : (tryPlatformSpecific ? "missed it\n" : "skipped it\n"));
1839 CFRelease(cheapStr
);
1841 // Check for global Info.plist
1843 infoURL
= CFURLCreateWithString(alloc
, infoURLFromBase
, url
);
1844 #if USE_GETDIRENTRIES
1847 for (tryGlobal
= false, idx
= 0; !tryGlobal
&& idx
< contentsRange
.length
; idx
++) {
1848 // Need to do this case-insensitive to accommodate Palm
1849 if (kCFCompareEqualTo
== CFStringCompare(_CFBundleInfoFileName
, CFArrayGetValueAtIndex(contents
, idx
), kCFCompareCaseInsensitive
)) tryGlobal
= true;
1853 if (tryGlobal
) CFURLCreateDataAndPropertiesFromResource(alloc
, infoURL
, &infoData
, NULL
, NULL
, NULL
);
1854 //fprintf(stderr, "looking for ");CFShow(infoURL);fprintf(stderr, infoData ? "found it\n" : (tryGlobal ? "missed it\n" : "skipped it\n"));
1858 result
= CFPropertyListCreateFromXMLData(alloc
, infoData
, kCFPropertyListMutableContainers
, NULL
);
1860 if (CFDictionaryGetTypeID() == CFGetTypeID(result
)) {
1861 CFDictionarySetValue((CFMutableDictionaryRef
)result
, _kCFBundleInfoPlistURLKey
, infoURL
);
1867 CFRelease(infoData
);
1870 result
= CFDictionaryCreateMutable(alloc
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1874 #if USE_GETDIRENTRIES
1875 if (contents
) CFRelease(contents
);
1881 static Boolean
_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorRef alloc
, CFURLRef url
, CFDictionaryRef infoDict
, UInt32
*packageType
, UInt32
*packageCreator
) {
1882 Boolean retVal
= false, hasType
= false, hasCreator
= false, releaseInfoDict
= false;
1884 CFDataRef pkgInfoData
= NULL
;
1886 // Check for a "real" new bundle
1887 tempURL
= CFURLCreateWithString(alloc
, _CFBundlePkgInfoURLFromBase2
, url
);
1888 CFURLCreateDataAndPropertiesFromResource(alloc
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
1890 if (pkgInfoData
== NULL
) {
1891 tempURL
= CFURLCreateWithString(alloc
, _CFBundlePkgInfoURLFromBase1
, url
);
1892 CFURLCreateDataAndPropertiesFromResource(alloc
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
1895 if (pkgInfoData
== NULL
) {
1896 // Check for a "pseudo" new bundle
1897 tempURL
= CFURLCreateWithString(alloc
, _CFBundlePseudoPkgInfoURLFromBase
, url
);
1898 CFURLCreateDataAndPropertiesFromResource(alloc
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
1902 // 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.
1903 // 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.
1904 // 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.
1906 if ((pkgInfoData
!= NULL
) && (CFDataGetLength(pkgInfoData
) >= (int)(sizeof(UInt32
) * 2))) {
1907 UInt32
*pkgInfo
= (UInt32
*)CFDataGetBytePtr(pkgInfoData
);
1909 if (packageType
!= NULL
) {
1910 *packageType
= CFSwapInt32BigToHost(pkgInfo
[0]);
1912 if (packageCreator
!= NULL
) {
1913 *packageCreator
= CFSwapInt32BigToHost(pkgInfo
[1]);
1915 retVal
= hasType
= hasCreator
= true;
1917 if (pkgInfoData
!= NULL
) CFRelease(pkgInfoData
);
1920 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(alloc
, url
, NULL
);
1921 releaseInfoDict
= true;
1924 CFStringRef typeString
= CFDictionaryGetValue(infoDict
, _kCFBundlePackageTypeKey
), creatorString
= CFDictionaryGetValue(infoDict
, _kCFBundleSignatureKey
);
1926 CFIndex usedBufLen
= 0;
1927 if (typeString
&& CFGetTypeID(typeString
) == CFStringGetTypeID() && CFStringGetLength(typeString
) == 4 && 4 == CFStringGetBytes(typeString
, CFRangeMake(0, 4), kCFStringEncodingMacRoman
, 0, false, (UInt8
*)&tmp
, 4, &usedBufLen
) && 4 == usedBufLen
) {
1928 if (packageType
!= NULL
) {
1929 *packageType
= CFSwapInt32BigToHost(tmp
);
1931 retVal
= hasType
= true;
1933 if (creatorString
&& CFGetTypeID(creatorString
) == CFStringGetTypeID() && CFStringGetLength(creatorString
) == 4 && 4 == CFStringGetBytes(creatorString
, CFRangeMake(0, 4), kCFStringEncodingMacRoman
, 0, false, (UInt8
*)&tmp
, 4, &usedBufLen
) && 4 == usedBufLen
) {
1934 if (packageCreator
!= NULL
) {
1935 *packageCreator
= CFSwapInt32BigToHost(tmp
);
1937 retVal
= hasCreator
= true;
1939 if (releaseInfoDict
) CFRelease(infoDict
);
1942 if (!hasType
|| !hasCreator
) {
1943 // If this looks like a bundle then manufacture the type and creator.
1944 if (retVal
|| _CFBundleURLLooksLikeBundle(url
)) {
1945 if (packageCreator
!= NULL
&& !hasCreator
) {
1946 *packageCreator
= 0x3f3f3f3f; // '????'
1948 if (packageType
!= NULL
&& !hasType
) {
1950 UniChar buff
[CFMaxPathSize
];
1951 CFIndex strLen
, startOfExtension
;
1952 CFURLRef absoluteURL
;
1954 // Detect "app", "debug", "profile", or "framework" extensions
1955 absoluteURL
= CFURLCopyAbsoluteURL(url
);
1956 urlStr
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1957 CFRelease(absoluteURL
);
1958 strLen
= CFStringGetLength(urlStr
);
1959 if (strLen
> CFMaxPathSize
) strLen
= CFMaxPathSize
;
1960 CFStringGetCharacters(urlStr
, CFRangeMake(0, strLen
), buff
);
1962 startOfExtension
= _CFStartOfPathExtension(buff
, strLen
);
1963 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
)'/'))) {
1965 *packageType
= 0x4150504c; // 'APPL'
1966 } 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
)'/'))) {
1967 // This is an app (debug version)
1968 *packageType
= 0x4150504c; // 'APPL'
1969 } 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
)'/'))) {
1970 // This is an app (profile version)
1971 *packageType
= 0x4150504c; // 'APPL'
1972 } 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
)'/'))) {
1973 // This is a service
1974 *packageType
= 0x4150504c; // 'APPL'
1975 } 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
)'/'))) {
1976 // This is a framework
1977 *packageType
= 0x464d574b; // 'FMWK'
1979 // Default to BNDL for generic bundle
1980 *packageType
= 0x424e444c; // 'BNDL'
1989 CF_EXPORT Boolean
_CFBundleGetPackageInfoInDirectory(CFAllocatorRef alloc
, CFURLRef url
, UInt32
*packageType
, UInt32
*packageCreator
) {return _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(alloc
, url
, NULL
, packageType
, packageCreator
);}
1991 CF_EXPORT
void CFBundleGetPackageInfo(CFBundleRef bundle
, UInt32
*packageType
, UInt32
*packageCreator
) {
1992 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
);
1993 if (!_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFGetAllocator(bundle
), bundleURL
, CFBundleGetInfoDictionary(bundle
), packageType
, packageCreator
)) {
1994 if (packageType
!= NULL
) {
1995 *packageType
= 0x424e444c; // 'BNDL'
1997 if (packageCreator
!= NULL
) {
1998 *packageCreator
= 0x3f3f3f3f; // '????'
2001 if (bundleURL
) CFRelease(bundleURL
);
2004 CF_EXPORT Boolean
CFBundleGetPackageInfoInDirectory(CFURLRef url
, UInt32
*packageType
, UInt32
*packageCreator
) {return _CFBundleGetPackageInfoInDirectory(NULL
, url
, packageType
, packageCreator
);}
2006 __private_extern__ CFStringRef
_CFBundleGetPlatformExecutablesSubdirectoryName(void) {
2007 #if defined(__MACOS8__)
2008 return CFSTR("MacOSClassic");
2009 #elif defined(__WIN32__)
2010 return CFSTR("Windows");
2011 #elif defined(__MACH__)
2012 return CFSTR("MacOS");
2013 #elif defined(__hpux__)
2014 return CFSTR("HPUX");
2015 #elif defined(__svr4__)
2016 return CFSTR("Solaris");
2017 #elif defined(__LINUX__)
2018 return CFSTR("Linux");
2019 #elif defined(__FREEBSD__)
2020 return CFSTR("FreeBSD");
2022 #warning CFBundle: Unknown architecture
2023 return CFSTR("Other");
2027 __private_extern__ CFStringRef
_CFBundleGetAlternatePlatformExecutablesSubdirectoryName(void) {
2028 #if defined(__MACOS8__)
2029 return CFSTR("Mac OS 8");
2030 #elif defined(__WIN32__)
2031 return CFSTR("WinNT");
2032 #elif defined(__MACH__)
2033 return CFSTR("Mac OS X");
2034 #elif defined(__hpux__)
2035 return CFSTR("HP-UX");
2036 #elif defined(__svr4__)
2037 return CFSTR("Solaris");
2038 #elif defined(__LINUX__)
2039 return CFSTR("Linux");
2040 #elif defined(__FREEBSD__)
2041 return CFSTR("FreeBSD");
2043 #warning CFBundle: Unknown architecture
2044 return CFSTR("Other");
2048 __private_extern__ CFStringRef
_CFBundleGetOtherPlatformExecutablesSubdirectoryName(void) {
2049 #if defined(__MACOS8__)
2050 return CFSTR("MacOS");
2051 #elif defined(__WIN32__)
2052 return CFSTR("Other");
2053 #elif defined(__MACH__)
2054 return CFSTR("MacOSClassic");
2055 #elif defined(__hpux__)
2056 return CFSTR("Other");
2057 #elif defined(__svr4__)
2058 return CFSTR("Other");
2059 #elif defined(__LINUX__)
2060 return CFSTR("Other");
2061 #elif defined(__FREEBSD__)
2062 return CFSTR("Other");
2064 #warning CFBundle: Unknown architecture
2065 return CFSTR("Other");
2069 __private_extern__ CFStringRef
_CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(void) {
2070 #if defined(__MACOS8__)
2071 return CFSTR("Mac OS X");
2072 #elif defined(__WIN32__)
2073 return CFSTR("Other");
2074 #elif defined(__MACH__)
2075 return CFSTR("Mac OS 8");
2076 #elif defined(__hpux__)
2077 return CFSTR("Other");
2078 #elif defined(__svr4__)
2079 return CFSTR("Other");
2080 #elif defined(__LINUX__)
2081 return CFSTR("Other");
2082 #elif defined(__FREEBSD__)
2083 return CFSTR("Other");
2085 #warning CFBundle: Unknown architecture
2086 return CFSTR("Other");
2090 __private_extern__ CFArrayRef
_CFBundleCopyBundleRegionsArray(CFBundleRef bundle
) {return CFBundleCopyBundleLocalizations(bundle
);}
2092 CF_EXPORT CFArrayRef
CFBundleCopyBundleLocalizations(CFBundleRef bundle
) {
2093 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
2094 CFURLRef resourcesURL
= CFBundleCopyResourcesDirectoryURL(bundle
);
2095 #if USE_GETDIRENTRIES
2096 CFURLRef absoluteURL
;
2097 CFStringRef directoryPath
;
2098 CFArrayRef contents
;
2099 CFRange contentsRange
;
2102 CFArrayRef urls
= ((_CFBundleLayoutVersion(bundle
) != 4) ? _CFContentsOfDirectory(CFGetAllocator(bundle
), NULL
, NULL
, resourcesURL
, _CFBundleLprojExtension
) : NULL
);
2104 CFArrayRef predefinedLocalizations
= NULL
;
2105 CFMutableArrayRef result
= NULL
;
2108 predefinedLocalizations
= CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
2109 if (predefinedLocalizations
!= NULL
&& CFGetTypeID(predefinedLocalizations
) != CFArrayGetTypeID()) {
2110 predefinedLocalizations
= NULL
;
2111 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleLocalizationsKey
);
2113 if (predefinedLocalizations
!= NULL
) {
2114 CFIndex i
, c
= CFArrayGetCount(predefinedLocalizations
);
2115 if (c
> 0 && !result
) result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2116 for (i
= 0; i
< c
; i
++) CFArrayAppendValue(result
, CFArrayGetValueAtIndex(predefinedLocalizations
, i
));
2120 #if USE_GETDIRENTRIES
2122 absoluteURL
= CFURLCopyAbsoluteURL(resourcesURL
);
2123 directoryPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
2124 contents
= _CFBundleCopyDirectoryContentsAtPath(directoryPath
, _CFBundleAllContents
);
2125 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
2126 for (idx
= 0; idx
< contentsRange
.length
; idx
++) {
2127 CFStringRef name
= CFArrayGetValueAtIndex(contents
, idx
);
2128 if (CFStringHasSuffix(name
, _CFBundleLprojExtensionWithDot
)) {
2129 CFStringRef localization
= CFStringCreateWithSubstring(NULL
, name
, CFRangeMake(0, CFStringGetLength(name
) - 6));
2130 if (!result
) result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2131 CFArrayAppendValue(result
, localization
);
2132 CFRelease(localization
);
2135 CFRelease(contents
);
2136 CFRelease(directoryPath
);
2137 CFRelease(absoluteURL
);
2141 CFIndex i
, c
= CFArrayGetCount(urls
);
2142 CFURLRef curURL
, curAbsoluteURL
;
2143 CFStringRef curStr
, regionStr
;
2144 UniChar buff
[CFMaxPathSize
];
2145 CFIndex strLen
, startOfLastPathComponent
, regionLen
;
2147 if (c
> 0 && !result
) result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2148 for (i
= 0; i
< c
; i
++) {
2149 curURL
= CFArrayGetValueAtIndex(urls
, i
);
2150 curAbsoluteURL
= CFURLCopyAbsoluteURL(curURL
);
2151 curStr
= CFURLCopyFileSystemPath(curAbsoluteURL
, PLATFORM_PATH_STYLE
);
2152 CFRelease(curAbsoluteURL
);
2153 strLen
= CFStringGetLength(curStr
);
2154 if (strLen
> CFMaxPathSize
) strLen
= CFMaxPathSize
;
2155 CFStringGetCharacters(curStr
, CFRangeMake(0, strLen
), buff
);
2157 startOfLastPathComponent
= _CFStartOfLastPathComponent(buff
, strLen
);
2158 regionLen
= _CFLengthAfterDeletingPathExtension(&(buff
[startOfLastPathComponent
]), strLen
- startOfLastPathComponent
);
2159 regionStr
= CFStringCreateWithCharacters(CFGetAllocator(bundle
), &(buff
[startOfLastPathComponent
]), regionLen
);
2160 CFArrayAppendValue(result
, regionStr
);
2161 CFRelease(regionStr
);
2169 CFStringRef developmentLocalization
= CFBundleGetDevelopmentRegion(bundle
);
2170 if (developmentLocalization
) {
2171 result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
2172 CFArrayAppendValue(result
, developmentLocalization
);
2175 if (resourcesURL
) CFRelease(resourcesURL
);
2181 CF_EXPORT CFDictionaryRef
CFBundleCopyInfoDictionaryForURL(CFURLRef url
) {
2182 CFDictionaryRef result
= NULL
;
2184 if (_CFIsResourceAtURL(url
, &isDir
)) {
2186 result
= _CFBundleCopyInfoDictionaryInDirectory(NULL
, url
, NULL
);
2188 result
= _CFBundleCopyInfoDictionaryInExecutable(url
);
2194 CFArrayRef
CFBundleCopyLocalizationsForURL(CFURLRef url
) {
2195 CFArrayRef result
= NULL
;
2196 CFBundleRef bundle
= CFBundleCreate(NULL
, url
);
2197 CFStringRef devLang
= NULL
;
2199 result
= CFBundleCopyBundleLocalizations(bundle
);
2202 CFDictionaryRef infoDict
= _CFBundleCopyInfoDictionaryInExecutable(url
);
2204 CFArrayRef predefinedLocalizations
= CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
2205 if (predefinedLocalizations
!= NULL
&& CFGetTypeID(predefinedLocalizations
) == CFArrayGetTypeID()) {
2206 result
= CFRetain(predefinedLocalizations
);
2209 devLang
= CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
2210 if (devLang
!= NULL
&& (CFGetTypeID(devLang
) == CFStringGetTypeID() && CFStringGetLength(devLang
) > 0)) {
2211 result
= CFArrayCreate(NULL
, (const void **)&devLang
, 1, &kCFTypeArrayCallBacks
);
2214 CFRelease(infoDict
);