2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* CFBundle_Resources.c
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Doug Davidson
30 #if defined(__MACOS8__) || defined(__WIN32__)
31 #define USE_GETDIRENTRIES 0
33 #define USE_GETDIRENTRIES 1
35 #define GETDIRENTRIES_CACHE_CAPACITY 100
37 #include "CFBundle_Internal.h"
38 #include <CoreFoundation/CFURLAccess.h>
39 #include <CoreFoundation/CFPropertyList.h>
40 #include <CoreFoundation/CFByteOrder.h>
41 #include <CoreFoundation/CFNumber.h>
43 #include "CFInternal.h"
46 #if defined(__MACOS8__)
51 #include <Resources.h>
52 #include <CodeFragments.h>
56 /* Unixy & Windows Headers */
68 // All new-style bundles will have these extensions.
69 CF_INLINE CFStringRef
_CFGetPlatformName(void) {
70 // MF:!!! This used to be based on NSInterfaceStyle, not hard-wired by compiler.
71 #if defined(__WIN32__)
72 return _CFBundleWindowsPlatformName
;
73 #elif defined(__MACOS8__)
74 return _CFBundleMacOS8PlatformName
;
75 #elif defined (__MACH__)
76 return _CFBundleMacOSXPlatformName
;
77 #elif defined(__svr4__)
78 return _CFBundleSolarisPlatformName
;
79 #elif defined(__hpux__)
80 return _CFBundleHPUXPlatformName
;
81 #elif defined(__LINUX__)
82 return _CFBundleLinuxPlatformName
;
83 #elif defined(__FREEBSD__)
84 return _CFBundleFreeBSDPlatformName
;
90 CF_INLINE CFStringRef
_CFGetAlternatePlatformName(void) {
91 #if defined (__MACH__)
92 return _CFBundleAlternateMacOSXPlatformName
;
93 #elif defined(__MACOS8__)
94 return _CFBundleAlternateMacOS8PlatformName
;
100 static CFSpinLock_t CFBundleResourceGlobalDataLock
= 0;
101 static UniChar
*_AppSupportUniChars1
= NULL
;
102 static CFIndex _AppSupportLen1
= 0;
103 static UniChar
*_AppSupportUniChars2
= NULL
;
104 static CFIndex _AppSupportLen2
= 0;
105 static UniChar
*_ResourcesUniChars
= NULL
;
106 static CFIndex _ResourcesLen
= 0;
107 static UniChar
*_PlatformUniChars
= NULL
;
108 static CFIndex _PlatformLen
= 0;
109 static UniChar
*_AlternatePlatformUniChars
= NULL
;
110 static CFIndex _AlternatePlatformLen
= 0;
111 static UniChar
*_LprojUniChars
= NULL
;
112 static CFIndex _LprojLen
= 0;
113 static UniChar
*_GlobalResourcesUniChars
= NULL
;
114 static CFIndex _GlobalResourcesLen
= 0;
115 static UniChar
*_InfoExtensionUniChars
= NULL
;
116 static CFIndex _InfoExtensionLen
= 0;
118 static void _CFBundleInitStaticUniCharBuffers(void) {
119 CFStringRef appSupportStr1
= _CFBundleSupportFilesDirectoryName1
;
120 CFStringRef appSupportStr2
= _CFBundleSupportFilesDirectoryName2
;
121 CFStringRef resourcesStr
= _CFBundleResourcesDirectoryName
;
122 CFStringRef platformStr
= _CFGetPlatformName();
123 CFStringRef alternatePlatformStr
= _CFGetAlternatePlatformName();
124 CFStringRef lprojStr
= _CFBundleLprojExtension
;
125 CFStringRef globalResourcesStr
= _CFBundleNonLocalizedResourcesDirectoryName
;
126 CFStringRef infoExtensionStr
= _CFBundleInfoExtension
;
128 CFAllocatorRef alloc
= __CFGetDefaultAllocator();
130 _AppSupportLen1
= CFStringGetLength(appSupportStr1
);
131 _AppSupportLen2
= CFStringGetLength(appSupportStr2
);
132 _ResourcesLen
= CFStringGetLength(resourcesStr
);
133 _PlatformLen
= CFStringGetLength(platformStr
);
134 _AlternatePlatformLen
= CFStringGetLength(alternatePlatformStr
);
135 _LprojLen
= CFStringGetLength(lprojStr
);
136 _GlobalResourcesLen
= CFStringGetLength(globalResourcesStr
);
137 _InfoExtensionLen
= CFStringGetLength(infoExtensionStr
);
139 _AppSupportUniChars1
= CFAllocatorAllocate(alloc
, sizeof(UniChar
) * (_AppSupportLen1
+ _AppSupportLen2
+ _ResourcesLen
+ _PlatformLen
+ _AlternatePlatformLen
+ _LprojLen
+ _GlobalResourcesLen
+ _InfoExtensionLen
), 0);
140 _AppSupportUniChars2
= _AppSupportUniChars1
+ _AppSupportLen1
;
141 _ResourcesUniChars
= _AppSupportUniChars2
+ _AppSupportLen2
;
142 _PlatformUniChars
= _ResourcesUniChars
+ _ResourcesLen
;
143 _AlternatePlatformUniChars
= _PlatformUniChars
+ _PlatformLen
;
144 _LprojUniChars
= _AlternatePlatformUniChars
+ _AlternatePlatformLen
;
145 _GlobalResourcesUniChars
= _LprojUniChars
+ _LprojLen
;
146 _InfoExtensionUniChars
= _GlobalResourcesUniChars
+ _GlobalResourcesLen
;
148 if (_AppSupportLen1
> 0) {
149 CFStringGetCharacters(appSupportStr1
, CFRangeMake(0, _AppSupportLen1
), _AppSupportUniChars1
);
151 if (_AppSupportLen2
> 0) {
152 CFStringGetCharacters(appSupportStr2
, CFRangeMake(0, _AppSupportLen2
), _AppSupportUniChars2
);
154 if (_ResourcesLen
> 0) {
155 CFStringGetCharacters(resourcesStr
, CFRangeMake(0, _ResourcesLen
), _ResourcesUniChars
);
157 if (_PlatformLen
> 0) {
158 CFStringGetCharacters(platformStr
, CFRangeMake(0, _PlatformLen
), _PlatformUniChars
);
160 if (_AlternatePlatformLen
> 0) {
161 CFStringGetCharacters(alternatePlatformStr
, CFRangeMake(0, _AlternatePlatformLen
), _AlternatePlatformUniChars
);
164 CFStringGetCharacters(lprojStr
, CFRangeMake(0, _LprojLen
), _LprojUniChars
);
166 if (_GlobalResourcesLen
> 0) {
167 CFStringGetCharacters(globalResourcesStr
, CFRangeMake(0, _GlobalResourcesLen
), _GlobalResourcesUniChars
);
169 if (_InfoExtensionLen
> 0) {
170 CFStringGetCharacters(infoExtensionStr
, CFRangeMake(0, _InfoExtensionLen
), _InfoExtensionUniChars
);
174 CF_INLINE
void _CFEnsureStaticBuffersInited(void) {
175 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
176 if (_AppSupportUniChars1
== NULL
) {
177 _CFBundleInitStaticUniCharBuffers();
179 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
182 #if USE_GETDIRENTRIES
184 static CFMutableDictionaryRef contentsCache
= NULL
;
185 static CFMutableDictionaryRef directoryContentsCache
= NULL
;
187 static CFArrayRef
_CFBundleCopyDirectoryContentsAtPath(CFStringRef path
, Boolean directoriesOnly
) {
188 CFArrayRef result
= NULL
;
190 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
191 if (directoriesOnly
) {
192 if (directoryContentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(directoryContentsCache
, path
);
194 if (contentsCache
) result
= (CFMutableArrayRef
)CFDictionaryGetValue(contentsCache
, path
);
196 if (result
) CFRetain(result
);
197 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
200 char cpathBuff
[CFMaxPathSize
], dirge
[8192];
201 CFIndex cpathLen
= 0;
202 int fd
= -1, numread
;
204 CFMutableArrayRef contents
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
), directoryContents
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
207 if (_CFStringGetFileSystemRepresentation(path
, cpathBuff
, CFMaxPathSize
)) {
208 cpathLen
= strlen(cpathBuff
);
209 fd
= open(cpathBuff
, O_RDONLY
, 0777);
212 while ((numread
= getdirentries(fd
, dirge
, sizeof(dirge
), &basep
)) > 0) {
214 for (dent
= (struct dirent
*)dirge
; dent
< (struct dirent
*)(dirge
+ numread
); dent
= (struct dirent
*)((char *)dent
+ dent
->d_reclen
)) {
215 CFIndex nameLen
= strlen(dent
->d_name
);
216 if (0 == dent
->d_fileno
|| (dent
->d_name
[0] == '.' && (nameLen
== 1 || (nameLen
== 2 && dent
->d_name
[1] == '.')))) continue;
217 name
= CFStringCreateWithCString(NULL
, dent
->d_name
, CFStringFileSystemEncoding());
219 CFArrayAppendValue(contents
, name
);
220 if (dent
->d_type
== DT_DIR
) {
221 CFArrayAppendValue(directoryContents
, name
);
222 } else if (dent
->d_type
== DT_UNKNOWN
) {
224 cpathBuff
[cpathLen
] = '/';
225 strncpy(cpathBuff
+ cpathLen
+ 1, dent
->d_name
, nameLen
);
226 cpathBuff
[cpathLen
+ nameLen
+ 1] = '\0';
227 if (stat(cpathBuff
, &statBuf
) == 0 && (statBuf
.st_mode
& S_IFMT
) == S_IFDIR
) CFArrayAppendValue(directoryContents
, name
);
228 cpathBuff
[cpathLen
] = '\0';
237 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
238 if (!contentsCache
) contentsCache
= CFDictionaryCreateMutable(NULL
, GETDIRENTRIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
239 if (GETDIRENTRIES_CACHE_CAPACITY
== CFDictionaryGetCount(contentsCache
)) CFDictionaryRemoveAllValues(contentsCache
);
240 CFDictionaryAddValue(contentsCache
, path
, contents
);
242 if (!directoryContentsCache
) directoryContentsCache
= CFDictionaryCreateMutable(NULL
, GETDIRENTRIES_CACHE_CAPACITY
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
243 if (GETDIRENTRIES_CACHE_CAPACITY
== CFDictionaryGetCount(directoryContentsCache
)) CFDictionaryRemoveAllValues(directoryContentsCache
);
244 CFDictionaryAddValue(directoryContentsCache
, path
, directoryContents
);
246 result
= CFRetain(directoriesOnly
? directoryContents
: contents
);
248 CFRelease(directoryContents
);
249 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
255 static void _CFBundleFlushContentsCaches(void) {
256 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
257 if (contentsCache
) CFDictionaryRemoveAllValues(contentsCache
);
258 if (directoryContentsCache
) CFDictionaryRemoveAllValues(directoryContentsCache
);
259 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
262 #endif /* USE_GETDIRENTRIES */
264 CF_EXPORT
void _CFBundleFlushCaches(void) {
265 #if USE_GETDIRENTRIES
266 _CFBundleFlushContentsCaches();
267 #endif /* USE_GETDIRENTRIES */
270 __private_extern__ Boolean
_CFIsResourceAtURL(CFURLRef url
, Boolean
*isDir
) {
273 if (_CFGetFileProperties(NULL
, url
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) {
275 *isDir
= ((exists
&& ((mode
& S_IFMT
) == S_IFDIR
)) ? true : false);
277 #if defined(__MACOS8__)
280 return (exists
&& (mode
& 0444));
281 #endif /* __MACOS8__ */
287 __private_extern__ Boolean
_CFIsResourceAtPath(CFStringRef path
, Boolean
*isDir
) {
288 Boolean result
= false;
289 CFURLRef url
= CFURLCreateWithFileSystemPath(CFGetAllocator(path
), path
, PLATFORM_PATH_STYLE
, false);
291 result
= _CFIsResourceAtURL(url
, isDir
);
297 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
) {
298 // pathUniChars is the full path to the directory we are searching.
299 // nameUniChars is what we are looking for.
300 // typeUniChars is the type we are looking for.
301 // platformUniChars is the platform name.
302 // cheapStr is available for our use for whatever we want.
303 // URLs for found resources get added to result.
304 CFIndex savedPathLen
;
305 Boolean platformGenericFound
= false, platformSpecificFound
= false;
306 Boolean platformGenericIsDir
= false, platformSpecificIsDir
= false;
307 CFStringRef platformGenericStr
= NULL
;
309 #if USE_GETDIRENTRIES
310 CFIndex dirPathLen
= pathLen
;
311 CFArrayRef contents
, directoryContents
;
312 CFRange contentsRange
, directoryContentsRange
;
314 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, dirPathLen
, dirPathLen
);
315 CFStringReplaceAll(cheapStr
, tmpString
);
316 //fprintf(stderr, "looking in ");CFShow(cheapStr);
317 contents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, false);
318 contentsRange
= CFRangeMake(0, CFArrayGetCount(contents
));
319 directoryContents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, true);
320 directoryContentsRange
= CFRangeMake(0, CFArrayGetCount(directoryContents
));
324 _CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, nameUniChars
, nameLen
);
326 // Save length with just name appended.
327 savedPathLen
= pathLen
;
329 // Check platform generic
331 _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
333 #if USE_GETDIRENTRIES
334 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ dirPathLen
+ 1, pathLen
- dirPathLen
- 1, pathLen
- dirPathLen
- 1);
335 CFStringReplaceAll(cheapStr
, tmpString
);
336 platformGenericFound
= CFArrayContainsValue(contents
, contentsRange
, cheapStr
);
337 platformGenericIsDir
= CFArrayContainsValue(directoryContents
, directoryContentsRange
, cheapStr
);
338 //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformGenericFound) fprintf(stderr, "found it\n"); if (platformGenericIsDir) fprintf(stderr, "a directory\n");
339 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
340 CFStringReplaceAll(cheapStr
, tmpString
);
342 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
343 CFStringReplaceAll(cheapStr
, tmpString
);
344 platformGenericFound
= _CFIsResourceAtPath(cheapStr
, &platformGenericIsDir
);
347 // Check for platform specific.
348 if (platformGenericFound
) {
349 platformGenericStr
= CFStringCreateCopy(alloc
, cheapStr
);
350 if (!platformSpecificFound
&& (_PlatformLen
> 0)) {
351 pathLen
= savedPathLen
;
352 pathUniChars
[pathLen
++] = (UniChar
)'-';
353 memmove(pathUniChars
+ pathLen
, _PlatformUniChars
, _PlatformLen
* sizeof(UniChar
));
354 pathLen
+= _PlatformLen
;
356 _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, typeUniChars
, typeLen
);
358 #if USE_GETDIRENTRIES
359 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ dirPathLen
+ 1, pathLen
- dirPathLen
- 1, pathLen
- dirPathLen
- 1);
360 CFStringReplaceAll(cheapStr
, tmpString
);
361 platformSpecificFound
= CFArrayContainsValue(contents
, contentsRange
, cheapStr
);
362 platformSpecificIsDir
= CFArrayContainsValue(directoryContents
, directoryContentsRange
, cheapStr
);
363 //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformSpecificFound) fprintf(stderr, "found it\n"); if (platformSpecificIsDir) fprintf(stderr, "a directory\n");
364 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
365 CFStringReplaceAll(cheapStr
, tmpString
);
367 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
368 CFStringReplaceAll(cheapStr
, tmpString
);
369 platformSpecificFound
= _CFIsResourceAtPath(cheapStr
, &platformSpecificIsDir
);
373 if (platformSpecificFound
) {
374 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, platformSpecificIsDir
);
375 CFArrayAppendValue(result
, url
);
377 } else if (platformGenericFound
) {
378 CFURLRef url
= CFURLCreateWithFileSystemPath(alloc
, ((platformGenericStr
!= NULL
) ? platformGenericStr
: cheapStr
), PLATFORM_PATH_STYLE
, platformGenericIsDir
);
379 CFArrayAppendValue(result
, url
);
382 if (platformGenericStr
!= NULL
) {
383 CFRelease(platformGenericStr
);
385 #if USE_GETDIRENTRIES
387 CFRelease(directoryContents
);
391 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
) {
394 // If we have a resName, just call the search API. We may have to loop over the resTypes.
396 _CFSearchBundleDirectory(alloc
, result
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, NULL
, 0, cheapStr
, tmpString
, version
);
398 CFIndex i
, c
= CFArrayGetCount(resTypes
);
399 for (i
=0; i
<c
; i
++) {
400 CFStringRef curType
= (CFStringRef
)CFArrayGetValueAtIndex(resTypes
, i
);
401 CFIndex typeLen
= CFStringGetLength(curType
);
402 #if defined(__MACOS8__) || defined(__WIN32__)
403 UniChar
*typeChars
= CFAllocatorAllocate(alloc
, sizeof(UniChar
) * typeLen
, 0);
406 UniChar typeChars
[typeLen
];
407 #endif /* __MACOS8__ */
408 CFStringGetCharacters(curType
, CFRangeMake(0, typeLen
), typeChars
);
409 _CFSearchBundleDirectory(alloc
, result
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, typeChars
, typeLen
, cheapStr
, tmpString
, version
);
410 if (limit
<= CFArrayGetCount(result
)) {
413 #if defined(__MACOS8__) || defined(__WIN32__)
414 CFAllocatorDeallocate(alloc
, typeChars
);
416 #endif /* __MACOS8__ */
420 // If we have no resName, do it by hand. We may have to loop over the resTypes.
421 unsigned char cpathBuff
[CFMaxPathSize
];
423 CFMutableArrayRef children
;
425 CFStringSetExternalCharactersNoCopy(tmpString
, workingUniChars
, workingLen
, workingLen
);
426 if (!_CFStringGetFileSystemRepresentation(tmpString
, cpathBuff
, CFMaxPathSize
)) return;
427 cpathLen
= strlen(cpathBuff
);
430 children
= _CFContentsOfDirectory(alloc
, cpathBuff
, NULL
, NULL
, NULL
);
432 CFIndex childIndex
, childCount
= CFArrayGetCount(children
);
433 for (childIndex
= 0; childIndex
< childCount
; childIndex
++) {
434 CFArrayAppendValue(result
, CFArrayGetValueAtIndex(children
, childIndex
));
439 CFIndex i
, c
= CFArrayGetCount(resTypes
);
440 for (i
=0; i
<c
; i
++) {
441 CFStringRef curType
= (CFStringRef
)CFArrayGetValueAtIndex(resTypes
, i
);
443 children
= _CFContentsOfDirectory(alloc
, cpathBuff
, NULL
, NULL
, curType
);
445 CFIndex childIndex
, childCount
= CFArrayGetCount(children
);
446 for (childIndex
= 0; childIndex
< childCount
; childIndex
++) {
447 CFArrayAppendValue(result
, CFArrayGetValueAtIndex(children
, childIndex
));
451 if (limit
<= CFArrayGetCount(result
)) {
459 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
) {
460 CFIndex savedWorkingLen
= workingLen
;
462 // Look directly in the directory specified in workingUniChars. as if it is a Resources directory.
464 // Add the non-localized resource directory.
465 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _GlobalResourcesUniChars
, _GlobalResourcesLen
);
467 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
);
469 _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
471 // Strip the non-localized resource directory.
472 workingLen
= savedWorkingLen
;
474 if (CFArrayGetCount(result
) < limit
) {
476 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
);
478 _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
481 // Now search the local resources.
482 workingLen
= savedWorkingLen
;
483 if (CFArrayGetCount(result
) < limit
) {
485 CFIndex langCount
= (searchLanguages
? CFArrayGetCount(searchLanguages
) : 0);
486 CFStringRef curLangStr
;
488 // MF:??? OK to hard-wire this length?
489 UniChar curLangUniChars
[255];
490 CFIndex numResults
= CFArrayGetCount(result
);
492 for (langIndex
= 0; langIndex
< langCount
; langIndex
++) {
493 curLangStr
= CFArrayGetValueAtIndex(searchLanguages
, langIndex
);
494 curLangLen
= CFStringGetLength(curLangStr
);
495 CFStringGetCharacters(curLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
496 savedWorkingLen
= workingLen
;
497 if (!_CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
)) {
498 workingLen
= savedWorkingLen
;
501 if (!_CFAppendPathExtension(workingUniChars
, &workingLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
)) {
502 workingLen
= savedWorkingLen
;
506 if (!_CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, subDirUniChars
, subDirLen
)) {
507 workingLen
= savedWorkingLen
;
511 _CFFindBundleResourcesInRawDir(alloc
, workingUniChars
, workingLen
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
513 // Back off this lproj component
514 workingLen
= savedWorkingLen
;
515 if (CFArrayGetCount(result
) != numResults
) {
516 // We found resources in a language we already searched. Don't look any farther.
517 // We also don't need to check the limit, since if the count changed at all, we are bailing.
524 extern void _CFStrSetDesiredCapacity(CFMutableStringRef str
, CFIndex len
);
526 CFArrayRef
_CFFindBundleResources(CFBundleRef bundle
, CFURLRef bundleURL
, CFStringRef subDirName
, CFArrayRef searchLanguages
, CFStringRef resName
, CFArrayRef resTypes
, CFIndex limit
, uint8_t version
) {
527 CFAllocatorRef alloc
= ((bundle
!= NULL
) ? CFGetAllocator(bundle
) : CFRetain(__CFGetDefaultAllocator()));
528 CFMutableArrayRef result
;
529 UniChar
*workingUniChars
, *nameUniChars
, *subDirUniChars
;
530 CFIndex nameLen
= (resName
? CFStringGetLength(resName
) : 0);
531 CFIndex subDirLen
= (subDirName
? CFStringGetLength(subDirName
) : 0);
532 CFIndex workingLen
, savedWorkingLen
;
533 CFURLRef absoluteURL
;
534 CFStringRef bundlePath
;
535 CFMutableStringRef cheapStr
, tmpString
;
537 result
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
538 // Init the one-time-only unichar buffers.
539 _CFEnsureStaticBuffersInited();
541 // Build UniChar buffers for some of the string pieces we need.
542 // One malloc will do.
543 nameUniChars
= CFAllocatorAllocate(alloc
, sizeof(UniChar
) * (nameLen
+ subDirLen
+ CFMaxPathSize
), 0);
544 subDirUniChars
= nameUniChars
+ nameLen
;
545 workingUniChars
= subDirUniChars
+ subDirLen
;
548 CFStringGetCharacters(resName
, CFRangeMake(0, nameLen
), nameUniChars
);
551 CFStringGetCharacters(subDirName
, CFRangeMake(0, subDirLen
), subDirUniChars
);
553 // Build a UniChar buffer with the absolute path to the bundle's resources directory.
554 // If no URL was passed, we get it from the bundle.
555 bundleURL
= ((bundleURL
!= NULL
) ? CFRetain(bundleURL
) : CFBundleCopyBundleURL(bundle
));
556 absoluteURL
= CFURLCopyAbsoluteURL(bundleURL
);
557 bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
558 CFRelease(absoluteURL
);
559 if ((workingLen
= CFStringGetLength(bundlePath
)) > 0) {
560 CFStringGetCharacters(bundlePath
, CFRangeMake(0, workingLen
), workingUniChars
);
562 CFRelease(bundlePath
);
563 CFRelease(bundleURL
);
564 savedWorkingLen
= workingLen
;
566 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _AppSupportUniChars1
, _AppSupportLen1
);
567 } else if (2 == version
) {
568 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _AppSupportUniChars2
, _AppSupportLen2
);
570 if (0 == version
|| 1 == version
|| 2 == version
) {
571 _CFAppendPathComponent(workingUniChars
, &workingLen
, CFMaxPathSize
, _ResourcesUniChars
, _ResourcesLen
);
574 // both of these used for temp string operations, for slightly
575 // different purposes, where each type is appropriate
576 cheapStr
= CFStringCreateMutable(alloc
, 0);
577 _CFStrSetDesiredCapacity(cheapStr
, CFMaxPathSize
);
578 tmpString
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, kCFAllocatorNull
);
580 _CFFindBundleResourcesInResourcesDir(alloc
, workingUniChars
, workingLen
, subDirUniChars
, subDirLen
, searchLanguages
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
582 // drd: This unfortunate hack is still necessary because of installer packages
583 if (0 == version
&& CFArrayGetCount(result
) == 0) {
584 // Try looking directly in the bundle path
585 workingLen
= savedWorkingLen
;
586 _CFFindBundleResourcesInResourcesDir(alloc
, workingUniChars
, workingLen
, subDirUniChars
, subDirLen
, searchLanguages
, nameUniChars
, nameLen
, resTypes
, limit
, version
, cheapStr
, tmpString
, result
);
590 CFRelease(tmpString
);
591 CFAllocatorDeallocate(alloc
, nameUniChars
);
592 if (bundle
== NULL
) {
599 CF_EXPORT CFURLRef
CFBundleCopyResourceURL(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
) {
600 CFURLRef result
= NULL
;
601 CFArrayRef languages
= _CFBundleGetLanguageSearchList(bundle
);
602 CFMutableArrayRef types
= NULL
;
606 types
= CFArrayCreateMutable(CFGetAllocator(bundle
), 1, &kCFTypeArrayCallBacks
);
607 CFArrayAppendValue(types
, resourceType
);
610 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, resourceName
, types
, 1, _CFBundleLayoutVersion(bundle
));
617 if (CFArrayGetCount(array
) > 0) {
618 result
= CFRetain(CFArrayGetValueAtIndex(array
, 0));
625 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfType(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
) {
626 CFArrayRef languages
= _CFBundleGetLanguageSearchList(bundle
);
627 CFMutableArrayRef types
= NULL
;
631 types
= CFArrayCreateMutable(CFGetAllocator(bundle
), 1, &kCFTypeArrayCallBacks
);
632 CFArrayAppendValue(types
, resourceType
);
635 // MF:!!! Better "limit" than 1,000,000?
636 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, NULL
, types
, 1000000, _CFBundleLayoutVersion(bundle
));
645 CF_EXPORT CFURLRef
_CFBundleCopyResourceURLForLanguage(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef language
) {return CFBundleCopyResourceURLForLocalization(bundle
, resourceName
, resourceType
, subDirName
, language
);}
647 CF_EXPORT CFURLRef
CFBundleCopyResourceURLForLocalization(CFBundleRef bundle
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef localizationName
) {
648 CFURLRef result
= NULL
;
649 CFMutableArrayRef languages
= CFArrayCreateMutable(CFGetAllocator(bundle
), 1, &kCFTypeArrayCallBacks
);
650 CFMutableArrayRef types
= NULL
;
653 if (localizationName
) CFArrayAppendValue(languages
, localizationName
);
656 types
= CFArrayCreateMutable(CFGetAllocator(bundle
), 1, &kCFTypeArrayCallBacks
);
657 CFArrayAppendValue(types
, resourceType
);
660 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, resourceName
, types
, 1, _CFBundleLayoutVersion(bundle
));
667 if (CFArrayGetCount(array
) > 0) {
668 result
= CFRetain(CFArrayGetValueAtIndex(array
, 0));
673 CFRelease(languages
);
678 CF_EXPORT CFArrayRef
_CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef language
) {return CFBundleCopyResourceURLsOfTypeForLocalization(bundle
, resourceType
, subDirName
, language
);}
680 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle
, CFStringRef resourceType
, CFStringRef subDirName
, CFStringRef localizationName
) {
681 CFMutableArrayRef languages
= CFArrayCreateMutable(CFGetAllocator(bundle
), 1, &kCFTypeArrayCallBacks
);
682 CFMutableArrayRef types
= NULL
;
685 if (localizationName
) CFArrayAppendValue(languages
, localizationName
);
688 types
= CFArrayCreateMutable(CFGetAllocator(bundle
), 1, &kCFTypeArrayCallBacks
);
689 CFArrayAppendValue(types
, resourceType
);
692 // MF:!!! Better "limit" than 1,000,000?
693 array
= _CFFindBundleResources(bundle
, NULL
, subDirName
, languages
, NULL
, types
, 1000000, _CFBundleLayoutVersion(bundle
));
699 CFRelease(languages
);
704 CF_EXPORT CFStringRef
CFBundleCopyLocalizedString(CFBundleRef bundle
, CFStringRef key
, CFStringRef value
, CFStringRef tableName
) {
705 CFStringRef result
= NULL
;
706 CFDictionaryRef stringTable
= NULL
;
708 if (key
== NULL
) return (value
? CFRetain(value
) : CFRetain(CFSTR("")));
710 if ((tableName
== NULL
) || CFEqual(tableName
, CFSTR(""))) {
711 tableName
= _CFBundleDefaultStringTableName
;
713 if (__CFBundleGetResourceData(bundle
)->_stringTableCache
!= NULL
) {
714 // See if we have the table cached.
715 stringTable
= CFDictionaryGetValue(__CFBundleGetResourceData(bundle
)->_stringTableCache
, tableName
);
717 if (stringTable
== NULL
) {
718 // Go load the table.
719 CFURLRef tableURL
= CFBundleCopyResourceURL(bundle
, tableName
, _CFBundleStringTableType
, NULL
);
721 CFStringRef nameForSharing
= NULL
;
722 if (stringTable
== NULL
) {
723 CFDataRef tableData
= NULL
;
726 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle
), tableURL
, &tableData
, NULL
, NULL
, &errCode
)) {
727 stringTable
= CFPropertyListCreateFromXMLData(CFGetAllocator(bundle
), tableData
, kCFPropertyListImmutable
, &errStr
);
728 if (errStr
!= NULL
) {
732 CFRelease(tableData
);
735 if (nameForSharing
) CFRelease(nameForSharing
);
738 if (stringTable
== NULL
) {
739 stringTable
= CFDictionaryCreate(CFGetAllocator(bundle
), NULL
, NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
741 if (__CFBundleGetResourceData(bundle
)->_stringTableCache
== NULL
) {
742 __CFBundleGetResourceData(bundle
)->_stringTableCache
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
744 CFDictionarySetValue(__CFBundleGetResourceData(bundle
)->_stringTableCache
, tableName
, stringTable
);
745 CFRelease(stringTable
);
748 result
= CFDictionaryGetValue(stringTable
, key
);
749 if (result
== NULL
) {
751 result
= CFRetain(key
);
752 } else if (CFEqual(value
, CFSTR(""))) {
753 result
= CFRetain(key
);
755 result
= CFRetain(value
);
764 CF_EXPORT CFURLRef
CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL
, CFStringRef resourceName
, CFStringRef resourceType
, CFStringRef subDirName
) {
765 CFURLRef result
= NULL
;
766 char buff
[CFMaxPathSize
];
767 CFURLRef newURL
= NULL
;
769 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
771 newURL
= CFURLCreateFromFileSystemRepresentation(NULL
, buff
, strlen(buff
), true);
772 if (NULL
== newURL
) {
773 newURL
= CFRetain(bundleURL
);
775 if (_CFBundleCouldBeBundle(newURL
)) {
777 CFArrayRef languages
= _CFBundleCopyLanguageSearchListInDirectory(NULL
, newURL
, &version
);
778 CFMutableArrayRef types
= NULL
;
782 types
= CFArrayCreateMutable(NULL
, 1, &kCFTypeArrayCallBacks
);
783 CFArrayAppendValue(types
, resourceType
);
786 array
= _CFFindBundleResources(NULL
, newURL
, subDirName
, languages
, resourceName
, types
, 1, version
);
792 CFRelease(languages
);
795 if (CFArrayGetCount(array
) > 0) {
796 result
= CFRetain(CFArrayGetValueAtIndex(array
, 0));
801 if (newURL
) CFRelease(newURL
);
805 CF_EXPORT CFArrayRef
CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleURL
, CFStringRef resourceType
, CFStringRef subDirName
) {
806 CFArrayRef array
= NULL
;
807 char buff
[CFMaxPathSize
];
808 CFURLRef newURL
= NULL
;
810 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
812 newURL
= CFURLCreateFromFileSystemRepresentation(NULL
, buff
, strlen(buff
), true);
813 if (NULL
== newURL
) {
814 newURL
= CFRetain(bundleURL
);
816 if (_CFBundleCouldBeBundle(newURL
)) {
818 CFArrayRef languages
= _CFBundleCopyLanguageSearchListInDirectory(NULL
, newURL
, &version
);
819 CFMutableArrayRef types
= NULL
;
822 types
= CFArrayCreateMutable(NULL
, 1, &kCFTypeArrayCallBacks
);
823 CFArrayAppendValue(types
, resourceType
);
826 // MF:!!! Better "limit" than 1,000,000?
827 array
= _CFFindBundleResources(NULL
, newURL
, subDirName
, languages
, NULL
, types
, 1000000, version
);
833 CFRelease(languages
);
835 if (newURL
) CFRelease(newURL
);
839 // string, with groups of 6 characters being 1 element in the array of locale abbreviations
840 const char * __CFBundleLocaleAbbreviationsArray
=
841 "en_US\0" "fr_FR\0" "en_GB\0" "de_DE\0" "it_IT\0" "nl_NL\0" "nl_BE\0" "sv_SE\0"
842 "es_ES\0" "da_DK\0" "pt_PT\0" "fr_CA\0" "no_NO\0" "he_IL\0" "ja_JP\0" "en_AU\0"
843 "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"
844 "tr_TR\0" "hr_HR\0" "nl_NL\0" "nl_BE\0" "en_CA\0" "en_CA\0" "pt_PT\0" "no_NO\0"
845 "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"
846 "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"
847 "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"
848 "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"
849 "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"
850 "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"
851 "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"
852 "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"
853 "ur_IN\0" "vi_VN\0" "fr_BE\0" "uz_UZ\0" "\0\0\0\0\0\0" "\0\0\0\0\0\0" "af_ZA\0" "eo\0\0\0\0"
854 "mr_IN\0" "bo\0\0\0\0" "ne_NP\0" "kl\0\0\0";
856 #define NUM_LOCALE_ABBREVIATIONS 108
857 #define LOCALE_ABBREVIATION_LENGTH 6
859 static const char * const __CFBundleLanguageNamesArray
[] = {
860 "English", "French", "German", "Italian", "Dutch", "Swedish", "Spanish", "Danish",
861 "Portuguese", "Norwegian", "Hebrew", "Japanese", "Arabic", "Finnish", "Greek", "Icelandic",
862 "Maltese", "Turkish", "Croatian", "Chinese", "Urdu", "Hindi", "Thai", "Korean",
863 "Lithuanian", "Polish", "Hungarian", "Estonian", "Latvian", "Sami", "Faroese", "Farsi",
864 "Russian", "Chinese", "Dutch", "Irish", "Albanian", "Romanian", "Czech", "Slovak",
865 "Slovenian", "Yiddish", "Serbian", "Macedonian", "Bulgarian", "Ukrainian", "Byelorussian", "Uzbek",
866 "Kazakh", "Azerbaijani", "Azerbaijani", "Armenian", "Georgian", "Moldavian", "Kirghiz", "Tajiki",
867 "Turkmen", "Mongolian", "Mongolian", "Pashto", "Kurdish", "Kashmiri", "Sindhi", "Tibetan",
868 "Nepali", "Sanskrit", "Marathi", "Bengali", "Assamese", "Gujarati", "Punjabi", "Oriya",
869 "Malayalam", "Kannada", "Tamil", "Telugu", "Sinhalese", "Burmese", "Khmer", "Lao",
870 "Vietnamese", "Indonesian", "Tagalog", "Malay", "Malay", "Amharic", "Tigrinya", "Oromo",
871 "Somali", "Swahili", "Kinyarwanda", "Rundi", "Nyanja", "Malagasy", "Esperanto", "",
872 "", "", "", "", "", "", "", "",
873 "", "", "", "", "", "", "", "",
874 "", "", "", "", "", "", "", "",
875 "", "", "", "", "", "", "", "",
876 "Welsh", "Basque", "Catalan", "Latin", "Quechua", "Guarani", "Aymara", "Tatar",
877 "Uighur", "Dzongkha", "Javanese", "Sundanese", "Galician", "Afrikaans", "Breton", "Inuktitut",
878 "Scottish", "Manx", "Irish", "Tongan", "Greek", "Greenlandic", "Azerbaijani"
881 #define NUM_LANGUAGE_NAMES 151
882 #define LANGUAGE_NAME_LENGTH 13
884 // string, with groups of 3 characters being 1 element in the array of abbreviations
885 const char * __CFBundleLanguageAbbreviationsArray
=
886 "en\0" "fr\0" "de\0" "it\0" "nl\0" "sv\0" "es\0" "da\0"
887 "pt\0" "no\0" "he\0" "ja\0" "ar\0" "fi\0" "el\0" "is\0"
888 "mt\0" "tr\0" "hr\0" "zh\0" "ur\0" "hi\0" "th\0" "ko\0"
889 "lt\0" "pl\0" "hu\0" "et\0" "lv\0" "se\0" "fo\0" "fa\0"
890 "ru\0" "zh\0" "nl\0" "ga\0" "sq\0" "ro\0" "cs\0" "sk\0"
891 "sl\0" "yi\0" "sr\0" "mk\0" "bg\0" "uk\0" "be\0" "uz\0"
892 "kk\0" "az\0" "az\0" "hy\0" "ka\0" "mo\0" "ky\0" "tg\0"
893 "tk\0" "mn\0" "mn\0" "ps\0" "ku\0" "ks\0" "sd\0" "bo\0"
894 "ne\0" "sa\0" "mr\0" "bn\0" "as\0" "gu\0" "pa\0" "or\0"
895 "ml\0" "kn\0" "ta\0" "te\0" "si\0" "my\0" "km\0" "lo\0"
896 "vi\0" "id\0" "tl\0" "ms\0" "ms\0" "am\0" "ti\0" "om\0"
897 "so\0" "sw\0" "rw\0" "rn\0" "\0\0\0" "mg\0" "eo\0" "\0\0\0"
898 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
899 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
900 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
901 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
902 "cy\0" "eu\0" "ca\0" "la\0" "qu\0" "gn\0" "ay\0" "tt\0"
903 "ug\0" "dz\0" "jv\0" "su\0" "gl\0" "af\0" "br\0" "iu\0"
904 "gd\0" "gv\0" "ga\0" "to\0" "el\0" "kl\0" "az\0";
906 #define NUM_LANGUAGE_ABBREVIATIONS 151
907 #define LANGUAGE_ABBREVIATION_LENGTH 3
909 static const SInt32 __CFBundleScriptCodesArray
[] = {
910 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 0, 0,
911 0, 0, 0, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 0, 4,
912 7, 25, 0, 0, 0, 0, 29, 29, 0, 5, 7, 7, 7, 7, 7, 7,
913 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
914 9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
915 30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
916 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
917 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
918 0, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 0, 28,
922 static const CFStringEncoding __CFBundleStringEncodingsArray
[] = {
923 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 6, 37,
924 0, 35, 36, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 37, 0x8C,
925 7, 25, 0, 39, 0, 38, 29, 29, 36, 5, 7, 7, 7, 0x98, 7, 7,
926 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
927 9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
928 30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
929 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
930 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
931 39, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 39, 0xEC,
932 39, 39, 40, 0, 6, 0, 0
935 static SInt32
_CFBundleGetLanguageCodeForLocalization(CFStringRef localizationName
) {
936 SInt32 result
= -1, i
;
938 CFIndex length
= CFStringGetLength(localizationName
);
939 if ((length
>= LANGUAGE_ABBREVIATION_LENGTH
- 1) && (length
<= 255) && CFStringGetCString(localizationName
, buff
, 255, kCFStringEncodingASCII
)) {
941 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_NAMES
; i
++) {
942 if (0 == strcmp(buff
, __CFBundleLanguageNamesArray
[i
])) result
= i
;
944 if (0 == strcmp(buff
, "zh_CN")) result
= 33; // hack for mixed-up Chinese language codes
945 buff
[LANGUAGE_ABBREVIATION_LENGTH
- 1] = '\0';
946 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_ABBREVIATIONS
* LANGUAGE_ABBREVIATION_LENGTH
; i
+= LANGUAGE_ABBREVIATION_LENGTH
) {
947 if (buff
[0] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 0) && buff
[1] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 1)) result
= i
/ LANGUAGE_ABBREVIATION_LENGTH
;
953 static CFStringRef
_CFBundleCopyLanguageAbbreviationForLanguageCode(SInt32 languageCode
) {
954 CFStringRef result
= NULL
;
955 if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_ABBREVIATIONS
) {
956 const char *languageAbbreviation
= __CFBundleLanguageAbbreviationsArray
+ languageCode
* LANGUAGE_ABBREVIATION_LENGTH
;
957 if (languageAbbreviation
!= NULL
&& *languageAbbreviation
!= '\0') {
958 result
= CFStringCreateWithCStringNoCopy(NULL
, languageAbbreviation
, kCFStringEncodingASCII
, kCFAllocatorNull
);
964 static CFStringRef
_CFBundleCopyLanguageNameForLanguageCode(SInt32 languageCode
) {
965 CFStringRef result
= NULL
;
966 if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_NAMES
) {
967 const char *languageName
= __CFBundleLanguageNamesArray
[languageCode
];
968 if (languageName
!= NULL
&& *languageName
!= '\0') {
969 result
= CFStringCreateWithCStringNoCopy(NULL
, languageName
, kCFStringEncodingASCII
, kCFAllocatorNull
);
975 static CFStringRef
_CFBundleCopyLanguageAbbreviationForLocalization(CFStringRef localizationName
) {
976 CFStringRef result
= NULL
;
977 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
978 if (languageCode
>= 0) {
979 result
= _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode
);
981 CFIndex length
= CFStringGetLength(localizationName
);
982 if (length
== LANGUAGE_ABBREVIATION_LENGTH
- 1 || (length
> LANGUAGE_ABBREVIATION_LENGTH
- 1 && CFStringGetCharacterAtIndex(localizationName
, LANGUAGE_ABBREVIATION_LENGTH
- 1) == '_')) {
983 result
= CFStringCreateWithSubstring(NULL
, localizationName
, CFRangeMake(0, LANGUAGE_ABBREVIATION_LENGTH
- 1));
989 static CFStringRef
_CFBundleCopyLanguageNameForLocalization(CFStringRef localizationName
) {
990 CFStringRef result
= NULL
;
991 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
992 if (languageCode
>= 0) {
993 result
= _CFBundleCopyLanguageNameForLanguageCode(languageCode
);
995 result
= CFStringCreateCopy(NULL
, localizationName
);
1000 static SInt32
_CFBundleGetLanguageCodeForRegionCode(SInt32 regionCode
) {
1001 SInt32 result
= -1, i
;
1002 if (52 == regionCode
) { // hack for mixed-up Chinese language codes
1004 } else if (0 <= regionCode
&& regionCode
< NUM_LOCALE_ABBREVIATIONS
) {
1005 const char *localeAbbreviation
= __CFBundleLocaleAbbreviationsArray
+ regionCode
* LOCALE_ABBREVIATION_LENGTH
;
1006 if (localeAbbreviation
!= NULL
&& *localeAbbreviation
!= '\0') {
1007 for (i
= 0; -1 == result
&& i
< NUM_LANGUAGE_ABBREVIATIONS
* LANGUAGE_ABBREVIATION_LENGTH
; i
+= LANGUAGE_ABBREVIATION_LENGTH
) {
1008 if (localeAbbreviation
[0] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 0) && localeAbbreviation
[1] == *(__CFBundleLanguageAbbreviationsArray
+ i
+ 1)) result
= i
/ LANGUAGE_ABBREVIATION_LENGTH
;
1015 static SInt32
_CFBundleGetRegionCodeForLanguageCode(SInt32 languageCode
) {
1016 SInt32 result
= -1, i
;
1017 if (19 == languageCode
) { // hack for mixed-up Chinese language codes
1019 } else if (0 <= languageCode
&& languageCode
< NUM_LANGUAGE_ABBREVIATIONS
) {
1020 const char *languageAbbreviation
= __CFBundleLanguageAbbreviationsArray
+ languageCode
* LANGUAGE_ABBREVIATION_LENGTH
;
1021 if (languageAbbreviation
!= NULL
&& *languageAbbreviation
!= '\0') {
1022 for (i
= 0; -1 == result
&& i
< NUM_LOCALE_ABBREVIATIONS
* LOCALE_ABBREVIATION_LENGTH
; i
+= LOCALE_ABBREVIATION_LENGTH
) {
1023 if (*(__CFBundleLocaleAbbreviationsArray
+ i
+ 0) == languageAbbreviation
[0] && *(__CFBundleLocaleAbbreviationsArray
+ i
+ 1) == languageAbbreviation
[1]) result
= i
/ LOCALE_ABBREVIATION_LENGTH
;
1030 static SInt32
_CFBundleGetRegionCodeForLocalization(CFStringRef localizationName
) {
1031 SInt32 result
= -1, i
;
1032 char buff
[LOCALE_ABBREVIATION_LENGTH
];
1033 CFIndex length
= CFStringGetLength(localizationName
);
1034 if ((length
>= LANGUAGE_ABBREVIATION_LENGTH
- 1) && (length
<= LOCALE_ABBREVIATION_LENGTH
- 1) && CFStringGetCString(localizationName
, buff
, LOCALE_ABBREVIATION_LENGTH
, kCFStringEncodingASCII
)) {
1035 buff
[LOCALE_ABBREVIATION_LENGTH
- 1] = '\0';
1036 for (i
= 0; -1 == result
&& i
< NUM_LOCALE_ABBREVIATIONS
* LOCALE_ABBREVIATION_LENGTH
; i
+= LOCALE_ABBREVIATION_LENGTH
) {
1037 if (0 == strcmp(buff
, __CFBundleLocaleAbbreviationsArray
+ i
)) result
= i
/ LOCALE_ABBREVIATION_LENGTH
;
1041 SInt32 languageCode
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1042 result
= _CFBundleGetRegionCodeForLanguageCode(languageCode
);
1047 static CFStringRef
_CFBundleCopyLocaleAbbreviationForRegionCode(SInt32 regionCode
) {
1048 CFStringRef result
= NULL
;
1049 if (0 <= regionCode
&& regionCode
< NUM_LOCALE_ABBREVIATIONS
) {
1050 const char *localeAbbreviation
= __CFBundleLocaleAbbreviationsArray
+ regionCode
* LOCALE_ABBREVIATION_LENGTH
;
1051 if (localeAbbreviation
!= NULL
&& *localeAbbreviation
!= '\0') {
1052 result
= CFStringCreateWithCStringNoCopy(NULL
, localeAbbreviation
, kCFStringEncodingASCII
, kCFAllocatorNull
);
1058 Boolean
CFBundleGetLocalizationInfoForLocalization(CFStringRef localizationName
, SInt32
*languageCode
, SInt32
*regionCode
, SInt32
*scriptCode
, CFStringEncoding
*stringEncoding
) {
1059 SInt32 language
= -1, region
= -1, script
= 0;
1060 CFStringEncoding encoding
= kCFStringEncodingMacRoman
;
1061 if (localizationName
) {
1062 language
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1063 region
= _CFBundleGetRegionCodeForLocalization(localizationName
);
1065 _CFBundleGetLanguageAndRegionCodes(&language
, ®ion
);
1067 if ((language
< 0 || language
> (int)(sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
))) && region
!= -1) language
= _CFBundleGetLanguageCodeForRegionCode(region
);
1068 if (region
== -1 && language
!= -1) region
= _CFBundleGetRegionCodeForLanguageCode(language
);
1069 if (language
>= 0 && language
< (int)(sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
))) {
1070 script
= __CFBundleScriptCodesArray
[language
];
1072 if (language
>= 0 && language
< (int)(sizeof(__CFBundleStringEncodingsArray
)/sizeof(CFStringEncoding
))) {
1073 encoding
= __CFBundleStringEncodingsArray
[language
];
1075 if (languageCode
) *languageCode
= language
;
1076 if (regionCode
) *regionCode
= region
;
1077 if (scriptCode
) *scriptCode
= script
;
1078 if (stringEncoding
) *stringEncoding
= encoding
;
1079 return (language
!= -1 || region
!= -1);
1082 CFStringRef
CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode
, SInt32 regionCode
, SInt32 scriptCode
, CFStringEncoding stringEncoding
) {
1083 CFStringRef localizationName
= NULL
;
1084 if (!localizationName
) {
1085 localizationName
= _CFBundleCopyLocaleAbbreviationForRegionCode(regionCode
);
1087 if (!localizationName
) {
1088 localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode
);
1090 if (!localizationName
) {
1091 SInt32 language
= -1, scriptLanguage
= -1, encodingLanguage
= -1;
1093 for (i
= 0; language
== -1 && i
< (sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
)); i
++) {
1094 if (__CFBundleScriptCodesArray
[i
] == scriptCode
&& __CFBundleStringEncodingsArray
[i
] == stringEncoding
) language
= i
;
1096 for (i
= 0; scriptLanguage
== -1 && i
< (sizeof(__CFBundleScriptCodesArray
)/sizeof(SInt32
)); i
++) {
1097 if (__CFBundleScriptCodesArray
[i
] == scriptCode
) scriptLanguage
= i
;
1099 for (i
= 0; encodingLanguage
== -1 && i
< (sizeof(__CFBundleStringEncodingsArray
)/sizeof(CFStringEncoding
)); i
++) {
1100 if (__CFBundleStringEncodingsArray
[i
] == stringEncoding
) encodingLanguage
= i
;
1102 localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(language
);
1103 if (!localizationName
) localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(encodingLanguage
);
1104 if (!localizationName
) localizationName
= _CFBundleCopyLanguageAbbreviationForLanguageCode(scriptLanguage
);
1106 return localizationName
;
1109 extern void *__CFAppleLanguages
;
1111 __private_extern__ CFArrayRef
_CFBundleCopyUserLanguages(Boolean useBackstops
) {
1112 CFArrayRef result
= NULL
;
1113 static CFArrayRef userLanguages
= NULL
;
1114 static Boolean didit
= false;
1115 CFArrayRef preferencesArray
= NULL
;
1116 // This is a temporary solution, until the argument domain is moved down into CFPreferences
1117 __CFSpinLock(&CFBundleResourceGlobalDataLock
);
1119 if (__CFAppleLanguages
) {
1121 CFIndex length
= strlen(__CFAppleLanguages
);
1123 data
= CFDataCreateWithBytesNoCopy(NULL
, __CFAppleLanguages
, length
, kCFAllocatorNull
);
1125 __CFSetNastyFile(CFSTR("<plist command-line argument>"));
1126 userLanguages
= CFPropertyListCreateFromXMLData(NULL
, data
, kCFPropertyListImmutable
, NULL
);
1131 if (!userLanguages
&& preferencesArray
) userLanguages
= CFRetain(preferencesArray
);
1132 { // could perhaps read out of LANG environment variable
1133 CFStringRef english
= CFSTR("English");
1134 if (!userLanguages
) userLanguages
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&english
, 1, &kCFTypeArrayCallBacks
);
1136 if (userLanguages
&& CFGetTypeID(userLanguages
) != CFArrayGetTypeID()) {
1137 CFRelease(userLanguages
);
1138 userLanguages
= NULL
;
1142 __CFSpinUnlock(&CFBundleResourceGlobalDataLock
);
1143 if (preferencesArray
) CFRelease(preferencesArray
);
1144 if (!result
&& userLanguages
) result
= CFRetain(userLanguages
);
1148 CF_EXPORT
void _CFBundleGetLanguageAndRegionCodes(SInt32
*languageCode
, SInt32
*regionCode
) {
1149 // an attempt to answer the question, "what language are we running in?"
1150 // note that the question cannot be answered fully since it may depend on the bundle
1151 SInt32 language
= -1, region
= -1;
1152 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1153 CFArrayRef languages
= NULL
;
1154 CFStringRef localizationName
= NULL
;
1156 languages
= _CFBundleGetLanguageSearchList(mainBundle
);
1157 if (languages
) CFRetain(languages
);
1159 if (!languages
) languages
= _CFBundleCopyUserLanguages(false);
1160 if (languages
&& (CFArrayGetCount(languages
) > 0)) {
1161 localizationName
= CFArrayGetValueAtIndex(languages
, 0);
1162 language
= _CFBundleGetLanguageCodeForLocalization(localizationName
);
1163 region
= _CFBundleGetRegionCodeForLocalization(localizationName
);
1168 if (language
== -1 && region
!= -1) language
= _CFBundleGetLanguageCodeForRegionCode(region
);
1169 if (region
== -1 && language
!= -1) region
= _CFBundleGetRegionCodeForLanguageCode(language
);
1170 if (languages
) CFRelease(languages
);
1171 if (languageCode
) *languageCode
= language
;
1172 if (regionCode
) *regionCode
= region
;
1175 static Boolean
_CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc
, UniChar
*pathUniChars
, CFIndex pathLen
, uint8_t version
, CFDictionaryRef infoDict
, CFStringRef curLangStr
, CFMutableArrayRef lprojNames
) {
1176 CFIndex curLangLen
= CFStringGetLength(curLangStr
);
1177 UniChar curLangUniChars
[255];
1178 CFIndex savedPathLen
;
1179 CFStringRef languageAbbreviation
= _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr
), languageName
= _CFBundleCopyLanguageNameForLocalization(curLangStr
);
1180 Boolean foundOne
= false;
1181 CFArrayRef predefinedLocalizations
= NULL
;
1182 CFRange predefinedLocalizationsRange
;
1183 CFMutableStringRef cheapStr
, tmpString
;
1184 #if USE_GETDIRENTRIES
1185 CFArrayRef directoryContents
;
1186 CFRange directoryContentsRange
;
1188 Boolean isDir
= false;
1191 // both of these used for temp string operations, for slightly
1192 // different purposes, where each type is appropriate
1193 cheapStr
= CFStringCreateMutable(alloc
, 0);
1194 _CFStrSetDesiredCapacity(cheapStr
, CFMaxPathSize
);
1195 tmpString
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, kCFAllocatorNull
);
1197 #if USE_GETDIRENTRIES
1198 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1199 CFStringReplaceAll(cheapStr
, tmpString
);
1200 directoryContents
= _CFBundleCopyDirectoryContentsAtPath(cheapStr
, true);
1201 directoryContentsRange
= CFRangeMake(0, CFArrayGetCount(directoryContents
));
1205 predefinedLocalizations
= CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
1206 if (predefinedLocalizations
!= NULL
&& CFGetTypeID(predefinedLocalizations
) != CFArrayGetTypeID()) {
1207 predefinedLocalizations
= NULL
;
1208 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleLocalizationsKey
);
1211 predefinedLocalizationsRange
= CFRangeMake(0, predefinedLocalizations
? CFArrayGetCount(predefinedLocalizations
) : 0);
1213 CFStringGetCharacters(curLangStr
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1214 savedPathLen
= pathLen
;
1215 _CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
);
1216 _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
);
1217 #if USE_GETDIRENTRIES
1218 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1219 CFStringReplaceAll(cheapStr
, tmpString
);
1220 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, curLangStr
)) || (version
!= 4 && CFArrayContainsValue(directoryContents
, directoryContentsRange
, cheapStr
))) {
1222 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1223 CFStringReplaceAll(cheapStr
, tmpString
);
1224 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, curLangStr
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1227 CFArrayAppendValue(lprojNames
, curLangStr
);
1230 // Now, if the curLangStr was a region name, and we can map it to a language name, try that too.
1231 if (languageAbbreviation
&& !CFEqual(curLangStr
, languageAbbreviation
)) {
1232 curLangLen
= CFStringGetLength(languageAbbreviation
);
1233 CFStringGetCharacters(languageAbbreviation
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1234 pathLen
= savedPathLen
;
1235 _CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
);
1236 _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
);
1237 #if USE_GETDIRENTRIES
1238 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1239 CFStringReplaceAll(cheapStr
, tmpString
);
1240 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageAbbreviation
)) || (version
!= 4 && CFArrayContainsValue(directoryContents
, directoryContentsRange
, cheapStr
))) {
1242 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1243 CFStringReplaceAll(cheapStr
, tmpString
);
1244 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageAbbreviation
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1247 CFArrayAppendValue(lprojNames
, languageAbbreviation
);
1251 if (languageName
&& !CFEqual(curLangStr
, languageName
)) {
1252 curLangLen
= CFStringGetLength(languageName
);
1253 CFStringGetCharacters(languageName
, CFRangeMake(0, curLangLen
), curLangUniChars
);
1254 pathLen
= savedPathLen
;
1255 _CFAppendPathComponent(pathUniChars
, &pathLen
, CFMaxPathSize
, curLangUniChars
, curLangLen
);
1256 _CFAppendPathExtension(pathUniChars
, &pathLen
, CFMaxPathSize
, _LprojUniChars
, _LprojLen
);
1257 #if USE_GETDIRENTRIES
1258 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
+ savedPathLen
+ 1, pathLen
- savedPathLen
- 1, pathLen
- savedPathLen
- 1);
1259 CFStringReplaceAll(cheapStr
, tmpString
);
1260 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageName
)) || (version
!= 4 && CFArrayContainsValue(directoryContents
, directoryContentsRange
, cheapStr
))) {
1262 CFStringSetExternalCharactersNoCopy(tmpString
, pathUniChars
, pathLen
, pathLen
);
1263 CFStringReplaceAll(cheapStr
, tmpString
);
1264 if ((predefinedLocalizations
&& CFArrayContainsValue(predefinedLocalizations
, predefinedLocalizationsRange
, languageName
)) || (version
!= 4 && _CFIsResourceAtPath(cheapStr
, &isDir
) && isDir
)) {
1267 CFArrayAppendValue(lprojNames
, languageName
);
1272 CFRelease(cheapStr
);
1273 CFRelease(tmpString
);
1274 if (languageAbbreviation
) CFRelease(languageAbbreviation
);
1275 if (languageName
) CFRelease(languageName
);
1276 #if USE_GETDIRENTRIES
1277 CFRelease(directoryContents
);
1283 static Boolean
CFBundleAllowMixedLocalizations(void) {
1284 static Boolean allowMixed
= false, examinedMain
= false;
1285 if (!examinedMain
) {
1286 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1287 CFDictionaryRef infoDict
= mainBundle
? CFBundleGetInfoDictionary(mainBundle
) : NULL
;
1288 CFTypeRef allowMixedValue
= infoDict
? CFDictionaryGetValue(infoDict
, _kCFBundleAllowMixedLocalizationsKey
) : NULL
;
1289 if (allowMixedValue
) {
1290 CFTypeID typeID
= CFGetTypeID(allowMixedValue
);
1291 if (typeID
== CFBooleanGetTypeID()) {
1292 allowMixed
= CFBooleanGetValue((CFBooleanRef
)allowMixedValue
);
1293 } else if (typeID
== CFStringGetTypeID()) {
1294 allowMixed
= (CFStringCompare((CFStringRef
)allowMixedValue
, CFSTR("true"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
|| CFStringCompare((CFStringRef
)allowMixedValue
, CFSTR("YES"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1295 } else if (typeID
== CFNumberGetTypeID()) {
1297 if (CFNumberGetValue((CFNumberRef
)allowMixedValue
, kCFNumberSInt32Type
, &val
)) allowMixed
= (val
!= 0);
1300 examinedMain
= true;
1305 __private_extern__
void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
, CFDictionaryRef infoDict
, CFMutableArrayRef lprojNames
, CFStringRef devLang
) {
1306 // This function will add zero, one or two elements to the lprojNames array.
1307 // 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.
1308 // 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.
1309 CFURLRef resourcesURL
= _CFBundleCopyResourcesDirectoryURLInDirectory(alloc
, bundleURL
, version
);
1310 CFURLRef absoluteURL
;
1313 CFStringRef resourcesPath
;
1314 UniChar pathUniChars
[CFMaxPathSize
];
1316 CFStringRef curLangStr
;
1317 Boolean foundOne
= false;
1319 CFArrayRef userLanguages
;
1321 // Init the one-time-only unichar buffers.
1322 _CFEnsureStaticBuffersInited();
1324 // Get the path to the resources and extract into a buffer.
1325 absoluteURL
= CFURLCopyAbsoluteURL(resourcesURL
);
1326 resourcesPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1327 CFRelease(absoluteURL
);
1328 pathLen
= CFStringGetLength(resourcesPath
);
1329 CFStringGetCharacters(resourcesPath
, CFRangeMake(0, pathLen
), pathUniChars
);
1330 CFRelease(resourcesURL
);
1331 CFRelease(resourcesPath
);
1333 // First check the main bundle.
1334 if (!CFBundleAllowMixedLocalizations()) {
1335 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1337 CFURLRef mainBundleURL
= CFBundleCopyBundleURL(mainBundle
);
1338 if (!CFEqual(bundleURL
, mainBundleURL
)) {
1339 // If there is a main bundle, and it isn't this one, try to use the language it prefers.
1340 CFArrayRef mainBundleLangs
= _CFBundleGetLanguageSearchList(mainBundle
);
1341 if (mainBundleLangs
&& (CFArrayGetCount(mainBundleLangs
) > 0)) {
1342 curLangStr
= CFArrayGetValueAtIndex(mainBundleLangs
, 0);
1343 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
);
1346 CFRelease(mainBundleURL
);
1351 // If we didn't find the main bundle's preferred language, look at the users' prefs again and find the best one.
1352 userLanguages
= _CFBundleCopyUserLanguages(true);
1353 count
= (userLanguages
? CFArrayGetCount(userLanguages
) : 0);
1354 for (idx
= 0; !foundOne
&& idx
< count
; idx
++) {
1355 curLangStr
= CFArrayGetValueAtIndex(userLanguages
, idx
);
1356 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, curLangStr
, lprojNames
);
1358 // use development region and U.S. English as backstops
1359 if (!foundOne
&& devLang
!= NULL
) {
1360 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, devLang
, lprojNames
);
1363 foundOne
= _CFBundleTryOnePreferredLprojNameInDirectory(alloc
, pathUniChars
, pathLen
, version
, infoDict
, CFSTR("en_US"), lprojNames
);
1365 if (userLanguages
!= NULL
) {
1366 CFRelease(userLanguages
);
1371 static Boolean
_CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array
, CFStringRef curLangStr
, CFMutableArrayRef lprojNames
) {
1372 Boolean foundOne
= false;
1373 CFRange range
= CFRangeMake(0, CFArrayGetCount(array
));
1374 CFStringRef languageAbbreviation
= _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr
), languageName
= _CFBundleCopyLanguageNameForLocalization(curLangStr
);
1376 if (CFArrayContainsValue(array
, range
, curLangStr
)) {
1378 CFArrayAppendValue(lprojNames
, curLangStr
);
1381 if (languageAbbreviation
&& !CFEqual(curLangStr
, languageAbbreviation
)) {
1382 if (CFArrayContainsValue(array
, range
, languageAbbreviation
)) {
1384 CFArrayAppendValue(lprojNames
, languageAbbreviation
);
1388 if (languageName
&& !CFEqual(curLangStr
, languageName
)) {
1389 if (CFArrayContainsValue(array
, range
, languageName
)) {
1391 CFArrayAppendValue(lprojNames
, languageName
);
1396 if (languageAbbreviation
) CFRelease(languageAbbreviation
);
1397 if (languageName
) CFRelease(languageName
);
1402 static CFArrayRef
_CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray
, CFArrayRef prefArray
, Boolean considerMain
) {
1403 CFMutableArrayRef lprojNames
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1404 Boolean foundOne
= false, releasePrefArray
= false;
1407 if (considerMain
&& !CFBundleAllowMixedLocalizations()) {
1408 CFBundleRef mainBundle
= CFBundleGetMainBundle();
1410 // If there is a main bundle, try to use the language it prefers.
1411 CFArrayRef mainBundleLangs
= _CFBundleGetLanguageSearchList(mainBundle
);
1412 if (mainBundleLangs
&& (CFArrayGetCount(mainBundleLangs
) > 0)) {
1413 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, CFArrayGetValueAtIndex(mainBundleLangs
, 0), lprojNames
);
1419 prefArray
= _CFBundleCopyUserLanguages(true);
1420 if (prefArray
) releasePrefArray
= true;
1422 count
= (prefArray
? CFArrayGetCount(prefArray
) : 0);
1423 for (idx
= 0; !foundOne
&& idx
< count
; idx
++) {
1424 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, CFArrayGetValueAtIndex(prefArray
, idx
), lprojNames
);
1426 // use U.S. English as backstop
1428 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, CFSTR("en_US"), lprojNames
);
1430 // use random entry as backstop
1431 if (!foundOne
&& CFArrayGetCount(lprojNames
) > 0) {
1432 foundOne
= _CFBundleTryOnePreferredLprojNameInArray(locArray
, CFArrayGetValueAtIndex(locArray
, 0), lprojNames
);
1435 if (CFArrayGetCount(lprojNames
) == 0) {
1436 // Total backstop behavior to avoid having an empty array.
1437 CFArrayAppendValue(lprojNames
, CFSTR("en"));
1439 if (releasePrefArray
) {
1440 CFRelease(prefArray
);
1445 CF_EXPORT CFArrayRef
CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray
, CFArrayRef prefArray
) {return _CFBundleCopyLocalizationsForPreferences(locArray
, prefArray
, false);}
1447 CF_EXPORT CFArrayRef
CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locArray
) {return _CFBundleCopyLocalizationsForPreferences(locArray
, NULL
, true);}
1449 __private_extern__ CFArrayRef
_CFBundleCopyLanguageSearchListInDirectory(CFAllocatorRef alloc
, CFURLRef url
, uint8_t *version
) {
1450 CFMutableArrayRef langs
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
1451 uint8_t localVersion
= 0;
1452 CFDictionaryRef infoDict
= _CFBundleCopyInfoDictionaryInDirectory(alloc
, url
, &localVersion
);
1453 CFStringRef devLang
= NULL
;
1454 if (infoDict
!= NULL
) {
1455 devLang
= CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1457 if (devLang
!= NULL
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) devLang
= NULL
;
1459 _CFBundleAddPreferredLprojNamesInDirectory(alloc
, url
, localVersion
, infoDict
, langs
, devLang
);
1461 if (devLang
!= NULL
&& CFArrayGetFirstIndexOfValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), devLang
) < 0) {
1462 CFArrayAppendValue(langs
, devLang
);
1464 if (CFArrayGetCount(langs
) == 0) {
1465 // Total backstop behavior to avoid having an empty array.
1466 CFArrayAppendValue(langs
, CFSTR("en"));
1468 if (infoDict
!= NULL
) {
1469 CFRelease(infoDict
);
1472 *version
= localVersion
;
1477 CF_EXPORT Boolean
_CFBundleURLLooksLikeBundle(CFURLRef url
) {
1478 Boolean result
= false;
1479 CFBundleRef bundle
= _CFBundleCreateIfLooksLikeBundle(NULL
, url
);
1487 // Note that subDirName is expected to be the string for a URL
1488 CF_INLINE Boolean
_CFBundleURLHasSubDir(CFURLRef url
, CFStringRef subDirName
) {
1490 Boolean isDir
, result
= false;
1492 dirURL
= CFURLCreateWithString(NULL
, subDirName
, url
);
1493 if (dirURL
!= NULL
) {
1494 if (_CFIsResourceAtURL(dirURL
, &isDir
) && isDir
) {
1502 __private_extern__ Boolean
_CFBundleURLLooksLikeBundleVersion(CFURLRef url
, uint8_t *version
) {
1503 Boolean result
= false;
1504 uint8_t localVersion
= 0;
1506 // check for existence of "Resources" or "Contents" or "Support Files"
1507 // but check for the most likely one first
1508 // version 0: old-style "Resources" bundles
1509 // version 1: obsolete "Support Files" bundles
1510 // version 2: modern "Contents" bundles
1511 // version 3: none of the above (see below)
1512 // version 4: not a bundle (for main bundle only)
1513 if (CFStringHasSuffix(CFURLGetString(url
), CFSTR(".framework/"))) {
1514 if (_CFBundleURLHasSubDir(url
, _CFBundleResourcesURLFromBase0
)) {
1517 } else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase2
)) {
1520 } else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase1
)) {
1525 if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase2
)) {
1528 } else if (_CFBundleURLHasSubDir(url
, _CFBundleResourcesURLFromBase0
)) {
1531 } else if (_CFBundleURLHasSubDir(url
, _CFBundleSupportFilesURLFromBase1
)) {
1536 if (result
&& version
) *version
= localVersion
;
1540 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc
, CFURLRef url
, uint8_t *version
) {
1541 CFDictionaryRef dict
= NULL
;
1542 char buff
[CFMaxPathSize
];
1543 uint8_t localVersion
= 0;
1545 if (CFURLGetFileSystemRepresentation(url
, true, buff
, CFMaxPathSize
)) {
1546 CFURLRef newURL
= CFURLCreateFromFileSystemRepresentation(alloc
, buff
, strlen(buff
), true);
1547 if (NULL
== newURL
) newURL
= CFRetain(url
);
1549 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) {
1550 // version 3 is for flattened pseudo-bundles with no Contents, Support Files, or Resources directories
1553 dict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(alloc
, newURL
, localVersion
);
1556 if (version
) *version
= localVersion
;
1560 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc
, CFURLRef url
, uint8_t version
) {
1561 CFDictionaryRef result
= NULL
;
1563 CFURLRef infoURL
= NULL
;
1564 CFDataRef infoData
= NULL
;
1565 UniChar buff
[CFMaxPathSize
];
1567 CFMutableStringRef cheapStr
;
1568 CFStringRef infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension0
, infoURLFromBase
= _CFBundleInfoURLFromBase0
;
1569 Boolean tryPlatformSpecific
= true, tryGlobal
= true;
1570 #if USE_GETDIRENTRIES
1571 CFArrayRef directoryContents
= NULL
;
1572 CFRange directoryContentsRange
= CFRangeMake(0, 0);
1575 _CFEnsureStaticBuffersInited();
1578 #if USE_GETDIRENTRIES
1579 // we want to read the Resources directory anyway, so we might as well do it now
1580 CFURLRef resourcesURL
= _CFBundleCopyResourcesDirectoryURLInDirectory(alloc
, url
, version
);
1581 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(resourcesURL
);
1582 CFStringRef resourcesPath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1583 directoryContents
= _CFBundleCopyDirectoryContentsAtPath(resourcesPath
, false);
1584 directoryContentsRange
= CFRangeMake(0, CFArrayGetCount(directoryContents
));
1585 CFRelease(resourcesPath
);
1586 CFRelease(absoluteURL
);
1587 CFRelease(resourcesURL
);
1589 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension0
;
1590 infoURLFromBase
= _CFBundleInfoURLFromBase0
;
1591 } else if (1 == version
) {
1592 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension1
;
1593 infoURLFromBase
= _CFBundleInfoURLFromBase1
;
1594 } else if (2 == version
) {
1595 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension2
;
1596 infoURLFromBase
= _CFBundleInfoURLFromBase2
;
1597 } else if (3 == version
) {
1598 CFStringRef posixPath
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
1599 // this test is necessary to exclude the case where a bundle is spuriously created from the innards of another bundle
1601 if (!(CFStringHasSuffix(posixPath
, _CFBundleSupportFilesDirectoryName1
) || CFStringHasSuffix(posixPath
, _CFBundleSupportFilesDirectoryName2
) || CFStringHasSuffix(posixPath
, _CFBundleResourcesDirectoryName
))) {
1602 infoURLFromBaseNoExtension
= _CFBundleInfoURLFromBaseNoExtension3
;
1603 infoURLFromBase
= _CFBundleInfoURLFromBase3
;
1605 CFRelease(posixPath
);
1609 len
= CFStringGetLength(infoURLFromBaseNoExtension
);
1610 CFStringGetCharacters(infoURLFromBaseNoExtension
, CFRangeMake(0, len
), buff
);
1611 buff
[len
++] = (UniChar
)'-';
1612 memmove(buff
+ len
, _PlatformUniChars
, _PlatformLen
* sizeof(UniChar
));
1613 len
+= _PlatformLen
;
1614 _CFAppendPathExtension(buff
, &len
, CFMaxPathSize
, _InfoExtensionUniChars
, _InfoExtensionLen
);
1615 cheapStr
= CFStringCreateMutable(alloc
, 0);
1616 CFStringAppendCharacters(cheapStr
, buff
, len
);
1617 infoURL
= CFURLCreateWithString(alloc
, cheapStr
, url
);
1618 #if USE_GETDIRENTRIES
1619 if (directoryContents
) {
1620 CFIndex resourcesLen
= CFStringGetLength(_CFBundleResourcesURLFromBase0
);
1621 CFStringDelete(cheapStr
, CFRangeMake(0, CFStringGetLength(cheapStr
)));
1622 CFStringAppendCharacters(cheapStr
, buff
+ resourcesLen
, len
- resourcesLen
);
1623 tryPlatformSpecific
= CFArrayContainsValue(directoryContents
, directoryContentsRange
, cheapStr
);
1626 if (tryPlatformSpecific
) CFURLCreateDataAndPropertiesFromResource(alloc
, infoURL
, &infoData
, NULL
, NULL
, NULL
);
1627 //fprintf(stderr, "looking for ");CFShow(infoURL);if (infoData) fprintf(stderr, "found it\n");
1628 CFRelease(cheapStr
);
1630 // Check for global Info.plist
1632 infoURL
= CFURLCreateWithString(alloc
, infoURLFromBase
, url
);
1633 #if USE_GETDIRENTRIES
1634 if (directoryContents
) tryGlobal
= CFArrayContainsValue(directoryContents
, directoryContentsRange
, _CFBundleInfoFileName
);
1636 if (tryGlobal
) CFURLCreateDataAndPropertiesFromResource(alloc
, infoURL
, &infoData
, NULL
, NULL
, NULL
);
1637 //fprintf(stderr, "looking for ");CFShow(infoURL);if (infoData) fprintf(stderr, "found it\n");
1641 result
= CFPropertyListCreateFromXMLData(alloc
, infoData
, kCFPropertyListMutableContainers
, NULL
);
1643 if (CFDictionaryGetTypeID() == CFGetTypeID(result
)) {
1644 CFDictionarySetValue((CFMutableDictionaryRef
)result
, _kCFBundleInfoPlistURLKey
, infoURL
);
1650 CFRelease(infoData
);
1653 result
= CFDictionaryCreateMutable(alloc
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1657 #if USE_GETDIRENTRIES
1658 if (directoryContents
) CFRelease(directoryContents
);
1664 static Boolean
_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorRef alloc
, CFURLRef url
, CFDictionaryRef infoDict
, UInt32
*packageType
, UInt32
*packageCreator
) {
1665 Boolean retVal
= false, hasType
= false, hasCreator
= false, releaseInfoDict
= false;
1667 CFDataRef pkgInfoData
= NULL
;
1669 // Check for a "real" new bundle
1670 tempURL
= CFURLCreateWithString(alloc
, _CFBundlePkgInfoURLFromBase2
, url
);
1671 CFURLCreateDataAndPropertiesFromResource(alloc
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
1673 if (pkgInfoData
== NULL
) {
1674 tempURL
= CFURLCreateWithString(alloc
, _CFBundlePkgInfoURLFromBase1
, url
);
1675 CFURLCreateDataAndPropertiesFromResource(alloc
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
1678 if (pkgInfoData
== NULL
) {
1679 // Check for a "pseudo" new bundle
1680 tempURL
= CFURLCreateWithString(alloc
, _CFBundlePseudoPkgInfoURLFromBase
, url
);
1681 CFURLCreateDataAndPropertiesFromResource(alloc
, tempURL
, &pkgInfoData
, NULL
, NULL
, NULL
);
1685 // 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.
1686 // 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.
1687 // 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.
1689 if ((pkgInfoData
!= NULL
) && (CFDataGetLength(pkgInfoData
) >= (int)(sizeof(UInt32
) * 2))) {
1690 UInt32
*pkgInfo
= (UInt32
*)CFDataGetBytePtr(pkgInfoData
);
1692 if (packageType
!= NULL
) {
1693 *packageType
= CFSwapInt32BigToHost(pkgInfo
[0]);
1695 if (packageCreator
!= NULL
) {
1696 *packageCreator
= CFSwapInt32BigToHost(pkgInfo
[1]);
1698 retVal
= hasType
= hasCreator
= true;
1700 if (pkgInfoData
!= NULL
) CFRelease(pkgInfoData
);
1703 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(alloc
, url
, NULL
);
1704 releaseInfoDict
= true;
1707 CFStringRef typeString
= CFDictionaryGetValue(infoDict
, _kCFBundlePackageTypeKey
), creatorString
= CFDictionaryGetValue(infoDict
, _kCFBundleSignatureKey
);
1709 CFIndex usedBufLen
= 0;
1710 if (typeString
&& CFGetTypeID(typeString
) == CFStringGetTypeID() && CFStringGetLength(typeString
) == 4 && 4 == CFStringGetBytes(typeString
, CFRangeMake(0, 4), kCFStringEncodingMacRoman
, 0, false, (UInt8
*)&tmp
, 4, &usedBufLen
) && 4 == usedBufLen
) {
1711 if (packageType
!= NULL
) {
1712 *packageType
= CFSwapInt32BigToHost(tmp
);
1714 retVal
= hasType
= true;
1716 if (creatorString
&& CFGetTypeID(creatorString
) == CFStringGetTypeID() && CFStringGetLength(creatorString
) == 4 && 4 == CFStringGetBytes(creatorString
, CFRangeMake(0, 4), kCFStringEncodingMacRoman
, 0, false, (UInt8
*)&tmp
, 4, &usedBufLen
) && 4 == usedBufLen
) {
1717 if (packageCreator
!= NULL
) {
1718 *packageCreator
= CFSwapInt32BigToHost(tmp
);
1720 retVal
= hasCreator
= true;
1722 if (releaseInfoDict
) CFRelease(infoDict
);
1725 if (!hasType
|| !hasCreator
) {
1726 // If this looks like a bundle then manufacture the type and creator.
1727 if (retVal
|| _CFBundleURLLooksLikeBundle(url
)) {
1728 if (packageCreator
!= NULL
&& !hasCreator
) {
1729 *packageCreator
= 0x3f3f3f3f; // '????'
1731 if (packageType
!= NULL
&& !hasType
) {
1733 UniChar buff
[CFMaxPathSize
];
1734 CFIndex strLen
, startOfExtension
;
1735 CFURLRef absoluteURL
;
1737 // Detect "app", "debug", "profile", or "framework" extensions
1738 absoluteURL
= CFURLCopyAbsoluteURL(url
);
1739 urlStr
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1740 CFRelease(absoluteURL
);
1741 strLen
= CFStringGetLength(urlStr
);
1742 CFStringGetCharacters(urlStr
, CFRangeMake(0, strLen
), buff
);
1744 startOfExtension
= _CFStartOfPathExtension(buff
, strLen
);
1745 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
)'/'))) {
1747 *packageType
= CFSwapInt32BigToHost(0x4150504c); // 'APPL'
1748 } 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
)'/'))) {
1749 // This is an app (debug version)
1750 *packageType
= CFSwapInt32BigToHost(0x4150504c); // 'APPL'
1751 } 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
)'/'))) {
1752 // This is an app (profile version)
1753 *packageType
= CFSwapInt32BigToHost(0x4150504c); // 'APPL'
1754 } 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
)'/'))) {
1755 // This is a service
1756 *packageType
= CFSwapInt32BigToHost(0x4150504c); // 'APPL'
1757 } 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
)'/'))) {
1758 // This is a framework
1759 *packageType
= CFSwapInt32BigToHost(0x464d574b); // 'FMWK'
1761 // Default to BNDL for generic bundle
1762 *packageType
= CFSwapInt32BigToHost(0x424e444C); // 'BNDL'
1771 CF_EXPORT Boolean
_CFBundleGetPackageInfoInDirectory(CFAllocatorRef alloc
, CFURLRef url
, UInt32
*packageType
, UInt32
*packageCreator
) {return _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(alloc
, url
, NULL
, packageType
, packageCreator
);}
1773 CF_EXPORT
void CFBundleGetPackageInfo(CFBundleRef bundle
, UInt32
*packageType
, UInt32
*packageCreator
) {
1774 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
);
1775 if (!_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFGetAllocator(bundle
), bundleURL
, CFBundleGetInfoDictionary(bundle
), packageType
, packageCreator
)) {
1776 if (packageType
!= NULL
) {
1777 *packageType
= CFSwapInt32BigToHost(0x424e444C); // 'BNDL'
1779 if (packageCreator
!= NULL
) {
1780 *packageCreator
= 0x3f3f3f3f; // '????'
1783 if (bundleURL
) CFRelease(bundleURL
);
1786 CF_EXPORT Boolean
CFBundleGetPackageInfoInDirectory(CFURLRef url
, UInt32
*packageType
, UInt32
*packageCreator
) {return _CFBundleGetPackageInfoInDirectory(NULL
, url
, packageType
, packageCreator
);}
1788 __private_extern__ CFStringRef
_CFBundleGetPlatformExecutablesSubdirectoryName(void) {
1789 #if defined(__MACOS8__)
1790 return CFSTR("MacOSClassic");
1791 #elif defined(__WIN32__)
1792 return CFSTR("Windows");
1793 #elif defined(__MACH__)
1794 return CFSTR("MacOS");
1795 #elif defined(__hpux__)
1796 return CFSTR("HPUX");
1797 #elif defined(__svr4__)
1798 return CFSTR("Solaris");
1799 #elif defined(__LINUX__)
1800 return CFSTR("Linux");
1801 #elif defined(__FREEBSD__)
1802 return CFSTR("FreeBSD");
1804 #warning CFBundle: Unknown architecture
1805 return CFSTR("Other");
1809 __private_extern__ CFStringRef
_CFBundleGetAlternatePlatformExecutablesSubdirectoryName(void) {
1810 #if defined(__MACOS8__)
1811 return CFSTR("Mac OS 8");
1812 #elif defined(__WIN32__)
1813 return CFSTR("WinNT");
1814 #elif defined(__MACH__)
1815 return CFSTR("Mac OS X");
1816 #elif defined(__hpux__)
1817 return CFSTR("HP-UX");
1818 #elif defined(__svr4__)
1819 return CFSTR("Solaris");
1820 #elif defined(__LINUX__)
1821 return CFSTR("Linux");
1822 #elif defined(__FREEBSD__)
1823 return CFSTR("FreeBSD");
1825 #warning CFBundle: Unknown architecture
1826 return CFSTR("Other");
1830 __private_extern__ CFStringRef
_CFBundleGetOtherPlatformExecutablesSubdirectoryName(void) {
1831 #if defined(__MACOS8__)
1832 return CFSTR("MacOS");
1833 #elif defined(__WIN32__)
1834 return CFSTR("Other");
1835 #elif defined(__MACH__)
1836 return CFSTR("MacOSClassic");
1837 #elif defined(__hpux__)
1838 return CFSTR("Other");
1839 #elif defined(__svr4__)
1840 return CFSTR("Other");
1841 #elif defined(__LINUX__)
1842 return CFSTR("Other");
1843 #elif defined(__FREEBSD__)
1844 return CFSTR("Other");
1846 #warning CFBundle: Unknown architecture
1847 return CFSTR("Other");
1851 __private_extern__ CFStringRef
_CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(void) {
1852 #if defined(__MACOS8__)
1853 return CFSTR("Mac OS X");
1854 #elif defined(__WIN32__)
1855 return CFSTR("Other");
1856 #elif defined(__MACH__)
1857 return CFSTR("Mac OS 8");
1858 #elif defined(__hpux__)
1859 return CFSTR("Other");
1860 #elif defined(__svr4__)
1861 return CFSTR("Other");
1862 #elif defined(__LINUX__)
1863 return CFSTR("Other");
1864 #elif defined(__FREEBSD__)
1865 return CFSTR("Other");
1867 #warning CFBundle: Unknown architecture
1868 return CFSTR("Other");
1872 __private_extern__ CFArrayRef
_CFBundleCopyBundleRegionsArray(CFBundleRef bundle
) {return CFBundleCopyBundleLocalizations(bundle
);}
1874 CF_EXPORT CFArrayRef
CFBundleCopyBundleLocalizations(CFBundleRef bundle
) {
1875 CFURLRef resourcesURL
= CFBundleCopyResourcesDirectoryURL(bundle
);
1876 uint8_t version
= _CFBundleLayoutVersion(bundle
);
1877 CFArrayRef urls
= ((version
!= 4) ? _CFContentsOfDirectory(CFGetAllocator(bundle
), NULL
, NULL
, resourcesURL
, CFSTR("lproj")) : NULL
);
1878 CFArrayRef predefinedLocalizations
= NULL
;
1879 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1880 CFMutableArrayRef result
= NULL
;
1883 predefinedLocalizations
= CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
1884 if (predefinedLocalizations
!= NULL
&& CFGetTypeID(predefinedLocalizations
) != CFArrayGetTypeID()) {
1885 predefinedLocalizations
= NULL
;
1886 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleLocalizationsKey
);
1888 if (predefinedLocalizations
!= NULL
) {
1889 CFIndex i
, c
= CFArrayGetCount(predefinedLocalizations
);
1890 if (c
> 0 && !result
) {
1891 result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
1893 for (i
=0; i
<c
; i
++) {
1894 CFArrayAppendValue(result
, CFArrayGetValueAtIndex(predefinedLocalizations
, i
));
1901 CFURLRef curURL
, curAbsoluteURL
;
1902 CFStringRef curStr
, regionStr
;
1903 UniChar buff
[CFMaxPathSize
];
1904 CFIndex strLen
, startOfLastPathComponent
, regionLen
;
1906 c
= CFArrayGetCount(urls
);
1907 if (c
> 0 && !result
) {
1908 result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
1910 for (i
= 0; i
< c
; i
++) {
1911 curURL
= CFArrayGetValueAtIndex(urls
, i
);
1912 curAbsoluteURL
= CFURLCopyAbsoluteURL(curURL
);
1913 curStr
= CFURLCopyFileSystemPath(curAbsoluteURL
, PLATFORM_PATH_STYLE
);
1914 CFRelease(curAbsoluteURL
);
1915 strLen
= CFStringGetLength(curStr
);
1916 CFStringGetCharacters(curStr
, CFRangeMake(0, strLen
), buff
);
1918 startOfLastPathComponent
= _CFStartOfLastPathComponent(buff
, strLen
);
1919 regionLen
= _CFLengthAfterDeletingPathExtension(&(buff
[startOfLastPathComponent
]), strLen
- startOfLastPathComponent
);
1920 regionStr
= CFStringCreateWithCharacters(CFGetAllocator(bundle
), &(buff
[startOfLastPathComponent
]), regionLen
);
1921 CFArrayAppendValue(result
, regionStr
);
1922 CFRelease(regionStr
);
1928 CFStringRef developmentLocalization
= CFBundleGetDevelopmentRegion(bundle
);
1929 if (developmentLocalization
) {
1930 result
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &kCFTypeArrayCallBacks
);
1931 CFArrayAppendValue(result
, developmentLocalization
);
1934 if (resourcesURL
) CFRelease(resourcesURL
);
1940 CF_EXPORT CFDictionaryRef
CFBundleCopyInfoDictionaryForURL(CFURLRef url
) {
1941 CFDictionaryRef result
= NULL
;
1943 if (_CFIsResourceAtURL(url
, &isDir
)) {
1945 result
= _CFBundleCopyInfoDictionaryInDirectory(NULL
, url
, NULL
);
1947 result
= _CFBundleCopyInfoDictionaryInExecutable(url
);
1953 CFArrayRef
CFBundleCopyLocalizationsForURL(CFURLRef url
) {
1954 CFArrayRef result
= NULL
;
1955 CFBundleRef bundle
= CFBundleCreate(NULL
, url
);
1956 CFStringRef devLang
= NULL
;
1958 result
= CFBundleCopyBundleLocalizations(bundle
);
1961 CFDictionaryRef infoDict
= _CFBundleCopyInfoDictionaryInExecutable(url
);
1963 CFArrayRef predefinedLocalizations
= CFDictionaryGetValue(infoDict
, kCFBundleLocalizationsKey
);
1964 if (predefinedLocalizations
!= NULL
&& CFGetTypeID(predefinedLocalizations
) == CFArrayGetTypeID()) {
1965 result
= CFRetain(predefinedLocalizations
);
1968 devLang
= CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1969 if (devLang
!= NULL
&& (CFGetTypeID(devLang
) == CFStringGetTypeID() && CFStringGetLength(devLang
) > 0)) {
1970 result
= CFArrayCreate(NULL
, (const void **)&devLang
, 1, &kCFTypeArrayCallBacks
);
1973 CFRelease(infoDict
);