X-Git-Url: https://git.saurik.com/apple/cf.git/blobdiff_plain/b0e0750aaee7a1a2cd8e3aa918bd9fc756e9dfcf..cf7d2af96685aba74e84652f9ed1098e9253902e:/CFBundle_Resources.c?ds=sidebyside diff --git a/CFBundle_Resources.c b/CFBundle_Resources.c index fc9ddae..ef084a6 100644 --- a/CFBundle_Resources.c +++ b/CFBundle_Resources.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Apple Inc. All rights reserved. + * Copyright (c) 2009 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -20,13 +20,17 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* CFBundle_Resources.c - Copyright (c) 1999-2007 Apple Inc. All rights reserved. - Responsibility: Doug Davidson +/* CFBundle_Resources.c + Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Responsibility: Doug Davidson */ -#if DEPLOYMENT_TARGET_MACOSX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #define READ_DIRECTORIES 1 +#elif DEPLOYMENT_TARGET_WINDOWS +#define READ_DIRECTORIES 0 +#else +#error Unknown or unspecified DEPLOYMENT_TARGET #endif #define READ_DIRECTORIES_CACHE_CAPACITY 128 @@ -36,17 +40,23 @@ #include #include #include +#include +#include #include #include "CFInternal.h" -#include "CFPriv.h" +#include #include #include #include #include #if DEPLOYMENT_TARGET_MACOSX -#include #include +#elif DEPLOYMENT_TARGET_EMBEDDED +#include +#elif DEPLOYMENT_TARGET_WINDOWS +#else +#error Unknown or unspecified DEPLOYMENT_TARGET #endif #if READ_DIRECTORIES @@ -57,8 +67,10 @@ // All new-style bundles will have these extensions. CF_INLINE CFStringRef _CFGetPlatformName(void) { -#if DEPLOYMENT_TARGET_MACOSX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED return _CFBundleMacOSXPlatformName; +#elif DEPLOYMENT_TARGET_WINDOWS + return _CFBundleWindowsPlatformName; #elif DEPLOYMENT_TARGET_SOLARIS return _CFBundleSolarisPlatformName; #elif DEPLOYMENT_TARGET_HPUX @@ -73,8 +85,12 @@ CF_INLINE CFStringRef _CFGetPlatformName(void) { } CF_INLINE CFStringRef _CFGetAlternatePlatformName(void) { -#if DEPLOYMENT_TARGET_MACOSX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED return _CFBundleAlternateMacOSXPlatformName; +#elif DEPLOYMENT_TARGET_WINDOWS + return CFSTR(""); +#else +#error Unknown or unspecified DEPLOYMENT_TARGET #endif } @@ -206,7 +222,6 @@ static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, _CFBund if (!foundIt) tryToOpen = false; } __CFSpinUnlock(&CFBundleResourceGlobalDataLock); - CFRelease(name); } CFRelease(dirName); @@ -372,7 +387,10 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res // cheapStr is available for our use for whatever we want. // URLs for found resources get added to result. CFIndex savedPathLen; - Boolean appendSucceeded = true, platformGenericFound = false, platformSpecificFound = false, platformGenericIsDir = false, platformSpecificIsDir = false, platformGenericIsUnknown = false, platformSpecificIsUnknown = false; + Boolean appendSucceeded = true, platformGenericFound = false, platformSpecificFound = false, platformGenericIsDir = false, platformSpecificIsDir = false; +#if READ_DIRECTORIES + Boolean platformGenericIsUnknown = false, platformSpecificIsUnknown = false; +#endif CFStringRef platformGenericStr = NULL; #if READ_DIRECTORIES @@ -595,64 +613,71 @@ CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStri CFAllocatorRef alloc = (bundle ? CFGetAllocator(bundle) : (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator())); CFMutableArrayRef result; UniChar *workingUniChars, *nameUniChars, *subDirUniChars; - CFIndex nameLen = (resName ? CFStringGetLength(resName) : 0); + CFIndex nameLen = 0; CFIndex subDirLen = (subDirName ? CFStringGetLength(subDirName) : 0); CFIndex workingLen, savedWorkingLen; CFURLRef absoluteURL; CFStringRef bundlePath; CFMutableStringRef cheapStr, tmpString; + char buff[CFMaxPathSize]; result = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); + if (resName) { + CFStringRef newResName = NULL; + if (CFStringGetFileSystemRepresentation(resName, buff, CFMaxPathSize)) newResName = CFStringCreateWithFileSystemRepresentation(alloc, buff); + resName = newResName ? newResName : (CFStringRef)CFRetain(resName); + nameLen = CFStringGetLength(resName); + } + // Init the one-time-only unichar buffers. _CFEnsureStaticBuffersInited(); // Build UniChar buffers for some of the string pieces we need. // One malloc will do. nameUniChars = (UniChar *)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); - // Build a UniChar buffer with the absolute path to the bundle's resources directory. - // If no URL was passed, we get it from the bundle. - bundleURL = (bundleURL ? (CFURLRef)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); - } + if (nameUniChars) { + subDirUniChars = nameUniChars + nameLen; + workingUniChars = subDirUniChars + subDirLen; + + if (nameLen > 0) CFStringGetCharacters(resName, CFRangeMake(0, nameLen), nameUniChars); + if (subDirLen > 0) CFStringGetCharacters(subDirName, CFRangeMake(0, subDirLen), subDirUniChars); + // Build a UniChar buffer with the absolute path to the bundle's resources directory. + // If no URL was passed, we get it from the bundle. + bundleURL = (bundleURL ? (CFURLRef)CFRetain(bundleURL) : CFBundleCopyBundleURL(bundle)); + absoluteURL = CFURLCopyAbsoluteURL(bundleURL); + bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); + if ((workingLen = CFStringGetLength(bundlePath)) > 0) CFStringGetCharacters(bundlePath, CFRangeMake(0, workingLen), workingUniChars); + 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); - // both of these used for temp string operations, for slightly - // different purposes, where each type is appropriate - cheapStr = CFStringCreateMutable(alloc, 0); - _CFStrSetDesiredCapacity(cheapStr, CFMaxPathSize); - tmpString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull); + // both of these used for temp string operations, for slightly different purposes, where each type is appropriate + 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); - - // drd: This unfortunate hack is still necessary because of installer packages - if (0 == version && CFArrayGetCount(result) == 0) { - // Try looking directly in the bundle path - workingLen = savedWorkingLen; _CFFindBundleResourcesInResourcesDir(alloc, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result); - } + + // drd: This unfortunate hack is still necessary because of installer packages and Spotlight importers + if (CFArrayGetCount(result) == 0 && (0 == version || (2 == version && bundlePath && CFEqual(CFSTR("/Library/Spotlight"), bundlePath)))) { + // Try looking directly in the bundle path + workingLen = savedWorkingLen; + _CFFindBundleResourcesInResourcesDir(alloc, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result); + } - CFRelease(cheapStr); - CFRelease(tmpString); - CFAllocatorDeallocate(alloc, nameUniChars); + CFRelease(absoluteURL); + CFRelease(bundlePath); + CFRelease(bundleURL); + CFRelease(cheapStr); + CFRelease(tmpString); + CFAllocatorDeallocate(alloc, nameUniChars); + } + if (resName) CFRelease(resName); if (!bundle) CFRelease(alloc); - return result; } @@ -660,11 +685,8 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURL(CFBundleRef bundle, CFStringRef resou CFURLRef result = NULL; CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle), types = NULL, array; if (resourceType) types = CFArrayCreate(CFGetAllocator(bundle), (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); - array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle)); - if (types) CFRelease(types); - if (array) { if (CFArrayGetCount(array) > 0) result = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); CFRelease(array); @@ -675,16 +697,16 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURL(CFBundleRef bundle, CFStringRef resou CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfType(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName) { CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle), types = NULL, array; if (resourceType) types = CFArrayCreate(CFGetAllocator(bundle), (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); - // MF:!!! Better "limit" than 1,000,000? 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 _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; @@ -692,44 +714,48 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURLForLocalization(CFBundleRef bundle, CF if (localizationName) languages = CFArrayCreate(CFGetAllocator(bundle), (const void **)&localizationName, 1, &kCFTypeArrayCallBacks); if (resourceType) types = CFArrayCreate(CFGetAllocator(bundle), (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); - array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle)); if (array) { if (CFArrayGetCount(array) > 0) result = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); CFRelease(array); } - if (types) CFRelease(types); if (languages) 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 _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) { CFArrayRef languages = NULL, types = NULL, array; if (localizationName) languages = CFArrayCreate(CFGetAllocator(bundle), (const void **)&localizationName, 1, &kCFTypeArrayCallBacks); if (resourceType) types = CFArrayCreate(CFGetAllocator(bundle), (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); - // MF:!!! Better "limit" than 1,000,000? array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, _CFBundleLayoutVersion(bundle)); - if (types) CFRelease(types); if (languages) CFRelease(languages); - return array; } CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName) { CFStringRef result = NULL; CFDictionaryRef stringTable = NULL; + static CFSpinLock_t CFBundleLocalizedStringLock = CFSpinLockInit; if (!key) return (value ? (CFStringRef)CFRetain(value) : (CFStringRef)CFRetain(CFSTR(""))); if (!tableName || CFEqual(tableName, CFSTR(""))) tableName = _CFBundleDefaultStringTableName; - if (__CFBundleGetResourceData(bundle)->_stringTableCache) stringTable = (CFDictionaryRef)CFDictionaryGetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName); + + __CFSpinLock(&CFBundleLocalizedStringLock); + if (__CFBundleGetResourceData(bundle)->_stringTableCache) { + stringTable = (CFDictionaryRef)CFDictionaryGetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName); + if (stringTable) CFRetain(stringTable); + } + __CFSpinUnlock(&CFBundleLocalizedStringLock); + if (!stringTable) { // Go load the table. CFURLRef tableURL = CFBundleCopyResourceURL(bundle, tableName, _CFBundleStringTableType, NULL); @@ -756,9 +782,13 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe CFRelease(tableURL); } if (!stringTable) stringTable = CFDictionaryCreate(CFGetAllocator(bundle), NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (!__CFBundleGetResourceData(bundle)->_stringTableCache) __CFBundleGetResourceData(bundle)->_stringTableCache = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName, stringTable); - CFRelease(stringTable); + + if (!CFStringHasSuffix(tableName, CFSTR(".nocache")) || !_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) { + __CFSpinLock(&CFBundleLocalizedStringLock); + if (!__CFBundleGetResourceData(bundle)->_stringTableCache) __CFBundleGetResourceData(bundle)->_stringTableCache = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName, stringTable); + __CFSpinUnlock(&CFBundleLocalizedStringLock); + } } result = (CFStringRef)CFDictionaryGetValue(stringTable, key); @@ -783,8 +813,7 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe } else { CFRetain(result); } - if (CFStringHasSuffix(tableName, CFSTR(".nocache")) && __CFBundleGetResourceData(bundle)->_stringTableCache && _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) CFDictionaryRemoveValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName); - + CFRelease(stringTable); return result; } @@ -801,12 +830,9 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL, CFStri uint8_t version = 0; CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault, newURL, &version), types = NULL, array; if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); - array = _CFFindBundleResources(NULL, newURL, subDirName, languages, resourceName, types, 1, version); - if (types) CFRelease(types); if (languages) CFRelease(languages); - if (array) { if (CFArrayGetCount(array) > 0) result = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); CFRelease(array); @@ -829,10 +855,8 @@ CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleUR uint8_t version = 0; CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault, newURL, &version), types = NULL; if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); - // MF:!!! Better "limit" than 1,000,000? array = _CFFindBundleResources(NULL, newURL, subDirName, languages, NULL, types, 1000000, version); - if (types) CFRelease(types); if (languages) CFRelease(languages); } @@ -857,8 +881,8 @@ const char * __CFBundleLocaleAbbreviationsArray = "ur_IN\0" "vi_VN\0" "fr_BE\0" "uz_UZ\0" "en_SG\0" "nn_NO\0" "af_ZA\0" "eo\0\0\0\0" "mr_IN\0" "bo\0\0\0\0" "ne_NP\0" "kl\0\0\0\0" "en_IE\0"; -#define NUM_LOCALE_ABBREVIATIONS 109 -#define LOCALE_ABBREVIATION_LENGTH 6 +#define NUM_LOCALE_ABBREVIATIONS 109 +#define LOCALE_ABBREVIATION_LENGTH 6 static const char * const __CFBundleLanguageNamesArray[] = { "English", "French", "German", "Italian", "Dutch", "Swedish", "Spanish", "Danish", @@ -882,8 +906,8 @@ static const char * const __CFBundleLanguageNamesArray[] = { "Scottish", "Manx", "Irish", "Tongan", "Greek", "Greenlandic", "Azerbaijani", "Nynorsk" }; -#define NUM_LANGUAGE_NAMES 152 -#define LANGUAGE_NAME_LENGTH 13 +#define NUM_LANGUAGE_NAMES 152 +#define LANGUAGE_NAME_LENGTH 13 // string, with groups of 3 characters being 1 element in the array of abbreviations const char * __CFBundleLanguageAbbreviationsArray = @@ -907,8 +931,8 @@ const char * __CFBundleLanguageAbbreviationsArray = "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" "nn\0"; -#define NUM_LANGUAGE_ABBREVIATIONS 152 -#define LANGUAGE_ABBREVIATION_LENGTH 3 +#define NUM_LANGUAGE_ABBREVIATIONS 152 +#define LANGUAGE_ABBREVIATION_LENGTH 3 #if defined(__CONSTANT_CFSTRINGS__) @@ -1026,7 +1050,7 @@ CF_INLINE CFStringRef _CFBundleCopyLanguageNameForLocalization(CFStringRef local static SInt32 _CFBundleGetLanguageCodeForRegionCode(SInt32 regionCode) { SInt32 result = -1, i; - if (52 == regionCode) { // hack for mixed-up Chinese language codes + if (52 == regionCode) { // hack for mixed-up Chinese language codes result = 33; } else if (0 <= regionCode && regionCode < NUM_LOCALE_ABBREVIATIONS) { const char *localeAbbreviation = __CFBundleLocaleAbbreviationsArray + regionCode * LOCALE_ABBREVIATION_LENGTH; @@ -1041,7 +1065,7 @@ static SInt32 _CFBundleGetLanguageCodeForRegionCode(SInt32 regionCode) { static SInt32 _CFBundleGetRegionCodeForLanguageCode(SInt32 languageCode) { SInt32 result = -1, i; - if (19 == languageCode) { // hack for mixed-up Chinese language codes + if (19 == languageCode) { // hack for mixed-up Chinese language codes result = 53; } else if (0 <= languageCode && languageCode < NUM_LANGUAGE_ABBREVIATIONS) { const char *languageAbbreviation = __CFBundleLanguageAbbreviationsArray + languageCode * LANGUAGE_ABBREVIATION_LENGTH; @@ -1060,7 +1084,7 @@ 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)) { + 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; @@ -1101,6 +1125,19 @@ Boolean CFBundleGetLocalizationInfoForLocalization(CFStringRef localizationName, if (!languages) languages = _CFBundleCopyUserLanguages(false); if (languages && CFArrayGetCount(languages) > 0) localizationName = (CFStringRef)CFArrayGetValueAtIndex(languages, 0); } + if (localizationName) { + LangCode langCode = -1; + RegionCode regCode = -1; + ScriptCode scrCode = 0; + CFStringEncoding enc = kCFStringEncodingMacRoman; + retval = CFLocaleGetLanguageRegionEncodingForLocaleIdentifier(localizationName, &langCode, ®Code, &scrCode, &enc); + if (retval) { + language = langCode; + region = regCode; + script = scrCode; + encoding = enc; + } + } if (!retval) { if (localizationName) { language = _CFBundleGetLanguageCodeForLocalization(localizationName); @@ -1127,15 +1164,11 @@ Boolean CFBundleGetLocalizationInfoForLocalization(CFStringRef localizationName, CFStringRef CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode, SInt32 regionCode, SInt32 scriptCode, CFStringEncoding stringEncoding) { CFStringRef localizationName = NULL; - if (!localizationName) { - localizationName = _CFBundleCopyLocaleAbbreviationForRegionCode(regionCode); - } - if (!localizationName && 0 <= languageCode && languageCode < SHRT_MAX) { - localizationName = CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes(kCFAllocatorSystemDefault, (LangCode)languageCode, (RegionCode)-1); - } - if (!localizationName) { - localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode); - } + if (!localizationName) localizationName = _CFBundleCopyLocaleAbbreviationForRegionCode(regionCode); +#if DEPLOYMENT_TARGET_MACOSX + if (!localizationName && 0 <= languageCode && languageCode < SHRT_MAX) localizationName = CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes(kCFAllocatorSystemDefault, (LangCode)languageCode, (RegionCode)-1); +#endif + if (!localizationName) localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode); if (!localizationName) { SInt32 language = -1, scriptLanguage = -1, encodingLanguage = -1; unsigned int i; @@ -1157,9 +1190,58 @@ CFStringRef CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode, SIn extern void *__CFAppleLanguages; +#if DEPLOYMENT_TARGET_WINDOWS + +extern CFStringRef copyLocaleLanguageName(void); +extern CFStringRef copyLocaleCountryName(void); + +static CFArrayRef copyWindowsLanguagePrefsArray() { + CFArrayRef result; + CFStringRef locales[4]; + CFStringRef languageName = copyLocaleLanguageName(), countryName = copyLocaleCountryName(); + if (!languageName) languageName = CFSTR("en"); + if (!countryName) countryName = CFSTR(""); + CFIndex i, localesCount = 0; + if (CFStringGetLength(countryName) > 0) locales[localesCount++] = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@_%@"), languageName, countryName); + if (CFStringGetLength(languageName) != 0) { + // special-case for zh since we don't have a generic zh localization + if (CFStringCompare(languageName, CFSTR("zh"), kCFCompareCaseInsensitive) != 0) { + locales[localesCount++] = CFStringCreateCopy(kCFAllocatorSystemDefault, languageName);//languageName; + } else { + CFStringRef moreSpecificLanguageName; + + // See http://intrigue-build.apple.com/changeset/14948 for the details on the change. Copied below is the snippet of the code change. + // According to http://www.microsoft.com/globaldev/reference/win2k/setup/lcid.mspx, the locales that use + // 126 // simplified chinese are CN (PRC) and SG (Singapore). The rest use traditional chinese. + // 127 languageName = (countryName == TEXT("CN") || countryName == TEXT("SG")) ? TEXT("zh_CN") : TEXT("zh_TW"); + + // Compare for CN or SG + if (CFStringCompare(countryName, CFSTR("CN"), kCFCompareCaseInsensitive) == 0 || CFStringCompare(countryName, CFSTR("SG"), kCFCompareCaseInsensitive) == 0) { + moreSpecificLanguageName = CFSTR("zh_CN"); + } else { + moreSpecificLanguageName = CFSTR("zh_TW"); + } + locales[localesCount++] = CFStringCreateCopy(kCFAllocatorSystemDefault, moreSpecificLanguageName); + } + // Don't need this now + if (languageName) CFRelease(languageName); + if (countryName) CFRelease(countryName); + } + if (localesCount == 0) locales[localesCount++] = CFStringCreateCopy(kCFAllocatorSystemDefault, CFSTR("en")); + result = CFArrayCreate(kCFAllocatorDefault, (const void **)locales, localesCount, &kCFTypeArrayCallBacks); + for (i = 0; i < localesCount; i++) CFRelease(locales[i]); + return result; +} + +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif + +static CFArrayRef _CFBundleUserLanguages = NULL; + __private_extern__ CFArrayRef _CFBundleCopyUserLanguages(Boolean useBackstops) { CFArrayRef result = NULL; - static CFArrayRef userLanguages = NULL; static Boolean didit = false; CFArrayRef preferencesArray = NULL; // This is a temporary solution, until the argument domain is moved down into CFPreferences @@ -1171,27 +1253,27 @@ __private_extern__ CFArrayRef _CFBundleCopyUserLanguages(Boolean useBackstops) { if (length > 0) { data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8 *)__CFAppleLanguages, length, kCFAllocatorNull); if (data) { - userLanguages = (CFArrayRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL); + _CFBundleUserLanguages = (CFArrayRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL); CFRelease(data); } } } - if (!userLanguages && preferencesArray) userLanguages = (CFArrayRef)CFRetain(preferencesArray); + if (!_CFBundleUserLanguages && preferencesArray) _CFBundleUserLanguages = (CFArrayRef)CFRetain(preferencesArray); Boolean useEnglishAsBackstop = true; // could perhaps read out of LANG environment variable - if (useEnglishAsBackstop && !userLanguages) { + if (useEnglishAsBackstop && !_CFBundleUserLanguages) { CFStringRef english = CFSTR("en"); - userLanguages = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&english, 1, &kCFTypeArrayCallBacks); + _CFBundleUserLanguages = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&english, 1, &kCFTypeArrayCallBacks); } - if (userLanguages && CFGetTypeID(userLanguages) != CFArrayGetTypeID()) { - CFRelease(userLanguages); - userLanguages = NULL; + if (_CFBundleUserLanguages && CFGetTypeID(_CFBundleUserLanguages) != CFArrayGetTypeID()) { + CFRelease(_CFBundleUserLanguages); + _CFBundleUserLanguages = NULL; } didit = true; } __CFSpinUnlock(&CFBundleResourceGlobalDataLock); if (preferencesArray) CFRelease(preferencesArray); - if (!result && userLanguages) result = (CFArrayRef)CFRetain(userLanguages); + if (!result && _CFBundleUserLanguages) result = (CFArrayRef)CFRetain(_CFBundleUserLanguages); return result; } @@ -1211,6 +1293,11 @@ CF_EXPORT void _CFBundleGetLanguageAndRegionCodes(SInt32 *languageCode, SInt32 * Boolean retval = false; LangCode langCode = -1; RegionCode regCode = -1; + retval = CFLocaleGetLanguageRegionEncodingForLocaleIdentifier(localizationName, &langCode, ®Code, NULL, NULL); + if (retval) { + language = langCode; + region = regCode; + } if (!retval) { language = _CFBundleGetLanguageCodeForLocalization(localizationName); region = _CFBundleGetRegionCodeForLocalization(localizationName); @@ -1227,12 +1314,12 @@ CF_EXPORT void _CFBundleGetLanguageAndRegionCodes(SInt32 *languageCode, SInt32 * } -static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc, UniChar *pathUniChars, CFIndex pathLen, uint8_t version, CFDictionaryRef infoDict, CFStringRef curLangStr, CFMutableArrayRef lprojNames) { +static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc, UniChar *pathUniChars, CFIndex pathLen, uint8_t version, CFDictionaryRef infoDict, CFStringRef curLangStr, CFMutableArrayRef lprojNames, Boolean fallBackToLanguage) { CFIndex curLangLen = CFStringGetLength(curLangStr), savedPathLen; UniChar curLangUniChars[255]; - CFStringRef altLangStr = NULL, modifiedLangStr = NULL, languageAbbreviation = NULL, languageName = NULL, canonicalLanguageIdentifier = NULL; + CFStringRef altLangStr = NULL, modifiedLangStr = NULL, languageAbbreviation = NULL, languageName = NULL, canonicalLanguageIdentifier = NULL, canonicalLanguageAbbreviation = NULL; CFMutableDictionaryRef canonicalLanguageIdentifiers = NULL, predefinedCanonicalLanguageIdentifiers = NULL; - Boolean foundOne = false; + Boolean foundOne = false, specifiesScript = false; CFArrayRef predefinedLocalizations = NULL; CFRange predefinedLocalizationsRange; CFMutableStringRef cheapStr, tmpString; @@ -1369,7 +1456,7 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc } } } - if (!altLangStr && (languageAbbreviation = _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr)) && !CFEqual(curLangStr, languageAbbreviation)) { + if (!specifiesScript && (foundOne || fallBackToLanguage) && !altLangStr && (languageAbbreviation = _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr)) && !CFEqual(curLangStr, languageAbbreviation)) { curLangLen = CFStringGetLength(languageAbbreviation); if (curLangLen > 255) curLangLen = 255; CFStringGetCharacters(languageAbbreviation, CFRangeMake(0, curLangLen), curLangUniChars); @@ -1389,7 +1476,7 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc } } } - if (!altLangStr && (languageName = _CFBundleCopyLanguageNameForLocalization(curLangStr)) && !CFEqual(curLangStr, languageName)) { + if (!specifiesScript && (foundOne || fallBackToLanguage) && !altLangStr && (languageName = _CFBundleCopyLanguageNameForLocalization(curLangStr)) && !CFEqual(curLangStr, languageName)) { curLangLen = CFStringGetLength(languageName); if (curLangLen > 255) curLangLen = 255; CFStringGetCharacters(languageName, CFRangeMake(0, curLangLen), curLangUniChars); @@ -1415,12 +1502,12 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc if (canonicalLanguageIdentifier) CFRelease(canonicalLanguageIdentifier); if (canonicalLanguageIdentifiers) CFRelease(canonicalLanguageIdentifiers); if (predefinedCanonicalLanguageIdentifiers) CFRelease(predefinedCanonicalLanguageIdentifiers); + if (canonicalLanguageAbbreviation) CFRelease(canonicalLanguageAbbreviation); CFRelease(cheapStr); CFRelease(tmpString); #if READ_DIRECTORIES CFRelease(contents); #endif /* READ_DIRECTORIES */ - return foundOne; } @@ -1446,20 +1533,36 @@ static Boolean CFBundleAllowMixedLocalizations(void) { return allowMixed; } +static Boolean _CFBundleLocalizationsHaveCommonPrefix(CFStringRef loc1, CFStringRef loc2) { + Boolean result = false; + CFIndex length1 = CFStringGetLength(loc1), length2 = CFStringGetLength(loc2), idx; + if (length1 > 3 && length2 > 3) { + for (idx = 0; idx < length1 && idx < length2; idx++) { + UniChar c1 = CFStringGetCharacterAtIndex(loc1, idx), c2 = CFStringGetCharacterAtIndex(loc2, idx); + if (idx >= 2 && (c1 == '-' || c1 == '_') && (c2 == '-' || c2 == '_')) { + result = true; + break; + } else if (c1 != c2) { + break; + } + } + } + return result; +} + __private_extern__ void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, uint8_t version, CFDictionaryRef infoDict, CFMutableArrayRef lprojNames, CFStringRef devLang) { // This function will add zero, one or two elements to the lprojNames array. // 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. // 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. CFURLRef resourcesURL = _CFBundleCopyResourcesDirectoryURLInDirectory(alloc, bundleURL, version); CFURLRef absoluteURL; - CFIndex idx; + CFIndex idx, startIdx; CFIndex count; CFStringRef resourcesPath; UniChar pathUniChars[CFMaxPathSize]; CFIndex pathLen; - CFStringRef curLangStr; + CFStringRef curLangStr, nextLangStr; Boolean foundOne = false; - CFArrayRef userLanguages; // Init the one-time-only unichar buffers. @@ -1480,15 +1583,17 @@ __private_extern__ void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRe CFBundleRef mainBundle = CFBundleGetMainBundle(); if (mainBundle) { CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle); - if (!CFEqual(bundleURL, mainBundleURL)) { - // If there is a main bundle, and it isn't this one, try to use the language it prefers. - CFArrayRef mainBundleLangs = _CFBundleGetLanguageSearchList(mainBundle); - if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) { - curLangStr = (CFStringRef)CFArrayGetValueAtIndex(mainBundleLangs, 0); - foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames); + if (mainBundleURL) { + if (!CFEqual(bundleURL, mainBundleURL)) { + // If there is a main bundle, and it isn't this one, try to use the language it prefers. + CFArrayRef mainBundleLangs = _CFBundleGetLanguageSearchList(mainBundle); + if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) { + curLangStr = (CFStringRef)CFArrayGetValueAtIndex(mainBundleLangs, 0); + foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, true); + } } + CFRelease(mainBundleURL); } - CFRelease(mainBundleURL); } } @@ -1496,21 +1601,35 @@ __private_extern__ void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRe // If we didn't find the main bundle's preferred language, look at the users' prefs again and find the best one. userLanguages = _CFBundleCopyUserLanguages(true); count = (userLanguages ? CFArrayGetCount(userLanguages) : 0); - for (idx = 0; !foundOne && idx < count; idx++) { + for (idx = 0, startIdx = -1; !foundOne && idx < count; idx++) { curLangStr = (CFStringRef)CFArrayGetValueAtIndex(userLanguages, idx); - foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames); + nextLangStr = (idx + 1 < count) ? (CFStringRef)CFArrayGetValueAtIndex(userLanguages, idx + 1) : NULL; + if (nextLangStr && _CFBundleLocalizationsHaveCommonPrefix(curLangStr, nextLangStr)) { + foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, false); + if (startIdx < 0) startIdx = idx; + } else if (startIdx >= 0 && startIdx <= idx) { + foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, false); + for (; !foundOne && startIdx <= idx; startIdx++) { + curLangStr = (CFStringRef)CFArrayGetValueAtIndex(userLanguages, startIdx); + foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, true); + } + startIdx = -1; + } else { + foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, true); + startIdx = -1; + } } // use development region and U.S. English as backstops - if (!foundOne && devLang) foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, devLang, lprojNames); - if (!foundOne) foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, CFSTR("en_US"), lprojNames); + if (!foundOne && devLang) foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, devLang, lprojNames, true); + if (!foundOne) foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, CFSTR("en_US"), lprojNames, true); if (userLanguages) CFRelease(userLanguages); } } -static Boolean _CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array, CFStringRef curLangStr, CFMutableArrayRef lprojNames) { - Boolean foundOne = false; +static Boolean _CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array, CFStringRef curLangStr, CFMutableArrayRef lprojNames, Boolean fallBackToLanguage) { + Boolean foundOne = false, specifiesScript = false; CFRange range = CFRangeMake(0, CFArrayGetCount(array)); - CFStringRef altLangStr = NULL, modifiedLangStr = NULL, languageAbbreviation = NULL, languageName = NULL, canonicalLanguageIdentifier = NULL; + CFStringRef altLangStr = NULL, modifiedLangStr = NULL, languageAbbreviation = NULL, languageName = NULL, canonicalLanguageIdentifier = NULL, canonicalLanguageAbbreviation = NULL; CFMutableDictionaryRef canonicalLanguageIdentifiers = NULL; if (range.length == 0) return foundOne; @@ -1541,13 +1660,13 @@ static Boolean _CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array, CFStri foundOne = true; } } - if (!altLangStr && (languageAbbreviation = _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr)) && !CFEqual(curLangStr, languageAbbreviation)) { + if (!specifiesScript && (foundOne || fallBackToLanguage) && !altLangStr && (languageAbbreviation = _CFBundleCopyLanguageAbbreviationForLocalization(curLangStr)) && !CFEqual(curLangStr, languageAbbreviation)) { if (CFArrayContainsValue(array, range, languageAbbreviation)) { if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), languageAbbreviation)) CFArrayAppendValue(lprojNames, languageAbbreviation); foundOne = true; } } - if (!altLangStr && (languageName = _CFBundleCopyLanguageNameForLocalization(curLangStr)) && !CFEqual(curLangStr, languageName)) { + if (!specifiesScript && (foundOne || fallBackToLanguage) && !altLangStr && (languageName = _CFBundleCopyLanguageNameForLocalization(curLangStr)) && !CFEqual(curLangStr, languageName)) { if (CFArrayContainsValue(array, range, languageName)) { if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), languageName)) CFArrayAppendValue(lprojNames, languageName); foundOne = true; @@ -1558,42 +1677,53 @@ static Boolean _CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array, CFStri if (languageName) CFRelease(languageName); if (canonicalLanguageIdentifier) CFRelease(canonicalLanguageIdentifier); if (canonicalLanguageIdentifiers) CFRelease(canonicalLanguageIdentifiers); - + if (canonicalLanguageAbbreviation) CFRelease(canonicalLanguageAbbreviation); return foundOne; } static CFArrayRef _CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray, Boolean considerMain) { CFMutableArrayRef lprojNames = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); Boolean foundOne = false, releasePrefArray = false; - CFIndex idx, count; + CFIndex idx, count, startIdx; if (considerMain && !CFBundleAllowMixedLocalizations()) { CFBundleRef mainBundle = CFBundleGetMainBundle(); if (mainBundle) { // If there is a main bundle, try to use the language it prefers. CFArrayRef mainBundleLangs = _CFBundleGetLanguageSearchList(mainBundle); - if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) { - foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, (CFStringRef)CFArrayGetValueAtIndex(mainBundleLangs, 0), lprojNames); - } + if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, (CFStringRef)CFArrayGetValueAtIndex(mainBundleLangs, 0), lprojNames, true); } } + if (!foundOne) { + CFStringRef curLangStr, nextLangStr; if (!prefArray) { prefArray = _CFBundleCopyUserLanguages(true); if (prefArray) releasePrefArray = true; } count = (prefArray ? CFArrayGetCount(prefArray) : 0); - for (idx = 0; !foundOne && idx < count; idx++) { - foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, (CFStringRef)CFArrayGetValueAtIndex(prefArray, idx), lprojNames); + for (idx = 0, startIdx = -1; !foundOne && idx < count; idx++) { + curLangStr = (CFStringRef)CFArrayGetValueAtIndex(prefArray, idx); + nextLangStr = (idx + 1 < count) ? (CFStringRef)CFArrayGetValueAtIndex(prefArray, idx + 1) : NULL; + if (nextLangStr && _CFBundleLocalizationsHaveCommonPrefix(curLangStr, nextLangStr)) { + foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, curLangStr, lprojNames, false); + if (startIdx < 0) startIdx = idx; + } else if (startIdx >= 0 && startIdx <= idx) { + foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, curLangStr, lprojNames, false); + for (; !foundOne && startIdx <= idx; startIdx++) { + curLangStr = (CFStringRef)CFArrayGetValueAtIndex(prefArray, startIdx); + foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, curLangStr, lprojNames, true); + } + startIdx = -1; + } else { + foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, curLangStr, lprojNames, true); + startIdx = -1; + } } // use U.S. English as backstop - if (!foundOne) { - foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFSTR("en_US"), lprojNames); - } + if (!foundOne) foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFSTR("en_US"), lprojNames, true); // use random entry as backstop - if (!foundOne && CFArrayGetCount(lprojNames) > 0) { - foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, (CFStringRef)CFArrayGetValueAtIndex(locArray, 0), lprojNames); - } + if (!foundOne && CFArrayGetCount(locArray) > 0) foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, (CFStringRef)CFArrayGetValueAtIndex(locArray, 0), lprojNames, true); } if (CFArrayGetCount(lprojNames) == 0) { // Total backstop behavior to avoid having an empty array. @@ -1605,9 +1735,13 @@ static CFArrayRef _CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, return lprojNames; } -CF_EXPORT CFArrayRef CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray) {return _CFBundleCopyLocalizationsForPreferences(locArray, prefArray, false);} +CF_EXPORT CFArrayRef CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray) { + return _CFBundleCopyLocalizationsForPreferences(locArray, prefArray, false); +} -CF_EXPORT CFArrayRef CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locArray) {return _CFBundleCopyLocalizationsForPreferences(locArray, NULL, true);} +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); @@ -1641,10 +1775,8 @@ CF_EXPORT Boolean _CFBundleURLLooksLikeBundle(CFURLRef url) { // Note that subDirName is expected to be the string for a URL CF_INLINE Boolean _CFBundleURLHasSubDir(CFURLRef url, CFStringRef subDirName) { - CFURLRef dirURL; Boolean isDir = false, result = false; - - dirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, subDirName, url); + CFURLRef dirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, subDirName, url); if (dirURL) { if (_CFIsResourceAtURL(dirURL, &isDir) && isDir) result = true; CFRelease(dirURL); @@ -1680,7 +1812,8 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint CFRelease(absoluteURL); #endif /* READ_DIRECTORIES */ if (localVersion == 3) { -#if DEPLOYMENT_TARGET_MACOSX +#if DEPLOYMENT_TARGET_EMBEDDED +#elif DEPLOYMENT_TARGET_MACOSX if (CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework/"))) { if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) localVersion = 2; @@ -1690,10 +1823,22 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint else if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1; } +#elif DEPLOYMENT_TARGET_WINDOWS + if (CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework\\"))) { + if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; + else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) localVersion = 2; + else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1; + } else { + if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) localVersion = 2; + else if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; + else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1; + } +#else +#error Unknown or unspecified DEPLOYMENT_TARGET #endif } if (version) *version = localVersion; - return !(localVersion == 3); + return (localVersion != 3); } __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc, CFURLRef url, uint8_t *version) { @@ -1753,35 +1898,18 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension2; infoURLFromBase = _CFBundleInfoURLFromBase2; } else if (3 == version) { -#if DEPLOYMENT_TARGET_MACOSX - CFStringRef posixPath = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); + CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); // this test is necessary to exclude the case where a bundle is spuriously created from the innards of another bundle - if (posixPath) { - if (!(CFStringHasSuffix(posixPath, _CFBundleSupportFilesDirectoryName1) || CFStringHasSuffix(posixPath, _CFBundleSupportFilesDirectoryName2) || CFStringHasSuffix(posixPath, _CFBundleResourcesDirectoryName))) { + if (path) { + if (!(CFStringHasSuffix(path, _CFBundleSupportFilesDirectoryName1) || CFStringHasSuffix(path, _CFBundleSupportFilesDirectoryName2) || CFStringHasSuffix(path, _CFBundleResourcesDirectoryName))) { #if READ_DIRECTORIES directoryURL = CFRetain(url); #endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension3; infoURLFromBase = _CFBundleInfoURLFromBase3; } - CFRelease(posixPath); + CFRelease(path); } -#elif 0 - CFStringRef windowsPath = CFURLCopyFileSystemPath(url, kCFURLWindowsPathStyle); - // this test is necessary to exclude the case where a bundle is spuriously created from the innards of another bundle - if (windowsPath) { - if (!(CFStringHasSuffix(windowsPath, _CFBundleSupportFilesDirectoryName1) || CFStringHasSuffix(windowsPath, _CFBundleSupportFilesDirectoryName2) || CFStringHasSuffix(windowsPath, _CFBundleResourcesDirectoryName))) { -#if READ_DIRECTORIES - directoryURL = CFRetain(url); -#endif /* READ_DIRECTORIES */ - infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension3; - infoURLFromBase = _CFBundleInfoURLFromBase3; - } - CFRelease(windowsPath); - } -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif } #if READ_DIRECTORIES if (directoryURL) { @@ -1933,19 +2061,19 @@ static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorR 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)'/'))) { + 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)'/')) { // This is an app *packageType = 0x4150504c; // 'APPL' - } 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)'/'))) { + } 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)'/')) { // This is an app (debug version) *packageType = 0x4150504c; // 'APPL' - } 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)'/'))) { + } 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)'/')) { // This is an app (profile version) *packageType = 0x4150504c; // 'APPL' - } 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)'/'))) { + } 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)'/')) { // This is a service *packageType = 0x4150504c; // 'APPL' - } 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)'/'))) { + } 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)'/')) { // This is a framework *packageType = 0x464d574b; // 'FMWK' } else { @@ -1959,7 +2087,9 @@ static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorR return retVal; } -CF_EXPORT Boolean _CFBundleGetPackageInfoInDirectory(CFAllocatorRef alloc, CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {return _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(alloc, url, NULL, packageType, packageCreator);} +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); @@ -1970,11 +2100,96 @@ CF_EXPORT void CFBundleGetPackageInfo(CFBundleRef bundle, UInt32 *packageType, U if (bundleURL) CFRelease(bundleURL); } -CF_EXPORT Boolean CFBundleGetPackageInfoInDirectory(CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {return _CFBundleGetPackageInfoInDirectory(kCFAllocatorSystemDefault, url, packageType, packageCreator);} +CF_EXPORT Boolean CFBundleGetPackageInfoInDirectory(CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) { + return _CFBundleGetPackageInfoInDirectory(kCFAllocatorSystemDefault, url, packageType, packageCreator); +} -__private_extern__ CFStringRef _CFBundleGetPlatformExecutablesSubdirectoryName(void) { +static void _CFBundleCheckSupportedPlatform(CFMutableArrayRef mutableArray, UniChar *buff, CFIndex startLen, CFStringRef platformName, CFStringRef platformIdentifier) { + CFIndex buffLen = startLen, platformLen = CFStringGetLength(platformName), extLen = CFStringGetLength(_CFBundleInfoExtension); + CFMutableStringRef str; + Boolean isDir; + if (buffLen + platformLen + extLen < CFMaxPathSize) { + CFStringGetCharacters(platformName, CFRangeMake(0, platformLen), buff + buffLen); + buffLen += platformLen; + buff[buffLen++] = (UniChar)'.'; + CFStringGetCharacters(_CFBundleInfoExtension, CFRangeMake(0, extLen), buff + buffLen); + buffLen += extLen; + str = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); + CFStringAppendCharacters(str, buff, buffLen); + if (_CFIsResourceAtPath(str, &isDir) && !isDir && CFArrayGetFirstIndexOfValue(mutableArray, CFRangeMake(0, CFArrayGetCount(mutableArray)), platformIdentifier) < 0) CFArrayAppendValue(mutableArray, platformIdentifier); + CFRelease(str); + } +} + +CF_EXPORT CFArrayRef _CFBundleGetSupportedPlatforms(CFBundleRef bundle) { + CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); + CFArrayRef platformArray = infoDict ? (CFArrayRef)CFDictionaryGetValue(infoDict, _kCFBundleSupportedPlatformsKey) : NULL; + if (platformArray && CFGetTypeID(platformArray) != CFArrayGetTypeID()) { + platformArray = NULL; + CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, _kCFBundleSupportedPlatformsKey); + } + if (!platformArray) { + CFURLRef infoPlistURL = infoDict ? (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleInfoPlistURLKey) : NULL, absoluteURL; + CFStringRef infoPlistPath; + UniChar buff[CFMaxPathSize]; + CFIndex buffLen, infoLen = CFStringGetLength(_CFBundleInfoURLFromBaseNoExtension3), startLen, extLen = CFStringGetLength(_CFBundleInfoExtension); + if (infoPlistURL) { + CFMutableArrayRef mutableArray = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks); + absoluteURL = CFURLCopyAbsoluteURL(infoPlistURL); + infoPlistPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); + CFRelease(absoluteURL); + buffLen = CFStringGetLength(infoPlistPath); + if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize; + CFStringGetCharacters(infoPlistPath, CFRangeMake(0, buffLen), buff); + CFRelease(infoPlistPath); + if (buffLen > 0) { + buffLen = _CFStartOfLastPathComponent(buff, buffLen); + if (buffLen > 0 && buffLen + infoLen + extLen < CFMaxPathSize) { + CFStringGetCharacters(_CFBundleInfoURLFromBaseNoExtension3, CFRangeMake(0, infoLen), buff + buffLen); + buffLen += infoLen; + buff[buffLen++] = (UniChar)'-'; + startLen = buffLen; + _CFBundleCheckSupportedPlatform(mutableArray, buff, startLen, CFSTR("macos"), CFSTR("MacOS")); + _CFBundleCheckSupportedPlatform(mutableArray, buff, startLen, CFSTR("macosx"), CFSTR("MacOS")); + _CFBundleCheckSupportedPlatform(mutableArray, buff, startLen, CFSTR("iphoneos"), CFSTR("iPhoneOS")); + _CFBundleCheckSupportedPlatform(mutableArray, buff, startLen, CFSTR("windows"), CFSTR("Windows")); + } + } + if (CFArrayGetCount(mutableArray) > 0) { + platformArray = (CFArrayRef)mutableArray; + CFDictionarySetValue((CFMutableDictionaryRef)infoDict, _kCFBundleSupportedPlatformsKey, platformArray); + } + CFRelease(mutableArray); + } + } + return platformArray; +} + +CF_EXPORT CFStringRef _CFBundleGetCurrentPlatform(void) { #if DEPLOYMENT_TARGET_MACOSX return CFSTR("MacOS"); +#elif DEPLOYMENT_TARGET_EMBEDDED + return CFSTR("iPhoneOS"); +#elif DEPLOYMENT_TARGET_WINDOWS + return CFSTR("Windows"); +#elif DEPLOYMENT_TARGET_SOLARIS + return CFSTR("Solaris"); +#elif DEPLOYMENT_TARGET_HPUX + return CFSTR("HPUX"); +#elif DEPLOYMENT_TARGET_LINUX + return CFSTR("Linux"); +#elif DEPLOYMENT_TARGET_FREEBSD + return CFSTR("FreeBSD"); +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif +} + +__private_extern__ CFStringRef _CFBundleGetPlatformExecutablesSubdirectoryName(void) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + return CFSTR("MacOS"); +#elif DEPLOYMENT_TARGET_WINDOWS + return CFSTR("Windows"); #elif DEPLOYMENT_TARGET_SOLARIS return CFSTR("Solaris"); #elif DEPLOYMENT_TARGET_HPUX @@ -1989,8 +2204,10 @@ __private_extern__ CFStringRef _CFBundleGetPlatformExecutablesSubdirectoryName(v } __private_extern__ CFStringRef _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(void) { -#if DEPLOYMENT_TARGET_MACOSX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED return CFSTR("Mac OS X"); +#elif DEPLOYMENT_TARGET_WINDOWS + return CFSTR("WinNT"); #elif DEPLOYMENT_TARGET_SOLARIS return CFSTR("Solaris"); #elif DEPLOYMENT_TARGET_HPUX @@ -2005,8 +2222,10 @@ __private_extern__ CFStringRef _CFBundleGetAlternatePlatformExecutablesSubdirect } __private_extern__ CFStringRef _CFBundleGetOtherPlatformExecutablesSubdirectoryName(void) { -#if DEPLOYMENT_TARGET_MACOSX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED return CFSTR("MacOSClassic"); +#elif DEPLOYMENT_TARGET_WINDOWS + return CFSTR("Other"); #elif DEPLOYMENT_TARGET_HPUX return CFSTR("Other"); #elif DEPLOYMENT_TARGET_SOLARIS @@ -2021,8 +2240,10 @@ __private_extern__ CFStringRef _CFBundleGetOtherPlatformExecutablesSubdirectoryN } __private_extern__ CFStringRef _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(void) { -#if DEPLOYMENT_TARGET_MACOSX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED return CFSTR("Mac OS 8"); +#elif DEPLOYMENT_TARGET_WINDOWS + return CFSTR("Other"); #elif DEPLOYMENT_TARGET_HPUX return CFSTR("Other"); #elif DEPLOYMENT_TARGET_SOLARIS @@ -2036,7 +2257,9 @@ __private_extern__ CFStringRef _CFBundleGetOtherAlternatePlatformExecutablesSubd #endif } -__private_extern__ CFArrayRef _CFBundleCopyBundleRegionsArray(CFBundleRef bundle) {return CFBundleCopyBundleLocalizations(bundle);} +__private_extern__ CFArrayRef _CFBundleCopyBundleRegionsArray(CFBundleRef bundle) { + return CFBundleCopyBundleLocalizations(bundle); +} CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); @@ -2122,7 +2345,6 @@ CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { } } if (resourcesURL) CFRelease(resourcesURL); - return result; }