#include "CFInternal.h"
#include <CoreFoundation/CFBase.h>
#include <CoreFoundation/CFURL.h>
#include <CoreFoundation/CFDictionary.h>
#include <CoreFoundation/CFURLAccess.h>
#include <CoreFoundation/CFDate.h>
#include <CoreFoundation/CFNumber.h>
#include <string.h>
#if DEPLOYMENT_TARGET_MACOSX
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <fcntl.h>
#include <dlfcn.h>
#endif
#if DEPLOYMENT_TARGET_MACOSX
DEFINE_WEAK_CFNETWORK_FUNC(Boolean, _CFURLCreateDataAndPropertiesFromResource, (CFAllocatorRef A, CFURLRef B, CFDataRef *C, CFDictionaryRef *D, CFArrayRef E, SInt32 *F), (A, B, C, D, E, F), false)
DEFINE_WEAK_CFNETWORK_FUNC(Boolean, _CFURLWriteDataAndPropertiesToResource, (CFURLRef A, CFDataRef B, CFDictionaryRef C, SInt32 *D), (A, B, C, D), false)
DEFINE_WEAK_CFNETWORK_FUNC(Boolean, _CFURLDestroyResource, (CFURLRef A, SInt32 *B), (A, B), false)
#endif
CONST_STRING_DECL(kCFURLFileExists, "kCFURLFileExists")
CONST_STRING_DECL(kCFURLFilePOSIXMode, "kCFURLFilePOSIXMode")
CONST_STRING_DECL(kCFURLFileDirectoryContents, "kCFURLFileDirectoryContents")
CONST_STRING_DECL(kCFURLFileLength, "kCFURLFileLength")
CONST_STRING_DECL(kCFURLFileLastModificationTime, "kCFURLFileLastModificationTime")
CONST_STRING_DECL(kCFURLFileOwnerID, "kCFURLFileOwnerID")
CONST_STRING_DECL(kCFURLHTTPStatusCode, "kCFURLHTTPStatusCode")
CONST_STRING_DECL(kCFURLHTTPStatusLine, "kCFURLHTTPStatusLine")
CONST_STRING_DECL(kCFDataURLDataLength, "kCFDataURLDataLength")
CONST_STRING_DECL(kCFDataURLMimeType, "kCFDataURLMimeType")
CONST_STRING_DECL(kCFDataURLTextEncodingName, "kCFDataURLTextEncodingName")
CONST_STRING_DECL(kCFFileURLExists, "kCFURLFileExists")
CONST_STRING_DECL(kCFFileURLPOSIXMode, "kCFURLFilePOSIXMode")
CONST_STRING_DECL(kCFFileURLDirectoryContents, "kCFURLFileDirectoryContents")
CONST_STRING_DECL(kCFFileURLSize, "kCFURLFileLength")
CONST_STRING_DECL(kCFFileURLLastModificationTime, "kCFURLFileLastModificationTime")
CONST_STRING_DECL(kCFHTTPURLStatusCode, "kCFURLHTTPStatusCode")
CONST_STRING_DECL(kCFHTTPURLStatusLine, "kCFURLHTTPStatusLine")
static CFDictionaryRef _CFFileURLCreatePropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFArrayRef desiredProperties, SInt32 *errorCode) {
static CFArrayRef _allProps = NULL;
CFRange arrayRange;
SInt32 idx;
CFMutableDictionaryRef propertyDict = NULL;
Boolean exists;
SInt32 posixMode;
int64_t size;
CFDateRef modTime = NULL, *modTimePtr = NULL;
CFArrayRef contents = NULL, *contentsPtr = NULL;
SInt32 ownerID;
if (errorCode) *errorCode = 0;
if (!desiredProperties) {
if (!_allProps) {
const void *values[9];
values[0] = kCFURLFileExists;
values[1] = kCFURLFilePOSIXMode;
values[2] = kCFURLFileDirectoryContents;
values[3] = kCFURLFileLength;
values[4] = kCFURLFileLastModificationTime;
values[5] = kCFURLFileOwnerID;
_allProps = CFArrayCreate(kCFAllocatorSystemDefault, values, 6, &kCFTypeArrayCallBacks);
}
desiredProperties = _allProps;
}
arrayRange.location = 0;
arrayRange.length = CFArrayGetCount(desiredProperties);
propertyDict = CFDictionaryCreateMutable(alloc, 0, & kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
if (arrayRange.length == 0) return propertyDict;
if (CFArrayContainsValue(desiredProperties, arrayRange, kCFURLFileDirectoryContents)) {
contentsPtr = &contents;
}
if (CFArrayContainsValue(desiredProperties, arrayRange, kCFURLFileLastModificationTime)) {
modTimePtr = &modTime;
}
if (_CFGetFileProperties(alloc, url, &exists, &posixMode, &size, modTimePtr, &ownerID, contentsPtr) != 0) {
if (errorCode) {
*errorCode = kCFURLUnknownError;
}
return propertyDict;
}
for (idx = 0; idx < arrayRange.length; idx ++) {
CFStringRef key = (CFMutableStringRef )CFArrayGetValueAtIndex(desiredProperties, idx);
if (key == kCFURLFilePOSIXMode || CFEqual(kCFURLFilePOSIXMode, key)) {
if (exists) {
CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt32Type, &posixMode);
CFDictionarySetValue(propertyDict, kCFURLFilePOSIXMode, num);
CFRelease(num);
} else if (errorCode) {
*errorCode = kCFURLUnknownError;
}
} else if (key == kCFURLFileDirectoryContents || CFEqual(kCFURLFileDirectoryContents, key)) {
if (exists && (posixMode & S_IFMT) == S_IFDIR && contents) {
CFDictionarySetValue(propertyDict, kCFURLFileDirectoryContents, contents);
} else if (errorCode) {
*errorCode = kCFURLUnknownError;
}
} else if (key == kCFURLFileLength || CFEqual(kCFURLFileLength, key)) {
if (exists) {
CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt64Type, &size);
CFDictionarySetValue(propertyDict, kCFURLFileLength, num);
CFRelease(num);
} else if (errorCode) {
*errorCode = kCFURLUnknownError;
}
} else if (key == kCFURLFileLastModificationTime || CFEqual(kCFURLFileLastModificationTime, key)) {
if (exists && modTime) {
CFDictionarySetValue(propertyDict, kCFURLFileLastModificationTime, modTime);
} else if (errorCode) {
*errorCode = kCFURLUnknownError;
}
} else if (key == kCFURLFileExists || CFEqual(kCFURLFileExists, key)) {
if (exists) {
CFDictionarySetValue(propertyDict, kCFURLFileExists, kCFBooleanTrue);
} else {
CFDictionarySetValue(propertyDict, kCFURLFileExists, kCFBooleanFalse);
}
} else if (key == kCFURLFileOwnerID || CFEqual(kCFURLFileOwnerID, key)) {
if (exists) {
CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt32Type, &ownerID);
CFDictionarySetValue(propertyDict, kCFURLFileOwnerID, num);
CFRelease(num);
} else if (errorCode) {
*errorCode = kCFURLUnknownError;
}
} else if (errorCode) {
*errorCode = kCFURLUnknownPropertyKeyError;
}
}
if (modTime) CFRelease(modTime);
if (contents) CFRelease(contents);
return propertyDict;
}
static Boolean _CFFileURLWritePropertiesToResource(CFURLRef url, CFDictionaryRef propertyDict, SInt32 *errorCode) {
CFTypeRef buffer[16];
CFTypeRef *keys;
CFTypeRef *values;
Boolean result = true;
SInt32 idx, count;
char cPath[CFMaxPathSize];
if (!CFURLGetFileSystemRepresentation(url, true, (unsigned char *)cPath, CFMaxPathSize)) {
if (errorCode) *errorCode = kCFURLImproperArgumentsError;
return false;
}
count = CFDictionaryGetCount(propertyDict);
if (count < 8) {
keys = buffer;
values = buffer+8;
} else {
keys = (CFTypeRef *)CFAllocatorAllocate(CFGetAllocator(url), sizeof(void *) * count * 2, 0);
values = keys + count;
}
CFDictionaryGetKeysAndValues(propertyDict, keys, values);
for (idx = 0; idx < count; idx ++) {
CFStringRef key = (CFStringRef)keys[idx];
CFTypeRef value = values[idx];
if (key == kCFURLFilePOSIXMode || CFEqual(kCFURLFilePOSIXMode, key)) {
SInt32 mode;
int err;
if (CFNumberGetTypeID() == CFGetTypeID(value)) {
CFNumberRef modeNum = (CFNumberRef)value;
CFNumberGetValue(modeNum, kCFNumberSInt32Type, &mode);
} else {
#if DEPLOYMENT_TARGET_MACOSX
#define MODE_TYPE mode_t
#endif
const MODE_TYPE *modePtr = (const MODE_TYPE *)CFDataGetBytePtr((CFDataRef)value);
mode = *modePtr;
}
err = chmod(cPath, mode);
if (err != 0) result = false;
} else {
result = false;
}
}
if ((CFTypeRef)keys != buffer) CFAllocatorDeallocate(CFGetAllocator(url), keys);
if (errorCode) *errorCode = result ? 0 : kCFURLUnknownError;
return result;
}
static Boolean _CFFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFArrayRef desiredProperties, CFDictionaryRef *fetchedProperties, SInt32 *errorCode) {
Boolean success = true;
if (errorCode) *errorCode = 0;
if (fetchedData) {
void *bytes;
CFIndex length;
Boolean releaseAlloc = false;
if (alloc == NULL) {
alloc = (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator());
releaseAlloc = true;
}
if (!_CFReadBytesFromFile(alloc, url, &bytes, &length, 0)) {
if (errorCode) *errorCode = kCFURLUnknownError;
*fetchedData = NULL;
success = false;
} else {
*fetchedData = CFDataCreateWithBytesNoCopy(alloc, (const UInt8 *)bytes, length, alloc);
}
if (releaseAlloc) {
CFRelease(alloc);
}
}
if (fetchedProperties) {
*fetchedProperties = _CFFileURLCreatePropertiesFromResource(alloc, url, desiredProperties, errorCode);
if (!*fetchedProperties) success = false;
}
return success;
}
static CFStringRef mimeTypeFromContentTypeComponent(CFStringRef component) {
CFIndex compLen = CFStringGetLength(component);
CFStringInlineBuffer buf;
CFIndex idx;
CFIndex firstChar = -1, lastChar = -1;
CFCharacterSetRef whitespaceSet = CFCharacterSetGetPredefined(kCFCharacterSetWhitespace);
CFStringInitInlineBuffer(component, &buf, CFRangeMake(0, compLen));
for (idx = 0; idx < compLen; idx ++) {
UniChar ch = CFStringGetCharacterFromInlineBuffer(&buf, idx);
if (ch == ';') {
break;
} else if (firstChar == -1) {
if (!CFCharacterSetIsCharacterMember(whitespaceSet, ch)) {
firstChar = idx;
}
} else if (!CFCharacterSetIsCharacterMember(whitespaceSet, ch)) {
lastChar = idx;
}
}
if (firstChar != -1 && lastChar != -1) {
CFMutableStringRef newContentType = CFStringCreateMutableCopy(CFGetAllocator(component), compLen, component);
if (lastChar != compLen - 1) {
CFStringDelete(newContentType, CFRangeMake(lastChar + 1, compLen - lastChar - 1));
}
if (firstChar > 0) {
CFStringDelete(newContentType, CFRangeMake(0, firstChar));
}
CFStringLowercase(newContentType, NULL);
return newContentType;
}
return NULL;
}
static CFStringRef charsetFromContentTypeHeader(CFStringRef contentType) {
CFRange range;
CFIndex compLen = CFStringGetLength(contentType);
CFIndex start, end, idx;
CFCharacterSetRef whitespaceSet;
CFMutableStringRef result;
CFStringRef kCFURLResponseCharsetPrefix = CFSTR("charset=");
if (!CFStringFindWithOptions(contentType, kCFURLResponseCharsetPrefix, CFRangeMake(0, compLen), kCFCompareCaseInsensitive, &range) || range.length == 0) return NULL;
whitespaceSet = CFCharacterSetGetPredefined(kCFCharacterSetWhitespace);
start = -1;
end = -1;
for (idx = range.location + range.length; idx < compLen; idx ++) {
UniChar ch = CFStringGetCharacterAtIndex(contentType, idx);
if (ch == ';' || ch == ',') break;
if (start == -1) {
if (!CFCharacterSetIsCharacterMember(whitespaceSet, ch)) {
start = idx;
end = idx;
}
} else if (!CFCharacterSetIsCharacterMember(whitespaceSet,ch)) {
end = idx;
}
}
if (start == -1) return NULL;
result = CFStringCreateMutableCopy(CFGetAllocator(contentType), compLen,contentType);
if (end != compLen) {
CFStringDelete(result, CFRangeMake(end+1, compLen-end-1));
}
CFStringDelete(result, CFRangeMake(0, start));
CFStringLowercase(result, NULL);
return result;
}
#define STATIC_BUFFER_SIZE 1024
static BOOL isHexDigit(char c)
{
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
}
static UInt8 hexDigitValue(char c)
{
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'A' && c <= 'F') {
return c - 'A' + 10;
}
if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
}
return 0;
}
static CFDataRef percentEscapeDecodeBuffer(CFAllocatorRef alloc, const UInt8* srcBuffer, CFRange range, Boolean stripWhitespace)
{
UInt8* dstBuffer;
UInt8 staticDstBuffer[STATIC_BUFFER_SIZE];
if (range.length > STATIC_BUFFER_SIZE) {
dstBuffer = (UInt8*) malloc(range.length);
} else {
dstBuffer = staticDstBuffer;
}
CFIndex end = range.location + range.length;
CFIndex i;
CFIndex j;
for (i = range.location, j = 0; i < end; ++i) {
char value;
if (srcBuffer[i] == '%' && end > i + 2 && isHexDigit(srcBuffer[i+1]) && isHexDigit(srcBuffer[i+2])) {
value = hexDigitValue(srcBuffer[i+1]) * 16 + hexDigitValue(srcBuffer[i+2]);
i += 2;
} else {
value = srcBuffer[i];
}
if (!stripWhitespace || !isspace(value)) {
dstBuffer[j++] = value;
}
}
CFDataRef result = CFDataCreate(alloc, dstBuffer, j);
if (dstBuffer != staticDstBuffer) {
free(dstBuffer);
}
return result;
}
static BOOL isBase64Digit(char c)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '+') || (c == '/');
}
static BOOL isBase64DigitOrEqualSign(char c)
{
return isBase64Digit(c) || c == '=';
}
static UInt8 base64DigitValue(char c)
{
if (c >= 'A' && c <= 'Z') {
return c - 'A';
} else if (c >= 'a' && c <= 'z') {
return 26 + c - 'a';
} else if (c >= '0' && c <= '9') {
return 52 + c - '0';
} else if (c == '+') {
return 62;
} else if (c == '/') {
return 63;
} else {
return 0;
}
}
static CFDataRef base64DecodeData(CFAllocatorRef alloc, CFDataRef data)
{
const UInt8 *srcBuffer = CFDataGetBytePtr(data);
CFIndex length = CFDataGetLength(data);
UInt8 *dstBuffer = NULL;
UInt8 staticDstBuffer[STATIC_BUFFER_SIZE];
CFDataRef result = NULL;
if (length % 4 != 0) {
goto done;
}
if (length > STATIC_BUFFER_SIZE) {
dstBuffer = (UInt8*) malloc(length);
} else {
dstBuffer = staticDstBuffer;
}
CFIndex i;
CFIndex j;
for (i = 0, j = 0; i < length; i+=4) {
if (!(isBase64Digit(srcBuffer[i]) &&
isBase64Digit(srcBuffer[i+1]) &&
isBase64DigitOrEqualSign(srcBuffer[i+2]) &&
isBase64DigitOrEqualSign(srcBuffer[i+3]))) {
if (dstBuffer != staticDstBuffer) {
free(dstBuffer);
}
return NULL;
}
dstBuffer[j++] = (base64DigitValue(srcBuffer[i]) << 2) + (base64DigitValue(srcBuffer[i+1]) >> 4);
if (srcBuffer[i+2] != '=') {
dstBuffer[j++] = ((base64DigitValue(srcBuffer[i+1]) & 0xf) << 4) + (base64DigitValue(srcBuffer[i+2]) >> 2);
}
if (srcBuffer[i+3] != '=') {
dstBuffer[j++] = ((base64DigitValue(srcBuffer[i+2]) & 0x3) << 6) + (base64DigitValue(srcBuffer[i+3]));
}
}
result = CFDataCreate(alloc, dstBuffer, j);
done:
if (dstBuffer != staticDstBuffer) {
free(dstBuffer);
}
return result;
}
static inline CFStringRef percentExpandAndTrimContentType(CFAllocatorRef alloc, CFStringRef str, CFRange range)
{
CFStringRef contentTypeUnexpanded = CFStringCreateWithSubstring(alloc, str, range);
CFStringRef contentTypeExpanded = CFURLCreateStringByReplacingPercentEscapes(alloc, contentTypeUnexpanded, CFSTR(""));
CFRelease(contentTypeUnexpanded);
CFMutableStringRef contentTypeHeader = CFStringCreateMutableCopy(alloc, 0, contentTypeExpanded);
CFRelease(contentTypeExpanded);
CFStringTrimWhitespace(contentTypeHeader);
return contentTypeHeader;
}
static Boolean parseDataRequestURL(CFURLRef url, CFDataRef* outData, CFStringRef* outMimeType, CFStringRef* outTextEncodingName)
{
Boolean result = FALSE;
CFAllocatorRef alloc = CFGetAllocator(url);
CFStringRef str = CFURLCopyResourceSpecifier(url);
if (str != NULL) {
CFRange commaRange = CFStringFind(str, CFSTR(","), 0);
if (commaRange.location != kCFNotFound) {
CFStringRef contentTypeHeader = percentExpandAndTrimContentType(alloc, str, CFRangeMake(0, commaRange.location));
CFStringRef mimeType = mimeTypeFromContentTypeComponent(contentTypeHeader);
CFStringRef textEncodingName = charsetFromContentTypeHeader(contentTypeHeader);
Boolean base64 = CFStringFind(contentTypeHeader, CFSTR(";base64"), kCFCompareCaseInsensitive).location != kCFNotFound;
if (mimeType == NULL) {
mimeType = (CFStringRef) CFRetain(CFSTR("text/plain"));
}
if (textEncodingName == NULL) {
textEncodingName = (CFStringRef) CFRetain(CFSTR("us-ascii"));
}
CFIndex bufferSize = CFURLGetBytes(url, NULL, 0);
UInt8* srcBuffer = (UInt8*) malloc(bufferSize);
CFURLGetBytes(url, srcBuffer, bufferSize);
CFRange dataRange = CFURLGetByteRangeForComponent(url, kCFURLComponentResourceSpecifier, NULL);
while (srcBuffer[dataRange.location] != ',') {
dataRange.location++;
dataRange.length--;
}
dataRange.location++;
dataRange.length--;
CFDataRef dataRef = NULL;
if (! base64) {
dataRef = percentEscapeDecodeBuffer(alloc, srcBuffer, dataRange, false);
} else {
CFDataRef unescapedAndStripped = percentEscapeDecodeBuffer(alloc, srcBuffer, dataRange, true);
if (unescapedAndStripped) {
dataRef = base64DecodeData(alloc, unescapedAndStripped);
CFRelease(unescapedAndStripped);
}
}
if (dataRef != NULL) {
*outData = dataRef;
*outMimeType = (CFStringRef) mimeType == NULL? NULL : CFStringCreateCopy(alloc, mimeType);
*outTextEncodingName = (CFStringRef) textEncodingName == NULL? NULL : CFStringCreateCopy(alloc, textEncodingName);
result = true;
}
free(srcBuffer);
if (contentTypeHeader) CFRelease(contentTypeHeader);
if (mimeType) CFRelease(mimeType);
if (textEncodingName) CFRelease(textEncodingName);
}
CFRelease(str);
}
return result;
}
static Boolean _CFDataURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFArrayRef desiredProperties, CFDictionaryRef *fetchedProperties, SInt32 *errorCode) {
Boolean success = true;
if (errorCode) *errorCode = 0;
CFDataRef data = NULL;
CFStringRef mimeType = NULL;
CFStringRef textEncodingName = NULL;
if (! parseDataRequestURL(url, &data, &mimeType, &textEncodingName)) {
if (errorCode)
*errorCode = kCFURLUnknownError;
*fetchedData = NULL;
success = false;
} else {
if (fetchedData) {
*fetchedData = CFDataCreateCopy(alloc, data);
}
if (fetchedProperties) {
const void* propKeys[] = {
kCFDataURLDataLength,
kCFDataURLMimeType,
kCFDataURLTextEncodingName,
};
const CFIndex propKeysCount = sizeof(propKeys) / sizeof(propKeys[0]);
if (desiredProperties == NULL) {
static CFArrayRef sAllProps = NULL;
if (sAllProps == NULL) {
sAllProps = CFArrayCreate(kCFAllocatorSystemDefault, propKeys, propKeysCount, &kCFTypeArrayCallBacks);
}
desiredProperties = sAllProps;
}
const void* vals[propKeysCount];
const void* keys[propKeysCount];
int ixVal = 0;
CFIndex count = CFArrayGetCount(desiredProperties);
for (CFIndex i = 0; i < count; i++) {
CFStringRef key = (CFStringRef) CFArrayGetValueAtIndex(desiredProperties, i);
if (CFEqual(key, kCFDataURLDataLength)) {
CFIndex len = CFDataGetLength(data);
keys[ixVal] = key;
vals[ixVal++] = CFNumberCreate(alloc, kCFNumberCFIndexType, &len);
} else if (CFEqual(key, kCFDataURLMimeType)) {
if (mimeType != NULL) {
keys[ixVal] = key;
vals[ixVal++] = CFStringCreateCopy(alloc, mimeType);
}
} else if (CFEqual(key, kCFDataURLTextEncodingName)) {
if (textEncodingName != NULL) {
keys[ixVal] = key;
vals[ixVal++] = CFStringCreateCopy(alloc, textEncodingName);
}
}
}
*fetchedProperties = CFDictionaryCreate(alloc, keys, vals, ixVal, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
for (CFIndex i = 0; i < ixVal; i++)
CFRelease(vals[i]);
if (*fetchedProperties == NULL)
success = false;
}
if (data) CFRelease(data);
if (mimeType) CFRelease(mimeType);
if (textEncodingName) CFRelease(textEncodingName);
}
return success;
}
Boolean CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFDictionaryRef *fetchedProperties, CFArrayRef desiredProperties, SInt32 *errorCode) {
CFStringRef scheme = CFURLCopyScheme(url);
if (!scheme) {
if (errorCode) *errorCode = kCFURLImproperArgumentsError;
if (fetchedData) *fetchedData = NULL;
if (fetchedProperties) *fetchedProperties = NULL;
return false;
} else {
Boolean result;
if (CFStringCompare(scheme, CFSTR("file"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
result = _CFFileURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, desiredProperties, fetchedProperties, errorCode);
} else if (CFStringCompare(scheme, CFSTR("data"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
result = _CFDataURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, desiredProperties, fetchedProperties, errorCode);
} else {
#if DEPLOYMENT_TARGET_MACOSX
result = __CFNetwork__CFURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, fetchedProperties, desiredProperties, errorCode);
if (!result) {
if (fetchedData) *fetchedData = NULL;
if (fetchedProperties) *fetchedProperties = NULL;
if (errorCode) *errorCode = kCFURLUnknownSchemeError;
}
#endif
}
CFRelease(scheme);
return result;
}
}
CFTypeRef CFURLCreatePropertyFromResource(CFAllocatorRef alloc, CFURLRef url, CFStringRef property, SInt32 *errorCode) {
CFArrayRef array = CFArrayCreate(alloc, (const void **)&property, 1, &kCFTypeArrayCallBacks);
CFDictionaryRef dict;
if (CFURLCreateDataAndPropertiesFromResource(alloc, url, NULL, &dict, array, errorCode)) {
CFTypeRef result = CFDictionaryGetValue(dict, property);
if (result) CFRetain(result);
CFRelease(array);
CFRelease(dict);
return result;
} else {
if (dict) CFRelease(dict);
CFRelease(array);
return NULL;
}
}
Boolean CFURLWriteDataAndPropertiesToResource(CFURLRef url, CFDataRef data, CFDictionaryRef propertyDict, SInt32 *errorCode) {
CFStringRef scheme = CFURLCopyScheme(url);
if (!scheme) {
if (errorCode) *errorCode = kCFURLImproperArgumentsError;
return false;
} else if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) {
Boolean success = true;
CFRelease(scheme);
if (errorCode) *errorCode = 0;
if (data) {
if (CFURLHasDirectoryPath(url)) {
char cPath[CFMaxPathSize];
if (!CFURLGetFileSystemRepresentation(url, true, (unsigned char *)cPath, CFMaxPathSize)) {
if (errorCode) *errorCode = kCFURLImproperArgumentsError;
success = false;
} else {
success = _CFCreateDirectory(cPath);
if (!success && errorCode) *errorCode = kCFURLUnknownError;
}
} else {
SInt32 length = CFDataGetLength(data);
const void *bytes = (0 == length) ? (const void *)"" : CFDataGetBytePtr(data);
success = _CFWriteBytesToFile(url, bytes, length);
if (!success && errorCode) *errorCode = kCFURLUnknownError;
}
}
if (propertyDict) {
if (!_CFFileURLWritePropertiesToResource(url, propertyDict, errorCode))
success = false;
}
return success;
} else {
CFRelease(scheme);
#if DEPLOYMENT_TARGET_MACOSX
Boolean result = __CFNetwork__CFURLWriteDataAndPropertiesToResource(url, data, propertyDict, errorCode);
if (!result) {
if (errorCode) *errorCode = kCFURLUnknownSchemeError;
}
return result;
#endif
}
}
Boolean CFURLDestroyResource(CFURLRef url, SInt32 *errorCode) {
CFStringRef scheme = CFURLCopyScheme(url);
char cPath[CFMaxPathSize];
if (!scheme) {
if (errorCode) *errorCode = kCFURLImproperArgumentsError;
return false;
} else if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) {
CFRelease(scheme);
if (!CFURLGetFileSystemRepresentation(url, true, (unsigned char *)cPath, CFMaxPathSize)) {
if (errorCode) *errorCode = kCFURLImproperArgumentsError;
return false;
}
if (CFURLHasDirectoryPath(url)) {
if (_CFRemoveDirectory(cPath)) {
if (errorCode) *errorCode = 0;
return true;
} else {
if (errorCode) *errorCode = kCFURLUnknownError;
return false;
}
} else {
if (_CFDeleteFile(cPath)) {
if (errorCode) *errorCode = 0;
return true;
} else {
if (errorCode) *errorCode = kCFURLUnknownError;
return false;
}
}
} else {
CFRelease(scheme);
#if DEPLOYMENT_TARGET_MACOSX
Boolean result = __CFNetwork__CFURLDestroyResource(url, errorCode);
if (!result) {
if (errorCode) *errorCode = kCFURLUnknownSchemeError;
}
return result;
#endif
}
}