]> git.saurik.com Git - apple/cf.git/blob - PlugIn.subproj/CFBundle_Resources.c
CF-368.18.tar.gz
[apple/cf.git] / PlugIn.subproj / CFBundle_Resources.c
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* CFBundle_Resources.c
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Doug Davidson
26 */
27
28 #if defined(__MACOS8__) || defined(__WIN32__)
29 #define USE_GETDIRENTRIES 0
30 #else
31 #define USE_GETDIRENTRIES 1
32 #endif
33 #define GETDIRENTRIES_CACHE_CAPACITY 128
34
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>
40 #include <string.h>
41 #include "CFInternal.h"
42 #include "CFPriv.h"
43
44 /* Unixy & Windows Headers */
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <unistd.h>
48 #include <stdio.h>
49 #if USE_GETDIRENTRIES
50 #include <dirent.h>
51 #endif
52
53
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;
71 #else
72 return CFSTR("");
73 #endif
74 }
75
76 CF_INLINE CFStringRef _CFGetAlternatePlatformName(void) {
77 #if defined (__MACH__)
78 return _CFBundleAlternateMacOSXPlatformName;
79 #elif defined(__MACOS8__)
80 return _CFBundleAlternateMacOS8PlatformName;
81 #else
82 return CFSTR("");
83 #endif
84 }
85
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;
103
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;
113
114 CFAllocatorRef alloc = __CFGetDefaultAllocator();
115
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);
124
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;
133
134 if (_AppSupportLen1 > 0) {
135 CFStringGetCharacters(appSupportStr1, CFRangeMake(0, _AppSupportLen1), _AppSupportUniChars1);
136 }
137 if (_AppSupportLen2 > 0) {
138 CFStringGetCharacters(appSupportStr2, CFRangeMake(0, _AppSupportLen2), _AppSupportUniChars2);
139 }
140 if (_ResourcesLen > 0) {
141 CFStringGetCharacters(resourcesStr, CFRangeMake(0, _ResourcesLen), _ResourcesUniChars);
142 }
143 if (_PlatformLen > 0) {
144 CFStringGetCharacters(platformStr, CFRangeMake(0, _PlatformLen), _PlatformUniChars);
145 }
146 if (_AlternatePlatformLen > 0) {
147 CFStringGetCharacters(alternatePlatformStr, CFRangeMake(0, _AlternatePlatformLen), _AlternatePlatformUniChars);
148 }
149 if (_LprojLen > 0) {
150 CFStringGetCharacters(lprojStr, CFRangeMake(0, _LprojLen), _LprojUniChars);
151 }
152 if (_GlobalResourcesLen > 0) {
153 CFStringGetCharacters(globalResourcesStr, CFRangeMake(0, _GlobalResourcesLen), _GlobalResourcesUniChars);
154 }
155 if (_InfoExtensionLen > 0) {
156 CFStringGetCharacters(infoExtensionStr, CFRangeMake(0, _InfoExtensionLen), _InfoExtensionUniChars);
157 }
158 }
159
160 CF_INLINE void _CFEnsureStaticBuffersInited(void) {
161 __CFSpinLock(&CFBundleResourceGlobalDataLock);
162 if (_AppSupportUniChars1 == NULL) {
163 _CFBundleInitStaticUniCharBuffers();
164 }
165 __CFSpinUnlock(&CFBundleResourceGlobalDataLock);
166 }
167
168 #if USE_GETDIRENTRIES
169
170 static CFMutableDictionaryRef contentsCache = NULL;
171 static CFMutableDictionaryRef directoryContentsCache = NULL;
172 static CFMutableDictionaryRef unknownContentsCache = NULL;
173
174 typedef enum {
175 _CFBundleAllContents = 0,
176 _CFBundleDirectoryContents = 1,
177 _CFBundleUnknownContents = 2
178 } _CFBundleDirectoryContentsType;
179
180 static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, _CFBundleDirectoryContentsType contentsType) {
181 CFArrayRef result = NULL;
182
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);
188 } else {
189 if (contentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(contentsCache, path);
190 }
191 if (result) CFRetain(result);
192 __CFSpinUnlock(&CFBundleResourceGlobalDataLock);
193
194 if (!result) {
195 Boolean tryToOpen = true, allDots = true;
196 char cpathBuff[CFMaxPathSize], dirge[8192];
197 CFIndex cpathLen = 0, idx, lastSlashIdx = 0;
198 int fd = -1, numread;
199 long basep = 0;
200 CFMutableArrayRef contents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), directoryContents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), unknownContents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
201 CFStringRef dirName, name;
202 struct stat statBuf;
203
204 if (_CFStringGetFileSystemRepresentation(path, cpathBuff, CFMaxPathSize)) {
205 cpathLen = strlen(cpathBuff);
206
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;
211 }
212 if (lastSlashIdx > 0 && lastSlashIdx + 1 < cpathLen && !allDots) {
213 cpathBuff[lastSlashIdx] = '\0';
214 dirName = CFStringCreateWithCString(NULL, cpathBuff, CFStringFileSystemEncoding());
215 if (dirName) {
216 name = CFStringCreateWithCString(NULL, cpathBuff + lastSlashIdx + 1, CFStringFileSystemEncoding());
217 if (name) {
218 // ??? we might like to use directoryContentsCache rather than contentsCache here, but we cannot unless we resolve DT_LNKs below
219 CFArrayRef dirDirContents = NULL;
220
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;
228 }
229 __CFSpinUnlock(&CFBundleResourceGlobalDataLock);
230
231 CFRelease(name);
232 }
233 CFRelease(dirName);
234 }
235 cpathBuff[lastSlashIdx] = '/';
236 }
237 if (tryToOpen) fd = open(cpathBuff, O_RDONLY, 0777);
238 }
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) {
241 struct dirent *dent;
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());
246 if (NULL != name) {
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);
255 }
256 CFRelease(name);
257 }
258 }
259 }
260 }
261 if (fd >= 0) close(fd);
262
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);
267
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);
271
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);
275
276 if (contentsType == _CFBundleUnknownContents) {
277 result = CFRetain(unknownContents);
278 } else if (contentsType == _CFBundleDirectoryContents) {
279 result = CFRetain(directoryContents);
280 } else {
281 result = CFRetain(contents);
282 }
283
284 CFRelease(contents);
285 CFRelease(directoryContents);
286 CFRelease(unknownContents);
287 __CFSpinUnlock(&CFBundleResourceGlobalDataLock);
288 }
289 return result;
290 }
291
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);
298 }
299
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]);
308 }
309 }
310 }
311 }
312
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);
319 }
320
321 #endif /* USE_GETDIRENTRIES */
322
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);
328 CFRelease(path);
329 CFRelease(absoluteURL);
330 #endif /* USE_GETDIRENTRIES */
331 }
332
333 CF_EXPORT void _CFBundleFlushCaches(void) {
334 #if USE_GETDIRENTRIES
335 _CFBundleFlushContentsCaches();
336 #endif /* USE_GETDIRENTRIES */
337 }
338
339 __private_extern__ Boolean _CFIsResourceAtURL(CFURLRef url, Boolean *isDir) {
340 Boolean exists;
341 SInt32 mode;
342 if (_CFGetFileProperties(NULL, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) {
343 if (isDir) {
344 *isDir = ((exists && ((mode & S_IFMT) == S_IFDIR)) ? true : false);
345 }
346 #if defined(__MACOS8__)
347 return (exists);
348 #else
349 return (exists && (mode & 0444));
350 #endif /* __MACOS8__ */
351 } else {
352 return false;
353 }
354 }
355
356 __private_extern__ Boolean _CFIsResourceAtPath(CFStringRef path, Boolean *isDir) {
357 Boolean result = false;
358 CFURLRef url = CFURLCreateWithFileSystemPath(CFGetAllocator(path), path, PLATFORM_PATH_STYLE, false);
359 if (url != NULL) {
360 result = _CFIsResourceAtURL(url, isDir);
361 CFRelease(url);
362 }
363 return result;
364 }
365
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;
376
377 #if USE_GETDIRENTRIES
378 CFIndex dirPathLen = pathLen;
379 CFArrayRef contents, directoryContents, unknownContents;
380 CFRange contentsRange, directoryContentsRange, unknownContentsRange;
381
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));
391 #endif
392
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");
409 }
410 #else
411 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
412 CFStringReplaceAll(cheapStr, tmpString);
413 platformGenericFound = _CFIsResourceAtPath(cheapStr, &platformGenericIsDir);
414 #endif
415 }
416
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");
439 }
440 #else
441 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
442 CFStringReplaceAll(cheapStr, tmpString);
443 platformSpecificFound = _CFIsResourceAtPath(cheapStr, &platformSpecificIsDir);
444 #endif
445 }
446 }
447 }
448 if (platformSpecificFound) {
449 CFURLRef url = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, platformSpecificIsDir);
450 CFArrayAppendValue(result, url);
451 CFRelease(url);
452 } else if (platformGenericFound) {
453 CFURLRef url = CFURLCreateWithFileSystemPath(alloc, ((platformGenericStr != NULL) ? platformGenericStr : cheapStr), PLATFORM_PATH_STYLE, platformGenericIsDir);
454 CFArrayAppendValue(result, url);
455 CFRelease(url);
456 }
457 if (platformGenericStr != NULL) {
458 CFRelease(platformGenericStr);
459 }
460 #if USE_GETDIRENTRIES
461 CFRelease(contents);
462 CFRelease(directoryContents);
463 CFRelease(unknownContents);
464 #endif
465 }
466
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) {
468
469 if (nameLen > 0) {
470 // If we have a resName, just call the search API. We may have to loop over the resTypes.
471 if (!resTypes) {
472 _CFSearchBundleDirectory(alloc, result, workingUniChars, workingLen, nameUniChars, nameLen, NULL, 0, cheapStr, tmpString, version);
473 } else {
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);
480 if (typeChars) {
481 #else
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)) {
487 break;
488 }
489 #if defined(__MACOS8__) || defined(__WIN32__)
490 CFAllocatorDeallocate(alloc, typeChars);
491 }
492 #endif /* __MACOS8__ */
493 }
494 }
495 } else {
496 // If we have no resName, do it by hand. We may have to loop over the resTypes.
497 unsigned char cpathBuff[CFMaxPathSize];
498 CFIndex cpathLen;
499 CFMutableArrayRef children;
500
501 CFStringSetExternalCharactersNoCopy(tmpString, workingUniChars, workingLen, workingLen);
502 if (!_CFStringGetFileSystemRepresentation(tmpString, cpathBuff, CFMaxPathSize)) return;
503 cpathLen = strlen(cpathBuff);
504
505 if (!resTypes) {
506 // ??? should this use _CFBundleCopyDirectoryContentsAtPath?
507 children = _CFContentsOfDirectory(alloc, cpathBuff, NULL, NULL, NULL);
508 if (children) {
509 CFIndex childIndex, childCount = CFArrayGetCount(children);
510 for (childIndex = 0; childIndex < childCount; childIndex++) {
511 CFArrayAppendValue(result, CFArrayGetValueAtIndex(children, childIndex));
512 }
513 CFRelease(children);
514 }
515 } else {
516 CFIndex i, c = CFArrayGetCount(resTypes);
517 for (i=0; i<c; i++) {
518 CFStringRef curType = (CFStringRef)CFArrayGetValueAtIndex(resTypes, i);
519
520 // ??? should this use _CFBundleCopyDirectoryContentsAtPath?
521 children = _CFContentsOfDirectory(alloc, cpathBuff, NULL, NULL, curType);
522 if (children) {
523 CFIndex childIndex, childCount = CFArrayGetCount(children);
524 for (childIndex = 0; childIndex < childCount; childIndex++) {
525 CFArrayAppendValue(result, CFArrayGetValueAtIndex(children, childIndex));
526 }
527 CFRelease(children);
528 }
529 if (limit <= CFArrayGetCount(result)) {
530 break;
531 }
532 }
533 }
534 }
535 }
536
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;
539
540 // Look directly in the directory specified in workingUniChars. as if it is a Resources directory.
541 if (1 == version) {
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;
548 }
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);
553 }
554
555 // Now search the local resources.
556 workingLen = savedWorkingLen;
557 if (CFArrayGetCount(result) < limit) {
558 CFIndex langIndex;
559 CFIndex langCount = (searchLanguages ? CFArrayGetCount(searchLanguages) : 0);
560 CFStringRef curLangStr;
561 CFIndex curLangLen;
562 // MF:??? OK to hard-wire this length?
563 UniChar curLangUniChars[255];
564 CFIndex numResults = CFArrayGetCount(result);
565
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;
574 continue;
575 }
576 if (!_CFAppendPathExtension(workingUniChars, &workingLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) {
577 workingLen = savedWorkingLen;
578 continue;
579 }
580 if (subDirLen > 0) {
581 if (!_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen)) {
582 workingLen = savedWorkingLen;
583 continue;
584 }
585 }
586 _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
587
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.
593 break;
594 }
595 }
596 }
597 }
598
599 extern void _CFStrSetDesiredCapacity(CFMutableStringRef str, CFIndex len);
600
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;
611
612 result = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
613 // Init the one-time-only unichar buffers.
614 _CFEnsureStaticBuffersInited();
615
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;
621
622 if (nameLen > 0) {
623 CFStringGetCharacters(resName, CFRangeMake(0, nameLen), nameUniChars);
624 }
625 if (subDirLen > 0) {
626 CFStringGetCharacters(subDirName, CFRangeMake(0, subDirLen), subDirUniChars);
627 }
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);
636 }
637 CFRelease(bundlePath);
638 CFRelease(bundleURL);
639 savedWorkingLen = workingLen;
640 if (1 == version) {
641 _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _AppSupportUniChars1, _AppSupportLen1);
642 } else if (2 == version) {
643 _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _AppSupportUniChars2, _AppSupportLen2);
644 }
645 if (0 == version || 1 == version || 2 == version) {
646 _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _ResourcesUniChars, _ResourcesLen);
647 }
648
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);
654
655 _CFFindBundleResourcesInResourcesDir(alloc, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
656
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);
662 }
663
664 CFRelease(cheapStr);
665 CFRelease(tmpString);
666 CFAllocatorDeallocate(alloc, nameUniChars);
667 if (bundle == NULL) {
668 CFRelease(alloc);
669 }
670
671 return result;
672 }
673
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);
678
679 array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle));
680
681 if (types) CFRelease(types);
682
683 if (array) {
684 if (CFArrayGetCount(array) > 0) result = CFRetain(CFArrayGetValueAtIndex(array, 0));
685 CFRelease(array);
686 }
687 return result;
688 }
689
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);
693
694 // MF:!!! Better "limit" than 1,000,000?
695 array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, _CFBundleLayoutVersion(bundle));
696
697 if (types) CFRelease(types);
698
699 return array;
700 }
701
702 CF_EXPORT CFURLRef _CFBundleCopyResourceURLForLanguage(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName, CFStringRef language) {return CFBundleCopyResourceURLForLocalization(bundle, resourceName, resourceType, subDirName, language);}
703
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;
707
708 if (localizationName) languages = CFArrayCreate(CFGetAllocator(bundle), (const void **)&localizationName, 1, &kCFTypeArrayCallBacks);
709 if (resourceType) types = CFArrayCreate(CFGetAllocator(bundle), (const void **)&resourceType, 1, &kCFTypeArrayCallBacks);
710
711 array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle));
712 if (array) {
713 if (CFArrayGetCount(array) > 0) result = CFRetain(CFArrayGetValueAtIndex(array, 0));
714 CFRelease(array);
715 }
716
717 if (types) CFRelease(types);
718 if (languages) CFRelease(languages);
719
720 return result;
721 }
722
723 CF_EXPORT CFArrayRef _CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef language) {return CFBundleCopyResourceURLsOfTypeForLocalization(bundle, resourceType, subDirName, language);}
724
725 CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef localizationName) {
726 CFArrayRef languages = NULL, types = NULL, array;
727
728 if (localizationName) languages = CFArrayCreate(CFGetAllocator(bundle), (const void **)&localizationName, 1, &kCFTypeArrayCallBacks);
729 if (resourceType) types = CFArrayCreate(CFGetAllocator(bundle), (const void **)&resourceType, 1, &kCFTypeArrayCallBacks);
730
731 // MF:!!! Better "limit" than 1,000,000?
732 array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, _CFBundleLayoutVersion(bundle));
733
734 if (types) CFRelease(types);
735 if (languages) CFRelease(languages);
736
737 return array;
738 }
739
740 CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName) {
741 CFStringRef result = NULL;
742 CFDictionaryRef stringTable = NULL;
743
744 if (key == NULL) return (value ? CFRetain(value) : CFRetain(CFSTR("")));
745
746 if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) {
747 tableName = _CFBundleDefaultStringTableName;
748 }
749 if (__CFBundleGetResourceData(bundle)->_stringTableCache != NULL) {
750 // See if we have the table cached.
751 stringTable = CFDictionaryGetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName);
752 }
753 if (stringTable == NULL) {
754 // Go load the table.
755 CFURLRef tableURL = CFBundleCopyResourceURL(bundle, tableName, _CFBundleStringTableType, NULL);
756 if (tableURL) {
757 CFStringRef nameForSharing = NULL;
758 if (stringTable == NULL) {
759 CFDataRef tableData = NULL;
760 SInt32 errCode;
761 CFStringRef errStr;
762 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle), tableURL, &tableData, NULL, NULL, &errCode)) {
763 stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), tableData, kCFPropertyListImmutable, &errStr);
764 if (errStr != NULL) {
765 CFRelease(errStr);
766 errStr = NULL;
767 }
768 if (stringTable && CFDictionaryGetTypeID() != CFGetTypeID(stringTable)) {
769 CFRelease(stringTable);
770 stringTable = NULL;
771 }
772 CFRelease(tableData);
773 }
774 }
775 if (nameForSharing) CFRelease(nameForSharing);
776 CFRelease(tableURL);
777 }
778 if (stringTable == NULL) {
779 stringTable = CFDictionaryCreate(CFGetAllocator(bundle), NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
780 }
781 if (__CFBundleGetResourceData(bundle)->_stringTableCache == NULL) {
782 __CFBundleGetResourceData(bundle)->_stringTableCache = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
783 }
784 CFDictionarySetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName, stringTable);
785 CFRelease(stringTable);
786 }
787
788 result = CFDictionaryGetValue(stringTable, key);
789 if (result == NULL) {
790 static int capitalize = -1;
791 if (value == NULL) {
792 result = CFRetain(key);
793 } else if (CFEqual(value, CFSTR(""))) {
794 result = CFRetain(key);
795 } else {
796 result = CFRetain(value);
797 }
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);
803 CFRelease(result);
804 result = capitalizedResult;
805 }
806 }
807 } else {
808 CFRetain(result);
809 }
810
811 return result;
812 }
813
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;
818
819 if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL;
820
821 newURL = CFURLCreateFromFileSystemRepresentation(NULL, buff, strlen(buff), true);
822 if (NULL == newURL) {
823 newURL = CFRetain(bundleURL);
824 }
825 if (_CFBundleCouldBeBundle(newURL)) {
826 uint8_t version = 0;
827 CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(NULL, newURL, &version), types = NULL, array;
828 if (resourceType) types = CFArrayCreate(NULL, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks);
829
830 array = _CFFindBundleResources(NULL, newURL, subDirName, languages, resourceName, types, 1, version);
831
832 if (types) CFRelease(types);
833 if (languages) CFRelease(languages);
834
835 if (array) {
836 if (CFArrayGetCount(array) > 0) result = CFRetain(CFArrayGetValueAtIndex(array, 0));
837 CFRelease(array);
838 }
839 }
840 if (newURL) CFRelease(newURL);
841 return result;
842 }
843
844 CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleURL, CFStringRef resourceType, CFStringRef subDirName) {
845 CFArrayRef array = NULL;
846 char buff[CFMaxPathSize];
847 CFURLRef newURL = NULL;
848
849 if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL;
850
851 newURL = CFURLCreateFromFileSystemRepresentation(NULL, buff, strlen(buff), true);
852 if (NULL == newURL) {
853 newURL = CFRetain(bundleURL);
854 }
855 if (_CFBundleCouldBeBundle(newURL)) {
856 uint8_t version = 0;
857 CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(NULL, newURL, &version), types = NULL;
858 if (resourceType) types = CFArrayCreate(NULL, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks);
859
860 // MF:!!! Better "limit" than 1,000,000?
861 array = _CFFindBundleResources(NULL, newURL, subDirName, languages, NULL, types, 1000000, version);
862
863 if (types) CFRelease(types);
864 if (languages) CFRelease(languages);
865 }
866 if (newURL) CFRelease(newURL);
867 return array;
868 }
869
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";
886
887 #define NUM_LOCALE_ABBREVIATIONS 109
888 #define LOCALE_ABBREVIATION_LENGTH 6
889
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"
910 };
911
912 #define NUM_LANGUAGE_NAMES 152
913 #define LANGUAGE_NAME_LENGTH 13
914
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";
936
937 #define NUM_LANGUAGE_ABBREVIATIONS 152
938 #define LANGUAGE_ABBREVIATION_LENGTH 3
939
940 #ifdef __CONSTANT_CFSTRINGS__
941
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")};
946
947 #define NUM_COMMON_LANGUAGE_NAMES 7
948
949 #endif // __CONSTANT_CFSTRINGS__
950
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
962 };
963
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
975 };
976
977 static SInt32 _CFBundleGetLanguageCodeForLocalization(CFStringRef localizationName) {
978 SInt32 result = -1, i;
979 char buff[256];
980 CFIndex length = CFStringGetLength(localizationName);
981 if ((length >= LANGUAGE_ABBREVIATION_LENGTH - 1) && (length <= 255) && CFStringGetCString(localizationName, buff, 255, kCFStringEncodingASCII)) {
982 buff[255] = '\0';
983 for (i = 0; -1 == result && i < NUM_LANGUAGE_NAMES; i++) {
984 if (0 == strcmp(buff, __CFBundleLanguageNamesArray[i])) result = i;
985 }
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;
992 }
993 }
994 return result;
995 }
996
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);
1003 }
1004 }
1005 return result;
1006 }
1007
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);
1014 }
1015 }
1016 return result;
1017 }
1018
1019 static inline CFStringRef _CFBundleCopyLanguageAbbreviationForLocalization(CFStringRef localizationName) {
1020 CFStringRef result = NULL;
1021 SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName);
1022 if (languageCode >= 0) {
1023 result = _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode);
1024 } else {
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));
1028 }
1029 }
1030 return result;
1031 }
1032
1033 static inline CFStringRef _CFBundleCopyModifiedLocalization(CFStringRef localizationName) {
1034 CFMutableStringRef result = NULL;
1035 CFIndex length = CFStringGetLength(localizationName);
1036 if (length >= 4) {
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("-"));
1041 }
1042 }
1043 return result;
1044 }
1045
1046 static inline CFStringRef _CFBundleCopyLanguageNameForLocalization(CFStringRef localizationName) {
1047 CFStringRef result = NULL;
1048 SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName);
1049 if (languageCode >= 0) {
1050 result = _CFBundleCopyLanguageNameForLanguageCode(languageCode);
1051 } else {
1052 result = CFStringCreateCopy(NULL, localizationName);
1053 }
1054 return result;
1055 }
1056
1057 static SInt32 _CFBundleGetLanguageCodeForRegionCode(SInt32 regionCode) {
1058 SInt32 result = -1, i;
1059 if (52 == regionCode) { // hack for mixed-up Chinese language codes
1060 result = 33;
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;
1066 }
1067 }
1068 }
1069 return result;
1070 }
1071
1072 static SInt32 _CFBundleGetRegionCodeForLanguageCode(SInt32 languageCode) {
1073 SInt32 result = -1, i;
1074 if (19 == languageCode) { // hack for mixed-up Chinese language codes
1075 result = 53;
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;
1081 }
1082 }
1083 }
1084 return result;
1085 }
1086
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;
1095 }
1096 }
1097 if (-1 == result) {
1098 SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName);
1099 result = _CFBundleGetRegionCodeForLanguageCode(languageCode);
1100 }
1101 return result;
1102 }
1103
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);
1110 }
1111 }
1112 return result;
1113 }
1114
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);
1121 } else {
1122 _CFBundleGetLanguageAndRegionCodes(&language, &region);
1123 }
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];
1128 }
1129 if (language >= 0 && language < (int)(sizeof(__CFBundleStringEncodingsArray)/sizeof(CFStringEncoding))) {
1130 encoding = __CFBundleStringEncodingsArray[language];
1131 }
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);
1137 }
1138
1139 CFStringRef CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode, SInt32 regionCode, SInt32 scriptCode, CFStringEncoding stringEncoding) {
1140 CFStringRef localizationName = NULL;
1141 if (!localizationName) {
1142 localizationName = _CFBundleCopyLocaleAbbreviationForRegionCode(regionCode);
1143 }
1144 if (!localizationName) {
1145 localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode);
1146 }
1147 if (!localizationName) {
1148 SInt32 language = -1, scriptLanguage = -1, encodingLanguage = -1;
1149 unsigned int i;
1150 for (i = 0; language == -1 && i < (sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32)); i++) {
1151 if (__CFBundleScriptCodesArray[i] == scriptCode && __CFBundleStringEncodingsArray[i] == stringEncoding) language = i;
1152 }
1153 for (i = 0; scriptLanguage == -1 && i < (sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32)); i++) {
1154 if (__CFBundleScriptCodesArray[i] == scriptCode) scriptLanguage = i;
1155 }
1156 for (i = 0; encodingLanguage == -1 && i < (sizeof(__CFBundleStringEncodingsArray)/sizeof(CFStringEncoding)); i++) {
1157 if (__CFBundleStringEncodingsArray[i] == stringEncoding) encodingLanguage = i;
1158 }
1159 localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(language);
1160 if (!localizationName) localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(encodingLanguage);
1161 if (!localizationName) localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(scriptLanguage);
1162 }
1163 return localizationName;
1164 }
1165
1166 extern void *__CFAppleLanguages;
1167
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);
1175 if (!didit) {
1176 if (__CFAppleLanguages) {
1177 CFDataRef data;
1178 CFIndex length = strlen(__CFAppleLanguages);
1179 if (length > 0) {
1180 data = CFDataCreateWithBytesNoCopy(NULL, __CFAppleLanguages, length, kCFAllocatorNull);
1181 if (data) {
1182 __CFSetNastyFile(CFSTR("<plist command-line argument>"));
1183 userLanguages = CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL);
1184 CFRelease(data);
1185 }
1186 }
1187 }
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);
1194 }
1195 if (userLanguages && CFGetTypeID(userLanguages) != CFArrayGetTypeID()) {
1196 CFRelease(userLanguages);
1197 userLanguages = NULL;
1198 }
1199 didit = true;
1200 }
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);
1211 }
1212 if (languageAbbreviation) {
1213 CFArrayAppendValue(mutableUserLanguages, languageAbbreviation);
1214 CFRelease(languageAbbreviation);
1215 }
1216 result = (CFArrayRef)mutableUserLanguages;
1217 }
1218 #endif /* __MACOS8__ */
1219 if (!result && userLanguages) result = CFRetain(userLanguages);
1220 return result;
1221 }
1222
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;
1230 if (mainBundle) {
1231 languages = _CFBundleGetLanguageSearchList(mainBundle);
1232 if (languages) CFRetain(languages);
1233 }
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);
1239 } else {
1240 #if defined(__MACOS8__)
1241 language = GetScriptVariable(smSystemScript, smScriptLang);
1242 region = GetScriptManagerVariable(smRegionCode);
1243 #else
1244 language = 0;
1245 region = 0;
1246 #endif /* __MACOS8__ */
1247 }
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;
1253 }
1254
1255
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;
1268 #else
1269 Boolean isDir = false;
1270 #endif
1271
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);
1277
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));
1283 #endif
1284
1285 if (infoDict) {
1286 predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey);
1287 if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) != CFArrayGetTypeID()) {
1288 predefinedLocalizations = NULL;
1289 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleLocalizationsKey);
1290 }
1291 }
1292 predefinedLocalizationsRange = CFRangeMake(0, predefinedLocalizations ? CFArrayGetCount(predefinedLocalizations) : 0);
1293
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))) {
1302 #else
1303 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
1304 CFStringReplaceAll(cheapStr, tmpString);
1305 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, curLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
1306 #endif
1307 if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), curLangStr)) CFArrayAppendValue(lprojNames, curLangStr);
1308 foundOne = true;
1309 if (CFStringGetLength(curLangStr) <= 2) {
1310 CFRelease(cheapStr);
1311 CFRelease(tmpString);
1312 #if USE_GETDIRENTRIES
1313 CFRelease(contents);
1314 #endif
1315 return foundOne;
1316 }
1317 }
1318 }
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];
1323 }
1324 #endif // __CONSTANT_CFSTRINGS__
1325 if (foundOne && altLangStr) {
1326 CFRelease(cheapStr);
1327 CFRelease(tmpString);
1328 #if USE_GETDIRENTRIES
1329 CFRelease(contents);
1330 #endif
1331 return foundOne;
1332 }
1333 if (altLangStr) {
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))) {
1343 #else
1344 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
1345 CFStringReplaceAll(cheapStr, tmpString);
1346 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, altLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
1347 #endif
1348 if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), altLangStr)) CFArrayAppendValue(lprojNames, altLangStr);
1349 foundOne = true;
1350 CFRelease(cheapStr);
1351 CFRelease(tmpString);
1352 #if USE_GETDIRENTRIES
1353 CFRelease(contents);
1354 #endif
1355 return foundOne;
1356 }
1357 }
1358 }
1359 #if USE_GETDIRENTRIES
1360 if (!foundOne) {
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;
1365 }
1366 if (!hasLocalizations) {
1367 CFRelease(cheapStr);
1368 CFRelease(tmpString);
1369 CFRelease(contents);
1370 return foundOne;
1371 }
1372 }
1373 #endif
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))) {
1384 #else
1385 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
1386 CFStringReplaceAll(cheapStr, tmpString);
1387 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, modifiedLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
1388 #endif
1389 if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), modifiedLangStr)) CFArrayAppendValue(lprojNames, modifiedLangStr);
1390 foundOne = true;
1391 }
1392 }
1393 }
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))) {
1404 #else
1405 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
1406 CFStringReplaceAll(cheapStr, tmpString);
1407 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageAbbreviation)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
1408 #endif
1409 if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), languageAbbreviation)) CFArrayAppendValue(lprojNames, languageAbbreviation);
1410 foundOne = true;
1411 }
1412 }
1413 }
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))) {
1424 #else
1425 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
1426 CFStringReplaceAll(cheapStr, tmpString);
1427 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageName)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
1428 #endif
1429 if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), languageName)) CFArrayAppendValue(lprojNames, languageName);
1430 foundOne = true;
1431 }
1432 }
1433 }
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);
1444 #endif
1445
1446 return foundOne;
1447 }
1448
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()) {
1462 SInt32 val = 0;
1463 if (CFNumberGetValue((CFNumberRef)allowMixedValue, kCFNumberSInt32Type, &val)) allowMixed = (val != 0);
1464 }
1465 }
1466 examinedMain = true;
1467 }
1468 return allowMixed;
1469 }
1470
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;
1477 CFIndex idx;
1478 CFIndex count;
1479 CFStringRef resourcesPath;
1480 UniChar pathUniChars[CFMaxPathSize];
1481 CFIndex pathLen;
1482 CFStringRef curLangStr;
1483 Boolean foundOne = false;
1484
1485 CFArrayRef userLanguages;
1486
1487 // Init the one-time-only unichar buffers.
1488 _CFEnsureStaticBuffersInited();
1489
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);
1499
1500 // First check the main bundle.
1501 if (!CFBundleAllowMixedLocalizations()) {
1502 CFBundleRef mainBundle = CFBundleGetMainBundle();
1503 if (mainBundle) {
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);
1511 }
1512 }
1513 CFRelease(mainBundleURL);
1514 }
1515 }
1516
1517 if (!foundOne) {
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);
1524 }
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);
1528 }
1529 if (!foundOne) {
1530 foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, CFSTR("en_US"), lprojNames);
1531 }
1532 if (userLanguages != NULL) {
1533 CFRelease(userLanguages);
1534 }
1535 }
1536 }
1537
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;
1543 CFIndex idx;
1544
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);
1548 foundOne = true;
1549 if (range.length == 1 || CFStringGetLength(curLangStr) <= 2) return foundOne;
1550 }
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];
1556 }
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);
1561 foundOne = true;
1562 return foundOne;
1563 }
1564 if (!altLangStr && (modifiedLangStr = _CFBundleCopyModifiedLocalization(curLangStr))) {
1565 if (CFArrayContainsValue(array, range, modifiedLangStr)) {
1566 if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), modifiedLangStr)) CFArrayAppendValue(lprojNames, modifiedLangStr);
1567 foundOne = true;
1568 }
1569 }
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);
1573 foundOne = true;
1574 }
1575 }
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);
1579 foundOne = true;
1580 }
1581 }
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);
1587
1588 return foundOne;
1589 }
1590
1591 static CFArrayRef _CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray, Boolean considerMain) {
1592 CFMutableArrayRef lprojNames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1593 Boolean foundOne = false, releasePrefArray = false;
1594 CFIndex idx, count;
1595
1596 if (considerMain && !CFBundleAllowMixedLocalizations()) {
1597 CFBundleRef mainBundle = CFBundleGetMainBundle();
1598 if (mainBundle) {
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);
1603 }
1604 }
1605 }
1606 if (!foundOne) {
1607 if (!prefArray) {
1608 prefArray = _CFBundleCopyUserLanguages(true);
1609 if (prefArray) releasePrefArray = true;
1610 }
1611 count = (prefArray ? CFArrayGetCount(prefArray) : 0);
1612 for (idx = 0; !foundOne && idx < count; idx++) {
1613 foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(prefArray, idx), lprojNames);
1614 }
1615 // use U.S. English as backstop
1616 if (!foundOne) {
1617 foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFSTR("en_US"), lprojNames);
1618 }
1619 // use random entry as backstop
1620 if (!foundOne && CFArrayGetCount(lprojNames) > 0) {
1621 foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(locArray, 0), lprojNames);
1622 }
1623 }
1624 if (CFArrayGetCount(lprojNames) == 0) {
1625 // Total backstop behavior to avoid having an empty array.
1626 CFArrayAppendValue(lprojNames, CFSTR("en"));
1627 }
1628 if (releasePrefArray) {
1629 CFRelease(prefArray);
1630 }
1631 return lprojNames;
1632 }
1633
1634 CF_EXPORT CFArrayRef CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray) {return _CFBundleCopyLocalizationsForPreferences(locArray, prefArray, false);}
1635
1636 CF_EXPORT CFArrayRef CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locArray) {return _CFBundleCopyLocalizationsForPreferences(locArray, NULL, true);}
1637
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);
1645 }
1646 if (devLang != NULL && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) devLang = NULL;
1647
1648 _CFBundleAddPreferredLprojNamesInDirectory(alloc, url, localVersion, infoDict, langs, devLang);
1649
1650 if (devLang != NULL && CFArrayGetFirstIndexOfValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), devLang) < 0) {
1651 CFArrayAppendValue(langs, devLang);
1652 }
1653 if (CFArrayGetCount(langs) == 0) {
1654 // Total backstop behavior to avoid having an empty array.
1655 CFArrayAppendValue(langs, CFSTR("en"));
1656 }
1657 if (infoDict != NULL) {
1658 CFRelease(infoDict);
1659 }
1660 if (version) {
1661 *version = localVersion;
1662 }
1663 return langs;
1664 }
1665
1666 CF_EXPORT Boolean _CFBundleURLLooksLikeBundle(CFURLRef url) {
1667 Boolean result = false;
1668 CFBundleRef bundle = _CFBundleCreateIfLooksLikeBundle(NULL, url);
1669 if (bundle) {
1670 result = true;
1671 CFRelease(bundle);
1672 }
1673 return result;
1674 }
1675
1676 // Note that subDirName is expected to be the string for a URL
1677 CF_INLINE Boolean _CFBundleURLHasSubDir(CFURLRef url, CFStringRef subDirName) {
1678 CFURLRef dirURL;
1679 Boolean isDir, result = false;
1680
1681 dirURL = CFURLCreateWithString(NULL, subDirName, url);
1682 if (dirURL != NULL) {
1683 if (_CFIsResourceAtURL(dirURL, &isDir) && isDir) {
1684 result = true;
1685 }
1686 CFRelease(dirURL);
1687 }
1688 return result;
1689 }
1690
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;
1709 } else {
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;
1713 }
1714 CFRelease(contents);
1715 CFRelease(directoryPath);
1716 CFRelease(absoluteURL);
1717 #endif
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;
1723 } else {
1724 if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) localVersion = 2;
1725 else if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0;
1726 else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1;
1727 }
1728 }
1729 if (version) *version = localVersion;
1730 return !(localVersion == 3);
1731 }
1732
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;
1737
1738 if (CFURLGetFileSystemRepresentation(url, true, buff, CFMaxPathSize)) {
1739 CFURLRef newURL = CFURLCreateFromFileSystemRepresentation(alloc, buff, strlen(buff), true);
1740 if (NULL == newURL) newURL = CFRetain(url);
1741
1742 if (!_CFBundleURLLooksLikeBundleVersion(newURL, &localVersion)) {
1743 // version 3 is for flattened pseudo-bundles with no Contents, Support Files, or Resources directories
1744 localVersion = 3;
1745 }
1746 dict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(alloc, newURL, localVersion);
1747 CFRelease(newURL);
1748 }
1749 if (version) *version = localVersion;
1750 return dict;
1751 }
1752
1753 __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc, CFURLRef url, uint8_t version) {
1754 CFDictionaryRef result = NULL;
1755 if (url != NULL) {
1756 CFURLRef infoURL = NULL;
1757 CFDataRef infoData = NULL;
1758 UniChar buff[CFMaxPathSize];
1759 CFIndex len;
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);
1768 #endif
1769
1770 _CFEnsureStaticBuffersInited();
1771
1772 if (0 == version) {
1773 #if USE_GETDIRENTRIES
1774 directoryURL = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase0, url);
1775 #endif
1776 infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension0;
1777 infoURLFromBase = _CFBundleInfoURLFromBase0;
1778 } else if (1 == version) {
1779 #if USE_GETDIRENTRIES
1780 directoryURL = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase1, url);
1781 #endif
1782 infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension1;
1783 infoURLFromBase = _CFBundleInfoURLFromBase1;
1784 } else if (2 == version) {
1785 #if USE_GETDIRENTRIES
1786 directoryURL = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase2, url);
1787 #endif
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
1793 if (posixPath) {
1794 if (!(CFStringHasSuffix(posixPath, _CFBundleSupportFilesDirectoryName1) || CFStringHasSuffix(posixPath, _CFBundleSupportFilesDirectoryName2) || CFStringHasSuffix(posixPath, _CFBundleResourcesDirectoryName))) {
1795 #if USE_GETDIRENTRIES
1796 directoryURL = CFRetain(url);
1797 #endif
1798 infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension3;
1799 infoURLFromBase = _CFBundleInfoURLFromBase3;
1800 }
1801 CFRelease(posixPath);
1802 }
1803 }
1804 #if USE_GETDIRENTRIES
1805 if (directoryURL) {
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);
1813 }
1814 #endif
1815
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
1826 if (contents) {
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;
1834 }
1835 }
1836 #endif
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);
1840 if (!infoData) {
1841 // Check for global Info.plist
1842 CFRelease(infoURL);
1843 infoURL = CFURLCreateWithString(alloc, infoURLFromBase, url);
1844 #if USE_GETDIRENTRIES
1845 if (contents) {
1846 CFIndex idx;
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;
1850 }
1851 }
1852 #endif
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"));
1855 }
1856
1857 if (infoData) {
1858 result = CFPropertyListCreateFromXMLData(alloc, infoData, kCFPropertyListMutableContainers, NULL);
1859 if (result) {
1860 if (CFDictionaryGetTypeID() == CFGetTypeID(result)) {
1861 CFDictionarySetValue((CFMutableDictionaryRef)result, _kCFBundleInfoPlistURLKey, infoURL);
1862 } else {
1863 CFRelease(result);
1864 result = NULL;
1865 }
1866 }
1867 CFRelease(infoData);
1868 }
1869 if (!result) {
1870 result = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1871 }
1872
1873 CFRelease(infoURL);
1874 #if USE_GETDIRENTRIES
1875 if (contents) CFRelease(contents);
1876 #endif
1877 }
1878 return result;
1879 }
1880
1881 static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorRef alloc, CFURLRef url, CFDictionaryRef infoDict, UInt32 *packageType, UInt32 *packageCreator) {
1882 Boolean retVal = false, hasType = false, hasCreator = false, releaseInfoDict = false;
1883 CFURLRef tempURL;
1884 CFDataRef pkgInfoData = NULL;
1885
1886 // Check for a "real" new bundle
1887 tempURL = CFURLCreateWithString(alloc, _CFBundlePkgInfoURLFromBase2, url);
1888 CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL);
1889 CFRelease(tempURL);
1890 if (pkgInfoData == NULL) {
1891 tempURL = CFURLCreateWithString(alloc, _CFBundlePkgInfoURLFromBase1, url);
1892 CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL);
1893 CFRelease(tempURL);
1894 }
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);
1899 CFRelease(tempURL);
1900 }
1901
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.
1905
1906 if ((pkgInfoData != NULL) && (CFDataGetLength(pkgInfoData) >= (int)(sizeof(UInt32) * 2))) {
1907 UInt32 *pkgInfo = (UInt32 *)CFDataGetBytePtr(pkgInfoData);
1908
1909 if (packageType != NULL) {
1910 *packageType = CFSwapInt32BigToHost(pkgInfo[0]);
1911 }
1912 if (packageCreator != NULL) {
1913 *packageCreator = CFSwapInt32BigToHost(pkgInfo[1]);
1914 }
1915 retVal = hasType = hasCreator = true;
1916 }
1917 if (pkgInfoData != NULL) CFRelease(pkgInfoData);
1918 if (!retVal) {
1919 if (!infoDict) {
1920 infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, NULL);
1921 releaseInfoDict = true;
1922 }
1923 if (infoDict) {
1924 CFStringRef typeString = CFDictionaryGetValue(infoDict, _kCFBundlePackageTypeKey), creatorString = CFDictionaryGetValue(infoDict, _kCFBundleSignatureKey);
1925 UInt32 tmp;
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);
1930 }
1931 retVal = hasType = true;
1932 }
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);
1936 }
1937 retVal = hasCreator = true;
1938 }
1939 if (releaseInfoDict) CFRelease(infoDict);
1940 }
1941 }
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; // '????'
1947 }
1948 if (packageType != NULL && !hasType) {
1949 CFStringRef urlStr;
1950 UniChar buff[CFMaxPathSize];
1951 CFIndex strLen, startOfExtension;
1952 CFURLRef absoluteURL;
1953
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);
1961 CFRelease(urlStr);
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)'/'))) {
1964 // This is an app
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'
1978 } else {
1979 // Default to BNDL for generic bundle
1980 *packageType = 0x424e444c; // 'BNDL'
1981 }
1982 }
1983 retVal = true;
1984 }
1985 }
1986 return retVal;
1987 }
1988
1989 CF_EXPORT Boolean _CFBundleGetPackageInfoInDirectory(CFAllocatorRef alloc, CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {return _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(alloc, url, NULL, packageType, packageCreator);}
1990
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'
1996 }
1997 if (packageCreator != NULL) {
1998 *packageCreator = 0x3f3f3f3f; // '????'
1999 }
2000 }
2001 if (bundleURL) CFRelease(bundleURL);
2002 }
2003
2004 CF_EXPORT Boolean CFBundleGetPackageInfoInDirectory(CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {return _CFBundleGetPackageInfoInDirectory(NULL, url, packageType, packageCreator);}
2005
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");
2021 #else
2022 #warning CFBundle: Unknown architecture
2023 return CFSTR("Other");
2024 #endif
2025 }
2026
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");
2042 #else
2043 #warning CFBundle: Unknown architecture
2044 return CFSTR("Other");
2045 #endif
2046 }
2047
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");
2063 #else
2064 #warning CFBundle: Unknown architecture
2065 return CFSTR("Other");
2066 #endif
2067 }
2068
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");
2084 #else
2085 #warning CFBundle: Unknown architecture
2086 return CFSTR("Other");
2087 #endif
2088 }
2089
2090 __private_extern__ CFArrayRef _CFBundleCopyBundleRegionsArray(CFBundleRef bundle) {return CFBundleCopyBundleLocalizations(bundle);}
2091
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;
2100 CFIndex idx;
2101 #else
2102 CFArrayRef urls = ((_CFBundleLayoutVersion(bundle) != 4) ? _CFContentsOfDirectory(CFGetAllocator(bundle), NULL, NULL, resourcesURL, _CFBundleLprojExtension) : NULL);
2103 #endif
2104 CFArrayRef predefinedLocalizations = NULL;
2105 CFMutableArrayRef result = NULL;
2106
2107 if (infoDict) {
2108 predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey);
2109 if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) != CFArrayGetTypeID()) {
2110 predefinedLocalizations = NULL;
2111 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleLocalizationsKey);
2112 }
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));
2117 }
2118 }
2119
2120 #if USE_GETDIRENTRIES
2121 if (resourcesURL) {
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);
2133 }
2134 }
2135 CFRelease(contents);
2136 CFRelease(directoryPath);
2137 CFRelease(absoluteURL);
2138 }
2139 #else
2140 if (urls) {
2141 CFIndex i, c = CFArrayGetCount(urls);
2142 CFURLRef curURL, curAbsoluteURL;
2143 CFStringRef curStr, regionStr;
2144 UniChar buff[CFMaxPathSize];
2145 CFIndex strLen, startOfLastPathComponent, regionLen;
2146
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);
2156
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);
2162 CFRelease(curStr);
2163 }
2164 CFRelease(urls);
2165 }
2166 #endif
2167
2168 if (!result) {
2169 CFStringRef developmentLocalization = CFBundleGetDevelopmentRegion(bundle);
2170 if (developmentLocalization) {
2171 result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks);
2172 CFArrayAppendValue(result, developmentLocalization);
2173 }
2174 }
2175 if (resourcesURL) CFRelease(resourcesURL);
2176
2177 return result;
2178 }
2179
2180
2181 CF_EXPORT CFDictionaryRef CFBundleCopyInfoDictionaryForURL(CFURLRef url) {
2182 CFDictionaryRef result = NULL;
2183 Boolean isDir;
2184 if (_CFIsResourceAtURL(url, &isDir)) {
2185 if (isDir) {
2186 result = _CFBundleCopyInfoDictionaryInDirectory(NULL, url, NULL);
2187 } else {
2188 result = _CFBundleCopyInfoDictionaryInExecutable(url);
2189 }
2190 }
2191 return result;
2192 }
2193
2194 CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) {
2195 CFArrayRef result = NULL;
2196 CFBundleRef bundle = CFBundleCreate(NULL, url);
2197 CFStringRef devLang = NULL;
2198 if (bundle) {
2199 result = CFBundleCopyBundleLocalizations(bundle);
2200 CFRelease(bundle);
2201 } else {
2202 CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInExecutable(url);
2203 if (infoDict) {
2204 CFArrayRef predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey);
2205 if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) == CFArrayGetTypeID()) {
2206 result = CFRetain(predefinedLocalizations);
2207 }
2208 if (!result) {
2209 devLang = CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey);
2210 if (devLang != NULL && (CFGetTypeID(devLang) == CFStringGetTypeID() && CFStringGetLength(devLang) > 0)) {
2211 result = CFArrayCreate(NULL, (const void **)&devLang, 1, &kCFTypeArrayCallBacks);
2212 }
2213 }
2214 CFRelease(infoDict);
2215 }
2216 }
2217 return result;
2218 }