CFBundle_Resources.c [plain text]
#if defined(__MACOS8__) || defined(__WIN32__)
#define USE_GETDIRENTRIES 0
#else
#define USE_GETDIRENTRIES 1
#endif
#define GETDIRENTRIES_CACHE_CAPACITY 100
#include "CFBundle_Internal.h"
#include <CoreFoundation/CFURLAccess.h>
#include <CoreFoundation/CFPropertyList.h>
#include <CoreFoundation/CFByteOrder.h>
#include <CoreFoundation/CFNumber.h>
#include <string.h>
#include "CFInternal.h"
#include "CFPriv.h"
#if defined(__MACOS8__)
#include <Script.h>
#include <stat.h>
#include <Files.h>
#include <Resources.h>
#include <CodeFragments.h>
#include <Errors.h>
#include <Gestalt.h>
#else
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#if USE_GETDIRENTRIES
#include <dirent.h>
#endif
#endif
CF_INLINE CFStringRef _CFGetPlatformName(void) {
#if defined(__WIN32__)
return _CFBundleWindowsPlatformName;
#elif defined(__MACOS8__)
return _CFBundleMacOS8PlatformName;
#elif defined (__MACH__)
return _CFBundleMacOSXPlatformName;
#elif defined(__svr4__)
return _CFBundleSolarisPlatformName;
#elif defined(__hpux__)
return _CFBundleHPUXPlatformName;
#elif defined(__LINUX__)
return _CFBundleLinuxPlatformName;
#elif defined(__FREEBSD__)
return _CFBundleFreeBSDPlatformName;
#else
return CFSTR("");
#endif
}
CF_INLINE CFStringRef _CFGetAlternatePlatformName(void) {
#if defined (__MACH__)
return _CFBundleAlternateMacOSXPlatformName;
#elif defined(__MACOS8__)
return _CFBundleAlternateMacOS8PlatformName;
#else
return CFSTR("");
#endif
}
static CFSpinLock_t CFBundleResourceGlobalDataLock = 0;
static UniChar *_AppSupportUniChars1 = NULL;
static CFIndex _AppSupportLen1 = 0;
static UniChar *_AppSupportUniChars2 = NULL;
static CFIndex _AppSupportLen2 = 0;
static UniChar *_ResourcesUniChars = NULL;
static CFIndex _ResourcesLen = 0;
static UniChar *_PlatformUniChars = NULL;
static CFIndex _PlatformLen = 0;
static UniChar *_AlternatePlatformUniChars = NULL;
static CFIndex _AlternatePlatformLen = 0;
static UniChar *_LprojUniChars = NULL;
static CFIndex _LprojLen = 0;
static UniChar *_GlobalResourcesUniChars = NULL;
static CFIndex _GlobalResourcesLen = 0;
static UniChar *_InfoExtensionUniChars = NULL;
static CFIndex _InfoExtensionLen = 0;
static void _CFBundleInitStaticUniCharBuffers(void) {
CFStringRef appSupportStr1 = _CFBundleSupportFilesDirectoryName1;
CFStringRef appSupportStr2 = _CFBundleSupportFilesDirectoryName2;
CFStringRef resourcesStr = _CFBundleResourcesDirectoryName;
CFStringRef platformStr = _CFGetPlatformName();
CFStringRef alternatePlatformStr = _CFGetAlternatePlatformName();
CFStringRef lprojStr = _CFBundleLprojExtension;
CFStringRef globalResourcesStr = _CFBundleNonLocalizedResourcesDirectoryName;
CFStringRef infoExtensionStr = _CFBundleInfoExtension;
CFAllocatorRef alloc = __CFGetDefaultAllocator();
_AppSupportLen1 = CFStringGetLength(appSupportStr1);
_AppSupportLen2 = CFStringGetLength(appSupportStr2);
_ResourcesLen = CFStringGetLength(resourcesStr);
_PlatformLen = CFStringGetLength(platformStr);
_AlternatePlatformLen = CFStringGetLength(alternatePlatformStr);
_LprojLen = CFStringGetLength(lprojStr);
_GlobalResourcesLen = CFStringGetLength(globalResourcesStr);
_InfoExtensionLen = CFStringGetLength(infoExtensionStr);
_AppSupportUniChars1 = CFAllocatorAllocate(alloc, sizeof(UniChar) * (_AppSupportLen1 + _AppSupportLen2 + _ResourcesLen + _PlatformLen + _AlternatePlatformLen + _LprojLen + _GlobalResourcesLen + _InfoExtensionLen), 0);
_AppSupportUniChars2 = _AppSupportUniChars1 + _AppSupportLen1;
_ResourcesUniChars = _AppSupportUniChars2 + _AppSupportLen2;
_PlatformUniChars = _ResourcesUniChars + _ResourcesLen;
_AlternatePlatformUniChars = _PlatformUniChars + _PlatformLen;
_LprojUniChars = _AlternatePlatformUniChars + _AlternatePlatformLen;
_GlobalResourcesUniChars = _LprojUniChars + _LprojLen;
_InfoExtensionUniChars = _GlobalResourcesUniChars + _GlobalResourcesLen;
if (_AppSupportLen1 > 0) {
CFStringGetCharacters(appSupportStr1, CFRangeMake(0, _AppSupportLen1), _AppSupportUniChars1);
}
if (_AppSupportLen2 > 0) {
CFStringGetCharacters(appSupportStr2, CFRangeMake(0, _AppSupportLen2), _AppSupportUniChars2);
}
if (_ResourcesLen > 0) {
CFStringGetCharacters(resourcesStr, CFRangeMake(0, _ResourcesLen), _ResourcesUniChars);
}
if (_PlatformLen > 0) {
CFStringGetCharacters(platformStr, CFRangeMake(0, _PlatformLen), _PlatformUniChars);
}
if (_AlternatePlatformLen > 0) {
CFStringGetCharacters(alternatePlatformStr, CFRangeMake(0, _AlternatePlatformLen), _AlternatePlatformUniChars);
}
if (_LprojLen > 0) {
CFStringGetCharacters(lprojStr, CFRangeMake(0, _LprojLen), _LprojUniChars);
}
if (_GlobalResourcesLen > 0) {
CFStringGetCharacters(globalResourcesStr, CFRangeMake(0, _GlobalResourcesLen), _GlobalResourcesUniChars);
}
if (_InfoExtensionLen > 0) {
CFStringGetCharacters(infoExtensionStr, CFRangeMake(0, _InfoExtensionLen), _InfoExtensionUniChars);
}
}
CF_INLINE void _CFEnsureStaticBuffersInited(void) {
__CFSpinLock(&CFBundleResourceGlobalDataLock);
if (_AppSupportUniChars1 == NULL) {
_CFBundleInitStaticUniCharBuffers();
}
__CFSpinUnlock(&CFBundleResourceGlobalDataLock);
}
#if USE_GETDIRENTRIES
static CFMutableDictionaryRef contentsCache = NULL;
static CFMutableDictionaryRef directoryContentsCache = NULL;
static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, Boolean directoriesOnly) {
CFArrayRef result = NULL;
__CFSpinLock(&CFBundleResourceGlobalDataLock);
if (directoriesOnly) {
if (directoryContentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(directoryContentsCache, path);
} else {
if (contentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(contentsCache, path);
}
if (result) CFRetain(result);
__CFSpinUnlock(&CFBundleResourceGlobalDataLock);
if (!result) {
char cpathBuff[CFMaxPathSize], dirge[8192];
CFIndex cpathLen = 0;
int fd = -1, numread;
long basep = 0;
CFMutableArrayRef contents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), directoryContents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFStringRef name;
if (_CFStringGetFileSystemRepresentation(path, cpathBuff, CFMaxPathSize)) {
cpathLen = strlen(cpathBuff);
fd = open(cpathBuff, O_RDONLY, 0777);
}
if (fd >= 0) {
while ((numread = getdirentries(fd, dirge, sizeof(dirge), &basep)) > 0) {
struct dirent *dent;
for (dent = (struct dirent *)dirge; dent < (struct dirent *)(dirge + numread); dent = (struct dirent *)((char *)dent + dent->d_reclen)) {
CFIndex nameLen = strlen(dent->d_name);
if (0 == dent->d_fileno || (dent->d_name[0] == '.' && (nameLen == 1 || (nameLen == 2 && dent->d_name[1] == '.')))) continue;
name = CFStringCreateWithCString(NULL, dent->d_name, CFStringFileSystemEncoding());
if (NULL != name) {
CFArrayAppendValue(contents, name);
if (dent->d_type == DT_DIR) {
CFArrayAppendValue(directoryContents, name);
} else if (dent->d_type == DT_UNKNOWN) {
struct stat statBuf;
cpathBuff[cpathLen] = '/';
strncpy(cpathBuff + cpathLen + 1, dent->d_name, nameLen);
cpathBuff[cpathLen + nameLen + 1] = '\0';
if (stat(cpathBuff, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFDIR) CFArrayAppendValue(directoryContents, name);
cpathBuff[cpathLen] = '\0';
}
CFRelease(name);
}
}
}
close(fd);
}
__CFSpinLock(&CFBundleResourceGlobalDataLock);
if (!contentsCache) contentsCache = CFDictionaryCreateMutable(NULL, GETDIRENTRIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (GETDIRENTRIES_CACHE_CAPACITY == CFDictionaryGetCount(contentsCache)) CFDictionaryRemoveAllValues(contentsCache);
CFDictionaryAddValue(contentsCache, path, contents);
if (!directoryContentsCache) directoryContentsCache = CFDictionaryCreateMutable(NULL, GETDIRENTRIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (GETDIRENTRIES_CACHE_CAPACITY == CFDictionaryGetCount(directoryContentsCache)) CFDictionaryRemoveAllValues(directoryContentsCache);
CFDictionaryAddValue(directoryContentsCache, path, directoryContents);
result = CFRetain(directoriesOnly ? directoryContents : contents);
CFRelease(contents);
CFRelease(directoryContents);
__CFSpinUnlock(&CFBundleResourceGlobalDataLock);
}
return result;
}
static void _CFBundleFlushContentsCaches(void) {
__CFSpinLock(&CFBundleResourceGlobalDataLock);
if (contentsCache) CFDictionaryRemoveAllValues(contentsCache);
if (directoryContentsCache) CFDictionaryRemoveAllValues(directoryContentsCache);
__CFSpinUnlock(&CFBundleResourceGlobalDataLock);
}
#endif
CF_EXPORT void _CFBundleFlushCaches(void) {
#if USE_GETDIRENTRIES
_CFBundleFlushContentsCaches();
#endif
}
__private_extern__ Boolean _CFIsResourceAtURL(CFURLRef url, Boolean *isDir) {
Boolean exists;
SInt32 mode;
if (_CFGetFileProperties(NULL, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) {
if (isDir) {
*isDir = ((exists && ((mode & S_IFMT) == S_IFDIR)) ? true : false);
}
#if defined(__MACOS8__)
return (exists);
#else
return (exists && (mode & 0444));
#endif
} else {
return false;
}
}
__private_extern__ Boolean _CFIsResourceAtPath(CFStringRef path, Boolean *isDir) {
Boolean result = false;
CFURLRef url = CFURLCreateWithFileSystemPath(CFGetAllocator(path), path, PLATFORM_PATH_STYLE, false);
if (url != NULL) {
result = _CFIsResourceAtURL(url, isDir);
CFRelease(url);
}
return result;
}
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) {
CFIndex savedPathLen;
Boolean platformGenericFound = false, platformSpecificFound = false;
Boolean platformGenericIsDir = false, platformSpecificIsDir = false;
CFStringRef platformGenericStr = NULL;
#if USE_GETDIRENTRIES
CFIndex dirPathLen = pathLen;
CFArrayRef contents, directoryContents;
CFRange contentsRange, directoryContentsRange;
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, dirPathLen, dirPathLen);
CFStringReplaceAll(cheapStr, tmpString);
contents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, false);
contentsRange = CFRangeMake(0, CFArrayGetCount(contents));
directoryContents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, true);
directoryContentsRange = CFRangeMake(0, CFArrayGetCount(directoryContents));
#endif
if (nameLen > 0) {
_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, nameUniChars, nameLen);
}
savedPathLen = pathLen;
if (typeLen > 0) {
_CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen);
}
#if USE_GETDIRENTRIES
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen + 1, pathLen - dirPathLen - 1, pathLen - dirPathLen - 1);
CFStringReplaceAll(cheapStr, tmpString);
platformGenericFound = CFArrayContainsValue(contents, contentsRange, cheapStr);
platformGenericIsDir = CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr);
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
CFStringReplaceAll(cheapStr, tmpString);
#else
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
CFStringReplaceAll(cheapStr, tmpString);
platformGenericFound = _CFIsResourceAtPath(cheapStr, &platformGenericIsDir);
#endif
if (platformGenericFound) {
platformGenericStr = CFStringCreateCopy(alloc, cheapStr);
if (!platformSpecificFound && (_PlatformLen > 0)) {
pathLen = savedPathLen;
pathUniChars[pathLen++] = (UniChar)'-';
memmove(pathUniChars + pathLen, _PlatformUniChars, _PlatformLen * sizeof(UniChar));
pathLen += _PlatformLen;
if (typeLen > 0) {
_CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen);
}
#if USE_GETDIRENTRIES
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen + 1, pathLen - dirPathLen - 1, pathLen - dirPathLen - 1);
CFStringReplaceAll(cheapStr, tmpString);
platformSpecificFound = CFArrayContainsValue(contents, contentsRange, cheapStr);
platformSpecificIsDir = CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr);
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
CFStringReplaceAll(cheapStr, tmpString);
#else
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
CFStringReplaceAll(cheapStr, tmpString);
platformSpecificFound = _CFIsResourceAtPath(cheapStr, &platformSpecificIsDir);
#endif
}
}
if (platformSpecificFound) {
CFURLRef url = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, platformSpecificIsDir);
CFArrayAppendValue(result, url);
CFRelease(url);
} else if (platformGenericFound) {
CFURLRef url = CFURLCreateWithFileSystemPath(alloc, ((platformGenericStr != NULL) ? platformGenericStr : cheapStr), PLATFORM_PATH_STYLE, platformGenericIsDir);
CFArrayAppendValue(result, url);
CFRelease(url);
}
if (platformGenericStr != NULL) {
CFRelease(platformGenericStr);
}
#if USE_GETDIRENTRIES
CFRelease(contents);
CFRelease(directoryContents);
#endif
}
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) {
if (nameLen > 0) {
if (!resTypes) {
_CFSearchBundleDirectory(alloc, result, workingUniChars, workingLen, nameUniChars, nameLen, NULL, 0, cheapStr, tmpString, version);
} else {
CFIndex i, c = CFArrayGetCount(resTypes);
for (i=0; i<c; i++) {
CFStringRef curType = (CFStringRef)CFArrayGetValueAtIndex(resTypes, i);
CFIndex typeLen = CFStringGetLength(curType);
#if defined(__MACOS8__) || defined(__WIN32__)
UniChar *typeChars = CFAllocatorAllocate(alloc, sizeof(UniChar) * typeLen, 0);
if (typeChars) {
#else
UniChar typeChars[typeLen];
#endif
CFStringGetCharacters(curType, CFRangeMake(0, typeLen), typeChars);
_CFSearchBundleDirectory(alloc, result, workingUniChars, workingLen, nameUniChars, nameLen, typeChars, typeLen, cheapStr, tmpString, version);
if (limit <= CFArrayGetCount(result)) {
break;
}
#if defined(__MACOS8__) || defined(__WIN32__)
CFAllocatorDeallocate(alloc, typeChars);
}
#endif
}
}
} else {
unsigned char cpathBuff[CFMaxPathSize];
CFIndex cpathLen;
CFMutableArrayRef children;
CFStringSetExternalCharactersNoCopy(tmpString, workingUniChars, workingLen, workingLen);
if (!_CFStringGetFileSystemRepresentation(tmpString, cpathBuff, CFMaxPathSize)) return;
cpathLen = strlen(cpathBuff);
if (!resTypes) {
children = _CFContentsOfDirectory(alloc, cpathBuff, NULL, NULL, NULL);
if (children) {
CFIndex childIndex, childCount = CFArrayGetCount(children);
for (childIndex = 0; childIndex < childCount; childIndex++) {
CFArrayAppendValue(result, CFArrayGetValueAtIndex(children, childIndex));
}
CFRelease(children);
}
} else {
CFIndex i, c = CFArrayGetCount(resTypes);
for (i=0; i<c; i++) {
CFStringRef curType = (CFStringRef)CFArrayGetValueAtIndex(resTypes, i);
children = _CFContentsOfDirectory(alloc, cpathBuff, NULL, NULL, curType);
if (children) {
CFIndex childIndex, childCount = CFArrayGetCount(children);
for (childIndex = 0; childIndex < childCount; childIndex++) {
CFArrayAppendValue(result, CFArrayGetValueAtIndex(children, childIndex));
}
CFRelease(children);
}
if (limit <= CFArrayGetCount(result)) {
break;
}
}
}
}
}
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) {
CFIndex savedWorkingLen = workingLen;
if (1 == version) {
_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _GlobalResourcesUniChars, _GlobalResourcesLen);
if (subDirLen > 0) {
_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen);
}
_CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
workingLen = savedWorkingLen;
}
if (CFArrayGetCount(result) < limit) {
if (subDirLen > 0) {
_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen);
}
_CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
}
workingLen = savedWorkingLen;
if (CFArrayGetCount(result) < limit) {
CFIndex langIndex;
CFIndex langCount = (searchLanguages ? CFArrayGetCount(searchLanguages) : 0);
CFStringRef curLangStr;
CFIndex curLangLen;
UniChar curLangUniChars[255];
CFIndex numResults = CFArrayGetCount(result);
for (langIndex = 0; langIndex < langCount; langIndex++) {
curLangStr = CFArrayGetValueAtIndex(searchLanguages, langIndex);
curLangLen = CFStringGetLength(curLangStr);
CFStringGetCharacters(curLangStr, CFRangeMake(0, curLangLen), curLangUniChars);
savedWorkingLen = workingLen;
if (!_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, curLangUniChars, curLangLen)) {
workingLen = savedWorkingLen;
continue;
}
if (!_CFAppendPathExtension(workingUniChars, &workingLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) {
workingLen = savedWorkingLen;
continue;
}
if (subDirLen > 0) {
if (!_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen)) {
workingLen = savedWorkingLen;
continue;
}
}
_CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
workingLen = savedWorkingLen;
if (CFArrayGetCount(result) != numResults) {
break;
}
}
}
}
extern void _CFStrSetDesiredCapacity(CFMutableStringRef str, CFIndex len);
CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef subDirName, CFArrayRef searchLanguages, CFStringRef resName, CFArrayRef resTypes, CFIndex limit, uint8_t version) {
CFAllocatorRef alloc = ((bundle != NULL) ? CFGetAllocator(bundle) : CFRetain(__CFGetDefaultAllocator()));
CFMutableArrayRef result;
UniChar *workingUniChars, *nameUniChars, *subDirUniChars;
CFIndex nameLen = (resName ? CFStringGetLength(resName) : 0);
CFIndex subDirLen = (subDirName ? CFStringGetLength(subDirName) : 0);
CFIndex workingLen, savedWorkingLen;
CFURLRef absoluteURL;
CFStringRef bundlePath;
CFMutableStringRef cheapStr, tmpString;
result = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
_CFEnsureStaticBuffersInited();
nameUniChars = CFAllocatorAllocate(alloc, sizeof(UniChar) * (nameLen + subDirLen + CFMaxPathSize), 0);
subDirUniChars = nameUniChars + nameLen;
workingUniChars = subDirUniChars + subDirLen;
if (nameLen > 0) {
CFStringGetCharacters(resName, CFRangeMake(0, nameLen), nameUniChars);
}
if (subDirLen > 0) {
CFStringGetCharacters(subDirName, CFRangeMake(0, subDirLen), subDirUniChars);
}
bundleURL = ((bundleURL != NULL) ? CFRetain(bundleURL) : CFBundleCopyBundleURL(bundle));
absoluteURL = CFURLCopyAbsoluteURL(bundleURL);
bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
CFRelease(absoluteURL);
if ((workingLen = CFStringGetLength(bundlePath)) > 0) {
CFStringGetCharacters(bundlePath, CFRangeMake(0, workingLen), workingUniChars);
}
CFRelease(bundlePath);
CFRelease(bundleURL);
savedWorkingLen = workingLen;
if (1 == version) {
_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _AppSupportUniChars1, _AppSupportLen1);
} else if (2 == version) {
_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _AppSupportUniChars2, _AppSupportLen2);
}
if (0 == version || 1 == version || 2 == version) {
_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _ResourcesUniChars, _ResourcesLen);
}
cheapStr = CFStringCreateMutable(alloc, 0);
_CFStrSetDesiredCapacity(cheapStr, CFMaxPathSize);
tmpString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull);
_CFFindBundleResourcesInResourcesDir(alloc, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
if (0 == version && CFArrayGetCount(result) == 0) {
workingLen = savedWorkingLen;
_CFFindBundleResourcesInResourcesDir(alloc, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result);
}
CFRelease(cheapStr);
CFRelease(tmpString);
CFAllocatorDeallocate(alloc, nameUniChars);
if (bundle == NULL) {
CFRelease(alloc);
}
return result;
}
CF_EXPORT CFURLRef CFBundleCopyResourceURL(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName) {
CFURLRef result = NULL;
CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle);
CFMutableArrayRef types = NULL;
CFArrayRef array;
if (resourceType) {
types = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
CFArrayAppendValue(types, resourceType);
}
array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle));
if (types) {
CFRelease(types);
}
if (array) {
if (CFArrayGetCount(array) > 0) {
result = CFRetain(CFArrayGetValueAtIndex(array, 0));
}
CFRelease(array);
}
return result;
}
CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfType(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName) {
CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle);
CFMutableArrayRef types = NULL;
CFArrayRef array;
if (resourceType) {
types = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
CFArrayAppendValue(types, resourceType);
}
array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, _CFBundleLayoutVersion(bundle));
if (types) {
CFRelease(types);
}
return array;
}
CF_EXPORT CFURLRef _CFBundleCopyResourceURLForLanguage(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName, CFStringRef language) {return CFBundleCopyResourceURLForLocalization(bundle, resourceName, resourceType, subDirName, language);}
CF_EXPORT CFURLRef CFBundleCopyResourceURLForLocalization(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName, CFStringRef localizationName) {
CFURLRef result = NULL;
CFMutableArrayRef languages = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
CFMutableArrayRef types = NULL;
CFArrayRef array;
if (localizationName) CFArrayAppendValue(languages, localizationName);
if (resourceType) {
types = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
CFArrayAppendValue(types, resourceType);
}
array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle));
if (types) {
CFRelease(types);
}
if (array) {
if (CFArrayGetCount(array) > 0) {
result = CFRetain(CFArrayGetValueAtIndex(array, 0));
}
CFRelease(array);
}
CFRelease(languages);
return result;
}
CF_EXPORT CFArrayRef _CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef language) {return CFBundleCopyResourceURLsOfTypeForLocalization(bundle, resourceType, subDirName, language);}
CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef localizationName) {
CFMutableArrayRef languages = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
CFMutableArrayRef types = NULL;
CFArrayRef array;
if (localizationName) CFArrayAppendValue(languages, localizationName);
if (resourceType) {
types = CFArrayCreateMutable(CFGetAllocator(bundle), 1, &kCFTypeArrayCallBacks);
CFArrayAppendValue(types, resourceType);
}
array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, _CFBundleLayoutVersion(bundle));
if (types) {
CFRelease(types);
}
CFRelease(languages);
return array;
}
CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName) {
CFStringRef result = NULL;
CFDictionaryRef stringTable = NULL;
if (key == NULL) return (value ? CFRetain(value) : CFRetain(CFSTR("")));
if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) {
tableName = _CFBundleDefaultStringTableName;
}
if (__CFBundleGetResourceData(bundle)->_stringTableCache != NULL) {
stringTable = CFDictionaryGetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName);
}
if (stringTable == NULL) {
CFURLRef tableURL = CFBundleCopyResourceURL(bundle, tableName, _CFBundleStringTableType, NULL);
if (tableURL) {
CFStringRef nameForSharing = NULL;
if (stringTable == NULL) {
CFDataRef tableData = NULL;
SInt32 errCode;
CFStringRef errStr;
if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle), tableURL, &tableData, NULL, NULL, &errCode)) {
stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), tableData, kCFPropertyListImmutable, &errStr);
if (errStr != NULL) {
CFRelease(errStr);
errStr = NULL;
}
CFRelease(tableData);
}
}
if (nameForSharing) CFRelease(nameForSharing);
CFRelease(tableURL);
}
if (stringTable == NULL) {
stringTable = CFDictionaryCreate(CFGetAllocator(bundle), NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
if (__CFBundleGetResourceData(bundle)->_stringTableCache == NULL) {
__CFBundleGetResourceData(bundle)->_stringTableCache = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName, stringTable);
CFRelease(stringTable);
}
result = CFDictionaryGetValue(stringTable, key);
if (result == NULL) {
if (value == NULL) {
result = CFRetain(key);
} else if (CFEqual(value, CFSTR(""))) {
result = CFRetain(key);
} else {
result = CFRetain(value);
}
} else {
CFRetain(result);
}
return result;
}
CF_EXPORT CFURLRef CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName) {
CFURLRef result = NULL;
char buff[CFMaxPathSize];
CFURLRef newURL = NULL;
if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL;
newURL = CFURLCreateFromFileSystemRepresentation(NULL, buff, strlen(buff), true);
if (NULL == newURL) {
newURL = CFRetain(bundleURL);
}
if (_CFBundleCouldBeBundle(newURL)) {
uint8_t version = 0;
CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(NULL, newURL, &version);
CFMutableArrayRef types = NULL;
CFArrayRef array;
if (resourceType) {
types = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
CFArrayAppendValue(types, resourceType);
}
array = _CFFindBundleResources(NULL, newURL, subDirName, languages, resourceName, types, 1, version);
if (types) {
CFRelease(types);
}
CFRelease(languages);
if (array) {
if (CFArrayGetCount(array) > 0) {
result = CFRetain(CFArrayGetValueAtIndex(array, 0));
}
CFRelease(array);
}
}
if (newURL) CFRelease(newURL);
return result;
}
CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleURL, CFStringRef resourceType, CFStringRef subDirName) {
CFArrayRef array = NULL;
char buff[CFMaxPathSize];
CFURLRef newURL = NULL;
if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL;
newURL = CFURLCreateFromFileSystemRepresentation(NULL, buff, strlen(buff), true);
if (NULL == newURL) {
newURL = CFRetain(bundleURL);
}
if (_CFBundleCouldBeBundle(newURL)) {
uint8_t version = 0;
CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(NULL, newURL, &version);
CFMutableArrayRef types = NULL;
if (resourceType) {
types = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
CFArrayAppendValue(types, resourceType);
}
array = _CFFindBundleResources(NULL, newURL, subDirName, languages, NULL, types, 1000000, version);
if (types) {
CFRelease(types);
}
CFRelease(languages);
}
if (newURL) CFRelease(newURL);
return array;
}
const char * __CFBundleLocaleAbbreviationsArray =
"en_US\0" "fr_FR\0" "en_GB\0" "de_DE\0" "it_IT\0" "nl_NL\0" "nl_BE\0" "sv_SE\0"
"es_ES\0" "da_DK\0" "pt_PT\0" "fr_CA\0" "no_NO\0" "he_IL\0" "ja_JP\0" "en_AU\0"
"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"
"tr_TR\0" "hr_HR\0" "nl_NL\0" "nl_BE\0" "en_CA\0" "en_CA\0" "pt_PT\0" "no_NO\0"
"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"
"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"
"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"
"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"
"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"
"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"
"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"
"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"
"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"
"mr_IN\0" "bo\0\0\0\0" "ne_NP\0" "kl\0\0\0";
#define NUM_LOCALE_ABBREVIATIONS 108
#define LOCALE_ABBREVIATION_LENGTH 6
static const char * const __CFBundleLanguageNamesArray[] = {
"English", "French", "German", "Italian", "Dutch", "Swedish", "Spanish", "Danish",
"Portuguese", "Norwegian", "Hebrew", "Japanese", "Arabic", "Finnish", "Greek", "Icelandic",
"Maltese", "Turkish", "Croatian", "Chinese", "Urdu", "Hindi", "Thai", "Korean",
"Lithuanian", "Polish", "Hungarian", "Estonian", "Latvian", "Sami", "Faroese", "Farsi",
"Russian", "Chinese", "Dutch", "Irish", "Albanian", "Romanian", "Czech", "Slovak",
"Slovenian", "Yiddish", "Serbian", "Macedonian", "Bulgarian", "Ukrainian", "Byelorussian", "Uzbek",
"Kazakh", "Azerbaijani", "Azerbaijani", "Armenian", "Georgian", "Moldavian", "Kirghiz", "Tajiki",
"Turkmen", "Mongolian", "Mongolian", "Pashto", "Kurdish", "Kashmiri", "Sindhi", "Tibetan",
"Nepali", "Sanskrit", "Marathi", "Bengali", "Assamese", "Gujarati", "Punjabi", "Oriya",
"Malayalam", "Kannada", "Tamil", "Telugu", "Sinhalese", "Burmese", "Khmer", "Lao",
"Vietnamese", "Indonesian", "Tagalog", "Malay", "Malay", "Amharic", "Tigrinya", "Oromo",
"Somali", "Swahili", "Kinyarwanda", "Rundi", "Nyanja", "Malagasy", "Esperanto", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"Welsh", "Basque", "Catalan", "Latin", "Quechua", "Guarani", "Aymara", "Tatar",
"Uighur", "Dzongkha", "Javanese", "Sundanese", "Galician", "Afrikaans", "Breton", "Inuktitut",
"Scottish", "Manx", "Irish", "Tongan", "Greek", "Greenlandic", "Azerbaijani"
};
#define NUM_LANGUAGE_NAMES 151
#define LANGUAGE_NAME_LENGTH 13
const char * __CFBundleLanguageAbbreviationsArray =
"en\0" "fr\0" "de\0" "it\0" "nl\0" "sv\0" "es\0" "da\0"
"pt\0" "no\0" "he\0" "ja\0" "ar\0" "fi\0" "el\0" "is\0"
"mt\0" "tr\0" "hr\0" "zh\0" "ur\0" "hi\0" "th\0" "ko\0"
"lt\0" "pl\0" "hu\0" "et\0" "lv\0" "se\0" "fo\0" "fa\0"
"ru\0" "zh\0" "nl\0" "ga\0" "sq\0" "ro\0" "cs\0" "sk\0"
"sl\0" "yi\0" "sr\0" "mk\0" "bg\0" "uk\0" "be\0" "uz\0"
"kk\0" "az\0" "az\0" "hy\0" "ka\0" "mo\0" "ky\0" "tg\0"
"tk\0" "mn\0" "mn\0" "ps\0" "ku\0" "ks\0" "sd\0" "bo\0"
"ne\0" "sa\0" "mr\0" "bn\0" "as\0" "gu\0" "pa\0" "or\0"
"ml\0" "kn\0" "ta\0" "te\0" "si\0" "my\0" "km\0" "lo\0"
"vi\0" "id\0" "tl\0" "ms\0" "ms\0" "am\0" "ti\0" "om\0"
"so\0" "sw\0" "rw\0" "rn\0" "\0\0\0" "mg\0" "eo\0" "\0\0\0"
"\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
"\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
"\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
"\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0" "\0\0\0"
"cy\0" "eu\0" "ca\0" "la\0" "qu\0" "gn\0" "ay\0" "tt\0"
"ug\0" "dz\0" "jv\0" "su\0" "gl\0" "af\0" "br\0" "iu\0"
"gd\0" "gv\0" "ga\0" "to\0" "el\0" "kl\0" "az\0";
#define NUM_LANGUAGE_ABBREVIATIONS 151
#define LANGUAGE_ABBREVIATION_LENGTH 3
static const SInt32 __CFBundleScriptCodesArray[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 0, 0,
0, 0, 0, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 0, 4,
7, 25, 0, 0, 0, 0, 29, 29, 0, 5, 7, 7, 7, 7, 7, 7,
7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 0, 28,
0, 0, 0, 0, 6, 0, 0
};
static const CFStringEncoding __CFBundleStringEncodingsArray[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 6, 37,
0, 35, 36, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 37, 0x8C,
7, 25, 0, 39, 0, 38, 29, 29, 36, 5, 7, 7, 7, 0x98, 7, 7,
7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26,
9, 9, 9, 13, 13, 11, 10, 12, 17, 16, 14, 15, 18, 19, 20, 22,
30, 0, 0, 0, 4, 28, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39, 0, 0, 0, 0, 0, 0, 7, 4, 26, 0, 0, 0, 0, 39, 0xEC,
39, 39, 40, 0, 6, 0, 0
};
static SInt32 _CFBundleGetLanguageCodeForLocalization(CFStringRef localizationName) {
SInt32 result = -1, i;
char buff[256];
CFIndex length = CFStringGetLength(localizationName);
if ((length >= LANGUAGE_ABBREVIATION_LENGTH - 1) && (length <= 255) && CFStringGetCString(localizationName, buff, 255, kCFStringEncodingASCII)) {
buff[255] = '\0';
for (i = 0; -1 == result && i < NUM_LANGUAGE_NAMES; i++) {
if (0 == strcmp(buff, __CFBundleLanguageNamesArray[i])) result = i;
}
if (0 == strcmp(buff, "zh_CN")) result = 33; buff[LANGUAGE_ABBREVIATION_LENGTH - 1] = '\0';
for (i = 0; -1 == result && i < NUM_LANGUAGE_ABBREVIATIONS * LANGUAGE_ABBREVIATION_LENGTH; i += LANGUAGE_ABBREVIATION_LENGTH) {
if (buff[0] == *(__CFBundleLanguageAbbreviationsArray + i + 0) && buff[1] == *(__CFBundleLanguageAbbreviationsArray + i + 1)) result = i / LANGUAGE_ABBREVIATION_LENGTH;
}
}
return result;
}
static CFStringRef _CFBundleCopyLanguageAbbreviationForLanguageCode(SInt32 languageCode) {
CFStringRef result = NULL;
if (0 <= languageCode && languageCode < NUM_LANGUAGE_ABBREVIATIONS) {
const char *languageAbbreviation = __CFBundleLanguageAbbreviationsArray + languageCode * LANGUAGE_ABBREVIATION_LENGTH;
if (languageAbbreviation != NULL && *languageAbbreviation != '\0') {
result = CFStringCreateWithCStringNoCopy(NULL, languageAbbreviation, kCFStringEncodingASCII, kCFAllocatorNull);
}
}
return result;
}
static CFStringRef _CFBundleCopyLanguageNameForLanguageCode(SInt32 languageCode) {
CFStringRef result = NULL;
if (0 <= languageCode && languageCode < NUM_LANGUAGE_NAMES) {
const char *languageName = __CFBundleLanguageNamesArray[languageCode];
if (languageName != NULL && *languageName != '\0') {
result = CFStringCreateWithCStringNoCopy(NULL, languageName, kCFStringEncodingASCII, kCFAllocatorNull);
}
}
return result;
}
static CFStringRef _CFBundleCopyLanguageAbbreviationForLocalization(CFStringRef localizationName) {
CFStringRef result = NULL;
SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName);
if (languageCode >= 0) {
result = _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode);
} else {
CFIndex length = CFStringGetLength(localizationName);
if (length == LANGUAGE_ABBREVIATION_LENGTH - 1 || (length > LANGUAGE_ABBREVIATION_LENGTH - 1 && CFStringGetCharacterAtIndex(localizationName, LANGUAGE_ABBREVIATION_LENGTH - 1) == '_')) {
result = CFStringCreateWithSubstring(NULL, localizationName, CFRangeMake(0, LANGUAGE_ABBREVIATION_LENGTH - 1));
}
}
return result;
}
static CFStringRef _CFBundleCopyLanguageNameForLocalization(CFStringRef localizationName) {
CFStringRef result = NULL;
SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName);
if (languageCode >= 0) {
result = _CFBundleCopyLanguageNameForLanguageCode(languageCode);
} else {
result = CFStringCreateCopy(NULL, localizationName);
}
return result;
}
static SInt32 _CFBundleGetLanguageCodeForRegionCode(SInt32 regionCode) {
SInt32 result = -1, i;
if (52 == regionCode) { result = 33;
} else if (0 <= regionCode && regionCode < NUM_LOCALE_ABBREVIATIONS) {
const char *localeAbbreviation = __CFBundleLocaleAbbreviationsArray + regionCode * LOCALE_ABBREVIATION_LENGTH;
if (localeAbbreviation != NULL && *localeAbbreviation != '\0') {
for (i = 0; -1 == result && i < NUM_LANGUAGE_ABBREVIATIONS * LANGUAGE_ABBREVIATION_LENGTH; i += LANGUAGE_ABBREVIATION_LENGTH) {
if (localeAbbreviation[0] == *(__CFBundleLanguageAbbreviationsArray + i + 0) && localeAbbreviation[1] == *(__CFBundleLanguageAbbreviationsArray + i + 1)) result = i / LANGUAGE_ABBREVIATION_LENGTH;
}
}
}
return result;
}
static SInt32 _CFBundleGetRegionCodeForLanguageCode(SInt32 languageCode) {
SInt32 result = -1, i;
if (19 == languageCode) { result = 53;
} else if (0 <= languageCode && languageCode < NUM_LANGUAGE_ABBREVIATIONS) {
const char *languageAbbreviation = __CFBundleLanguageAbbreviationsArray + languageCode * LANGUAGE_ABBREVIATION_LENGTH;
if (languageAbbreviation != NULL && *languageAbbreviation != '\0') {
for (i = 0; -1 == result && i < NUM_LOCALE_ABBREVIATIONS * LOCALE_ABBREVIATION_LENGTH; i += LOCALE_ABBREVIATION_LENGTH) {
if (*(__CFBundleLocaleAbbreviationsArray + i + 0) == languageAbbreviation[0] && *(__CFBundleLocaleAbbreviationsArray + i + 1) == languageAbbreviation[1]) result = i / LOCALE_ABBREVIATION_LENGTH;
}
}
}
return result;
}
static SInt32 _CFBundleGetRegionCodeForLocalization(CFStringRef localizationName) {
SInt32 result = -1, i;
char buff[LOCALE_ABBREVIATION_LENGTH];
CFIndex length = CFStringGetLength(localizationName);
if ((length >= LANGUAGE_ABBREVIATION_LENGTH - 1) && (length <= LOCALE_ABBREVIATION_LENGTH - 1) && CFStringGetCString(localizationName, buff, LOCALE_ABBREVIATION_LENGTH, kCFStringEncodingASCII)) {
buff[LOCALE_ABBREVIATION_LENGTH - 1] = '\0';
for (i = 0; -1 == result && i < NUM_LOCALE_ABBREVIATIONS * LOCALE_ABBREVIATION_LENGTH; i += LOCALE_ABBREVIATION_LENGTH) {
if (0 == strcmp(buff, __CFBundleLocaleAbbreviationsArray + i)) result = i / LOCALE_ABBREVIATION_LENGTH;
}
}
if (-1 == result) {
SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName);
result = _CFBundleGetRegionCodeForLanguageCode(languageCode);
}
return result;
}
static CFStringRef _CFBundleCopyLocaleAbbreviationForRegionCode(SInt32 regionCode) {
CFStringRef result = NULL;
if (0 <= regionCode && regionCode < NUM_LOCALE_ABBREVIATIONS) {
const char *localeAbbreviation = __CFBundleLocaleAbbreviationsArray + regionCode * LOCALE_ABBREVIATION_LENGTH;
if (localeAbbreviation != NULL && *localeAbbreviation != '\0') {
result = CFStringCreateWithCStringNoCopy(NULL, localeAbbreviation, kCFStringEncodingASCII, kCFAllocatorNull);
}
}
return result;
}
Boolean CFBundleGetLocalizationInfoForLocalization(CFStringRef localizationName, SInt32 *languageCode, SInt32 *regionCode, SInt32 *scriptCode, CFStringEncoding *stringEncoding) {
SInt32 language = -1, region = -1, script = 0;
CFStringEncoding encoding = kCFStringEncodingMacRoman;
if (localizationName) {
language = _CFBundleGetLanguageCodeForLocalization(localizationName);
region = _CFBundleGetRegionCodeForLocalization(localizationName);
} else {
_CFBundleGetLanguageAndRegionCodes(&language, ®ion);
}
if ((language < 0 || language > (int)(sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32))) && region != -1) language = _CFBundleGetLanguageCodeForRegionCode(region);
if (region == -1 && language != -1) region = _CFBundleGetRegionCodeForLanguageCode(language);
if (language >= 0 && language < (int)(sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32))) {
script = __CFBundleScriptCodesArray[language];
}
if (language >= 0 && language < (int)(sizeof(__CFBundleStringEncodingsArray)/sizeof(CFStringEncoding))) {
encoding = __CFBundleStringEncodingsArray[language];
}
if (languageCode) *languageCode = language;
if (regionCode) *regionCode = region;
if (scriptCode) *scriptCode = script;
if (stringEncoding) *stringEncoding = encoding;
return (language != -1 || region != -1);
}
CFStringRef CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode, SInt32 regionCode, SInt32 scriptCode, CFStringEncoding stringEncoding) {
CFStringRef localizationName = NULL;
if (!localizationName) {
localizationName = _CFBundleCopyLocaleAbbreviationForRegionCode(regionCode);
}
if (!localizationName) {
localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode);
}
if (!localizationName) {
SInt32 language = -1, scriptLanguage = -1, encodingLanguage = -1;
unsigned int i;
for (i = 0; language == -1 && i < (sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32)); i++) {
if (__CFBundleScriptCodesArray[i] == scriptCode && __CFBundleStringEncodingsArray[i] == stringEncoding) language = i;
}
for (i = 0; scriptLanguage == -1 && i < (sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32)); i++) {
if (__CFBundleScriptCodesArray[i] == scriptCode) scriptLanguage = i;
}
for (i = 0; encodingLanguage == -1 && i < (sizeof(__CFBundleStringEncodingsArray)/sizeof(CFStringEncoding)); i++) {
if (__CFBundleStringEncodingsArray[i] == stringEncoding) encodingLanguage = i;
}
localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(language);
if (!localizationName) localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(encodingLanguage);
if (!localizationName) localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(scriptLanguage);
}
return localizationName;
}
extern void *__CFAppleLanguages;
__private_extern__ CFArrayRef _CFBundleCopyUserLanguages(Boolean useBackstops) {
CFArrayRef result = NULL;
static CFArrayRef userLanguages = NULL;
static Boolean didit = false;
CFArrayRef preferencesArray = NULL;
__CFSpinLock(&CFBundleResourceGlobalDataLock);
if (!didit) {
if (__CFAppleLanguages) {
CFDataRef data;
CFIndex length = strlen(__CFAppleLanguages);
if (length > 0) {
data = CFDataCreateWithBytesNoCopy(NULL, __CFAppleLanguages, length, kCFAllocatorNull);
if (data) {
__CFSetNastyFile(CFSTR("<plist command-line argument>"));
userLanguages = CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL);
CFRelease(data);
}
}
}
if (!userLanguages && preferencesArray) userLanguages = CFRetain(preferencesArray);
{ CFStringRef english = CFSTR("English");
if (!userLanguages) userLanguages = CFArrayCreate(kCFAllocatorDefault, (const void **)&english, 1, &kCFTypeArrayCallBacks);
}
if (userLanguages && CFGetTypeID(userLanguages) != CFArrayGetTypeID()) {
CFRelease(userLanguages);
userLanguages = NULL;
}
didit = true;
}
__CFSpinUnlock(&CFBundleResourceGlobalDataLock);
if (preferencesArray) CFRelease(preferencesArray);
if (!result && userLanguages) result = CFRetain(userLanguages);
return result;
}
CF_EXPORT void _CFBundleGetLanguageAndRegionCodes(SInt32 *languageCode, SInt32 *regionCode) {
SInt32 language = -1, region = -1;
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFArrayRef languages = NULL;
CFStringRef localizationName = NULL;
if (mainBundle) {
languages = _CFBundleGetLanguageSearchList(mainBundle);
if (languages) CFRetain(languages);
}
if (!languages) languages = _CFBundleCopyUserLanguages(false);
if (languages && (CFArrayGetCount(languages) > 0)) {
localizationName = CFArrayGetValueAtIndex(languages, 0);
language = _CFBundleGetLanguageCodeForLocalization(localizationName);
region = _CFBundleGetRegionCodeForLocalization(localizationName);
} else {
language = 0;
region = 0;
}
if (language == -1 && region != -1) language = _CFBundleGetLanguageCodeForRegionCode(region);
if (region == -1 && language != -1) region = _CFBundleGetRegionCodeForLanguageCode(language);
if (languages) CFRelease(languages);
if (languageCode) *languageCode = language;
if (regionCode) *regionCode = region;
}
static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc, UniChar *pathUniChars, CFIndex pathLen, uint8_t version, CFDictionaryRef infoDict, CFStringRef curLangStr, CFMutableArrayRef lprojNames) {
CFIndex curLangLen = CFStringGetLength(curLangStr);
UniChar curLangUniChars[255];
CFIndex savedPathLen;
CFStringRef languageAbbreviation = _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr), languageName = _CFBundleCopyLanguageNameForLocalization(curLangStr);
Boolean foundOne = false;
CFArrayRef predefinedLocalizations = NULL;
CFRange predefinedLocalizationsRange;
CFMutableStringRef cheapStr, tmpString;
#if USE_GETDIRENTRIES
CFArrayRef directoryContents;
CFRange directoryContentsRange;
#else
Boolean isDir = false;
#endif
cheapStr = CFStringCreateMutable(alloc, 0);
_CFStrSetDesiredCapacity(cheapStr, CFMaxPathSize);
tmpString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull);
#if USE_GETDIRENTRIES
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
CFStringReplaceAll(cheapStr, tmpString);
directoryContents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, true);
directoryContentsRange = CFRangeMake(0, CFArrayGetCount(directoryContents));
#endif
if (infoDict) {
predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey);
if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) != CFArrayGetTypeID()) {
predefinedLocalizations = NULL;
CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleLocalizationsKey);
}
}
predefinedLocalizationsRange = CFRangeMake(0, predefinedLocalizations ? CFArrayGetCount(predefinedLocalizations) : 0);
CFStringGetCharacters(curLangStr, CFRangeMake(0, curLangLen), curLangUniChars);
savedPathLen = pathLen;
_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen);
_CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen);
#if USE_GETDIRENTRIES
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1);
CFStringReplaceAll(cheapStr, tmpString);
if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, curLangStr)) || (version != 4 && CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr))) {
#else
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
CFStringReplaceAll(cheapStr, tmpString);
if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, curLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
#endif
CFArrayAppendValue(lprojNames, curLangStr);
foundOne = true;
}
if (languageAbbreviation && !CFEqual(curLangStr, languageAbbreviation)) {
curLangLen = CFStringGetLength(languageAbbreviation);
CFStringGetCharacters(languageAbbreviation, CFRangeMake(0, curLangLen), curLangUniChars);
pathLen = savedPathLen;
_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen);
_CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen);
#if USE_GETDIRENTRIES
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1);
CFStringReplaceAll(cheapStr, tmpString);
if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageAbbreviation)) || (version != 4 && CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr))) {
#else
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
CFStringReplaceAll(cheapStr, tmpString);
if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageAbbreviation)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
#endif
CFArrayAppendValue(lprojNames, languageAbbreviation);
foundOne = true;
}
}
if (languageName && !CFEqual(curLangStr, languageName)) {
curLangLen = CFStringGetLength(languageName);
CFStringGetCharacters(languageName, CFRangeMake(0, curLangLen), curLangUniChars);
pathLen = savedPathLen;
_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen);
_CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen);
#if USE_GETDIRENTRIES
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1);
CFStringReplaceAll(cheapStr, tmpString);
if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageName)) || (version != 4 && CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr))) {
#else
CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen);
CFStringReplaceAll(cheapStr, tmpString);
if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageName)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) {
#endif
CFArrayAppendValue(lprojNames, languageName);
foundOne = true;
}
}
CFRelease(cheapStr);
CFRelease(tmpString);
if (languageAbbreviation) CFRelease(languageAbbreviation);
if (languageName) CFRelease(languageName);
#if USE_GETDIRENTRIES
CFRelease(directoryContents);
#endif
return foundOne;
}
static Boolean CFBundleAllowMixedLocalizations(void) {
static Boolean allowMixed = false, examinedMain = false;
if (!examinedMain) {
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFDictionaryRef infoDict = mainBundle ? CFBundleGetInfoDictionary(mainBundle) : NULL;
CFTypeRef allowMixedValue = infoDict ? CFDictionaryGetValue(infoDict, _kCFBundleAllowMixedLocalizationsKey) : NULL;
if (allowMixedValue) {
CFTypeID typeID = CFGetTypeID(allowMixedValue);
if (typeID == CFBooleanGetTypeID()) {
allowMixed = CFBooleanGetValue((CFBooleanRef)allowMixedValue);
} else if (typeID == CFStringGetTypeID()) {
allowMixed = (CFStringCompare((CFStringRef)allowMixedValue, CFSTR("true"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare((CFStringRef)allowMixedValue, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
} else if (typeID == CFNumberGetTypeID()) {
SInt32 val = 0;
if (CFNumberGetValue((CFNumberRef)allowMixedValue, kCFNumberSInt32Type, &val)) allowMixed = (val != 0);
}
}
examinedMain = true;
}
return allowMixed;
}
__private_extern__ void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, uint8_t version, CFDictionaryRef infoDict, CFMutableArrayRef lprojNames, CFStringRef devLang) {
CFURLRef resourcesURL = _CFBundleCopyResourcesDirectoryURLInDirectory(alloc, bundleURL, version);
CFURLRef absoluteURL;
CFIndex idx;
CFIndex count;
CFStringRef resourcesPath;
UniChar pathUniChars[CFMaxPathSize];
CFIndex pathLen;
CFStringRef curLangStr;
Boolean foundOne = false;
CFArrayRef userLanguages;
_CFEnsureStaticBuffersInited();
absoluteURL = CFURLCopyAbsoluteURL(resourcesURL);
resourcesPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
CFRelease(absoluteURL);
pathLen = CFStringGetLength(resourcesPath);
CFStringGetCharacters(resourcesPath, CFRangeMake(0, pathLen), pathUniChars);
CFRelease(resourcesURL);
CFRelease(resourcesPath);
if (!CFBundleAllowMixedLocalizations()) {
CFBundleRef mainBundle = CFBundleGetMainBundle();
if (mainBundle) {
CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);
if (!CFEqual(bundleURL, mainBundleURL)) {
CFArrayRef mainBundleLangs = _CFBundleGetLanguageSearchList(mainBundle);
if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) {
curLangStr = CFArrayGetValueAtIndex(mainBundleLangs, 0);
foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames);
}
}
CFRelease(mainBundleURL);
}
}
if (!foundOne) {
userLanguages = _CFBundleCopyUserLanguages(true);
count = (userLanguages ? CFArrayGetCount(userLanguages) : 0);
for (idx = 0; !foundOne && idx < count; idx++) {
curLangStr = CFArrayGetValueAtIndex(userLanguages, idx);
foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames);
}
if (!foundOne && devLang != NULL) {
foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, devLang, lprojNames);
}
if (!foundOne) {
foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, CFSTR("en_US"), lprojNames);
}
if (userLanguages != NULL) {
CFRelease(userLanguages);
}
}
}
static Boolean _CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array, CFStringRef curLangStr, CFMutableArrayRef lprojNames) {
Boolean foundOne = false;
CFRange range = CFRangeMake(0, CFArrayGetCount(array));
CFStringRef languageAbbreviation = _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr), languageName = _CFBundleCopyLanguageNameForLocalization(curLangStr);
if (CFArrayContainsValue(array, range, curLangStr)) {
CFArrayAppendValue(lprojNames, curLangStr);
foundOne = true;
}
if (languageAbbreviation && !CFEqual(curLangStr, languageAbbreviation)) {
if (CFArrayContainsValue(array, range, languageAbbreviation)) {
CFArrayAppendValue(lprojNames, languageAbbreviation);
foundOne = true;
}
}
if (languageName && !CFEqual(curLangStr, languageName)) {
if (CFArrayContainsValue(array, range, languageName)) {
CFArrayAppendValue(lprojNames, languageName);
foundOne = true;
}
}
if (languageAbbreviation) CFRelease(languageAbbreviation);
if (languageName) CFRelease(languageName);
return foundOne;
}
static CFArrayRef _CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray, Boolean considerMain) {
CFMutableArrayRef lprojNames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
Boolean foundOne = false, releasePrefArray = false;
CFIndex idx, count;
if (considerMain && !CFBundleAllowMixedLocalizations()) {
CFBundleRef mainBundle = CFBundleGetMainBundle();
if (mainBundle) {
CFArrayRef mainBundleLangs = _CFBundleGetLanguageSearchList(mainBundle);
if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) {
foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(mainBundleLangs, 0), lprojNames);
}
}
}
if (!foundOne) {
if (!prefArray) {
prefArray = _CFBundleCopyUserLanguages(true);
if (prefArray) releasePrefArray = true;
}
count = (prefArray ? CFArrayGetCount(prefArray) : 0);
for (idx = 0; !foundOne && idx < count; idx++) {
foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(prefArray, idx), lprojNames);
}
if (!foundOne) {
foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFSTR("en_US"), lprojNames);
}
if (!foundOne && CFArrayGetCount(lprojNames) > 0) {
foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(locArray, 0), lprojNames);
}
}
if (CFArrayGetCount(lprojNames) == 0) {
CFArrayAppendValue(lprojNames, CFSTR("en"));
}
if (releasePrefArray) {
CFRelease(prefArray);
}
return lprojNames;
}
CF_EXPORT CFArrayRef CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray) {return _CFBundleCopyLocalizationsForPreferences(locArray, prefArray, false);}
CF_EXPORT CFArrayRef CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locArray) {return _CFBundleCopyLocalizationsForPreferences(locArray, NULL, true);}
__private_extern__ CFArrayRef _CFBundleCopyLanguageSearchListInDirectory(CFAllocatorRef alloc, CFURLRef url, uint8_t *version) {
CFMutableArrayRef langs = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
uint8_t localVersion = 0;
CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, &localVersion);
CFStringRef devLang = NULL;
if (infoDict != NULL) {
devLang = CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey);
}
if (devLang != NULL && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) devLang = NULL;
_CFBundleAddPreferredLprojNamesInDirectory(alloc, url, localVersion, infoDict, langs, devLang);
if (devLang != NULL && CFArrayGetFirstIndexOfValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), devLang) < 0) {
CFArrayAppendValue(langs, devLang);
}
if (CFArrayGetCount(langs) == 0) {
CFArrayAppendValue(langs, CFSTR("en"));
}
if (infoDict != NULL) {
CFRelease(infoDict);
}
if (version) {
*version = localVersion;
}
return langs;
}
CF_EXPORT Boolean _CFBundleURLLooksLikeBundle(CFURLRef url) {
Boolean result = false;
CFBundleRef bundle = _CFBundleCreateIfLooksLikeBundle(NULL, url);
if (bundle) {
result = true;
CFRelease(bundle);
}
return result;
}
CF_INLINE Boolean _CFBundleURLHasSubDir(CFURLRef url, CFStringRef subDirName) {
CFURLRef dirURL;
Boolean isDir, result = false;
dirURL = CFURLCreateWithString(NULL, subDirName, url);
if (dirURL != NULL) {
if (_CFIsResourceAtURL(dirURL, &isDir) && isDir) {
result = true;
}
CFRelease(dirURL);
}
return result;
}
__private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint8_t *version) {
Boolean result = false;
uint8_t localVersion = 0;
if (CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework/"))) {
if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) {
result = true;
localVersion = 0;
} else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) {
result = true;
localVersion = 2;
} else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) {
result = true;
localVersion = 1;
}
} else {
if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) {
result = true;
localVersion = 2;
} else if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) {
result = true;
localVersion = 0;
} else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) {
result = true;
localVersion = 1;
}
}
if (result && version) *version = localVersion;
return result;
}
__private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc, CFURLRef url, uint8_t *version) {
CFDictionaryRef dict = NULL;
char buff[CFMaxPathSize];
uint8_t localVersion = 0;
if (CFURLGetFileSystemRepresentation(url, true, buff, CFMaxPathSize)) {
CFURLRef newURL = CFURLCreateFromFileSystemRepresentation(alloc, buff, strlen(buff), true);
if (NULL == newURL) newURL = CFRetain(url);
if (!_CFBundleURLLooksLikeBundleVersion(newURL, &localVersion)) {
localVersion = 3;
}
dict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(alloc, newURL, localVersion);
CFRelease(newURL);
}
if (version) *version = localVersion;
return dict;
}
__private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc, CFURLRef url, uint8_t version) {
CFDictionaryRef result = NULL;
if (url != NULL) {
CFURLRef infoURL = NULL;
CFDataRef infoData = NULL;
UniChar buff[CFMaxPathSize];
CFIndex len;
CFMutableStringRef cheapStr;
CFStringRef infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension0, infoURLFromBase = _CFBundleInfoURLFromBase0;
Boolean tryPlatformSpecific = true, tryGlobal = true;
#if USE_GETDIRENTRIES
CFArrayRef directoryContents = NULL;
CFRange directoryContentsRange = CFRangeMake(0, 0);
#endif
_CFEnsureStaticBuffersInited();
if (0 == version) {
#if USE_GETDIRENTRIES
CFURLRef resourcesURL = _CFBundleCopyResourcesDirectoryURLInDirectory(alloc, url, version);
CFURLRef absoluteURL = CFURLCopyAbsoluteURL(resourcesURL);
CFStringRef resourcesPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
directoryContents = _CFBundleCopyDirectoryContentsAtPath(resourcesPath, false);
directoryContentsRange = CFRangeMake(0, CFArrayGetCount(directoryContents));
CFRelease(resourcesPath);
CFRelease(absoluteURL);
CFRelease(resourcesURL);
#endif
infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension0;
infoURLFromBase = _CFBundleInfoURLFromBase0;
} else if (1 == version) {
infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension1;
infoURLFromBase = _CFBundleInfoURLFromBase1;
} else if (2 == version) {
infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension2;
infoURLFromBase = _CFBundleInfoURLFromBase2;
} else if (3 == version) {
CFStringRef posixPath = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
if (posixPath) {
if (!(CFStringHasSuffix(posixPath, _CFBundleSupportFilesDirectoryName1) || CFStringHasSuffix(posixPath, _CFBundleSupportFilesDirectoryName2) || CFStringHasSuffix(posixPath, _CFBundleResourcesDirectoryName))) {
infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension3;
infoURLFromBase = _CFBundleInfoURLFromBase3;
}
CFRelease(posixPath);
}
}
len = CFStringGetLength(infoURLFromBaseNoExtension);
CFStringGetCharacters(infoURLFromBaseNoExtension, CFRangeMake(0, len), buff);
buff[len++] = (UniChar)'-';
memmove(buff + len, _PlatformUniChars, _PlatformLen * sizeof(UniChar));
len += _PlatformLen;
_CFAppendPathExtension(buff, &len, CFMaxPathSize, _InfoExtensionUniChars, _InfoExtensionLen);
cheapStr = CFStringCreateMutable(alloc, 0);
CFStringAppendCharacters(cheapStr, buff, len);
infoURL = CFURLCreateWithString(alloc, cheapStr, url);
#if USE_GETDIRENTRIES
if (directoryContents) {
CFIndex resourcesLen = CFStringGetLength(_CFBundleResourcesURLFromBase0);
CFStringDelete(cheapStr, CFRangeMake(0, CFStringGetLength(cheapStr)));
CFStringAppendCharacters(cheapStr, buff + resourcesLen, len - resourcesLen);
tryPlatformSpecific = CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr);
}
#endif
if (tryPlatformSpecific) CFURLCreateDataAndPropertiesFromResource(alloc, infoURL, &infoData, NULL, NULL, NULL);
CFRelease(cheapStr);
if (!infoData) {
CFRelease(infoURL);
infoURL = CFURLCreateWithString(alloc, infoURLFromBase, url);
#if USE_GETDIRENTRIES
if (directoryContents) tryGlobal = CFArrayContainsValue(directoryContents, directoryContentsRange, _CFBundleInfoFileName);
#endif
if (tryGlobal) CFURLCreateDataAndPropertiesFromResource(alloc, infoURL, &infoData, NULL, NULL, NULL);
}
if (infoData) {
result = CFPropertyListCreateFromXMLData(alloc, infoData, kCFPropertyListMutableContainers, NULL);
if (result) {
if (CFDictionaryGetTypeID() == CFGetTypeID(result)) {
CFDictionarySetValue((CFMutableDictionaryRef)result, _kCFBundleInfoPlistURLKey, infoURL);
} else {
CFRelease(result);
result = NULL;
}
}
CFRelease(infoData);
}
if (!result) {
result = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
CFRelease(infoURL);
#if USE_GETDIRENTRIES
if (directoryContents) CFRelease(directoryContents);
#endif
}
return result;
}
static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorRef alloc, CFURLRef url, CFDictionaryRef infoDict, UInt32 *packageType, UInt32 *packageCreator) {
Boolean retVal = false, hasType = false, hasCreator = false, releaseInfoDict = false;
CFURLRef tempURL;
CFDataRef pkgInfoData = NULL;
tempURL = CFURLCreateWithString(alloc, _CFBundlePkgInfoURLFromBase2, url);
CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL);
CFRelease(tempURL);
if (pkgInfoData == NULL) {
tempURL = CFURLCreateWithString(alloc, _CFBundlePkgInfoURLFromBase1, url);
CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL);
CFRelease(tempURL);
}
if (pkgInfoData == NULL) {
tempURL = CFURLCreateWithString(alloc, _CFBundlePseudoPkgInfoURLFromBase, url);
CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL);
CFRelease(tempURL);
}
if ((pkgInfoData != NULL) && (CFDataGetLength(pkgInfoData) >= (int)(sizeof(UInt32) * 2))) {
UInt32 *pkgInfo = (UInt32 *)CFDataGetBytePtr(pkgInfoData);
if (packageType != NULL) {
*packageType = CFSwapInt32BigToHost(pkgInfo[0]);
}
if (packageCreator != NULL) {
*packageCreator = CFSwapInt32BigToHost(pkgInfo[1]);
}
retVal = hasType = hasCreator = true;
}
if (pkgInfoData != NULL) CFRelease(pkgInfoData);
if (!retVal) {
if (!infoDict) {
infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, NULL);
releaseInfoDict = true;
}
if (infoDict) {
CFStringRef typeString = CFDictionaryGetValue(infoDict, _kCFBundlePackageTypeKey), creatorString = CFDictionaryGetValue(infoDict, _kCFBundleSignatureKey);
UInt32 tmp;
CFIndex usedBufLen = 0;
if (typeString && CFGetTypeID(typeString) == CFStringGetTypeID() && CFStringGetLength(typeString) == 4 && 4 == CFStringGetBytes(typeString, CFRangeMake(0, 4), kCFStringEncodingMacRoman, 0, false, (UInt8 *)&tmp, 4, &usedBufLen) && 4 == usedBufLen) {
if (packageType != NULL) {
*packageType = CFSwapInt32BigToHost(tmp);
}
retVal = hasType = true;
}
if (creatorString && CFGetTypeID(creatorString) == CFStringGetTypeID() && CFStringGetLength(creatorString) == 4 && 4 == CFStringGetBytes(creatorString, CFRangeMake(0, 4), kCFStringEncodingMacRoman, 0, false, (UInt8 *)&tmp, 4, &usedBufLen) && 4 == usedBufLen) {
if (packageCreator != NULL) {
*packageCreator = CFSwapInt32BigToHost(tmp);
}
retVal = hasCreator = true;
}
if (releaseInfoDict) CFRelease(infoDict);
}
}
if (!hasType || !hasCreator) {
if (retVal || _CFBundleURLLooksLikeBundle(url)) {
if (packageCreator != NULL && !hasCreator) {
*packageCreator = 0x3f3f3f3f; }
if (packageType != NULL && !hasType) {
CFStringRef urlStr;
UniChar buff[CFMaxPathSize];
CFIndex strLen, startOfExtension;
CFURLRef absoluteURL;
absoluteURL = CFURLCopyAbsoluteURL(url);
urlStr = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
CFRelease(absoluteURL);
strLen = CFStringGetLength(urlStr);
CFStringGetCharacters(urlStr, CFRangeMake(0, strLen), buff);
CFRelease(urlStr);
startOfExtension = _CFStartOfPathExtension(buff, strLen);
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)'/'))) {
*packageType = CFSwapInt32BigToHost(0x4150504c); } 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)'/'))) {
*packageType = CFSwapInt32BigToHost(0x4150504c); } 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)'/'))) {
*packageType = CFSwapInt32BigToHost(0x4150504c); } 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)'/'))) {
*packageType = CFSwapInt32BigToHost(0x4150504c); } 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)'/'))) {
*packageType = CFSwapInt32BigToHost(0x464d574b); } else {
*packageType = CFSwapInt32BigToHost(0x424e444C); }
}
retVal = true;
}
}
return retVal;
}
CF_EXPORT Boolean _CFBundleGetPackageInfoInDirectory(CFAllocatorRef alloc, CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {return _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(alloc, url, NULL, packageType, packageCreator);}
CF_EXPORT void CFBundleGetPackageInfo(CFBundleRef bundle, UInt32 *packageType, UInt32 *packageCreator) {
CFURLRef bundleURL = CFBundleCopyBundleURL(bundle);
if (!_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFGetAllocator(bundle), bundleURL, CFBundleGetInfoDictionary(bundle), packageType, packageCreator)) {
if (packageType != NULL) {
*packageType = CFSwapInt32BigToHost(0x424e444C); }
if (packageCreator != NULL) {
*packageCreator = 0x3f3f3f3f; }
}
if (bundleURL) CFRelease(bundleURL);
}
CF_EXPORT Boolean CFBundleGetPackageInfoInDirectory(CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {return _CFBundleGetPackageInfoInDirectory(NULL, url, packageType, packageCreator);}
__private_extern__ CFStringRef _CFBundleGetPlatformExecutablesSubdirectoryName(void) {
#if defined(__MACOS8__)
return CFSTR("MacOSClassic");
#elif defined(__WIN32__)
return CFSTR("Windows");
#elif defined(__MACH__)
return CFSTR("MacOS");
#elif defined(__hpux__)
return CFSTR("HPUX");
#elif defined(__svr4__)
return CFSTR("Solaris");
#elif defined(__LINUX__)
return CFSTR("Linux");
#elif defined(__FREEBSD__)
return CFSTR("FreeBSD");
#else
#warning CFBundle: Unknown architecture
return CFSTR("Other");
#endif
}
__private_extern__ CFStringRef _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(void) {
#if defined(__MACOS8__)
return CFSTR("Mac OS 8");
#elif defined(__WIN32__)
return CFSTR("WinNT");
#elif defined(__MACH__)
return CFSTR("Mac OS X");
#elif defined(__hpux__)
return CFSTR("HP-UX");
#elif defined(__svr4__)
return CFSTR("Solaris");
#elif defined(__LINUX__)
return CFSTR("Linux");
#elif defined(__FREEBSD__)
return CFSTR("FreeBSD");
#else
#warning CFBundle: Unknown architecture
return CFSTR("Other");
#endif
}
__private_extern__ CFStringRef _CFBundleGetOtherPlatformExecutablesSubdirectoryName(void) {
#if defined(__MACOS8__)
return CFSTR("MacOS");
#elif defined(__WIN32__)
return CFSTR("Other");
#elif defined(__MACH__)
return CFSTR("MacOSClassic");
#elif defined(__hpux__)
return CFSTR("Other");
#elif defined(__svr4__)
return CFSTR("Other");
#elif defined(__LINUX__)
return CFSTR("Other");
#elif defined(__FREEBSD__)
return CFSTR("Other");
#else
#warning CFBundle: Unknown architecture
return CFSTR("Other");
#endif
}
__private_extern__ CFStringRef _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(void) {
#if defined(__MACOS8__)
return CFSTR("Mac OS X");
#elif defined(__WIN32__)
return CFSTR("Other");
#elif defined(__MACH__)
return CFSTR("Mac OS 8");
#elif defined(__hpux__)
return CFSTR("Other");
#elif defined(__svr4__)
return CFSTR("Other");
#elif defined(__LINUX__)
return CFSTR("Other");
#elif defined(__FREEBSD__)
return CFSTR("Other");
#else
#warning CFBundle: Unknown architecture
return CFSTR("Other");
#endif
}
__private_extern__ CFArrayRef _CFBundleCopyBundleRegionsArray(CFBundleRef bundle) {return CFBundleCopyBundleLocalizations(bundle);}
CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) {
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
uint8_t version = _CFBundleLayoutVersion(bundle);
CFArrayRef urls = ((version != 4) ? _CFContentsOfDirectory(CFGetAllocator(bundle), NULL, NULL, resourcesURL, CFSTR("lproj")) : NULL);
CFArrayRef predefinedLocalizations = NULL;
CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
CFMutableArrayRef result = NULL;
if (infoDict) {
predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey);
if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) != CFArrayGetTypeID()) {
predefinedLocalizations = NULL;
CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleLocalizationsKey);
}
if (predefinedLocalizations != NULL) {
CFIndex i, c = CFArrayGetCount(predefinedLocalizations);
if (c > 0 && !result) {
result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks);
}
for (i=0; i<c; i++) {
CFArrayAppendValue(result, CFArrayGetValueAtIndex(predefinedLocalizations, i));
}
}
}
if (urls) {
CFIndex i, c;
CFURLRef curURL, curAbsoluteURL;
CFStringRef curStr, regionStr;
UniChar buff[CFMaxPathSize];
CFIndex strLen, startOfLastPathComponent, regionLen;
c = CFArrayGetCount(urls);
if (c > 0 && !result) {
result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks);
}
for (i = 0; i < c; i++) {
curURL = CFArrayGetValueAtIndex(urls, i);
curAbsoluteURL = CFURLCopyAbsoluteURL(curURL);
curStr = CFURLCopyFileSystemPath(curAbsoluteURL, PLATFORM_PATH_STYLE);
CFRelease(curAbsoluteURL);
strLen = CFStringGetLength(curStr);
CFStringGetCharacters(curStr, CFRangeMake(0, strLen), buff);
startOfLastPathComponent = _CFStartOfLastPathComponent(buff, strLen);
regionLen = _CFLengthAfterDeletingPathExtension(&(buff[startOfLastPathComponent]), strLen - startOfLastPathComponent);
regionStr = CFStringCreateWithCharacters(CFGetAllocator(bundle), &(buff[startOfLastPathComponent]), regionLen);
CFArrayAppendValue(result, regionStr);
CFRelease(regionStr);
CFRelease(curStr);
}
CFRelease(urls);
}
if (!result) {
CFStringRef developmentLocalization = CFBundleGetDevelopmentRegion(bundle);
if (developmentLocalization) {
result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(result, developmentLocalization);
}
}
if (resourcesURL) CFRelease(resourcesURL);
return result;
}
CF_EXPORT CFDictionaryRef CFBundleCopyInfoDictionaryForURL(CFURLRef url) {
CFDictionaryRef result = NULL;
Boolean isDir;
if (_CFIsResourceAtURL(url, &isDir)) {
if (isDir) {
result = _CFBundleCopyInfoDictionaryInDirectory(NULL, url, NULL);
} else {
result = _CFBundleCopyInfoDictionaryInExecutable(url);
}
}
return result;
}
CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) {
CFArrayRef result = NULL;
CFBundleRef bundle = CFBundleCreate(NULL, url);
CFStringRef devLang = NULL;
if (bundle) {
result = CFBundleCopyBundleLocalizations(bundle);
CFRelease(bundle);
} else {
CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInExecutable(url);
if (infoDict) {
CFArrayRef predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey);
if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) == CFArrayGetTypeID()) {
result = CFRetain(predefinedLocalizations);
}
if (!result) {
devLang = CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey);
if (devLang != NULL && (CFGetTypeID(devLang) == CFStringGetTypeID() && CFStringGetLength(devLang) > 0)) {
result = CFArrayCreate(NULL, (const void **)&devLang, 1, &kCFTypeArrayCallBacks);
}
}
CFRelease(infoDict);
}
}
return result;
}