CFBundle_InfoPlist.c [plain text]
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFNumber.h>
#include "CFBundle_Internal.h"
#include "CFByteOrder.h"
#include "CFURLAccess.h"
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_EMBEDDED_MINI
#include <dirent.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#endif
#if !__CONSTANT_STRINGS__
#define _CFBundleNumberOfPlatforms 7
static CFStringRef _CFBundleSupportedPlatforms[_CFBundleNumberOfPlatforms] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
static const char *_CFBundleSupportedPlatformStrings[_CFBundleNumberOfPlatforms] = { "iphoneos", "macos", "windows", "linux", "freebsd", "solaris", "hpux" };
#define _CFBundleNumberOfProducts 3
static CFStringRef _CFBundleSupportedProducts[_CFBundleNumberOfProducts] = { NULL, NULL, NULL };
static const char *_CFBundleSupportedProductStrings[_CFBundleNumberOfProducts] = { "iphone", "ipod", "ipad" };
#define _CFBundleNumberOfiPhoneOSPlatformProducts 3
static CFStringRef _CFBundleSupportediPhoneOSPlatformProducts[_CFBundleNumberOfiPhoneOSPlatformProducts] = { NULL, NULL, NULL };
static const char *_CFBundleSupportediPhoneOSPlatformProductStrings[_CFBundleNumberOfiPhoneOSPlatformProducts] = { "iphone", "ipod", "ipad" };
CF_PRIVATE void _CFBundleResourcesInitialize() {
for (unsigned int i = 0; i < _CFBundleNumberOfPlatforms; i++) _CFBundleSupportedPlatforms[i] = CFStringCreateWithCString(kCFAllocatorSystemDefault, _CFBundleSupportedPlatformStrings[i], kCFStringEncodingUTF8);
for (unsigned int i = 0; i < _CFBundleNumberOfProducts; i++) _CFBundleSupportedProducts[i] = CFStringCreateWithCString(kCFAllocatorSystemDefault, _CFBundleSupportedProductStrings[i], kCFStringEncodingUTF8);
for (unsigned int i = 0; i < _CFBundleNumberOfiPhoneOSPlatformProducts; i++) _CFBundleSupportediPhoneOSPlatformProducts[i] = CFStringCreateWithCString(kCFAllocatorSystemDefault, _CFBundleSupportediPhoneOSPlatformProductStrings[i], kCFStringEncodingUTF8);
}
#else
#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#define _CFBundleNumberOfPlatforms 1
static CFStringRef _CFBundleSupportedPlatforms[_CFBundleNumberOfPlatforms] = { CFSTR("iphoneos") };
#else
#define _CFBundleNumberOfPlatforms 7
static CFStringRef _CFBundleSupportedPlatforms[_CFBundleNumberOfPlatforms] = { CFSTR("iphoneos"), CFSTR("macos"), CFSTR("windows"), CFSTR("linux"), CFSTR("freebsd"), CFSTR("solaris"), CFSTR("hpux") };
#endif
#define _CFBundleNumberOfProducts 3
static CFStringRef _CFBundleSupportedProducts[_CFBundleNumberOfProducts] = { CFSTR("iphone"), CFSTR("ipod"), CFSTR("ipad") };
#define _CFBundleNumberOfiPhoneOSPlatformProducts 3
static CFStringRef _CFBundleSupportediPhoneOSPlatformProducts[_CFBundleNumberOfiPhoneOSPlatformProducts] = { CFSTR("iphone"), CFSTR("ipod"), CFSTR("ipad") };
CF_PRIVATE void _CFBundleResourcesInitialize() { }
#endif
#pragma mark -
#pragma mark Product and Platform Getters - Exported
static CFStringRef _cfBundlePlatform = NULL;
CF_EXPORT void _CFSetProductName(CFStringRef str) {
if (str) CFRetain(str);
_cfBundlePlatform = str;
}
CF_EXPORT CFStringRef _CFGetProductName(void) {
#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
if (!_cfBundlePlatform) {
const char *isClassic = __CFgetenv("CLASSIC");
if (isClassic && strnlen(isClassic, 1) >= 1 && isClassic[0] == '1') {
_cfBundlePlatform = CFSTR("iphone");
} else {
char buffer[256];
memset(buffer, 0, sizeof(buffer));
size_t buflen = sizeof(buffer);
int ret = sysctlbyname("hw.machine", buffer, &buflen, NULL, 0);
if (0 == ret || (-1 == ret && ENOMEM == errno)) {
if (6 <= buflen && 0 == memcmp(buffer, "iPhone", 6)) {
_cfBundlePlatform = CFSTR("iphone");
} else if (4 <= buflen && 0 == memcmp(buffer, "iPod", 4)) {
_cfBundlePlatform = CFSTR("ipod");
} else if (4 <= buflen && 0 == memcmp(buffer, "iPad", 4)) {
_cfBundlePlatform = CFSTR("ipad");
} else {
const char *env = __CFgetenv("IPHONE_SIMULATOR_DEVICE");
if (env) {
if (0 == strcmp(env, "iPhone")) {
_cfBundlePlatform = CFSTR("iphone");
} else if (0 == strcmp(env, "iPad")) {
_cfBundlePlatform = CFSTR("ipad");
} else {
}
} else {
}
}
}
}
if (!_cfBundlePlatform) _cfBundlePlatform = CFSTR("iphone"); }
return _cfBundlePlatform;
#endif
return CFSTR("");
}
CF_EXPORT CFStringRef _CFGetPlatformName(void) {
#if DEPLOYMENT_TARGET_MACOSX
return _CFBundleMacOSXPlatformName;
#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
return _CFBundleiPhoneOSPlatformName;
#elif DEPLOYMENT_TARGET_WINDOWS
return _CFBundleWindowsPlatformName;
#elif DEPLOYMENT_TARGET_SOLARIS
return _CFBundleSolarisPlatformName;
#elif DEPLOYMENT_TARGET_HPUX
return _CFBundleHPUXPlatformName;
#elif DEPLOYMENT_TARGET_LINUX
return _CFBundleLinuxPlatformName;
#elif DEPLOYMENT_TARGET_FREEBSD
return _CFBundleFreeBSDPlatformName;
#else
#error Unknown or unspecified DEPLOYMENT_TARGET
#endif
}
CF_EXPORT CFStringRef _CFGetAlternatePlatformName(void) {
#if DEPLOYMENT_TARGET_MACOSX
return _CFBundleAlternateMacOSXPlatformName;
#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
return _CFBundleMacOSXPlatformName;
#elif DEPLOYMENT_TARGET_WINDOWS
return CFSTR("");
#else
#error Unknown or unspecified DEPLOYMENT_TARGET
#endif
}
#pragma mark -
#pragma mark Product and Platform Suffix Processing - Internal
static Boolean _isValidPlatformSuffix(CFStringRef suffix) {
for (CFIndex idx = 0; idx < _CFBundleNumberOfPlatforms; idx++) {
if (CFEqual(suffix, _CFBundleSupportedPlatforms[idx])) return true;
}
return false;
}
CF_PRIVATE Boolean _CFBundleSupportedPlatformName(CFStringRef fileName, CFRange searchRange) {
for (CFIndex i = 0; i < _CFBundleNumberOfPlatforms; i++) {
if (CFStringFindWithOptions(fileName, _CFBundleSupportedPlatforms[i], searchRange, kCFCompareAnchored, NULL)) {
return true;
}
}
return false;
}
static Boolean _isValidProductSuffix(CFStringRef suffix) {
for (CFIndex idx = 0; idx < _CFBundleNumberOfProducts; idx++) {
if (CFEqual(suffix, _CFBundleSupportedProducts[idx])) return true;
}
return false;
}
CF_PRIVATE Boolean _CFBundleSupportedProductName(CFStringRef fileName, CFRange searchRange) {
for (CFIndex i = 0; i < _CFBundleNumberOfProducts; i++) {
if (CFStringFindWithOptions(fileName, _CFBundleSupportedProducts[i], searchRange, kCFCompareAnchored, NULL)) {
return true;
}
}
return false;
}
static Boolean _isValidiPhoneOSPlatformProductSuffix(CFStringRef suffix) {
for (CFIndex idx = 0; idx < _CFBundleNumberOfiPhoneOSPlatformProducts; idx++) {
if (CFEqual(suffix, _CFBundleSupportediPhoneOSPlatformProducts[idx])) return true;
}
return false;
}
static Boolean _isValidPlatformAndProductSuffixPair(CFStringRef platform, CFStringRef product) {
if (!platform && !product) return true;
if (!platform) {
return _isValidProductSuffix(product);
}
if (!product) {
return _isValidPlatformSuffix(platform);
}
if (CFEqual(platform, _CFBundleiPhoneOSPlatformName)) {
return _isValidiPhoneOSPlatformProductSuffix(product);
}
return false;
}
static Boolean _isBlacklistedKey(CFStringRef keyName) {
#if __CONSTANT_STRINGS__
#define _CFBundleNumberOfBlacklistedInfoDictionaryKeys 2
static const CFStringRef _CFBundleBlacklistedInfoDictionaryKeys[_CFBundleNumberOfBlacklistedInfoDictionaryKeys] = { CFSTR("CFBundleExecutable"), CFSTR("CFBundleIdentifier") };
for (CFIndex idx = 0; idx < _CFBundleNumberOfBlacklistedInfoDictionaryKeys; idx++) {
if (CFEqual(keyName, _CFBundleBlacklistedInfoDictionaryKeys[idx])) return true;
}
#endif
return false;
}
static Boolean _isOverrideKey(CFStringRef fullKey, CFStringRef *outBaseKey, CFStringRef *outPlatformSuffix, CFStringRef *outProductSuffix) {
if (outBaseKey) {
*outBaseKey = NULL;
}
if (outPlatformSuffix) {
*outPlatformSuffix = NULL;
}
if (outProductSuffix) {
*outProductSuffix = NULL;
}
if (!fullKey)
return false;
CFRange minusRange = CFStringFind(fullKey, CFSTR("-"), kCFCompareBackwards);
CFRange tildeRange = CFStringFind(fullKey, CFSTR("~"), kCFCompareBackwards);
if (minusRange.location == kCFNotFound && tildeRange.location == kCFNotFound) return false;
if (minusRange.location != kCFNotFound && tildeRange.location != kCFNotFound && tildeRange.location <= minusRange.location) return false;
CFIndex strLen = CFStringGetLength(fullKey);
CFRange baseKeyRange = (minusRange.location != kCFNotFound) ? CFRangeMake(0, minusRange.location) : CFRangeMake(0, tildeRange.location);
CFRange platformRange = CFRangeMake(kCFNotFound, 0);
CFRange productRange = CFRangeMake(kCFNotFound, 0);
if (minusRange.location != kCFNotFound) {
platformRange.location = minusRange.location + minusRange.length;
platformRange.length = ((tildeRange.location != kCFNotFound) ? tildeRange.location : strLen) - platformRange.location;
}
if (tildeRange.location != kCFNotFound) {
productRange.location = tildeRange.location + tildeRange.length;
productRange.length = strLen - productRange.location;
}
if (baseKeyRange.length < 1) return false;
if (platformRange.location != kCFNotFound && platformRange.length < 1) return false;
if (productRange.location != kCFNotFound && productRange.length < 1) return false;
CFStringRef platform = (platformRange.location != kCFNotFound) ? CFStringCreateWithSubstring(kCFAllocatorSystemDefault, fullKey, platformRange) : NULL;
CFStringRef product = (productRange.location != kCFNotFound) ? CFStringCreateWithSubstring(kCFAllocatorSystemDefault, fullKey, productRange) : NULL;
Boolean result = _isValidPlatformAndProductSuffixPair(platform, product);
if (result) {
if (outBaseKey) {
*outBaseKey = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, fullKey, baseKeyRange);
}
if (outPlatformSuffix) {
*outPlatformSuffix = platform;
} else {
if (platform && !(0)) CFRelease(platform);
}
if (outProductSuffix) {
*outProductSuffix = product;
} else {
if (product && !(0)) CFRelease(product);
}
} else {
if (platform && !(0)) CFRelease(platform);
if (product && !(0)) CFRelease(product);
}
return result;
}
static Boolean _isCurrentPlatformAndProduct(CFStringRef platform, CFStringRef product) {
if (!platform && !product) return true;
if (!platform) {
return CFEqual(_CFGetProductName(), product);
}
if (!product) {
return CFEqual(_CFGetPlatformName(), platform);
}
return CFEqual(_CFGetProductName(), product) && CFEqual(_CFGetPlatformName(), platform);
}
static CFArrayRef _CopySortedOverridesForBaseKey(CFStringRef keyName, CFDictionaryRef dict) {
CFMutableArrayRef overrides = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
CFStringRef keyNameWithBoth = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@-%@~%@"), keyName, _CFGetPlatformName(), _CFGetProductName());
CFStringRef keyNameWithProduct = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@~%@"), keyName, _CFGetProductName());
CFStringRef keyNameWithPlatform = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@-%@"), keyName, _CFGetPlatformName());
CFIndex count = CFDictionaryGetCount(dict);
if (count > 0) {
CFTypeRef *keys = (CFTypeRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0);
CFTypeRef *values = &(keys[count]);
CFDictionaryGetKeysAndValues(dict, keys, values);
for (CFIndex idx = 0; idx < count; idx++) {
if (CFEqual(keys[idx], keyNameWithBoth)) {
CFArrayAppendValue(overrides, keys[idx]);
break;
}
}
for (CFIndex idx = 0; idx < count; idx++) {
if (CFEqual(keys[idx], keyNameWithProduct)) {
CFArrayAppendValue(overrides, keys[idx]);
break;
}
}
for (CFIndex idx = 0; idx < count; idx++) {
if (CFEqual(keys[idx], keyNameWithPlatform)) {
CFArrayAppendValue(overrides, keys[idx]);
break;
}
}
for (CFIndex idx = 0; idx < count; idx++) {
if (CFEqual(keys[idx], keyName)) {
CFArrayAppendValue(overrides, keys[idx]);
break;
}
}
CFAllocatorDeallocate(kCFAllocatorSystemDefault, keys);
}
CFRelease(keyNameWithProduct);
CFRelease(keyNameWithPlatform);
CFRelease(keyNameWithBoth);
return overrides;
}
CF_PRIVATE void _CFBundleInfoPlistProcessInfoDictionary(CFMutableDictionaryRef dict) {
if (!dict) return;
CFIndex count = CFDictionaryGetCount(dict);
if (count > 0) {
CFTypeRef *keys = (CFTypeRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0);
CFTypeRef *values = &(keys[count]);
CFMutableArrayRef guard = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
CFDictionaryGetKeysAndValues(dict, keys, values);
for (CFIndex idx = 0; idx < count; idx++) {
CFStringRef keyPlatformSuffix, keyProductSuffix, keyName;
if (_isOverrideKey((CFStringRef)keys[idx], &keyName, &keyPlatformSuffix, &keyProductSuffix)) {
CFArrayRef keysForBaseKey = NULL;
if (_isCurrentPlatformAndProduct(keyPlatformSuffix, keyProductSuffix) && !_isBlacklistedKey(keyName) && CFDictionaryContainsKey(dict, keys[idx])) {
keysForBaseKey = _CopySortedOverridesForBaseKey(keyName, dict);
CFIndex keysForBaseKeyCount = CFArrayGetCount(keysForBaseKey);
CFArrayAppendValue(guard, keysForBaseKey);
CFTypeRef highestPriorityKey = CFArrayGetValueAtIndex(keysForBaseKey, 0);
CFDictionarySetValue(dict, keyName, CFDictionaryGetValue(dict, highestPriorityKey));
for (CFIndex presentKeysIdx = 0; presentKeysIdx < keysForBaseKeyCount; presentKeysIdx++) {
CFStringRef currentKey = (CFStringRef)CFArrayGetValueAtIndex(keysForBaseKey, presentKeysIdx);
if (!CFEqual(currentKey, keyName))
CFDictionaryRemoveValue(dict, currentKey);
}
} else {
CFDictionaryRemoveValue(dict, keys[idx]);
}
if (keyPlatformSuffix) CFRelease(keyPlatformSuffix);
if (keyProductSuffix) CFRelease(keyProductSuffix);
CFRelease(keyName);
if (keysForBaseKey) CFRelease(keysForBaseKey);
}
}
CFAllocatorDeallocate(kCFAllocatorSystemDefault, keys);
CFRelease(guard);
}
}
#pragma mark -
#pragma mark Info Plist Functions
CF_PRIVATE CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc, CFURLRef url, uint8_t *version) {
CFDictionaryRef dict = NULL;
unsigned char buff[CFMaxPathSize];
uint8_t localVersion = 0;
if (CFURLGetFileSystemRepresentation(url, true, buff, CFMaxPathSize)) {
CFURLRef newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, buff, strlen((char *)buff), true);
if (!newURL) newURL = (CFURLRef)CFRetain(url);
localVersion = _CFBundleGetBundleVersionForURL(newURL);
dict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(alloc, newURL, localVersion);
CFRelease(newURL);
}
if (version) *version = localVersion;
return dict;
}
CF_PRIVATE CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc, CFURLRef url, uint8_t version) {
if (!url) return NULL;
CFDictionaryRef result = NULL;
CFStringRef platformInfoURLFromBase = _CFBundlePlatformInfoURLFromBase0;
CFStringRef infoURLFromBase = _CFBundleInfoURLFromBase0;
CFURLRef directoryURL = NULL;
if (0 == version) {
directoryURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase0, url);
platformInfoURLFromBase = _CFBundlePlatformInfoURLFromBase0;
infoURLFromBase = _CFBundleInfoURLFromBase0;
} else if (1 == version) {
directoryURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase1, url);
platformInfoURLFromBase = _CFBundlePlatformInfoURLFromBase1;
infoURLFromBase = _CFBundleInfoURLFromBase1;
} else if (2 == version) {
directoryURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase2, url);
platformInfoURLFromBase = _CFBundlePlatformInfoURLFromBase2;
infoURLFromBase = _CFBundleInfoURLFromBase2;
} else if (3 == version) {
CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
if (path) {
if (!(CFStringHasSuffix(path, _CFBundleSupportFilesDirectoryName1) || CFStringHasSuffix(path, _CFBundleSupportFilesDirectoryName2) || CFStringHasSuffix(path, _CFBundleResourcesDirectoryName))) {
directoryURL = (CFURLRef)CFRetain(url);
platformInfoURLFromBase = _CFBundlePlatformInfoURLFromBase3;
infoURLFromBase = _CFBundleInfoURLFromBase3;
}
CFRelease(path);
}
}
CFURLRef absoluteURL;
if (directoryURL) {
absoluteURL = CFURLCopyAbsoluteURL(directoryURL);
CFStringRef directoryPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
CFRelease(absoluteURL);
__block CFURLRef infoPlistURL = NULL;
__block CFURLRef platformInfoPlistURL = NULL;
CFIndex infoPlistLength = CFStringGetLength(_CFBundleInfoPlistName);
CFIndex platformInfoPlistLength = CFStringGetLength(_CFBundlePlatformInfoPlistName);
_CFIterateDirectory(directoryPath, ^Boolean(CFStringRef fileName, uint8_t fileType) {
if (_CFBundlePlatformInfoPlistName != _CFBundleInfoPlistName) {
if (!platformInfoPlistURL && CFStringGetLength(fileName) == platformInfoPlistLength && CFStringCompareWithOptions(fileName, _CFBundlePlatformInfoPlistName, CFRangeMake(0, platformInfoPlistLength), kCFCompareCaseInsensitive | kCFCompareAnchored) == kCFCompareEqualTo) {
platformInfoPlistURL = CFURLCreateWithString(kCFAllocatorSystemDefault, platformInfoURLFromBase, url);
}
}
if (!infoPlistURL && CFStringGetLength(fileName) == infoPlistLength && CFStringCompareWithOptions(fileName, _CFBundleInfoPlistName, CFRangeMake(0, infoPlistLength), kCFCompareCaseInsensitive | kCFCompareAnchored) == kCFCompareEqualTo) {
infoPlistURL = CFURLCreateWithString(kCFAllocatorSystemDefault, infoURLFromBase, url);
}
if (_CFBundlePlatformInfoPlistName != _CFBundleInfoPlistName) {
if (infoPlistURL && platformInfoPlistURL) return false;
} else {
if (infoPlistURL) return false;
}
return true;
});
CFRelease(directoryPath);
CFRelease(directoryURL);
CFDataRef infoData = NULL;
CFURLRef finalInfoPlistURL = NULL;
if (platformInfoPlistURL) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, platformInfoPlistURL, &infoData, NULL, NULL, NULL);
#pragma GCC diagnostic pop
if (infoData) finalInfoPlistURL = platformInfoPlistURL;
}
if (!infoData && infoPlistURL) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, infoPlistURL, &infoData, NULL, NULL, NULL);
#pragma GCC diagnostic pop
if (infoData) finalInfoPlistURL = infoPlistURL;
}
if (infoData) {
CFErrorRef error = NULL;
result = (CFDictionaryRef)CFPropertyListCreateWithData(alloc, infoData, kCFPropertyListMutableContainers, NULL, &error);
if (result) {
if (CFDictionaryGetTypeID() == CFGetTypeID(result)) {
CFDictionarySetValue((CFMutableDictionaryRef)result, _kCFBundleInfoPlistURLKey, finalInfoPlistURL);
} else {
CFRelease(result);
result = NULL;
}
} else if (error) {
CFDictionaryRef userInfo = CFErrorCopyUserInfo(error);
CFLog(kCFLogLevelError, CFSTR("There was an error parsing the Info.plist for the bundle at URL %@\n %@\n %@"), infoPlistURL, error, userInfo);
if (userInfo) CFRelease(userInfo);
CFRelease(error);
}
if (!result) {
result = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue((CFMutableDictionaryRef)result, _kCFBundleRawInfoPlistURLKey, finalInfoPlistURL);
}
CFRelease(infoData);
}
if (platformInfoPlistURL) CFRelease(platformInfoPlistURL);
if (infoPlistURL) CFRelease(infoPlistURL);
}
if (!result) {
result = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
_CFBundleInfoPlistProcessInfoDictionary((CFMutableDictionaryRef)result);
return result;
}
CF_EXPORT CFDictionaryRef CFBundleCopyInfoDictionaryForURL(CFURLRef url) {
CFDictionaryRef result = NULL;
Boolean isDir = false;
if (_CFIsResourceAtURL(url, &isDir)) {
if (isDir) {
result = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault, url, NULL);
} else {
result = _CFBundleCopyInfoDictionaryInExecutable(url);
}
}
if (result && (0)) CFRetain(result); 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(kCFAllocatorSystemDefault, _CFBundlePkgInfoURLFromBase2, url);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, tempURL, &pkgInfoData, NULL, NULL, NULL);
#pragma GCC diagnostic pop
CFRelease(tempURL);
if (!pkgInfoData) {
tempURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundlePkgInfoURLFromBase1, url);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, tempURL, &pkgInfoData, NULL, NULL, NULL);
#pragma GCC diagnostic pop
CFRelease(tempURL);
}
if (!pkgInfoData) {
tempURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundlePseudoPkgInfoURLFromBase, url);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, tempURL, &pkgInfoData, NULL, NULL, NULL);
#pragma GCC diagnostic pop
CFRelease(tempURL);
}
if (pkgInfoData && CFDataGetLength(pkgInfoData) >= (int)(sizeof(UInt32) * 2)) {
UInt32 *pkgInfo = (UInt32 *)CFDataGetBytePtr(pkgInfoData);
if (packageType) *packageType = CFSwapInt32BigToHost(pkgInfo[0]);
if (packageCreator) *packageCreator = CFSwapInt32BigToHost(pkgInfo[1]);
retVal = hasType = hasCreator = true;
}
if (pkgInfoData) CFRelease(pkgInfoData);
if (!retVal) {
if (!infoDict) {
infoDict = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault, url, NULL);
releaseInfoDict = true;
}
if (infoDict) {
CFStringRef typeString = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundlePackageTypeKey), creatorString = (CFStringRef)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) *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) *packageCreator = CFSwapInt32BigToHost(tmp);
retVal = hasCreator = true;
}
if (releaseInfoDict && !(0)) CFRelease(infoDict);
}
}
if (!hasType || !hasCreator) {
if (retVal || _CFBundleURLLooksLikeBundle(url)) {
if (packageCreator && !hasCreator) *packageCreator = 0x3f3f3f3f; if (packageType && !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);
if (strLen > CFMaxPathSize) strLen = CFMaxPathSize;
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)PATH_SEP)) {
*packageType = 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)PATH_SEP)) {
*packageType = 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)PATH_SEP)) {
*packageType = 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)PATH_SEP)) {
*packageType = 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)PATH_SEP)) {
*packageType = 0x464d574b; } else {
*packageType = 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(kCFAllocatorSystemDefault, bundleURL, CFBundleGetInfoDictionary(bundle), packageType, packageCreator)) {
if (packageType) *packageType = 0x424e444c; if (packageCreator) *packageCreator = 0x3f3f3f3f; }
if (bundleURL) CFRelease(bundleURL);
}
CF_EXPORT Boolean CFBundleGetPackageInfoInDirectory(CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {
return _CFBundleGetPackageInfoInDirectory(kCFAllocatorSystemDefault, url, packageType, packageCreator);
}
CFDictionaryRef CFBundleCopyInfoDictionaryInDirectory(CFURLRef url) {
CFDictionaryRef dict = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault, url, NULL);
return dict;
}
static void _CFBundleInfoPlistFixupInfoDictionary(CFBundleRef bundle, CFMutableDictionaryRef infoDict) {
CFTypeRef unknownVersionValue = CFDictionaryGetValue(infoDict, _kCFBundleNumericVersionKey);
CFNumberRef versNum;
UInt32 vers = 0;
if (!unknownVersionValue) unknownVersionValue = CFDictionaryGetValue(infoDict, kCFBundleVersionKey);
if (unknownVersionValue) {
if (CFGetTypeID(unknownVersionValue) == CFStringGetTypeID()) {
vers = _CFVersionNumberFromString((CFStringRef)unknownVersionValue);
versNum = CFNumberCreate(CFGetAllocator(bundle), kCFNumberSInt32Type, &vers);
CFDictionarySetValue(infoDict, _kCFBundleNumericVersionKey, versNum);
CFRelease(versNum);
} else if (CFGetTypeID(unknownVersionValue) == CFNumberGetTypeID()) {
} else {
CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, _kCFBundleNumericVersionKey);
}
}
}
CFDictionaryRef CFBundleGetInfoDictionary(CFBundleRef bundle) {
__CFLock(&bundle->_lock);
if (!bundle->_infoDict) {
bundle->_infoDict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(kCFAllocatorSystemDefault, bundle->_url, bundle->_version);
if (bundle->_infoDict) _CFBundleInfoPlistFixupInfoDictionary(bundle, (CFMutableDictionaryRef)bundle->_infoDict);
}
__CFUnlock(&bundle->_lock);
return bundle->_infoDict;
}
CFDictionaryRef _CFBundleGetLocalInfoDictionary(CFBundleRef bundle) {
return CFBundleGetLocalInfoDictionary(bundle);
}
CFDictionaryRef CFBundleGetLocalInfoDictionary(CFBundleRef bundle) {
CFDictionaryRef localInfoDict = NULL;
__CFLock(&bundle->_lock);
localInfoDict = bundle->_localInfoDict;
if (!localInfoDict) {
__CFUnlock(&bundle->_lock);
CFURLRef url = CFBundleCopyResourceURL(bundle, _CFBundleLocalInfoName, _CFBundleStringTableType, NULL);
if (url) {
CFDataRef data;
SInt32 errCode;
CFStringRef errStr = NULL;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, url, &data, NULL, NULL, &errCode)) {
localInfoDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, &errStr);
if (errStr) CFRelease(errStr);
if (localInfoDict && CFDictionaryGetTypeID() != CFGetTypeID(localInfoDict)) {
CFRelease(localInfoDict);
localInfoDict = NULL;
}
CFRelease(data);
}
#pragma GCC diagnostic pop
CFRelease(url);
}
if (localInfoDict) _CFBundleInfoPlistProcessInfoDictionary((CFMutableDictionaryRef)localInfoDict);
__CFLock(&bundle->_lock);
if (!bundle->_localInfoDict) {
bundle->_localInfoDict = localInfoDict;
} else {
if (localInfoDict) CFRelease(localInfoDict);
localInfoDict = bundle->_localInfoDict;
}
}
__CFUnlock(&bundle->_lock);
return localInfoDict;
}
CFPropertyListRef _CFBundleGetValueForInfoKey(CFBundleRef bundle, CFStringRef key) {
return (CFPropertyListRef)CFBundleGetValueForInfoDictionaryKey(bundle, key);
}
CFTypeRef CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle, CFStringRef key) {
CFTypeRef result = NULL;
if (bundle && key) {
CFDictionaryRef dict = CFBundleGetLocalInfoDictionary(bundle);
if (dict) result = CFDictionaryGetValue(dict, key);
if (!result) {
dict = CFBundleGetInfoDictionary(bundle);
if (dict) result = CFDictionaryGetValue(dict, key);
}
}
return result;
}
CFStringRef CFBundleGetIdentifier(CFBundleRef bundle) {
CFStringRef bundleID = NULL;
CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
if (infoDict) bundleID = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleIdentifierKey);
return bundleID;
}
static void __addPlatformAndProductNamesToKeys(const void *value, void *context) {
CFMutableSetRef newKeys = (CFMutableSetRef)context;
CFStringRef key = (CFStringRef)value;
CFStringRef firstPartOfKey = NULL;
CFStringRef restOfKey = NULL;
CFRange range;
Boolean success = CFStringFindWithOptions(key, CFSTR(":"), CFRangeMake(0, CFStringGetLength(key)), 0, &range);
if (success) {
firstPartOfKey = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, key, CFRangeMake(0, range.location));
restOfKey = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, key, CFRangeMake(range.location + 1, CFStringGetLength(key) - range.location - 1));
} else {
firstPartOfKey = (CFStringRef)CFRetain(key);
}
CFStringRef newKeyWithPlatform = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@-%@%@%@"), firstPartOfKey, _CFGetPlatformName(), restOfKey ? CFSTR(":") : CFSTR(""), restOfKey ? restOfKey : CFSTR(""));
CFStringRef newKeyWithProduct = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@~%@%@%@"), firstPartOfKey, _CFGetProductName(), restOfKey ? CFSTR(":") : CFSTR(""), restOfKey ? restOfKey : CFSTR(""));
CFStringRef newKeyWithProductAndPlatform = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@-%@~%@%@%@"), firstPartOfKey, _CFGetPlatformName(), _CFGetProductName(), restOfKey ? CFSTR(":") : CFSTR(""), restOfKey ? restOfKey : CFSTR(""));
CFSetAddValue(newKeys, key);
CFSetAddValue(newKeys, newKeyWithPlatform);
CFSetAddValue(newKeys, newKeyWithProduct);
CFSetAddValue(newKeys, newKeyWithProductAndPlatform);
if (firstPartOfKey) CFRelease(firstPartOfKey);
if (restOfKey) CFRelease(restOfKey);
CFRelease(newKeyWithPlatform);
CFRelease(newKeyWithProduct);
CFRelease(newKeyWithProductAndPlatform);
}
CF_PRIVATE Boolean _CFReadMappedFromFile(CFStringRef path, Boolean map, Boolean uncached, void **outBytes, CFIndex *outLength, CFErrorRef *errorPtr);
static CFPropertyListRef _CFBundleCreateFilteredInfoPlistWithURL(CFURLRef infoPlistURL, CFSetRef keyPaths, _CFBundleFilteredPlistOptions options) {
CFPropertyListRef result = NULL;
if (!infoPlistURL) return CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFURLRef absoluteURL = CFURLCopyAbsoluteURL(infoPlistURL);
CFStringRef filePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
CFRelease(absoluteURL);
if (!filePath) return CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
void *bytes = NULL;
CFIndex length = 0;
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
Boolean mapped = options & _CFBundleFilteredPlistMemoryMapped ? true : false;
#else
Boolean mapped = false;
#endif
Boolean success = _CFReadMappedFromFile(filePath, mapped, false, &bytes, &length, NULL);
CFRelease(filePath);
if (!success) return CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDataRef infoPlistData = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8 *)bytes, length, kCFAllocatorNull);
CFMutableSetRef newKeyPaths = CFSetCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(keyPaths), &kCFTypeSetCallBacks);
CFSetApplyFunction(keyPaths, __addPlatformAndProductNamesToKeys, newKeyPaths);
success = _CFPropertyListCreateFiltered(kCFAllocatorSystemDefault, infoPlistData, kCFPropertyListMutableContainers, newKeyPaths, &result, NULL);
if (!success || !result) {
result = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
} else {
_CFBundleInfoPlistProcessInfoDictionary((CFMutableDictionaryRef)result);
}
CFRelease(newKeyPaths);
CFRelease(infoPlistData);
if (mapped) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
munmap(bytes, length);
#endif
} else {
free(bytes);
}
return result;
}
CF_EXPORT CFPropertyListRef _CFBundleCreateFilteredInfoPlist(CFBundleRef bundle, CFSetRef keyPaths, _CFBundleFilteredPlistOptions options) {
CFURLRef infoPlistURL = _CFBundleCopyInfoPlistURL(bundle);
CFPropertyListRef result = _CFBundleCreateFilteredInfoPlistWithURL(infoPlistURL, keyPaths, options);
if (infoPlistURL) CFRelease(infoPlistURL);
return result;
}
CF_EXPORT CFPropertyListRef _CFBundleCreateFilteredLocalizedInfoPlist(CFBundleRef bundle, CFSetRef keyPaths, CFStringRef localizationName, _CFBundleFilteredPlistOptions options) {
CFURLRef infoPlistURL = CFBundleCopyResourceURLForLocalization(bundle, _CFBundleLocalInfoName, _CFBundleStringTableType, NULL, localizationName);
CFPropertyListRef result = _CFBundleCreateFilteredInfoPlistWithURL(infoPlistURL, keyPaths, options);
if (infoPlistURL) CFRelease(infoPlistURL);
return result;
}
CF_EXPORT CFURLRef _CFBundleCopyInfoPlistURL(CFBundleRef bundle) {
CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
CFURLRef url = (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleInfoPlistURLKey);
if (!url) url = (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleRawInfoPlistURLKey);
return (url ? (CFURLRef)CFRetain(url) : NULL);
}