]> git.saurik.com Git - apple/cf.git/blob - PlugIn.subproj/CFBundle_Resources.c
CF-299.32.tar.gz
[apple/cf.git] / PlugIn.subproj / CFBundle_Resources.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* CFBundle_Resources.c
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Doug Davidson
28 */
29
30 #if defined(__MACOS8__) || defined(__WIN32__)
31 #define USE_GETDIRENTRIES 0
32 #else
33 #define USE_GETDIRENTRIES 1
34 #endif
35 #define GETDIRENTRIES_CACHE_CAPACITY 100
36
37 #include "CFBundle_Internal.h"
38 #include <CoreFoundation/CFURLAccess.h>
39 #include <CoreFoundation/CFPropertyList.h>
40 #include <CoreFoundation/CFByteOrder.h>
41 #include <CoreFoundation/CFNumber.h>
42 #include <string.h>
43 #include "CFInternal.h"
44 #include "CFPriv.h"
45
46 #if defined(__MACOS8__)
47 /* MacOS8 Headers */
48 #include <Script.h>
49 #include <stat.h>
50 #include <Files.h>
51 #include <Resources.h>
52 #include <CodeFragments.h>
53 #include <Errors.h>
54 #include <Gestalt.h>
55 #else
56 /* Unixy & Windows Headers */
57 #include <sys/stat.h>
58 #include <fcntl.h>
59 #include <unistd.h>
60 #include <stdio.h>
61 #if USE_GETDIRENTRIES
62 #include <dirent.h>
63 #endif
64 #endif
65
66
67
68 // All new-style bundles will have these extensions.
69 CF_INLINE CFStringRef _CFGetPlatformName(void) {
70 // MF:!!! This used to be based on NSInterfaceStyle, not hard-wired by compiler.
71 #if defined(__WIN32__)
72 return _CFBundleWindowsPlatformName;
73 #elif defined(__MACOS8__)
74 return _CFBundleMacOS8PlatformName;
75 #elif defined (__MACH__)
76 return _CFBundleMacOSXPlatformName;
77 #elif defined(__svr4__)
78 return _CFBundleSolarisPlatformName;
79 #elif defined(__hpux__)
80 return _CFBundleHPUXPlatformName;
81 #elif defined(__LINUX__)
82 return _CFBundleLinuxPlatformName;
83 #elif defined(__FREEBSD__)
84 return _CFBundleFreeBSDPlatformName;
85 #else
86 return CFSTR("");
87 #endif
88 }
89
90 CF_INLINE CFStringRef _CFGetAlternatePlatformName(void) {
91 #if defined (__MACH__)
92 return _CFBundleAlternateMacOSXPlatformName;
93 #elif defined(__MACOS8__)
94 return _CFBundleAlternateMacOS8PlatformName;
95 #else
96 return CFSTR("");
97 #endif
98 }
99
100 static CFSpinLock_t CFBundleResourceGlobalDataLock = 0;
101 static UniChar *_AppSupportUniChars1 = NULL;
102 static CFIndex _AppSupportLen1 = 0;
103 static UniChar *_AppSupportUniChars2 = NULL;
104 static CFIndex _AppSupportLen2 = 0;
105 static UniChar *_ResourcesUniChars = NULL;
106 static CFIndex _ResourcesLen = 0;
107 static UniChar *_PlatformUniChars = NULL;
108 static CFIndex _PlatformLen = 0;
109 static UniChar *_AlternatePlatformUniChars = NULL;
110 static CFIndex _AlternatePlatformLen = 0;
111 static UniChar *_LprojUniChars = NULL;
112 static CFIndex _LprojLen = 0;
113 static UniChar *_GlobalResourcesUniChars = NULL;
114 static CFIndex _GlobalResourcesLen = 0;
115 static UniChar *_InfoExtensionUniChars = NULL;
116 static CFIndex _InfoExtensionLen = 0;
117
118 static void _CFBundleInitStaticUniCharBuffers(void) {
119 CFStringRef appSupportStr1 = _CFBundleSupportFilesDirectoryName1;
120 CFStringRef appSupportStr2 = _CFBundleSupportFilesDirectoryName2;
121 CFStringRef resourcesStr = _CFBundleResourcesDirectoryName;
122 CFStringRef platformStr = _CFGetPlatformName();
123 CFStringRef alternatePlatformStr = _CFGetAlternatePlatformName();
124 CFStringRef lprojStr = _CFBundleLprojExtension;
125 CFStringRef globalResourcesStr = _CFBundleNonLocalizedResourcesDirectoryName;
126 CFStringRef infoExtensionStr = _CFBundleInfoExtension;
127
128 CFAllocatorRef alloc = __CFGetDefaultAllocator();
129
130 _AppSupportLen1 = CFStringGetLength(appSupportStr1);
131 _AppSupportLen2 = CFStringGetLength(appSupportStr2);
132 _ResourcesLen = CFStringGetLength(resourcesStr);
133 _PlatformLen = CFStringGetLength(platformStr);
134 _AlternatePlatformLen = CFStringGetLength(alternatePlatformStr);
135 _LprojLen = CFStringGetLength(lprojStr);
136 _GlobalResourcesLen = CFStringGetLength(globalResourcesStr);
137 _InfoExtensionLen = CFStringGetLength(infoExtensionStr);
138
139 _AppSupportUniChars1 = CFAllocatorAllocate(alloc, sizeof(UniChar) * (_AppSupportLen1 + _AppSupportLen2 + _ResourcesLen + _PlatformLen + _AlternatePlatformLen + _LprojLen + _GlobalResourcesLen + _InfoExtensionLen), 0);
140 _AppSupportUniChars2 = _AppSupportUniChars1 + _AppSupportLen1;
141 _ResourcesUniChars = _AppSupportUniChars2 + _AppSupportLen2;
142 _PlatformUniChars = _ResourcesUniChars + _ResourcesLen;
143 _AlternatePlatformUniChars = _PlatformUniChars + _PlatformLen;
144 _LprojUniChars = _AlternatePlatformUniChars + _AlternatePlatformLen;
145 _GlobalResourcesUniChars = _LprojUniChars + _LprojLen;
146 _InfoExtensionUniChars = _GlobalResourcesUniChars + _GlobalResourcesLen;
147
148 if (_AppSupportLen1 > 0) {
149 CFStringGetCharacters(appSupportStr1, CFRangeMake(0, _AppSupportLen1), _AppSupportUniChars1);
150 }
151 if (_AppSupportLen2 > 0) {
152 CFStringGetCharacters(appSupportStr2, CFRangeMake(0, _AppSupportLen2), _AppSupportUniChars2);
153 }
154 if (_ResourcesLen > 0) {
155 CFStringGetCharacters(resourcesStr, CFRangeMake(0, _ResourcesLen), _ResourcesUniChars);
156 }
157 if (_PlatformLen > 0) {
158 CFStringGetCharacters(platformStr, CFRangeMake(0, _PlatformLen), _PlatformUniChars);
159 }
160 if (_AlternatePlatformLen > 0) {
161 CFStringGetCharacters(alternatePlatformStr, CFRangeMake(0, _AlternatePlatformLen), _AlternatePlatformUniChars);
162 }
163 if (_LprojLen > 0) {
164 CFStringGetCharacters(lprojStr, CFRangeMake(0, _LprojLen), _LprojUniChars);
165 }
166 if (_GlobalResourcesLen > 0) {
167 CFStringGetCharacters(globalResourcesStr, CFRangeMake(0, _GlobalResourcesLen), _GlobalResourcesUniChars);
168 }
169 if (_InfoExtensionLen > 0) {
170 CFStringGetCharacters(infoExtensionStr, CFRangeMake(0, _InfoExtensionLen), _InfoExtensionUniChars);
171 }
172 }
173
174 CF_INLINE void _CFEnsureStaticBuffersInited(void) {
175 __CFSpinLock(&CFBundleResourceGlobalDataLock);
176 if (_AppSupportUniChars1 == NULL) {
177 _CFBundleInitStaticUniCharBuffers();
178 }
179 __CFSpinUnlock(&CFBundleResourceGlobalDataLock);
180 }
181
182 #if USE_GETDIRENTRIES
183
184 static CFMutableDictionaryRef contentsCache = NULL;
185 static CFMutableDictionaryRef directoryContentsCache = NULL;
186
187 static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, Boolean directoriesOnly) {
188 CFArrayRef result = NULL;
189
190 __CFSpinLock(&CFBundleResourceGlobalDataLock);
191 if (directoriesOnly) {
192 if (directoryContentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(directoryContentsCache, path);
193 } else {
194 if (contentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(contentsCache, path);
195 }
196 if (result) CFRetain(result);
197 __CFSpinUnlock(&CFBundleResourceGlobalDataLock);
198
199 if (!result) {
200 char cpathBuff[CFMaxPathSize], dirge[8192];
201 CFIndex cpathLen = 0;
202 int fd = -1, numread;
203 long basep = 0;
204 CFMutableArrayRef contents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), directoryContents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
205 CFStringRef name;
206
207 if (_CFStringGetFileSystemRepresentation(path, cpathBuff, CFMaxPathSize)) {
208 cpathLen = strlen(cpathBuff);
209 fd = open(cpathBuff, O_RDONLY, 0777);
210 }
211 if (fd >= 0) {
212 while ((numread = getdirentries(fd, dirge, sizeof(dirge), &basep)) > 0) {
213 struct dirent *dent;
214 for (dent = (struct dirent *)dirge; dent < (struct dirent *)(dirge + numread); dent = (struct dirent *)((char *)dent + dent->d_reclen)) {
215 CFIndex nameLen = strlen(dent->d_name);
216 if (0 == dent->d_fileno || (dent->d_name[0] == '.' && (nameLen == 1 || (nameLen == 2 && dent->d_name[1] == '.')))) continue;
217 name = CFStringCreateWithCString(NULL, dent->d_name, CFStringFileSystemEncoding());
218 if (NULL != name) {
219 CFArrayAppendValue(contents, name);
220 if (dent->d_type == DT_DIR) {
221 CFArrayAppendValue(directoryContents, name);
222 } else if (dent->d_type == DT_UNKNOWN) {
223 struct stat statBuf;
224 cpathBuff[cpathLen] = '/';
225 strncpy(cpathBuff + cpathLen + 1, dent->d_name, nameLen);
226 cpathBuff[cpathLen + nameLen + 1] = '\0';
227 if (stat(cpathBuff, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFDIR) CFArrayAppendValue(directoryContents, name);
228 cpathBuff[cpathLen] = '\0';
229 }
230 CFRelease(name);
231 }
232 }
233 }
234 close(fd);
235 }
236
237 __CFSpinLock(&CFBundleResourceGlobalDataLock);
238 if (!contentsCache) contentsCache = CFDictionaryCreateMutable(NULL, GETDIRENTRIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
239 if (GETDIRENTRIES_CACHE_CAPACITY == CFDictionaryGetCount(contentsCache)) CFDictionaryRemoveAllValues(contentsCache);
240 CFDictionaryAddValue(contentsCache, path, contents);
241
242 if (!directoryContentsCache) directoryContentsCache = CFDictionaryCreateMutable(NULL, GETDIRENTRIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
243 if (GETDIRENTRIES_CACHE_CAPACITY == CFDictionaryGetCount(directoryContentsCache)) CFDictionaryRemoveAllValues(directoryContentsCache);
244 CFDictionaryAddValue(directoryContentsCache, path, directoryContents);
245
246 result = CFRetain(directoriesOnly ? directoryContents : contents);
247 CFRelease(contents);
248 CFRelease(directoryContents);
249 __CFSpinUnlock(&CFBundleResourceGlobalDataLock);
250 }
251
252 return result;
253 }
254
255 static void _CFBundleFlushContentsCaches(void) {
256 __CFSpinLock(&CFBundleResourceGlobalDataLock);
257 if (contentsCache) CFDictionaryRemoveAllValues(contentsCache);
258 if (directoryContentsCache) CFDictionaryRemoveAllValues(directoryContentsCache);
259 __CFSpinUnlock(&CFBundleResourceGlobalDataLock);
260 }
261
262 #endif /* USE_GETDIRENTRIES */
263
264 CF_EXPORT void _CFBundleFlushCaches(void) {
265 #if USE_GETDIRENTRIES
266 _CFBundleFlushContentsCaches();
267 #endif /* USE_GETDIRENTRIES */
268 }
269
270 __private_extern__ Boolean _CFIsResourceAtURL(CFURLRef url, Boolean *isDir) {
271 Boolean exists;
272 SInt32 mode;
273 if (_CFGetFileProperties(NULL, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) {
274 if (isDir) {
275 *isDir = ((exists && ((mode & S_IFMT) == S_IFDIR)) ? true : false);
276 }
277 #if defined(__MACOS8__)
278 return (exists);
279 #else
280 return (exists && (mode & 0444));
281 #endif /* __MACOS8__ */
282 } else {
283 return false;
284 }
285 }
286
287 __private_extern__ Boolean _CFIsResourceAtPath(CFStringRef path, Boolean *isDir) {
288 Boolean result = false;
289 CFURLRef url = CFURLCreateWithFileSystemPath(CFGetAllocator(path), path, PLATFORM_PATH_STYLE, false);
290 if (url != NULL) {
291 result = _CFIsResourceAtURL(url, isDir);
292 CFRelease(url);
293 }
294 return result;
295 }
296
297 static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef result, UniChar *pathUniChars, CFIndex pathLen, UniChar *nameUniChars, CFIndex nameLen, UniChar *typeUniChars, CFIndex typeLen, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, uint8_t version) {
298 // pathUniChars is the full path to the directory we are searching.
299 // nameUniChars is what we are looking for.
300 // typeUniChars is the type we are looking for.
301 // platformUniChars is the platform name.
302 // cheapStr is available for our use for whatever we want.
303 // URLs for found resources get added to result.
304 CFIndex savedPathLen;
305 Boolean platformGenericFound = false, platformSpecificFound = false;
306 Boolean platformGenericIsDir = false, platformSpecificIsDir = false;
307 CFStringRef platformGenericStr = NULL;
308
309 #if USE_GETDIRENTRIES
310 CFIndex dirPathLen = pathLen;
311 CFArrayRef contents, directoryContents;
312 CFRange contentsRange, directoryContentsRange;
313
314 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, dirPathLen, dirPathLen);
315 CFStringReplaceAll(cheapStr, tmpString);
316 //fprintf(stderr, "looking in ");CFShow(cheapStr);
317 contents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, false);
318 contentsRange = CFRangeMake(0, CFArrayGetCount(contents));
319 directoryContents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, true);
320 directoryContentsRange = CFRangeMake(0, CFArrayGetCount(directoryContents));
321 #endif
322
323 if (nameLen > 0) {
324 _CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, nameUniChars, nameLen);
325 }
326 // Save length with just name appended.
327 savedPathLen = pathLen;
328
329 // Check platform generic
330 if (typeLen > 0) {
331 _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen);
332 }
333 #if USE_GETDIRENTRIES
334 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen + 1, pathLen - dirPathLen - 1, pathLen - dirPathLen - 1);
335 CFStringReplaceAll(cheapStr, tmpString);
336 platformGenericFound = CFArrayContainsValue(contents, contentsRange, cheapStr);
337 platformGenericIsDir = CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr);
338 //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformGenericFound) fprintf(stderr, "found it\n"); if (platformGenericIsDir) fprintf(stderr, "a directory\n");
339 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
340 CFStringReplaceAll(cheapStr, tmpString);
341 #else
342 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
343 CFStringReplaceAll(cheapStr, tmpString);
344 platformGenericFound = _CFIsResourceAtPath(cheapStr, &platformGenericIsDir);
345 #endif
346
347 // Check for platform specific.
348 if (platformGenericFound) {
349 platformGenericStr = CFStringCreateCopy(alloc, cheapStr);
350 if (!platformSpecificFound && (_PlatformLen > 0)) {
351 pathLen = savedPathLen;
352 pathUniChars[pathLen++] = (UniChar)'-';
353 memmove(pathUniChars + pathLen, _PlatformUniChars, _PlatformLen * sizeof(UniChar));
354 pathLen += _PlatformLen;
355 if (typeLen > 0) {
356 _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen);
357 }
358 #if USE_GETDIRENTRIES
359 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen + 1, pathLen - dirPathLen - 1, pathLen - dirPathLen - 1);
360 CFStringReplaceAll(cheapStr, tmpString);
361 platformSpecificFound = CFArrayContainsValue(contents, contentsRange, cheapStr);
362 platformSpecificIsDir = CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr);
363 //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformSpecificFound) fprintf(stderr, "found it\n"); if (platformSpecificIsDir) fprintf(stderr, "a directory\n");
364 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
365 CFStringReplaceAll(cheapStr, tmpString);
366 #else
367 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
368 CFStringReplaceAll(cheapStr, tmpString);
369 platformSpecificFound = _CFIsResourceAtPath(cheapStr, &platformSpecificIsDir);
370 #endif
371 }
372 }
373 if (platformSpecificFound) {
374 CFURLRef url = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, platformSpecificIsDir);
375 CFArrayAppendValue(result, url);
376 CFRelease(url);
377 } else if (platformGenericFound) {
378 CFURLRef url = CFURLCreateWithFileSystemPath(alloc, ((platformGenericStr != NULL) ? platformGenericStr : cheapStr), PLATFORM_PATH_STYLE, platformGenericIsDir);
379 CFArrayAppendValue(result, url);
380 CFRelease(url);
381 }
382 if (platformGenericStr != NULL) {
383 CFRelease(platformGenericStr);
384 }
385 #if USE_GETDIRENTRIES
386 CFRelease(contents);
387 CFRelease(directoryContents);
388 #endif
389 }
390
391 static void _CFFindBundleResourcesInRawDir(CFAllocatorRef alloc, UniChar *workingUniChars, CFIndex workingLen, UniChar *nameUniChars, CFIndex nameLen, CFArrayRef resTypes, CFIndex limit, uint8_t version, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, CFMutableArrayRef result) {
392
393 if (nameLen > 0) {
394 // If we have a resName, just call the search API. We may have to loop over the resTypes.
395 if (!resTypes) {
396 _CFSearchBundleDirectory(alloc, result, workingUniChars, workingLen, nameUniChars, nameLen, NULL, 0, cheapStr, tmpString, version);
397 } else {
398 CFIndex i, c = CFArrayGetCount(resTypes);
399 for (i=0; i<c; i++) {
400 CFStringRef curType = (CFStringRef)CFArrayGetValueAtIndex(resTypes, i);
401 CFIndex typeLen = CFStringGetLength(curType);
402 #if defined(__MACOS8__) || defined(__WIN32__)
403 UniChar *typeChars = CFAllocatorAllocate(alloc, sizeof(UniChar) * typeLen, 0);
404 if (typeChars) {
405 #else
406 UniChar typeChars[typeLen];
407 #endif /* __MACOS8__ */
408 CFStringGetCharacters(curType, CFRangeMake(0, typeLen), typeChars);
409 _CFSearchBundleDirectory(alloc, result, workingUniChars, workingLen, nameUniChars, nameLen, typeChars, typeLen, cheapStr, tmpString, version);
410 if (limit <= CFArrayGetCount(result)) {
411 break;
412 }
413 #if defined(__MACOS8__) || defined(__WIN32__)
414 CFAllocatorDeallocate(alloc, typeChars);
415 }
416 #endif /* __MACOS8__ */
417 }
418 }
419 } else {
420 // If we have no resName, do it by hand. We may have to loop over the resTypes.
421 unsigned char cpathBuff[CFMaxPathSize];
422 CFIndex cpathLen;
423 CFMutableArrayRef children;
424
425 CFStringSetExternalCharactersNoCopy(tmpString, workingUniChars, workingLen, workingLen);
426 if (!_CFStringGetFileSystemRepresentation(tmpString, cpathBuff, CFMaxPathSize)) return;
427 cpathLen = strlen(cpathBuff);
428
429 if (!resTypes) {
430 children = _CFContentsOfDirectory(alloc, cpathBuff, NULL, NULL, NULL);
431 if (children) {
432 CFIndex childIndex, childCount = CFArrayGetCount(children);
433 for (childIndex = 0; childIndex < childCount; childIndex++) {
434 CFArrayAppendValue(result, CFArrayGetValueAtIndex(children, childIndex));
435 }
436 CFRelease(children);
437 }
438 } else {
439 CFIndex i, c = CFArrayGetCount(resTypes);
440 for (i=0; i<c; i++) {
441 CFStringRef curType = (CFStringRef)CFArrayGetValueAtIndex(resTypes, i);
442
443 children = _CFContentsOfDirectory(alloc, cpathBuff, NULL, NULL, curType);
444 if (children) {
445 CFIndex childIndex, childCount = CFArrayGetCount(children);
446 for (childIndex = 0; childIndex < childCount; childIndex++) {
447 CFArrayAppendValue(result, CFArrayGetValueAtIndex(children, childIndex));
448 }
449 CFRelease(children);
450 }
451 if (limit <= CFArrayGetCount(result)) {
452 break;
453 }
454 }
455 }
456 }
457 }
458
459 static void _CFFindBundleResourcesInResourcesDir(CFAllocatorRef alloc, UniChar *workingUniChars, CFIndex workingLen, UniChar *subDirUniChars, CFIndex subDirLen, CFArrayRef searchLanguages, UniChar *nameUniChars, CFIndex nameLen, CFArrayRef resTypes, CFIndex limit, uint8_t version, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, CFMutableArrayRef result) {
460 CFIndex savedWorkingLen = workingLen;
461
462 // Look directly in the directory specified in workingUniChars. as if it is a Resources directory.
463 if (1 == version) {
464 // Add the non-localized resource directory.
465 _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _GlobalResourcesUniChars, _GlobalResourcesLen);
466 if (subDirLen > 0) {
467 _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen);
468 }
469 _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
470
471 // Strip the non-localized resource directory.
472 workingLen = savedWorkingLen;
473 }
474 if (CFArrayGetCount(result) < limit) {
475 if (subDirLen > 0) {
476 _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen);
477 }
478 _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
479 }
480
481 // Now search the local resources.
482 workingLen = savedWorkingLen;
483 if (CFArrayGetCount(result) < limit) {
484 CFIndex langIndex;
485 CFIndex langCount = (searchLanguages ? CFArrayGetCount(searchLanguages) : 0);
486 CFStringRef curLangStr;
487 CFIndex curLangLen;
488 // MF:??? OK to hard-wire this length?
489 UniChar curLangUniChars[255];
490 CFIndex numResults = CFArrayGetCount(result);
491
492 for (langIndex = 0; langIndex < langCount; langIndex++) {
493 curLangStr = CFArrayGetValueAtIndex(searchLanguages, langIndex);
494 curLangLen = CFStringGetLength(curLangStr);
495 CFStringGetCharacters(curLangStr, CFRangeMake(0, curLangLen), curLangUniChars);
496 savedWorkingLen = workingLen;
497 if (!_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, curLangUniChars, curLangLen)) {
498 workingLen = savedWorkingLen;
499 continue;
500 }
501 if (!_CFAppendPathExtension(workingUniChars, &workingLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) {
502 workingLen = savedWorkingLen;
503 continue;
504 }
505 if (subDirLen > 0) {
506 if (!_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen)) {
507 workingLen = savedWorkingLen;
508 continue;
509 }
510 }
511 _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
512
513 // Back off this lproj component
514 workingLen = savedWorkingLen;
515 if (CFArrayGetCount(result) != numResults) {
516 // We found resources in a language we already searched. Don't look any farther.
517 // We also don't need to check the limit, since if the count changed at all, we are bailing.
518 break;
519 }
520 }
521 }
522 }
523
524 extern void _CFStrSetDesiredCapacity(CFMutableStringRef str, CFIndex len);
525
526 CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef subDirName, CFArrayRef searchLanguages, CFStringRef resName, CFArrayRef resTypes, CFIndex limit, uint8_t version) {
527 CFAllocatorRef alloc = ((bundle != NULL) ? CFGetAllocator(bundle) : CFRetain(__CFGetDefaultAllocator()));
528 CFMutableArrayRef result;
529 UniChar *workingUniChars, *nameUniChars, *subDirUniChars;
530 CFIndex nameLen = (resName ? CFStringGetLength(resName) : 0);
531 CFIndex subDirLen = (subDirName ? CFStringGetLength(subDirName) : 0);
532 CFIndex workingLen, savedWorkingLen;
533 CFURLRef absoluteURL;
534 CFStringRef bundlePath;
535 CFMutableStringRef cheapStr, tmpString;
536
537 result = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
538 // Init the one-time-only unichar buffers.
539 _CFEnsureStaticBuffersInited();
540
541 // Build UniChar buffers for some of the string pieces we need.
542 // One malloc will do.
543 nameUniChars = CFAllocatorAllocate(alloc, sizeof(UniChar) * (nameLen + subDirLen + CFMaxPathSize), 0);
544 subDirUniChars = nameUniChars + nameLen;
545 workingUniChars = subDirUniChars + subDirLen;
546
547 if (nameLen > 0) {
548 CFStringGetCharacters(resName, CFRangeMake(0, nameLen), nameUniChars);
549 }
550 if (subDirLen > 0) {
551 CFStringGetCharacters(subDirName, CFRangeMake(0, subDirLen), subDirUniChars);
552 }
553 // Build a UniChar buffer with the absolute path to the bundle's resources directory.
554 // If no URL was passed, we get it from the bundle.
555 bundleURL = ((bundleURL != NULL) ? CFRetain(bundleURL) : CFBundleCopyBundleURL(bundle));
556 absoluteURL = CFURLCopyAbsoluteURL(bundleURL);
557 bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
558 CFRelease(absoluteURL);
559 if ((workingLen = CFStringGetLength(bundlePath)) > 0) {
560 CFStringGetCharacters(bundlePath, CFRangeMake(0, workingLen), workingUniChars);
561 }
562 CFRelease(bundlePath);
563 CFRelease(bundleURL);
564 savedWorkingLen = workingLen;
565 if (1 == version) {
566 _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _AppSupportUniChars1, _AppSupportLen1);
567 } else if (2 == version) {
568 _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _AppSupportUniChars2, _AppSupportLen2);
569 }
570 if (0 == version || 1 == version || 2 == version) {
571 _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _ResourcesUniChars, _ResourcesLen);
572 }
573
574 // both of these used for temp string operations, for slightly
575 // different purposes, where each type is appropriate
576 cheapStr = CFStringCreateMutable(alloc, 0);
577 _CFStrSetDesiredCapacity(cheapStr, CFMaxPathSize);
578 tmpString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull);
579
580 _CFFindBundleResourcesInResourcesDir(alloc, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
581
582 // drd: This unfortunate hack is still necessary because of installer packages
583 if (0 == version && CFArrayGetCount(result) == 0) {
584 // Try looking directly in the bundle path
585 workingLen = savedWorkingLen;
586 _CFFindBundleResourcesInResourcesDir(alloc, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
587 }
588
589 CFRelease(cheapStr);
590 CFRelease(tmpString);
591 CFAllocatorDeallocate(alloc, nameUniChars);
592 if (bundle == NULL) {
593 CFRelease(alloc);
594 }
595
596 return result;
597 }
598
599 CF_EXPORT CFURLRef CFBundleCopyResourceURL(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName) {
600 CFURLRef result = NULL;
601 CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle);
602 CFMutableArrayRef types = NULL;
603 CFArrayRef array;
604
605 if (resourceType) {
606 types = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
607 CFArrayAppendValue(types, resourceType);
608 }
609
610 array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle));
611
612 if (types) {
613 CFRelease(types);
614 }
615
616 if (array) {
617 if (CFArrayGetCount(array) > 0) {
618 result = CFRetain(CFArrayGetValueAtIndex(array, 0));
619 }
620 CFRelease(array);
621 }
622 return result;
623 }
624
625 CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfType(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName) {
626 CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle);
627 CFMutableArrayRef types = NULL;
628 CFArrayRef array;
629
630 if (resourceType) {
631 types = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
632 CFArrayAppendValue(types, resourceType);
633 }
634
635 // MF:!!! Better "limit" than 1,000,000?
636 array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, _CFBundleLayoutVersion(bundle));
637
638 if (types) {
639 CFRelease(types);
640 }
641
642 return array;
643 }
644
645 CF_EXPORT CFURLRef _CFBundleCopyResourceURLForLanguage(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName, CFStringRef language) {return CFBundleCopyResourceURLForLocalization(bundle, resourceName, resourceType, subDirName, language);}
646
647 CF_EXPORT CFURLRef CFBundleCopyResourceURLForLocalization(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName, CFStringRef localizationName) {
648 CFURLRef result = NULL;
649 CFMutableArrayRef languages = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
650 CFMutableArrayRef types = NULL;
651 CFArrayRef array;
652
653 if (localizationName) CFArrayAppendValue(languages, localizationName);
654
655 if (resourceType) {
656 types = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
657 CFArrayAppendValue(types, resourceType);
658 }
659
660 array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle));
661
662 if (types) {
663 CFRelease(types);
664 }
665
666 if (array) {
667 if (CFArrayGetCount(array) > 0) {
668 result = CFRetain(CFArrayGetValueAtIndex(array, 0));
669 }
670 CFRelease(array);
671 }
672
673 CFRelease(languages);
674
675 return result;
676 }
677
678 CF_EXPORT CFArrayRef _CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef language) {return CFBundleCopyResourceURLsOfTypeForLocalization(bundle, resourceType, subDirName, language);}
679
680 CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef localizationName) {
681 CFMutableArrayRef languages = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
682 CFMutableArrayRef types = NULL;
683 CFArrayRef array;
684
685 if (localizationName) CFArrayAppendValue(languages, localizationName);
686
687 if (resourceType) {
688 types = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
689 CFArrayAppendValue(types, resourceType);
690 }
691
692 // MF:!!! Better "limit" than 1,000,000?
693 array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, _CFBundleLayoutVersion(bundle));
694
695 if (types) {
696 CFRelease(types);
697 }
698
699 CFRelease(languages);
700
701 return array;
702 }
703
704 CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName) {
705 CFStringRef result = NULL;
706 CFDictionaryRef stringTable = NULL;
707
708 if (key == NULL) return (value ? CFRetain(value) : CFRetain(CFSTR("")));
709
710 if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) {
711 tableName = _CFBundleDefaultStringTableName;
712 }
713 if (__CFBundleGetResourceData(bundle)->_stringTableCache != NULL) {
714 // See if we have the table cached.
715 stringTable = CFDictionaryGetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName);
716 }
717 if (stringTable == NULL) {
718 // Go load the table.
719 CFURLRef tableURL = CFBundleCopyResourceURL(bundle, tableName, _CFBundleStringTableType, NULL);
720 if (tableURL) {
721 CFStringRef nameForSharing = NULL;
722 if (stringTable == NULL) {
723 CFDataRef tableData = NULL;
724 SInt32 errCode;
725 CFStringRef errStr;
726 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle), tableURL, &tableData, NULL, NULL, &errCode)) {
727 stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), tableData, kCFPropertyListImmutable, &errStr);
728 if (errStr != NULL) {
729 CFRelease(errStr);
730 errStr = NULL;
731 }
732 CFRelease(tableData);
733 }
734 }
735 if (nameForSharing) CFRelease(nameForSharing);
736 CFRelease(tableURL);
737 }
738 if (stringTable == NULL) {
739 stringTable = CFDictionaryCreate(CFGetAllocator(bundle), NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
740 }
741 if (__CFBundleGetResourceData(bundle)->_stringTableCache == NULL) {
742 __CFBundleGetResourceData(bundle)->_stringTableCache = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
743 }
744 CFDictionarySetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName, stringTable);
745 CFRelease(stringTable);
746 }
747
748 result = CFDictionaryGetValue(stringTable, key);
749 if (result == NULL) {
750 if (value == NULL) {
751 result = CFRetain(key);
752 } else if (CFEqual(value, CFSTR(""))) {
753 result = CFRetain(key);
754 } else {
755 result = CFRetain(value);
756 }
757 } else {
758 CFRetain(result);
759 }
760
761 return result;
762 }
763
764 CF_EXPORT CFURLRef CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName) {
765 CFURLRef result = NULL;
766 char buff[CFMaxPathSize];
767 CFURLRef newURL = NULL;
768
769 if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL;
770
771 newURL = CFURLCreateFromFileSystemRepresentation(NULL, buff, strlen(buff), true);
772 if (NULL == newURL) {
773 newURL = CFRetain(bundleURL);
774 }
775 if (_CFBundleCouldBeBundle(newURL)) {
776 uint8_t version = 0;
777 CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(NULL, newURL, &version);
778 CFMutableArrayRef types = NULL;
779 CFArrayRef array;
780
781 if (resourceType) {
782 types = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
783 CFArrayAppendValue(types, resourceType);
784 }
785
786 array = _CFFindBundleResources(NULL, newURL, subDirName, languages, resourceName, types, 1, version);
787
788 if (types) {
789 CFRelease(types);
790 }
791
792 CFRelease(languages);
793
794 if (array) {
795 if (CFArrayGetCount(array) > 0) {
796 result = CFRetain(CFArrayGetValueAtIndex(array, 0));
797 }
798 CFRelease(array);
799 }
800 }
801 if (newURL) CFRelease(newURL);
802 return result;
803 }
804
805 CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleURL, CFStringRef resourceType, CFStringRef subDirName) {
806 CFArrayRef array = NULL;
807 char buff[CFMaxPathSize];
808 CFURLRef newURL = NULL;
809
810 if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL;
811
812 newURL = CFURLCreateFromFileSystemRepresentation(NULL, buff, strlen(buff), true);
813 if (NULL == newURL) {
814 newURL = CFRetain(bundleURL);
815 }
816 if (_CFBundleCouldBeBundle(newURL)) {
817 uint8_t version = 0;
818 CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(NULL, newURL, &version);
819 CFMutableArrayRef types = NULL;
820
821 if (resourceType) {
822 types = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
823 CFArrayAppendValue(types, resourceType);
824 }
825
826 // MF:!!! Better "limit" than 1,000,000?
827 array = _CFFindBundleResources(NULL, newURL, subDirName, languages, NULL, types, 1000000, version);
828
829 if (types) {
830 CFRelease(types);
831 }
832
833 CFRelease(languages);
834 }
835 if (newURL) CFRelease(newURL);
836 return array;
837 }
838
839 // string, with groups of 6 characters being 1 element in the array of locale abbreviations
840 const char * __CFBundleLocaleAbbreviationsArray =
841 "en_US\0" "fr_FR\0" "en_GB\0" "de_DE\0" "it_IT\0" "nl_NL\0" "nl_BE\0" "sv_SE\0"
842 "es_ES\0" "da_DK\0" "pt_PT\0" "fr_CA\0" "no_NO\0" "he_IL\0" "ja_JP\0" "en_AU\0"
843 "ar\0\0\0\0" "fi_FI\0" "fr_CH\0" "de_CH\0" "el_GR\0" "is_IS\0" "mt_MT\0" "\0\0\0\0\0\0"
844 "tr_TR\0" "hr_HR\0" "nl_NL\0" "nl_BE\0" "en_CA\0" "en_CA\0" "pt_PT\0" "no_NO\0"
845 "da_DK\0" "hi_IN\0" "ur_PK\0" "tr_TR\0" "it_CH\0" "en\0\0\0\0" "\0\0\0\0\0\0" "ro_RO\0"
846 "el_GR\0" "lt_LT\0" "pl_PL\0" "hu_HU\0" "et_EE\0" "lv_LV\0" "se\0\0\0\0" "fo_FO\0"
847 "fa_IR\0" "ru_RU\0" "ga_IE\0" "ko_KR\0" "zh_CN\0" "zh_TW\0" "th_TH\0" "\0\0\0\0\0\0"
848 "cs_CZ\0" "sk_SK\0" "\0\0\0\0\0\0" "hu_HU\0" "bn\0\0\0\0" "be_BY\0" "uk_UA\0" "\0\0\0\0\0\0"
849 "el_GR\0" "sr_YU\0" "sl_SI\0" "mk_MK\0" "hr_HR\0" "\0\0\0\0\0\0" "de_DE\0" "pt_BR\0"
850 "bg_BG\0" "ca_ES\0" "\0\0\0\0\0\0" "gd\0\0\0\0" "gv\0\0\0\0" "br\0\0\0\0" "iu_CA\0" "cy\0\0\0\0"
851 "en_CA\0" "ga_IE\0" "en_CA\0" "dz_BT\0" "hy_AM\0" "ka_GE\0" "es\0\0\0\0" "es_ES\0"
852 "to_TO\0" "pl_PL\0" "ca_ES\0" "fr\0\0\0\0" "de_AT\0" "es\0\0\0\0" "gu_IN\0" "pa\0\0\0\0"
853 "ur_IN\0" "vi_VN\0" "fr_BE\0" "uz_UZ\0" "\0\0\0\0\0\0" "\0\0\0\0\0\0" "af_ZA\0" "eo\0\0\0\0"
854 "mr_IN\0" "bo\0\0\0\0" "ne_NP\0" "kl\0\0\0";
855
856 #define NUM_LOCALE_ABBREVIATIONS 108
857 #define LOCALE_ABBREVIATION_LENGTH 6
858
859 static const char * const __CFBundleLanguageNamesArray[] = {
860 "English", "French", "German", "Italian", "Dutch", "Swedish", "Spanish", "Danish",
861 "Portuguese", "Norwegian", "Hebrew", "Japanese", "Arabic", "Finnish", "Greek", "Icelandic",
862 "Maltese", "Turkish", "Croatian", "Chinese", "Urdu", "Hindi", "Thai", "Korean",
863 "Lithuanian", "Polish", "Hungarian", "Estonian", "Latvian", "Sami", "Faroese", "Farsi",
864 "Russian", "Chinese", "Dutch", "Irish", "Albanian", "Romanian", "Czech", "Slovak",
865 "Slovenian", "Yiddish", "Serbian", "Macedonian", "Bulgarian", "Ukrainian", "Byelorussian", "Uzbek",
866 "Kazakh", "Azerbaijani", "Azerbaijani", "Armenian", "Georgian", "Moldavian", "Kirghiz", "Tajiki",
867 "Turkmen", "Mongolian", "Mongolian", "Pashto", "Kurdish", "Kashmiri", "Sindhi", "Tibetan",
868 "Nepali", "Sanskrit", "Marathi", "Bengali", "Assamese", "Gujarati", "Punjabi", "Oriya",
869 "Malayalam", "Kannada", "Tamil", "Telugu", "Sinhalese", "Burmese", "Khmer", "Lao",
870 "Vietnamese", "Indonesian", "Tagalog", "Malay", "Malay", "Amharic", "Tigrinya", "Oromo",
871 "Somali", "Swahili", "Kinyarwanda", "Rundi", "Nyanja", "Malagasy", "Esperanto", "",
872 "", "", "", "", "", "", "", "",
873 "", "", "", "", "", "", "", "",
874 "", "", "", "", "", "", "", "",
875 "", "", "", "", "", "", "", "",
876 "Welsh", "Basque", "Catalan", "Latin", "Quechua", "Guarani", "Aymara", "Tatar",
877 "Uighur", "Dzongkha", "Javanese", "Sundanese", "Galician", "Afrikaans", "Breton", "Inuktitut",
878 "Scottish", "Manx", "Irish", "Tongan", "Greek", "Greenlandic", "Azerbaijani"
879 };
880
881 #define NUM_LANGUAGE_NAMES 151
882 #define LANGUAGE_NAME_LENGTH 13
883
884 // string, with groups of 3 characters being 1 element in the array of abbreviations
885 const char * __CFBundleLanguageAbbreviationsArray =
886 "en\0" "fr\0" "de\0" "it\0" "nl\0" "sv\0" "es\0" "da\0"
887 "pt\0" "no\0" "he\0" "ja\0" "ar\0" "fi\0" "el\0" "is\0"
888 "mt\0" "tr\0" "hr\0" "zh\0" "ur\0" "hi\0" "th\0" "ko\0"
889 "lt\0" "pl\0" "hu\0" "et\0" "lv\0" "se\0" "fo\0" "fa\0"
890 "ru\0" "zh\0" "nl\0" "ga\0" "sq\0" "ro\0" "cs\0" "sk\0"
891 "sl\0" "yi\0" "sr\0" "mk\0" "bg\0" "uk\0" "be\0" "uz\0"
892 "kk\0" "az\0" "az\0" "hy\0" "ka\0" "mo\0" "ky\0" "tg\0"
893 "tk\0" "mn\0" "mn\0" "ps\0" "ku\0" "ks\0" "sd\0" "bo\0"
894 "ne\0" "sa\0" "mr\0" "bn\0" "as\0" "gu\0" "pa\0" "or\0"
895 "ml\0" "kn\0" "ta\0" "te\0" "si\0" "my\0" "km\0" "lo\0"
896 "vi\0" "id\0" "tl\0" "ms\0" "ms\0" "am\0" "ti\0" "om\0"
897 "so\0" "sw\0" "rw\0" "rn\0" "\0\0\0" "mg\0" "eo\0" "\0\0\0"
898 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
899 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
900 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
901 "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
902 "cy\0" "eu\0" "ca\0" "la\0" "qu\0" "gn\0" "ay\0" "tt\0"
903 "ug\0" "dz\0" "jv\0" "su\0" "gl\0" "af\0" "br\0" "iu\0"
904 "gd\0" "gv\0" "ga\0" "to\0" "el\0" "kl\0" "az\0";
905
906 #define NUM_LANGUAGE_ABBREVIATIONS 151
907 #define LANGUAGE_ABBREVIATION_LENGTH 3
908
909 static const SInt32 __CFBundleScriptCodesArray[] = {
910 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 0, 0,
911 0, 0, 0, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 0, 4,
912 7, 25, 0, 0, 0, 0, 29, 29, 0, 5, 7, 7, 7, 7, 7, 7,
913 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
914 9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
915 30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
916 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
917 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
918 0, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 0, 28,
919 0, 0, 0, 0, 6, 0, 0
920 };
921
922 static const CFStringEncoding __CFBundleStringEncodingsArray[] = {
923 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 6, 37,
924 0, 35, 36, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 37, 0x8C,
925 7, 25, 0, 39, 0, 38, 29, 29, 36, 5, 7, 7, 7, 0x98, 7, 7,
926 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
927 9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
928 30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
929 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
930 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
931 39, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 39, 0xEC,
932 39, 39, 40, 0, 6, 0, 0
933 };
934
935 static SInt32 _CFBundleGetLanguageCodeForLocalization(CFStringRef localizationName) {
936 SInt32 result = -1, i;
937 char buff[256];
938 CFIndex length = CFStringGetLength(localizationName);
939 if ((length >= LANGUAGE_ABBREVIATION_LENGTH - 1) && (length <= 255) && CFStringGetCString(localizationName, buff, 255, kCFStringEncodingASCII)) {
940 buff[255] = '\0';
941 for (i = 0; -1 == result && i < NUM_LANGUAGE_NAMES; i++) {
942 if (0 == strcmp(buff, __CFBundleLanguageNamesArray[i])) result = i;
943 }
944 if (0 == strcmp(buff, "zh_CN")) result = 33; // hack for mixed-up Chinese language codes
945 buff[LANGUAGE_ABBREVIATION_LENGTH - 1] = '\0';
946 for (i = 0; -1 == result && i < NUM_LANGUAGE_ABBREVIATIONS * LANGUAGE_ABBREVIATION_LENGTH; i += LANGUAGE_ABBREVIATION_LENGTH) {
947 if (buff[0] == *(__CFBundleLanguageAbbreviationsArray + i + 0) && buff[1] == *(__CFBundleLanguageAbbreviationsArray + i + 1)) result = i / LANGUAGE_ABBREVIATION_LENGTH;
948 }
949 }
950 return result;
951 }
952
953 static CFStringRef _CFBundleCopyLanguageAbbreviationForLanguageCode(SInt32 languageCode) {
954 CFStringRef result = NULL;
955 if (0 <= languageCode && languageCode < NUM_LANGUAGE_ABBREVIATIONS) {
956 const char *languageAbbreviation = __CFBundleLanguageAbbreviationsArray + languageCode * LANGUAGE_ABBREVIATION_LENGTH;
957 if (languageAbbreviation != NULL && *languageAbbreviation != '\0') {
958 result = CFStringCreateWithCStringNoCopy(NULL, languageAbbreviation, kCFStringEncodingASCII, kCFAllocatorNull);
959 }
960 }
961 return result;
962 }
963
964 static CFStringRef _CFBundleCopyLanguageNameForLanguageCode(SInt32 languageCode) {
965 CFStringRef result = NULL;
966 if (0 <= languageCode && languageCode < NUM_LANGUAGE_NAMES) {
967 const char *languageName = __CFBundleLanguageNamesArray[languageCode];
968 if (languageName != NULL && *languageName != '\0') {
969 result = CFStringCreateWithCStringNoCopy(NULL, languageName, kCFStringEncodingASCII, kCFAllocatorNull);
970 }
971 }
972 return result;
973 }
974
975 static CFStringRef _CFBundleCopyLanguageAbbreviationForLocalization(CFStringRef localizationName) {
976 CFStringRef result = NULL;
977 SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName);
978 if (languageCode >= 0) {
979 result = _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode);
980 } else {
981 CFIndex length = CFStringGetLength(localizationName);
982 if (length == LANGUAGE_ABBREVIATION_LENGTH - 1 || (length > LANGUAGE_ABBREVIATION_LENGTH - 1 && CFStringGetCharacterAtIndex(localizationName, LANGUAGE_ABBREVIATION_LENGTH - 1) == '_')) {
983 result = CFStringCreateWithSubstring(NULL, localizationName, CFRangeMake(0, LANGUAGE_ABBREVIATION_LENGTH - 1));
984 }
985 }
986 return result;
987 }
988
989 static CFStringRef _CFBundleCopyLanguageNameForLocalization(CFStringRef localizationName) {
990 CFStringRef result = NULL;
991 SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName);
992 if (languageCode >= 0) {
993 result = _CFBundleCopyLanguageNameForLanguageCode(languageCode);
994 } else {
995 result = CFStringCreateCopy(NULL, localizationName);
996 }
997 return result;
998 }
999
1000 static SInt32 _CFBundleGetLanguageCodeForRegionCode(SInt32 regionCode) {
1001 SInt32 result = -1, i;
1002 if (52 == regionCode) { // hack for mixed-up Chinese language codes
1003 result = 33;
1004 } else if (0 <= regionCode && regionCode < NUM_LOCALE_ABBREVIATIONS) {
1005 const char *localeAbbreviation = __CFBundleLocaleAbbreviationsArray + regionCode * LOCALE_ABBREVIATION_LENGTH;
1006 if (localeAbbreviation != NULL && *localeAbbreviation != '\0') {
1007 for (i = 0; -1 == result && i < NUM_LANGUAGE_ABBREVIATIONS * LANGUAGE_ABBREVIATION_LENGTH; i += LANGUAGE_ABBREVIATION_LENGTH) {
1008 if (localeAbbreviation[0] == *(__CFBundleLanguageAbbreviationsArray + i + 0) && localeAbbreviation[1] == *(__CFBundleLanguageAbbreviationsArray + i + 1)) result = i / LANGUAGE_ABBREVIATION_LENGTH;
1009 }
1010 }
1011 }
1012 return result;
1013 }
1014
1015 static SInt32 _CFBundleGetRegionCodeForLanguageCode(SInt32 languageCode) {
1016 SInt32 result = -1, i;
1017 if (19 == languageCode) { // hack for mixed-up Chinese language codes
1018 result = 53;
1019 } else if (0 <= languageCode && languageCode < NUM_LANGUAGE_ABBREVIATIONS) {
1020 const char *languageAbbreviation = __CFBundleLanguageAbbreviationsArray + languageCode * LANGUAGE_ABBREVIATION_LENGTH;
1021 if (languageAbbreviation != NULL && *languageAbbreviation != '\0') {
1022 for (i = 0; -1 == result && i < NUM_LOCALE_ABBREVIATIONS * LOCALE_ABBREVIATION_LENGTH; i += LOCALE_ABBREVIATION_LENGTH) {
1023 if (*(__CFBundleLocaleAbbreviationsArray + i + 0) == languageAbbreviation[0] && *(__CFBundleLocaleAbbreviationsArray + i + 1) == languageAbbreviation[1]) result = i / LOCALE_ABBREVIATION_LENGTH;
1024 }
1025 }
1026 }
1027 return result;
1028 }
1029
1030 static SInt32 _CFBundleGetRegionCodeForLocalization(CFStringRef localizationName) {
1031 SInt32 result = -1, i;
1032 char buff[LOCALE_ABBREVIATION_LENGTH];
1033 CFIndex length = CFStringGetLength(localizationName);
1034 if ((length >= LANGUAGE_ABBREVIATION_LENGTH - 1) && (length <= LOCALE_ABBREVIATION_LENGTH - 1) && CFStringGetCString(localizationName, buff, LOCALE_ABBREVIATION_LENGTH, kCFStringEncodingASCII)) {
1035 buff[LOCALE_ABBREVIATION_LENGTH - 1] = '\0';
1036 for (i = 0; -1 == result && i < NUM_LOCALE_ABBREVIATIONS * LOCALE_ABBREVIATION_LENGTH; i += LOCALE_ABBREVIATION_LENGTH) {
1037 if (0 == strcmp(buff, __CFBundleLocaleAbbreviationsArray + i)) result = i / LOCALE_ABBREVIATION_LENGTH;
1038 }
1039 }
1040 if (-1 == result) {
1041 SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName);
1042 result = _CFBundleGetRegionCodeForLanguageCode(languageCode);
1043 }
1044 return result;
1045 }
1046
1047 static CFStringRef _CFBundleCopyLocaleAbbreviationForRegionCode(SInt32 regionCode) {
1048 CFStringRef result = NULL;
1049 if (0 <= regionCode && regionCode < NUM_LOCALE_ABBREVIATIONS) {
1050 const char *localeAbbreviation = __CFBundleLocaleAbbreviationsArray + regionCode * LOCALE_ABBREVIATION_LENGTH;
1051 if (localeAbbreviation != NULL && *localeAbbreviation != '\0') {
1052 result = CFStringCreateWithCStringNoCopy(NULL, localeAbbreviation, kCFStringEncodingASCII, kCFAllocatorNull);
1053 }
1054 }
1055 return result;
1056 }
1057
1058 Boolean CFBundleGetLocalizationInfoForLocalization(CFStringRef localizationName, SInt32 *languageCode, SInt32 *regionCode, SInt32 *scriptCode, CFStringEncoding *stringEncoding) {
1059 SInt32 language = -1, region = -1, script = 0;
1060 CFStringEncoding encoding = kCFStringEncodingMacRoman;
1061 if (localizationName) {
1062 language = _CFBundleGetLanguageCodeForLocalization(localizationName);
1063 region = _CFBundleGetRegionCodeForLocalization(localizationName);
1064 } else {
1065 _CFBundleGetLanguageAndRegionCodes(&language, &region);
1066 }
1067 if ((language < 0 || language > (int)(sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32))) && region != -1) language = _CFBundleGetLanguageCodeForRegionCode(region);
1068 if (region == -1 && language != -1) region = _CFBundleGetRegionCodeForLanguageCode(language);
1069 if (language >= 0 && language < (int)(sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32))) {
1070 script = __CFBundleScriptCodesArray[language];
1071 }
1072 if (language >= 0 && language < (int)(sizeof(__CFBundleStringEncodingsArray)/sizeof(CFStringEncoding))) {
1073 encoding = __CFBundleStringEncodingsArray[language];
1074 }
1075 if (languageCode) *languageCode = language;
1076 if (regionCode) *regionCode = region;
1077 if (scriptCode) *scriptCode = script;
1078 if (stringEncoding) *stringEncoding = encoding;
1079 return (language != -1 || region != -1);
1080 }
1081
1082 CFStringRef CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode, SInt32 regionCode, SInt32 scriptCode, CFStringEncoding stringEncoding) {
1083 CFStringRef localizationName = NULL;
1084 if (!localizationName) {
1085 localizationName = _CFBundleCopyLocaleAbbreviationForRegionCode(regionCode);
1086 }
1087 if (!localizationName) {
1088 localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode);
1089 }
1090 if (!localizationName) {
1091 SInt32 language = -1, scriptLanguage = -1, encodingLanguage = -1;
1092 unsigned int i;
1093 for (i = 0; language == -1 && i < (sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32)); i++) {
1094 if (__CFBundleScriptCodesArray[i] == scriptCode && __CFBundleStringEncodingsArray[i] == stringEncoding) language = i;
1095 }
1096 for (i = 0; scriptLanguage == -1 && i < (sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32)); i++) {
1097 if (__CFBundleScriptCodesArray[i] == scriptCode) scriptLanguage = i;
1098 }
1099 for (i = 0; encodingLanguage == -1 && i < (sizeof(__CFBundleStringEncodingsArray)/sizeof(CFStringEncoding)); i++) {
1100 if (__CFBundleStringEncodingsArray[i] == stringEncoding) encodingLanguage = i;
1101 }
1102 localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(language);
1103 if (!localizationName) localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(encodingLanguage);
1104 if (!localizationName) localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(scriptLanguage);
1105 }
1106 return localizationName;
1107 }
1108
1109 extern void *__CFAppleLanguages;
1110
1111 __private_extern__ CFArrayRef _CFBundleCopyUserLanguages(Boolean useBackstops) {
1112 CFArrayRef result = NULL;
1113 static CFArrayRef userLanguages = NULL;
1114 static Boolean didit = false;
1115 CFArrayRef preferencesArray = NULL;
1116 // This is a temporary solution, until the argument domain is moved down into CFPreferences
1117 __CFSpinLock(&CFBundleResourceGlobalDataLock);
1118 if (!didit) {
1119 if (__CFAppleLanguages) {
1120 CFDataRef data;
1121 CFIndex length = strlen(__CFAppleLanguages);
1122 if (length > 0) {
1123 data = CFDataCreateWithBytesNoCopy(NULL, __CFAppleLanguages, length, kCFAllocatorNull);
1124 if (data) {
1125 __CFSetNastyFile(CFSTR("<plist command-line argument>"));
1126 userLanguages = CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL);
1127 CFRelease(data);
1128 }
1129 }
1130 }
1131 if (!userLanguages && preferencesArray) userLanguages = CFRetain(preferencesArray);
1132 { // could perhaps read out of LANG environment variable
1133 CFStringRef english = CFSTR("English");
1134 if (!userLanguages) userLanguages = CFArrayCreate(kCFAllocatorDefault, (const void **)&english, 1, &kCFTypeArrayCallBacks);
1135 }
1136 if (userLanguages && CFGetTypeID(userLanguages) != CFArrayGetTypeID()) {
1137 CFRelease(userLanguages);
1138 userLanguages = NULL;
1139 }
1140 didit = true;
1141 }
1142 __CFSpinUnlock(&CFBundleResourceGlobalDataLock);
1143 if (preferencesArray) CFRelease(preferencesArray);
1144 if (!result && userLanguages) result = CFRetain(userLanguages);
1145 return result;
1146 }
1147
1148 CF_EXPORT void _CFBundleGetLanguageAndRegionCodes(SInt32 *languageCode, SInt32 *regionCode) {
1149 // an attempt to answer the question, "what language are we running in?"
1150 // note that the question cannot be answered fully since it may depend on the bundle
1151 SInt32 language = -1, region = -1;
1152 CFBundleRef mainBundle = CFBundleGetMainBundle();
1153 CFArrayRef languages = NULL;
1154 CFStringRef localizationName = NULL;
1155 if (mainBundle) {
1156 languages = _CFBundleGetLanguageSearchList(mainBundle);
1157 if (languages) CFRetain(languages);
1158 }
1159 if (!languages) languages = _CFBundleCopyUserLanguages(false);
1160 if (languages && (CFArrayGetCount(languages) > 0)) {
1161 localizationName = CFArrayGetValueAtIndex(languages, 0);
1162 language = _CFBundleGetLanguageCodeForLocalization(localizationName);
1163 region = _CFBundleGetRegionCodeForLocalization(localizationName);
1164 } else {
1165 language = 0;
1166 region = 0;
1167 }
1168 if (language == -1 && region != -1) language = _CFBundleGetLanguageCodeForRegionCode(region);
1169 if (region == -1 && language != -1) region = _CFBundleGetRegionCodeForLanguageCode(language);
1170 if (languages) CFRelease(languages);
1171 if (languageCode) *languageCode = language;
1172 if (regionCode) *regionCode = region;
1173 }
1174
1175 static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc, UniChar *pathUniChars, CFIndex pathLen, uint8_t version, CFDictionaryRef infoDict, CFStringRef curLangStr, CFMutableArrayRef lprojNames) {
1176 CFIndex curLangLen = CFStringGetLength(curLangStr);
1177 UniChar curLangUniChars[255];
1178 CFIndex savedPathLen;
1179 CFStringRef languageAbbreviation = _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr), languageName = _CFBundleCopyLanguageNameForLocalization(curLangStr);
1180 Boolean foundOne = false;
1181 CFArrayRef predefinedLocalizations = NULL;
1182 CFRange predefinedLocalizationsRange;
1183 CFMutableStringRef cheapStr, tmpString;
1184 #if USE_GETDIRENTRIES
1185 CFArrayRef directoryContents;
1186 CFRange directoryContentsRange;
1187 #else
1188 Boolean isDir = false;
1189 #endif
1190
1191 // both of these used for temp string operations, for slightly
1192 // different purposes, where each type is appropriate
1193 cheapStr = CFStringCreateMutable(alloc, 0);
1194 _CFStrSetDesiredCapacity(cheapStr, CFMaxPathSize);
1195 tmpString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull);
1196
1197 #if USE_GETDIRENTRIES
1198 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
1199 CFStringReplaceAll(cheapStr, tmpString);
1200 directoryContents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, true);
1201 directoryContentsRange = CFRangeMake(0, CFArrayGetCount(directoryContents));
1202 #endif
1203
1204 if (infoDict) {
1205 predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey);
1206 if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) != CFArrayGetTypeID()) {
1207 predefinedLocalizations = NULL;
1208 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleLocalizationsKey);
1209 }
1210 }
1211 predefinedLocalizationsRange = CFRangeMake(0, predefinedLocalizations ? CFArrayGetCount(predefinedLocalizations) : 0);
1212
1213 CFStringGetCharacters(curLangStr, CFRangeMake(0, curLangLen), curLangUniChars);
1214 savedPathLen = pathLen;
1215 _CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen);
1216 _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen);
1217 #if USE_GETDIRENTRIES
1218 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1);
1219 CFStringReplaceAll(cheapStr, tmpString);
1220 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, curLangStr)) || (version != 4 && CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr))) {
1221 #else
1222 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
1223 CFStringReplaceAll(cheapStr, tmpString);
1224 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, curLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
1225 #endif
1226 // We found one.
1227 CFArrayAppendValue(lprojNames, curLangStr);
1228 foundOne = true;
1229 }
1230 // Now, if the curLangStr was a region name, and we can map it to a language name, try that too.
1231 if (languageAbbreviation && !CFEqual(curLangStr, languageAbbreviation)) {
1232 curLangLen = CFStringGetLength(languageAbbreviation);
1233 CFStringGetCharacters(languageAbbreviation, CFRangeMake(0, curLangLen), curLangUniChars);
1234 pathLen = savedPathLen;
1235 _CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen);
1236 _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen);
1237 #if USE_GETDIRENTRIES
1238 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1);
1239 CFStringReplaceAll(cheapStr, tmpString);
1240 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageAbbreviation)) || (version != 4 && CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr))) {
1241 #else
1242 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
1243 CFStringReplaceAll(cheapStr, tmpString);
1244 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageAbbreviation)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
1245 #endif
1246 // We found one.
1247 CFArrayAppendValue(lprojNames, languageAbbreviation);
1248 foundOne = true;
1249 }
1250 }
1251 if (languageName && !CFEqual(curLangStr, languageName)) {
1252 curLangLen = CFStringGetLength(languageName);
1253 CFStringGetCharacters(languageName, CFRangeMake(0, curLangLen), curLangUniChars);
1254 pathLen = savedPathLen;
1255 _CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen);
1256 _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen);
1257 #if USE_GETDIRENTRIES
1258 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1);
1259 CFStringReplaceAll(cheapStr, tmpString);
1260 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageName)) || (version != 4 && CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr))) {
1261 #else
1262 CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
1263 CFStringReplaceAll(cheapStr, tmpString);
1264 if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageName)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
1265 #endif
1266 // We found one.
1267 CFArrayAppendValue(lprojNames, languageName);
1268 foundOne = true;
1269 }
1270 }
1271
1272 CFRelease(cheapStr);
1273 CFRelease(tmpString);
1274 if (languageAbbreviation) CFRelease(languageAbbreviation);
1275 if (languageName) CFRelease(languageName);
1276 #if USE_GETDIRENTRIES
1277 CFRelease(directoryContents);
1278 #endif
1279
1280 return foundOne;
1281 }
1282
1283 static Boolean CFBundleAllowMixedLocalizations(void) {
1284 static Boolean allowMixed = false, examinedMain = false;
1285 if (!examinedMain) {
1286 CFBundleRef mainBundle = CFBundleGetMainBundle();
1287 CFDictionaryRef infoDict = mainBundle ? CFBundleGetInfoDictionary(mainBundle) : NULL;
1288 CFTypeRef allowMixedValue = infoDict ? CFDictionaryGetValue(infoDict, _kCFBundleAllowMixedLocalizationsKey) : NULL;
1289 if (allowMixedValue) {
1290 CFTypeID typeID = CFGetTypeID(allowMixedValue);
1291 if (typeID == CFBooleanGetTypeID()) {
1292 allowMixed = CFBooleanGetValue((CFBooleanRef)allowMixedValue);
1293 } else if (typeID == CFStringGetTypeID()) {
1294 allowMixed = (CFStringCompare((CFStringRef)allowMixedValue, CFSTR("true"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare((CFStringRef)allowMixedValue, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
1295 } else if (typeID == CFNumberGetTypeID()) {
1296 SInt32 val = 0;
1297 if (CFNumberGetValue((CFNumberRef)allowMixedValue, kCFNumberSInt32Type, &val)) allowMixed = (val != 0);
1298 }
1299 }
1300 examinedMain = true;
1301 }
1302 return allowMixed;
1303 }
1304
1305 __private_extern__ void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, uint8_t version, CFDictionaryRef infoDict, CFMutableArrayRef lprojNames, CFStringRef devLang) {
1306 // This function will add zero, one or two elements to the lprojNames array.
1307 // It examines the users preferred language list and the lproj directories inside the bundle directory. It picks the lproj directory that is highest on the users list.
1308 // The users list can contain region names (like "en_US" for US English). In this case, if the region lproj exists, it will be added, and, if the region's associated language lproj exists that will be added.
1309 CFURLRef resourcesURL = _CFBundleCopyResourcesDirectoryURLInDirectory(alloc, bundleURL, version);
1310 CFURLRef absoluteURL;
1311 CFIndex idx;
1312 CFIndex count;
1313 CFStringRef resourcesPath;
1314 UniChar pathUniChars[CFMaxPathSize];
1315 CFIndex pathLen;
1316 CFStringRef curLangStr;
1317 Boolean foundOne = false;
1318
1319 CFArrayRef userLanguages;
1320
1321 // Init the one-time-only unichar buffers.
1322 _CFEnsureStaticBuffersInited();
1323
1324 // Get the path to the resources and extract into a buffer.
1325 absoluteURL = CFURLCopyAbsoluteURL(resourcesURL);
1326 resourcesPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
1327 CFRelease(absoluteURL);
1328 pathLen = CFStringGetLength(resourcesPath);
1329 CFStringGetCharacters(resourcesPath, CFRangeMake(0, pathLen), pathUniChars);
1330 CFRelease(resourcesURL);
1331 CFRelease(resourcesPath);
1332
1333 // First check the main bundle.
1334 if (!CFBundleAllowMixedLocalizations()) {
1335 CFBundleRef mainBundle = CFBundleGetMainBundle();
1336 if (mainBundle) {
1337 CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);
1338 if (!CFEqual(bundleURL, mainBundleURL)) {
1339 // If there is a main bundle, and it isn't this one, try to use the language it prefers.
1340 CFArrayRef mainBundleLangs = _CFBundleGetLanguageSearchList(mainBundle);
1341 if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) {
1342 curLangStr = CFArrayGetValueAtIndex(mainBundleLangs, 0);
1343 foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames);
1344 }
1345 }
1346 CFRelease(mainBundleURL);
1347 }
1348 }
1349
1350 if (!foundOne) {
1351 // If we didn't find the main bundle's preferred language, look at the users' prefs again and find the best one.
1352 userLanguages = _CFBundleCopyUserLanguages(true);
1353 count = (userLanguages ? CFArrayGetCount(userLanguages) : 0);
1354 for (idx = 0; !foundOne && idx < count; idx++) {
1355 curLangStr = CFArrayGetValueAtIndex(userLanguages, idx);
1356 foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames);
1357 }
1358 // use development region and U.S. English as backstops
1359 if (!foundOne && devLang != NULL) {
1360 foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, devLang, lprojNames);
1361 }
1362 if (!foundOne) {
1363 foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, CFSTR("en_US"), lprojNames);
1364 }
1365 if (userLanguages != NULL) {
1366 CFRelease(userLanguages);
1367 }
1368 }
1369 }
1370
1371 static Boolean _CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array, CFStringRef curLangStr, CFMutableArrayRef lprojNames) {
1372 Boolean foundOne = false;
1373 CFRange range = CFRangeMake(0, CFArrayGetCount(array));
1374 CFStringRef languageAbbreviation = _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr), languageName = _CFBundleCopyLanguageNameForLocalization(curLangStr);
1375
1376 if (CFArrayContainsValue(array, range, curLangStr)) {
1377 // We found one.
1378 CFArrayAppendValue(lprojNames, curLangStr);
1379 foundOne = true;
1380 }
1381 if (languageAbbreviation && !CFEqual(curLangStr, languageAbbreviation)) {
1382 if (CFArrayContainsValue(array, range, languageAbbreviation)) {
1383 // We found one.
1384 CFArrayAppendValue(lprojNames, languageAbbreviation);
1385 foundOne = true;
1386 }
1387 }
1388 if (languageName && !CFEqual(curLangStr, languageName)) {
1389 if (CFArrayContainsValue(array, range, languageName)) {
1390 // We found one.
1391 CFArrayAppendValue(lprojNames, languageName);
1392 foundOne = true;
1393 }
1394 }
1395
1396 if (languageAbbreviation) CFRelease(languageAbbreviation);
1397 if (languageName) CFRelease(languageName);
1398
1399 return foundOne;
1400 }
1401
1402 static CFArrayRef _CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray, Boolean considerMain) {
1403 CFMutableArrayRef lprojNames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1404 Boolean foundOne = false, releasePrefArray = false;
1405 CFIndex idx, count;
1406
1407 if (considerMain && !CFBundleAllowMixedLocalizations()) {
1408 CFBundleRef mainBundle = CFBundleGetMainBundle();
1409 if (mainBundle) {
1410 // If there is a main bundle, try to use the language it prefers.
1411 CFArrayRef mainBundleLangs = _CFBundleGetLanguageSearchList(mainBundle);
1412 if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) {
1413 foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(mainBundleLangs, 0), lprojNames);
1414 }
1415 }
1416 }
1417 if (!foundOne) {
1418 if (!prefArray) {
1419 prefArray = _CFBundleCopyUserLanguages(true);
1420 if (prefArray) releasePrefArray = true;
1421 }
1422 count = (prefArray ? CFArrayGetCount(prefArray) : 0);
1423 for (idx = 0; !foundOne && idx < count; idx++) {
1424 foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(prefArray, idx), lprojNames);
1425 }
1426 // use U.S. English as backstop
1427 if (!foundOne) {
1428 foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFSTR("en_US"), lprojNames);
1429 }
1430 // use random entry as backstop
1431 if (!foundOne && CFArrayGetCount(lprojNames) > 0) {
1432 foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(locArray, 0), lprojNames);
1433 }
1434 }
1435 if (CFArrayGetCount(lprojNames) == 0) {
1436 // Total backstop behavior to avoid having an empty array.
1437 CFArrayAppendValue(lprojNames, CFSTR("en"));
1438 }
1439 if (releasePrefArray) {
1440 CFRelease(prefArray);
1441 }
1442 return lprojNames;
1443 }
1444
1445 CF_EXPORT CFArrayRef CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray) {return _CFBundleCopyLocalizationsForPreferences(locArray, prefArray, false);}
1446
1447 CF_EXPORT CFArrayRef CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locArray) {return _CFBundleCopyLocalizationsForPreferences(locArray, NULL, true);}
1448
1449 __private_extern__ CFArrayRef _CFBundleCopyLanguageSearchListInDirectory(CFAllocatorRef alloc, CFURLRef url, uint8_t *version) {
1450 CFMutableArrayRef langs = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
1451 uint8_t localVersion = 0;
1452 CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, &localVersion);
1453 CFStringRef devLang = NULL;
1454 if (infoDict != NULL) {
1455 devLang = CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey);
1456 }
1457 if (devLang != NULL && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) devLang = NULL;
1458
1459 _CFBundleAddPreferredLprojNamesInDirectory(alloc, url, localVersion, infoDict, langs, devLang);
1460
1461 if (devLang != NULL && CFArrayGetFirstIndexOfValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), devLang) < 0) {
1462 CFArrayAppendValue(langs, devLang);
1463 }
1464 if (CFArrayGetCount(langs) == 0) {
1465 // Total backstop behavior to avoid having an empty array.
1466 CFArrayAppendValue(langs, CFSTR("en"));
1467 }
1468 if (infoDict != NULL) {
1469 CFRelease(infoDict);
1470 }
1471 if (version) {
1472 *version = localVersion;
1473 }
1474 return langs;
1475 }
1476
1477 CF_EXPORT Boolean _CFBundleURLLooksLikeBundle(CFURLRef url) {
1478 Boolean result = false;
1479 CFBundleRef bundle = _CFBundleCreateIfLooksLikeBundle(NULL, url);
1480 if (bundle) {
1481 result = true;
1482 CFRelease(bundle);
1483 }
1484 return result;
1485 }
1486
1487 // Note that subDirName is expected to be the string for a URL
1488 CF_INLINE Boolean _CFBundleURLHasSubDir(CFURLRef url, CFStringRef subDirName) {
1489 CFURLRef dirURL;
1490 Boolean isDir, result = false;
1491
1492 dirURL = CFURLCreateWithString(NULL, subDirName, url);
1493 if (dirURL != NULL) {
1494 if (_CFIsResourceAtURL(dirURL, &isDir) && isDir) {
1495 result = true;
1496 }
1497 CFRelease(dirURL);
1498 }
1499 return result;
1500 }
1501
1502 __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint8_t *version) {
1503 Boolean result = false;
1504 uint8_t localVersion = 0;
1505
1506 // check for existence of "Resources" or "Contents" or "Support Files"
1507 // but check for the most likely one first
1508 // version 0: old-style "Resources" bundles
1509 // version 1: obsolete "Support Files" bundles
1510 // version 2: modern "Contents" bundles
1511 // version 3: none of the above (see below)
1512 // version 4: not a bundle (for main bundle only)
1513 if (CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework/"))) {
1514 if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) {
1515 result = true;
1516 localVersion = 0;
1517 } else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) {
1518 result = true;
1519 localVersion = 2;
1520 } else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) {
1521 result = true;
1522 localVersion = 1;
1523 }
1524 } else {
1525 if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) {
1526 result = true;
1527 localVersion = 2;
1528 } else if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) {
1529 result = true;
1530 localVersion = 0;
1531 } else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) {
1532 result = true;
1533 localVersion = 1;
1534 }
1535 }
1536 if (result && version) *version = localVersion;
1537 return result;
1538 }
1539
1540 __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc, CFURLRef url, uint8_t *version) {
1541 CFDictionaryRef dict = NULL;
1542 char buff[CFMaxPathSize];
1543 uint8_t localVersion = 0;
1544
1545 if (CFURLGetFileSystemRepresentation(url, true, buff, CFMaxPathSize)) {
1546 CFURLRef newURL = CFURLCreateFromFileSystemRepresentation(alloc, buff, strlen(buff), true);
1547 if (NULL == newURL) newURL = CFRetain(url);
1548
1549 if (!_CFBundleURLLooksLikeBundleVersion(newURL, &localVersion)) {
1550 // version 3 is for flattened pseudo-bundles with no Contents, Support Files, or Resources directories
1551 localVersion = 3;
1552 }
1553 dict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(alloc, newURL, localVersion);
1554 CFRelease(newURL);
1555 }
1556 if (version) *version = localVersion;
1557 return dict;
1558 }
1559
1560 __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc, CFURLRef url, uint8_t version) {
1561 CFDictionaryRef result = NULL;
1562 if (url != NULL) {
1563 CFURLRef infoURL = NULL;
1564 CFDataRef infoData = NULL;
1565 UniChar buff[CFMaxPathSize];
1566 CFIndex len;
1567 CFMutableStringRef cheapStr;
1568 CFStringRef infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension0, infoURLFromBase = _CFBundleInfoURLFromBase0;
1569 Boolean tryPlatformSpecific = true, tryGlobal = true;
1570 #if USE_GETDIRENTRIES
1571 CFArrayRef directoryContents = NULL;
1572 CFRange directoryContentsRange = CFRangeMake(0, 0);
1573 #endif
1574
1575 _CFEnsureStaticBuffersInited();
1576
1577 if (0 == version) {
1578 #if USE_GETDIRENTRIES
1579 // we want to read the Resources directory anyway, so we might as well do it now
1580 CFURLRef resourcesURL = _CFBundleCopyResourcesDirectoryURLInDirectory(alloc, url, version);
1581 CFURLRef absoluteURL = CFURLCopyAbsoluteURL(resourcesURL);
1582 CFStringRef resourcesPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
1583 directoryContents = _CFBundleCopyDirectoryContentsAtPath(resourcesPath, false);
1584 directoryContentsRange = CFRangeMake(0, CFArrayGetCount(directoryContents));
1585 CFRelease(resourcesPath);
1586 CFRelease(absoluteURL);
1587 CFRelease(resourcesURL);
1588 #endif
1589 infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension0;
1590 infoURLFromBase = _CFBundleInfoURLFromBase0;
1591 } else if (1 == version) {
1592 infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension1;
1593 infoURLFromBase = _CFBundleInfoURLFromBase1;
1594 } else if (2 == version) {
1595 infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension2;
1596 infoURLFromBase = _CFBundleInfoURLFromBase2;
1597 } else if (3 == version) {
1598 CFStringRef posixPath = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
1599 // this test is necessary to exclude the case where a bundle is spuriously created from the innards of another bundle
1600 if (posixPath) {
1601 if (!(CFStringHasSuffix(posixPath, _CFBundleSupportFilesDirectoryName1) || CFStringHasSuffix(posixPath, _CFBundleSupportFilesDirectoryName2) || CFStringHasSuffix(posixPath, _CFBundleResourcesDirectoryName))) {
1602 infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension3;
1603 infoURLFromBase = _CFBundleInfoURLFromBase3;
1604 }
1605 CFRelease(posixPath);
1606 }
1607 }
1608
1609 len = CFStringGetLength(infoURLFromBaseNoExtension);
1610 CFStringGetCharacters(infoURLFromBaseNoExtension, CFRangeMake(0, len), buff);
1611 buff[len++] = (UniChar)'-';
1612 memmove(buff + len, _PlatformUniChars, _PlatformLen * sizeof(UniChar));
1613 len += _PlatformLen;
1614 _CFAppendPathExtension(buff, &len, CFMaxPathSize, _InfoExtensionUniChars, _InfoExtensionLen);
1615 cheapStr = CFStringCreateMutable(alloc, 0);
1616 CFStringAppendCharacters(cheapStr, buff, len);
1617 infoURL = CFURLCreateWithString(alloc, cheapStr, url);
1618 #if USE_GETDIRENTRIES
1619 if (directoryContents) {
1620 CFIndex resourcesLen = CFStringGetLength(_CFBundleResourcesURLFromBase0);
1621 CFStringDelete(cheapStr, CFRangeMake(0, CFStringGetLength(cheapStr)));
1622 CFStringAppendCharacters(cheapStr, buff + resourcesLen, len - resourcesLen);
1623 tryPlatformSpecific = CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr);
1624 }
1625 #endif
1626 if (tryPlatformSpecific) CFURLCreateDataAndPropertiesFromResource(alloc, infoURL, &infoData, NULL, NULL, NULL);
1627 //fprintf(stderr, "looking for ");CFShow(infoURL);if (infoData) fprintf(stderr, "found it\n");
1628 CFRelease(cheapStr);
1629 if (!infoData) {
1630 // Check for global Info.plist
1631 CFRelease(infoURL);
1632 infoURL = CFURLCreateWithString(alloc, infoURLFromBase, url);
1633 #if USE_GETDIRENTRIES
1634 if (directoryContents) tryGlobal = CFArrayContainsValue(directoryContents, directoryContentsRange, _CFBundleInfoFileName);
1635 #endif
1636 if (tryGlobal) CFURLCreateDataAndPropertiesFromResource(alloc, infoURL, &infoData, NULL, NULL, NULL);
1637 //fprintf(stderr, "looking for ");CFShow(infoURL);if (infoData) fprintf(stderr, "found it\n");
1638 }
1639
1640 if (infoData) {
1641 result = CFPropertyListCreateFromXMLData(alloc, infoData, kCFPropertyListMutableContainers, NULL);
1642 if (result) {
1643 if (CFDictionaryGetTypeID() == CFGetTypeID(result)) {
1644 CFDictionarySetValue((CFMutableDictionaryRef)result, _kCFBundleInfoPlistURLKey, infoURL);
1645 } else {
1646 CFRelease(result);
1647 result = NULL;
1648 }
1649 }
1650 CFRelease(infoData);
1651 }
1652 if (!result) {
1653 result = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1654 }
1655
1656 CFRelease(infoURL);
1657 #if USE_GETDIRENTRIES
1658 if (directoryContents) CFRelease(directoryContents);
1659 #endif
1660 }
1661 return result;
1662 }
1663
1664 static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorRef alloc, CFURLRef url, CFDictionaryRef infoDict, UInt32 *packageType, UInt32 *packageCreator) {
1665 Boolean retVal = false, hasType = false, hasCreator = false, releaseInfoDict = false;
1666 CFURLRef tempURL;
1667 CFDataRef pkgInfoData = NULL;
1668
1669 // Check for a "real" new bundle
1670 tempURL = CFURLCreateWithString(alloc, _CFBundlePkgInfoURLFromBase2, url);
1671 CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL);
1672 CFRelease(tempURL);
1673 if (pkgInfoData == NULL) {
1674 tempURL = CFURLCreateWithString(alloc, _CFBundlePkgInfoURLFromBase1, url);
1675 CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL);
1676 CFRelease(tempURL);
1677 }
1678 if (pkgInfoData == NULL) {
1679 // Check for a "pseudo" new bundle
1680 tempURL = CFURLCreateWithString(alloc, _CFBundlePseudoPkgInfoURLFromBase, url);
1681 CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL);
1682 CFRelease(tempURL);
1683 }
1684
1685 // Now, either we have a pkgInfoData or not. If not, then is it because this is a new bundle without one (do we allow this?), or is it dbecause it is an old bundle.
1686 // If we allow new bundles to not have a PkgInfo (because they already have the same data in the Info.plist), then we have to go read the info plist which makes failure expensive.
1687 // drd: So we assume that a new bundle _must_ have a PkgInfo if they have this data at all, otherwise we manufacture it from the extension.
1688
1689 if ((pkgInfoData != NULL) && (CFDataGetLength(pkgInfoData) >= (int)(sizeof(UInt32) * 2))) {
1690 UInt32 *pkgInfo = (UInt32 *)CFDataGetBytePtr(pkgInfoData);
1691
1692 if (packageType != NULL) {
1693 *packageType = CFSwapInt32BigToHost(pkgInfo[0]);
1694 }
1695 if (packageCreator != NULL) {
1696 *packageCreator = CFSwapInt32BigToHost(pkgInfo[1]);
1697 }
1698 retVal = hasType = hasCreator = true;
1699 }
1700 if (pkgInfoData != NULL) CFRelease(pkgInfoData);
1701 if (!retVal) {
1702 if (!infoDict) {
1703 infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, NULL);
1704 releaseInfoDict = true;
1705 }
1706 if (infoDict) {
1707 CFStringRef typeString = CFDictionaryGetValue(infoDict, _kCFBundlePackageTypeKey), creatorString = CFDictionaryGetValue(infoDict, _kCFBundleSignatureKey);
1708 UInt32 tmp;
1709 CFIndex usedBufLen = 0;
1710 if (typeString && CFGetTypeID(typeString) == CFStringGetTypeID() && CFStringGetLength(typeString) == 4 && 4 == CFStringGetBytes(typeString, CFRangeMake(0, 4), kCFStringEncodingMacRoman, 0, false, (UInt8 *)&tmp, 4, &usedBufLen) && 4 == usedBufLen) {
1711 if (packageType != NULL) {
1712 *packageType = CFSwapInt32BigToHost(tmp);
1713 }
1714 retVal = hasType = true;
1715 }
1716 if (creatorString && CFGetTypeID(creatorString) == CFStringGetTypeID() && CFStringGetLength(creatorString) == 4 && 4 == CFStringGetBytes(creatorString, CFRangeMake(0, 4), kCFStringEncodingMacRoman, 0, false, (UInt8 *)&tmp, 4, &usedBufLen) && 4 == usedBufLen) {
1717 if (packageCreator != NULL) {
1718 *packageCreator = CFSwapInt32BigToHost(tmp);
1719 }
1720 retVal = hasCreator = true;
1721 }
1722 if (releaseInfoDict) CFRelease(infoDict);
1723 }
1724 }
1725 if (!hasType || !hasCreator) {
1726 // If this looks like a bundle then manufacture the type and creator.
1727 if (retVal || _CFBundleURLLooksLikeBundle(url)) {
1728 if (packageCreator != NULL && !hasCreator) {
1729 *packageCreator = 0x3f3f3f3f; // '????'
1730 }
1731 if (packageType != NULL && !hasType) {
1732 CFStringRef urlStr;
1733 UniChar buff[CFMaxPathSize];
1734 CFIndex strLen, startOfExtension;
1735 CFURLRef absoluteURL;
1736
1737 // Detect "app", "debug", "profile", or "framework" extensions
1738 absoluteURL = CFURLCopyAbsoluteURL(url);
1739 urlStr = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
1740 CFRelease(absoluteURL);
1741 strLen = CFStringGetLength(urlStr);
1742 CFStringGetCharacters(urlStr, CFRangeMake(0, strLen), buff);
1743 CFRelease(urlStr);
1744 startOfExtension = _CFStartOfPathExtension(buff, strLen);
1745 if (((strLen - startOfExtension == 4) || (strLen - startOfExtension == 5)) && (buff[startOfExtension] == (UniChar)'.') && (buff[startOfExtension+1] == (UniChar)'a') && (buff[startOfExtension+2] == (UniChar)'p') && (buff[startOfExtension+3] == (UniChar)'p') && ((strLen - startOfExtension == 4) || (buff[startOfExtension+4] == (UniChar)'/'))) {
1746 // This is an app
1747 *packageType = CFSwapInt32BigToHost(0x4150504c); // 'APPL'
1748 } else if (((strLen - startOfExtension == 6) || (strLen - startOfExtension == 7)) && (buff[startOfExtension] == (UniChar)'.') && (buff[startOfExtension+1] == (UniChar)'d') && (buff[startOfExtension+2] == (UniChar)'e') && (buff[startOfExtension+3] == (UniChar)'b') && (buff[startOfExtension+4] == (UniChar)'u') && (buff[startOfExtension+5] == (UniChar)'g') && ((strLen - startOfExtension == 6) || (buff[startOfExtension+6] == (UniChar)'/'))) {
1749 // This is an app (debug version)
1750 *packageType = CFSwapInt32BigToHost(0x4150504c); // 'APPL'
1751 } else if (((strLen - startOfExtension == 8) || (strLen - startOfExtension == 9)) && (buff[startOfExtension] == (UniChar)'.') && (buff[startOfExtension+1] == (UniChar)'p') && (buff[startOfExtension+2] == (UniChar)'r') && (buff[startOfExtension+3] == (UniChar)'o') && (buff[startOfExtension+4] == (UniChar)'f') && (buff[startOfExtension+5] == (UniChar)'i') && (buff[startOfExtension+6] == (UniChar)'l') && (buff[startOfExtension+7] == (UniChar)'e') && ((strLen - startOfExtension == 8) || (buff[startOfExtension+8] == (UniChar)'/'))) {
1752 // This is an app (profile version)
1753 *packageType = CFSwapInt32BigToHost(0x4150504c); // 'APPL'
1754 } else if (((strLen - startOfExtension == 8) || (strLen - startOfExtension == 9)) && (buff[startOfExtension] == (UniChar)'.') && (buff[startOfExtension+1] == (UniChar)'s') && (buff[startOfExtension+2] == (UniChar)'e') && (buff[startOfExtension+3] == (UniChar)'r') && (buff[startOfExtension+4] == (UniChar)'v') && (buff[startOfExtension+5] == (UniChar)'i') && (buff[startOfExtension+6] == (UniChar)'c') && (buff[startOfExtension+7] == (UniChar)'e') && ((strLen - startOfExtension == 8) || (buff[startOfExtension+8] == (UniChar)'/'))) {
1755 // This is a service
1756 *packageType = CFSwapInt32BigToHost(0x4150504c); // 'APPL'
1757 } else if (((strLen - startOfExtension == 10) || (strLen - startOfExtension == 11)) && (buff[startOfExtension] == (UniChar)'.') && (buff[startOfExtension+1] == (UniChar)'f') && (buff[startOfExtension+2] == (UniChar)'r') && (buff[startOfExtension+3] == (UniChar)'a') && (buff[startOfExtension+4] == (UniChar)'m') && (buff[startOfExtension+5] == (UniChar)'e') && (buff[startOfExtension+6] == (UniChar)'w') && (buff[startOfExtension+7] == (UniChar)'o') && (buff[startOfExtension+8] == (UniChar)'r') && (buff[startOfExtension+9] == (UniChar)'k') && ((strLen - startOfExtension == 10) || (buff[startOfExtension+10] == (UniChar)'/'))) {
1758 // This is a framework
1759 *packageType = CFSwapInt32BigToHost(0x464d574b); // 'FMWK'
1760 } else {
1761 // Default to BNDL for generic bundle
1762 *packageType = CFSwapInt32BigToHost(0x424e444C); // 'BNDL'
1763 }
1764 }
1765 retVal = true;
1766 }
1767 }
1768 return retVal;
1769 }
1770
1771 CF_EXPORT Boolean _CFBundleGetPackageInfoInDirectory(CFAllocatorRef alloc, CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {return _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(alloc, url, NULL, packageType, packageCreator);}
1772
1773 CF_EXPORT void CFBundleGetPackageInfo(CFBundleRef bundle, UInt32 *packageType, UInt32 *packageCreator) {
1774 CFURLRef bundleURL = CFBundleCopyBundleURL(bundle);
1775 if (!_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFGetAllocator(bundle), bundleURL, CFBundleGetInfoDictionary(bundle), packageType, packageCreator)) {
1776 if (packageType != NULL) {
1777 *packageType = CFSwapInt32BigToHost(0x424e444C); // 'BNDL'
1778 }
1779 if (packageCreator != NULL) {
1780 *packageCreator = 0x3f3f3f3f; // '????'
1781 }
1782 }
1783 if (bundleURL) CFRelease(bundleURL);
1784 }
1785
1786 CF_EXPORT Boolean CFBundleGetPackageInfoInDirectory(CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {return _CFBundleGetPackageInfoInDirectory(NULL, url, packageType, packageCreator);}
1787
1788 __private_extern__ CFStringRef _CFBundleGetPlatformExecutablesSubdirectoryName(void) {
1789 #if defined(__MACOS8__)
1790 return CFSTR("MacOSClassic");
1791 #elif defined(__WIN32__)
1792 return CFSTR("Windows");
1793 #elif defined(__MACH__)
1794 return CFSTR("MacOS");
1795 #elif defined(__hpux__)
1796 return CFSTR("HPUX");
1797 #elif defined(__svr4__)
1798 return CFSTR("Solaris");
1799 #elif defined(__LINUX__)
1800 return CFSTR("Linux");
1801 #elif defined(__FREEBSD__)
1802 return CFSTR("FreeBSD");
1803 #else
1804 #warning CFBundle: Unknown architecture
1805 return CFSTR("Other");
1806 #endif
1807 }
1808
1809 __private_extern__ CFStringRef _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(void) {
1810 #if defined(__MACOS8__)
1811 return CFSTR("Mac OS 8");
1812 #elif defined(__WIN32__)
1813 return CFSTR("WinNT");
1814 #elif defined(__MACH__)
1815 return CFSTR("Mac OS X");
1816 #elif defined(__hpux__)
1817 return CFSTR("HP-UX");
1818 #elif defined(__svr4__)
1819 return CFSTR("Solaris");
1820 #elif defined(__LINUX__)
1821 return CFSTR("Linux");
1822 #elif defined(__FREEBSD__)
1823 return CFSTR("FreeBSD");
1824 #else
1825 #warning CFBundle: Unknown architecture
1826 return CFSTR("Other");
1827 #endif
1828 }
1829
1830 __private_extern__ CFStringRef _CFBundleGetOtherPlatformExecutablesSubdirectoryName(void) {
1831 #if defined(__MACOS8__)
1832 return CFSTR("MacOS");
1833 #elif defined(__WIN32__)
1834 return CFSTR("Other");
1835 #elif defined(__MACH__)
1836 return CFSTR("MacOSClassic");
1837 #elif defined(__hpux__)
1838 return CFSTR("Other");
1839 #elif defined(__svr4__)
1840 return CFSTR("Other");
1841 #elif defined(__LINUX__)
1842 return CFSTR("Other");
1843 #elif defined(__FREEBSD__)
1844 return CFSTR("Other");
1845 #else
1846 #warning CFBundle: Unknown architecture
1847 return CFSTR("Other");
1848 #endif
1849 }
1850
1851 __private_extern__ CFStringRef _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(void) {
1852 #if defined(__MACOS8__)
1853 return CFSTR("Mac OS X");
1854 #elif defined(__WIN32__)
1855 return CFSTR("Other");
1856 #elif defined(__MACH__)
1857 return CFSTR("Mac OS 8");
1858 #elif defined(__hpux__)
1859 return CFSTR("Other");
1860 #elif defined(__svr4__)
1861 return CFSTR("Other");
1862 #elif defined(__LINUX__)
1863 return CFSTR("Other");
1864 #elif defined(__FREEBSD__)
1865 return CFSTR("Other");
1866 #else
1867 #warning CFBundle: Unknown architecture
1868 return CFSTR("Other");
1869 #endif
1870 }
1871
1872 __private_extern__ CFArrayRef _CFBundleCopyBundleRegionsArray(CFBundleRef bundle) {return CFBundleCopyBundleLocalizations(bundle);}
1873
1874 CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) {
1875 CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
1876 uint8_t version = _CFBundleLayoutVersion(bundle);
1877 CFArrayRef urls = ((version != 4) ? _CFContentsOfDirectory(CFGetAllocator(bundle), NULL, NULL, resourcesURL, CFSTR("lproj")) : NULL);
1878 CFArrayRef predefinedLocalizations = NULL;
1879 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1880 CFMutableArrayRef result = NULL;
1881
1882 if (infoDict) {
1883 predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey);
1884 if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) != CFArrayGetTypeID()) {
1885 predefinedLocalizations = NULL;
1886 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleLocalizationsKey);
1887 }
1888 if (predefinedLocalizations != NULL) {
1889 CFIndex i, c = CFArrayGetCount(predefinedLocalizations);
1890 if (c > 0 && !result) {
1891 result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks);
1892 }
1893 for (i=0; i<c; i++) {
1894 CFArrayAppendValue(result, CFArrayGetValueAtIndex(predefinedLocalizations, i));
1895 }
1896 }
1897 }
1898
1899 if (urls) {
1900 CFIndex i, c;
1901 CFURLRef curURL, curAbsoluteURL;
1902 CFStringRef curStr, regionStr;
1903 UniChar buff[CFMaxPathSize];
1904 CFIndex strLen, startOfLastPathComponent, regionLen;
1905
1906 c = CFArrayGetCount(urls);
1907 if (c > 0 && !result) {
1908 result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks);
1909 }
1910 for (i = 0; i < c; i++) {
1911 curURL = CFArrayGetValueAtIndex(urls, i);
1912 curAbsoluteURL = CFURLCopyAbsoluteURL(curURL);
1913 curStr = CFURLCopyFileSystemPath(curAbsoluteURL, PLATFORM_PATH_STYLE);
1914 CFRelease(curAbsoluteURL);
1915 strLen = CFStringGetLength(curStr);
1916 CFStringGetCharacters(curStr, CFRangeMake(0, strLen), buff);
1917
1918 startOfLastPathComponent = _CFStartOfLastPathComponent(buff, strLen);
1919 regionLen = _CFLengthAfterDeletingPathExtension(&(buff[startOfLastPathComponent]), strLen - startOfLastPathComponent);
1920 regionStr = CFStringCreateWithCharacters(CFGetAllocator(bundle), &(buff[startOfLastPathComponent]), regionLen);
1921 CFArrayAppendValue(result, regionStr);
1922 CFRelease(regionStr);
1923 CFRelease(curStr);
1924 }
1925 CFRelease(urls);
1926 }
1927 if (!result) {
1928 CFStringRef developmentLocalization = CFBundleGetDevelopmentRegion(bundle);
1929 if (developmentLocalization) {
1930 result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks);
1931 CFArrayAppendValue(result, developmentLocalization);
1932 }
1933 }
1934 if (resourcesURL) CFRelease(resourcesURL);
1935
1936 return result;
1937 }
1938
1939
1940 CF_EXPORT CFDictionaryRef CFBundleCopyInfoDictionaryForURL(CFURLRef url) {
1941 CFDictionaryRef result = NULL;
1942 Boolean isDir;
1943 if (_CFIsResourceAtURL(url, &isDir)) {
1944 if (isDir) {
1945 result = _CFBundleCopyInfoDictionaryInDirectory(NULL, url, NULL);
1946 } else {
1947 result = _CFBundleCopyInfoDictionaryInExecutable(url);
1948 }
1949 }
1950 return result;
1951 }
1952
1953 CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) {
1954 CFArrayRef result = NULL;
1955 CFBundleRef bundle = CFBundleCreate(NULL, url);
1956 CFStringRef devLang = NULL;
1957 if (bundle) {
1958 result = CFBundleCopyBundleLocalizations(bundle);
1959 CFRelease(bundle);
1960 } else {
1961 CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInExecutable(url);
1962 if (infoDict) {
1963 CFArrayRef predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey);
1964 if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) == CFArrayGetTypeID()) {
1965 result = CFRetain(predefinedLocalizations);
1966 }
1967 if (!result) {
1968 devLang = CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey);
1969 if (devLang != NULL && (CFGetTypeID(devLang) == CFStringGetTypeID() && CFStringGetLength(devLang) > 0)) {
1970 result = CFArrayCreate(NULL, (const void **)&devLang, 1, &kCFTypeArrayCallBacks);
1971 }
1972 }
1973 CFRelease(infoDict);
1974 }
1975 }
1976 return result;
1977 }