1/* 2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// CoreFoundation related utilities 27// 28#include <security_utilities/cfutilities.h> 29#include <security_utilities/errors.h> 30#include <security_utilities/debugging.h> 31#include <cstdarg> 32#include <vector> 33 34 35namespace Security { 36 37 38ModuleNexus<CFEmptyArray> cfEmptyArray; 39 40CFEmptyArray::CFEmptyArray() 41{ 42 mArray = CFArrayCreate(NULL, NULL, 0, NULL); 43} 44 45 46// 47// Turn a C(++) string into a CFURLRef indicating a file: path 48// 49CFURLRef makeCFURL(const char *s, bool isDirectory, CFURLRef base) 50{ 51 if (base) 52 return CFURLCreateWithFileSystemPathRelativeToBase(NULL, 53 CFTempString(s), kCFURLPOSIXPathStyle, isDirectory, base); 54 else 55 return CFURLCreateWithFileSystemPath(NULL, 56 CFTempString(s), kCFURLPOSIXPathStyle, isDirectory); 57} 58 59CFURLRef makeCFURL(CFStringRef s, bool isDirectory, CFURLRef base) 60{ 61 if (base) 62 return CFURLCreateWithFileSystemPathRelativeToBase(NULL, s, kCFURLPOSIXPathStyle, isDirectory, base); 63 else 64 return CFURLCreateWithFileSystemPath(NULL, s, kCFURLPOSIXPathStyle, isDirectory); 65} 66 67 68// 69// CFMallocData objects 70// 71CFMallocData::operator CFDataRef () 72{ 73 CFDataRef result = makeCFDataMalloc(mData, mSize); 74 if (!result) 75 CFError::throwMe(); 76 mData = NULL; // release ownership 77 return result; 78} 79 80 81// 82// Make CFDictionaries from stuff 83// 84CFDictionaryRef makeCFDictionary(unsigned count, ...) 85{ 86 CFTypeRef keys[count], values[count]; 87 va_list args; 88 va_start(args, count); 89 for (unsigned n = 0; n < count; n++) { 90 keys[n] = va_arg(args, CFTypeRef); 91 values[n] = va_arg(args, CFTypeRef); 92 } 93 va_end(args); 94 return CFDictionaryCreate(NULL, (const void **)keys, (const void **)values, count, 95 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 96} 97 98CFMutableDictionaryRef makeCFMutableDictionary() 99{ 100 if (CFMutableDictionaryRef r = CFDictionaryCreateMutable(NULL, 0, 101 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) 102 return r; 103 CFError::throwMe(); 104} 105 106CFMutableDictionaryRef makeCFMutableDictionary(unsigned count, ...) 107{ 108 CFMutableDictionaryRef dict = makeCFMutableDictionary(); 109 if (count > 0) { 110 va_list args; 111 va_start(args, count); 112 for (unsigned n = 0; n < count; n++) { 113 CFTypeRef key = va_arg(args, CFTypeRef); 114 CFTypeRef value = va_arg(args, CFTypeRef); 115 CFDictionaryAddValue(dict, key, value); 116 } 117 va_end(args); 118 } 119 return dict; 120} 121 122CFMutableDictionaryRef makeCFMutableDictionary(CFDictionaryRef dict) 123{ 124 if (CFMutableDictionaryRef r = CFDictionaryCreateMutableCopy(NULL, 0, dict)) 125 return r; 126 CFError::throwMe(); 127} 128 129CFDictionaryRef makeCFDictionaryFrom(CFDataRef data) 130{ 131 if (data) { 132 CFPropertyListRef plist = CFPropertyListCreateFromXMLData(NULL, data, 133 kCFPropertyListImmutable, NULL); 134 if (plist && CFGetTypeID(plist) != CFDictionaryGetTypeID()) 135 CFError::throwMe(); 136 return CFDictionaryRef(plist); 137 } else 138 return NULL; 139 140} 141 142CFDictionaryRef makeCFDictionaryFrom(const void *data, size_t length) 143{ 144 return makeCFDictionaryFrom(CFTempData(data, length).get()); 145} 146 147 148// 149// Turn a CFString into a UTF8-encoded C++ string. 150// If release==true, the argument will be CFReleased even in case of error. 151// 152string cfString(CFStringRef str) 153{ 154 if (!str) 155 return ""; 156 // quick path first 157 if (const char *s = CFStringGetCStringPtr(str, kCFStringEncodingUTF8)) { 158 return s; 159 } 160 161 // need to extract into buffer 162 string ret; 163 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8); 164 std::vector<char> buffer; 165 buffer.resize(length + 1); 166 if (CFStringGetCString(str, &buffer[0], length + 1, kCFStringEncodingUTF8)) 167 ret = &buffer[0]; 168 return ret; 169} 170 171string cfStringRelease(CFStringRef inStr) 172{ 173 CFRef<CFStringRef> str(inStr); 174 return cfString(str); 175} 176 177string cfString(CFURLRef inUrl) 178{ 179 if (!inUrl) 180 CFError::throwMe(); 181 182 UInt8 buffer[PATH_MAX+1]; 183 if (CFURLGetFileSystemRepresentation(inUrl, true, buffer, sizeof(buffer))) 184 return string(reinterpret_cast<char *>(buffer)); 185 else 186 CFError::throwMe(); 187} 188 189string cfStringRelease(CFURLRef inUrl) 190{ 191 CFRef<CFURLRef> bundle(inUrl); 192 return cfString(bundle); 193} 194 195string cfString(CFBundleRef inBundle) 196{ 197 if (!inBundle) 198 CFError::throwMe(); 199 return cfStringRelease(CFBundleCopyBundleURL(inBundle)); 200} 201 202string cfStringRelease(CFBundleRef inBundle) 203{ 204 CFRef<CFBundleRef> bundle(inBundle); 205 return cfString(bundle); 206} 207 208 209string cfString(CFTypeRef it, OSStatus err) 210{ 211 if (it == NULL) 212 MacOSError::throwMe(err); 213 CFTypeID id = CFGetTypeID(it); 214 if (id == CFStringGetTypeID()) 215 return cfString(CFStringRef(it)); 216 else if (id == CFURLGetTypeID()) 217 return cfString(CFURLRef(it)); 218 else if (id == CFBundleGetTypeID()) 219 return cfString(CFBundleRef(it)); 220 else 221 return cfString(CFCopyDescription(it), true); 222} 223 224 225// 226// CFURLAccess wrappers for specific purposes 227// 228CFDataRef cfLoadFile(CFURLRef url) 229{ 230 assert(url); 231 CFDataRef data; 232 SInt32 error; 233 if (CFURLCreateDataAndPropertiesFromResource(NULL, url, 234 &data, NULL, NULL, &error)) { 235 return data; 236 } else { 237 secdebug("cfloadfile", "failed to fetch %s error=%d", cfString(url).c_str(), int(error)); 238 return NULL; 239 } 240} 241 242CFDataRef cfLoadFile(int fd, size_t bytes) 243{ 244 uint8_t *buffer = (uint8_t *) malloc(bytes); 245 246 if (buffer == NULL) 247 return NULL; 248 249 if (read(fd, buffer, bytes) != bytes) { 250 free(buffer); 251 return NULL; 252 } 253 254 CFDataRef result = CFDataCreateWithBytesNoCopy(kCFAllocatorMalloc, buffer, bytes, kCFAllocatorMalloc); 255 256 // If CFDataCreateWithBytesNoCopy fails, the buffer is not free()-ed 257 if (result == NULL) { 258 free(buffer); 259 return NULL; 260 } 261 262 return result; 263} 264 265// 266// CFArray creators 267// 268CFArrayRef makeCFArray(CFIndex count, ...) 269{ 270 CFTypeRef elements[count]; 271 va_list args; 272 va_start(args, count); 273 for (CFIndex n = 0; n < count; n++) 274 elements[n] = va_arg(args, CFTypeRef); 275 va_end(args); 276 return CFArrayCreate(NULL, elements, count, &kCFTypeArrayCallBacks); 277} 278 279CFMutableArrayRef makeCFMutableArray(CFIndex count, ...) 280{ 281 CFMutableArrayRef array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 282 va_list args; 283 va_start(args, count); 284 for (CFIndex n = 0; n < count; n++) 285 CFArrayAppendValue(array, va_arg(args, CFTypeRef)); 286 va_end(args); 287 return array; 288} 289 290 291} // end namespace Security 292