#include "CFAdditions.h"
#include "KEXTPrivate.h"
#include <IOKit/IOCFURLAccess.h>
KEXTEntityType KEXTBundleGetEntityType(void)
{
return (KEXTEntityType)CFSTR("BundleDescriptor");
}
CFStringRef KEXTBundleGetPrimaryKey(KEXTBundleRef bundle)
{
return CFDictionaryGetValue(bundle, CFSTR("PrimaryKey"));
}
static inline CFStringRef _KEXTBundleGetName(CFDictionaryRef props, Boolean isCF)
{
if ( isCF )
return CFDictionaryGetValue(props, CFSTR("CFBundleIdentifier"));
else
return CFDictionaryGetValue(props, CFSTR("Name"));
}
static inline CFStringRef
_KEXTBundleCopyInfo(CFDictionaryRef props, Boolean isCF)
{
CFStringRef infoStr;
if ( isCF ) {
infoStr = CFDictionaryGetValue(props, CFSTR("CFBundleGetInfoString"));
if (infoStr)
goto retainAndReturn;
infoStr = CFDictionaryGetValue(props, CFSTR("CFBundleGetInfoHTML"));
if (infoStr)
goto retainAndReturn;
infoStr = CFDictionaryGetValue(props, CFSTR("CFBundleVersion"));
if (!infoStr)
goto nullOut;
}
else {
CFStringRef vendor = CFDictionaryGetValue(props, CFSTR(kVendorKey));
CFStringRef version = CFDictionaryGetValue(props, CFSTR("Version"));
if (vendor && version) {
infoStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
CFSTR("%@ - %@"), vendor, version);
return infoStr; }
else if (vendor)
infoStr = vendor;
else if (version)
infoStr = version;
else
goto nullOut;
}
retainAndReturn:
CFRetain(infoStr);
return infoStr;
nullOut:
return CFSTR("");
}
KEXTBundleRef KEXTBundleCreate(CFURLRef url, CFDictionaryRef properties, Boolean isCFStyle)
{
CFStringRef path;
CFStringRef name;
CFStringRef info;
CFStringRef primaryKey;
KEXTBundleRef bundle;
if ( !properties || !url || (CFURLGetTypeID() != CFGetTypeID(url)) ) {
return NULL;
}
bundle = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if ( !bundle ) {
return NULL;
}
name = _KEXTBundleGetName(properties, isCFStyle);
if ( !name ) {
CFRelease(bundle);
return NULL;
}
CFDictionarySetValue(bundle, CFSTR("BundleName"), name);
primaryKey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("KEXTBundle?%@"), name);
CFDictionarySetValue(bundle, CFSTR("PrimaryKey"), primaryKey);
CFRelease(primaryKey);
CFDictionarySetValue(bundle, CFSTR("BundleURL"), CFURLGetString(url));
CFDictionarySetValue(bundle, CFSTR("EntityType"), CFSTR("BundleDescriptor"));
path = CFURLGetString(url);
CFDictionarySetValue(bundle, CFSTR("BundlePath"), path);
CFDictionarySetValue(bundle, CFSTR("BundleFormat"),
( isCFStyle )? CFSTR("CF") : CFSTR("Legacy"));
info = _KEXTBundleCopyInfo(properties, isCFStyle);
if ( info )
CFDictionarySetValue(bundle, CFSTR("BundleInfo"), info);
return bundle;
}
KEXTBundleRef KEXTBundleRetain(KEXTBundleRef bundle)
{
return (KEXTBundleRef)CFRetain(bundle);
}
void KEXTBundleRelease(KEXTBundleRef bundle)
{
CFRelease(bundle);
}
KEXTValidation KEXTBundleValidate(KEXTBundleRef bundle)
{
KEXTValidation ret;
CFDateRef date;
CFDateRef moddate;
CFURLRef url;
CFBooleanRef val;
SInt32 err;
if ( !bundle ) {
printf("Not bundle???\n");
return 1;
}
url = KEXTBundleCopyURL(bundle);
if ( !url ) {
return 0;
}
ret = kKEXTBundleValidateNoChange;
do {
Boolean boolval;
val = IOURLCreatePropertyFromResource(kCFAllocatorDefault, url, kIOURLFileExists, &err);
if ( !val ) {
ret = kKEXTBundleValidateRemoved;
break;
}
boolval = CFBooleanGetValue(val);
CFRelease(val);
if ( !boolval ) {
ret = kKEXTBundleValidateRemoved;
break;
}
date = IOURLCreatePropertyFromResource(kCFAllocatorDefault, url, kIOURLFileLastModificationTime, &err);
if ( !date ) {
ret = kKEXTBundleValidateRemoved;
break;
}
moddate = CFDictionaryGetValue((CFMutableDictionaryRef)bundle, CFSTR("ModificationDate"));
boolval = CFEqual(moddate, date);
CFRelease(date);
if ( !boolval ) {
ret = kKEXTBundleValidateModified;
break;
}
} while ( false );
CFRelease(url);
return ret;
}
CFURLRef KEXTBundleCopyURL(KEXTBundleRef bundle)
{
CFStringRef string;
CFURLRef url;
if ( !bundle )
return NULL;
string = CFDictionaryGetValue(bundle, CFSTR("BundleURL"));
if ( !string )
return NULL;
url = CFURLCreateWithString(kCFAllocatorDefault, string, NULL);
return url;
}
CFTypeRef KEXTBundleGetProperty(KEXTBundleRef bundle, CFStringRef key)
{
if ( !key || !bundle )
return NULL;
return CFDictionaryGetValue(bundle, key);
}
static CFURLRef _KEXTBundleCreateURLForPath(CFStringRef path)
{
CFURLRef url;
CFBooleanRef val;
Boolean bval;
SInt32 err;
url = CFURLCreateWithString(kCFAllocatorDefault, path, NULL);
if ( !url ) {
return NULL;
}
val = IOURLCreatePropertyFromResource(kCFAllocatorDefault, url, kIOURLFileExists, &err);
if ( !val ) {
CFRelease(url);
return NULL;
}
bval = CFBooleanGetValue(val);
CFRelease(val);
if ( !bval ) {
CFRelease(url);
return NULL;
}
return url;
}
__private_extern__ CFURLRef
_KEXTBundleCreateFileURL(KEXTBundleRef bundle, CFStringRef name, CFStringRef type)
{
CFURLRef newUrl;
CFStringRef urlStr;
CFStringRef formatStr;
CFStringRef fileStr;
CFStringRef newPath;
urlStr = CFDictionaryGetValue(bundle, CFSTR("BundleURL"));
if ( !urlStr )
return NULL;
if ( type )
fileStr = CFStringCreateWithFormat(NULL, NULL,
CFSTR("%@.%@"), name, type);
else {
fileStr = name;
CFRetain(fileStr);
}
if ( CFStringHasSuffix(urlStr, CFSTR("/")) )
formatStr = CFSTR("%@%@%@");
else
formatStr = CFSTR("%@/%@%@");
newPath = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, formatStr, urlStr, CFSTR("Contents/"), fileStr);
newUrl = _KEXTBundleCreateURLForPath(newPath);
CFRelease(newPath);
if ( newUrl )
goto foundFileNowExit;
newPath = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, formatStr, urlStr, CFSTR("Contents/MacOS/"), fileStr);
newUrl = _KEXTBundleCreateURLForPath(newPath);
CFRelease(newPath);
if ( newUrl )
goto foundFileNowExit;
newPath = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, formatStr, urlStr, CFSTR("Contents/Resources/"), fileStr);
newUrl = _KEXTBundleCreateURLForPath(newPath);
CFRelease(newPath);
if ( newUrl )
goto foundFileNowExit;
newPath = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, formatStr, urlStr, CFSTR(""), fileStr);
newUrl = _KEXTBundleCreateURLForPath(newPath);
CFRelease(newPath);
foundFileNowExit:
CFRelease(fileStr);
return newUrl;
}
CFURLRef KEXTBundleCreateURLForResource(KEXTBundleRef bundle, CFStringRef name, CFStringRef type, KEXTReturn * error)
{
CFURLRef url;
if ( !bundle || !name ) {
*error = kKEXTReturnBadArgument;
return NULL;
}
url = _KEXTBundleCreateFileURL(bundle, name, type);
if ( !url ) {
*error = kKEXTReturnResourceNotFound;
return NULL;
}
return url;
}
Boolean KEXTBundleEqual(KEXTBundleRef bundle1, KEXTBundleRef bundle2)
{
return CFEqual(bundle1, bundle2);
}
Boolean KEXTBundleMatchProperties(KEXTBundleRef bundle1, KEXTBundleRef bundle2, CFTypeRef match)
{
if ( !bundle1 || !bundle2 )
return false;
return CFDictionaryMatch(bundle1, bundle2, match);
}
CFArrayRef KEXTBundleGetModuleKeys(KEXTBundleRef bundle)
{
return CFDictionaryGetValue(bundle, CFSTR("BundleModules"));
}
CFArrayRef KEXTBundleGetPersonalityKeys(KEXTBundleRef bundle)
{
return CFDictionaryGetValue(bundle, CFSTR("BundlePersons"));
}
void _KEXTBundleShow(KEXTBundleRef bundle)
{
if ( bundle ) {
CFShow(bundle);
}
}