1/* 2 * Copyright (c) 2000-2004 Apple Computer, 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 CFStringRef ss = CFStringCreateWithCStringNoCopy(NULL, s, kCFStringEncodingUTF8, kCFAllocatorNull); 52 CFURLRef returnValue = NULL; 53 54 if (base) 55 { 56 returnValue = CFURLCreateWithFileSystemPathRelativeToBase(NULL, 57 ss, kCFURLPOSIXPathStyle, isDirectory, base); 58 } 59 else 60 { 61 returnValue = CFURLCreateWithFileSystemPath(NULL, 62 ss, kCFURLPOSIXPathStyle, isDirectory); 63 } 64 65 CFRelease(ss); 66 return returnValue; 67} 68 69CFURLRef makeCFURL(CFStringRef s, bool isDirectory, CFURLRef base) 70{ 71 if (base) 72 return CFURLCreateWithFileSystemPathRelativeToBase(NULL, s, kCFURLPOSIXPathStyle, isDirectory, base); 73 else 74 return CFURLCreateWithFileSystemPath(NULL, s, kCFURLPOSIXPathStyle, isDirectory); 75} 76 77 78// 79// CFMallocData objects 80// 81CFMallocData::operator CFDataRef () 82{ 83 CFDataRef result = makeCFDataMalloc(mData, mSize); 84 if (!result) 85 CFError::throwMe(); 86 mData = NULL; // release ownership 87 return result; 88} 89 90 91// 92// Make CFDictionaries from stuff 93// 94CFDictionaryRef makeCFDictionary(unsigned count, ...) 95{ 96 CFTypeRef keys[count], values[count]; 97 va_list args; 98 va_start(args, count); 99 for (unsigned n = 0; n < count; n++) { 100 keys[n] = va_arg(args, CFTypeRef); 101 values[n] = va_arg(args, CFTypeRef); 102 } 103 va_end(args); 104 return CFDictionaryCreate(NULL, (const void **)keys, (const void **)values, count, 105 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 106} 107 108CFMutableDictionaryRef makeCFMutableDictionary() 109{ 110 if (CFMutableDictionaryRef r = CFDictionaryCreateMutable(NULL, 0, 111 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) 112 return r; 113 CFError::throwMe(); 114} 115 116CFMutableDictionaryRef makeCFMutableDictionary(unsigned count, ...) 117{ 118 CFMutableDictionaryRef dict = makeCFMutableDictionary(); 119 if (count > 0) { 120 va_list args; 121 va_start(args, count); 122 for (unsigned n = 0; n < count; n++) { 123 CFTypeRef key = va_arg(args, CFTypeRef); 124 CFTypeRef value = va_arg(args, CFTypeRef); 125 CFDictionaryAddValue(dict, key, value); 126 } 127 va_end(args); 128 } 129 return dict; 130} 131 132CFMutableDictionaryRef makeCFMutableDictionary(CFDictionaryRef dict) 133{ 134 if (CFMutableDictionaryRef r = CFDictionaryCreateMutableCopy(NULL, 0, dict)) 135 return r; 136 CFError::throwMe(); 137} 138 139CFDictionaryRef makeCFDictionaryFrom(CFDataRef data) 140{ 141 if (data) { 142 CFPropertyListRef plist = CFPropertyListCreateFromXMLData(NULL, data, 143 kCFPropertyListImmutable, NULL); 144 if (plist && CFGetTypeID(plist) != CFDictionaryGetTypeID()) 145 CFError::throwMe(); 146 return CFDictionaryRef(plist); 147 } else 148 return NULL; 149 150} 151 152CFDictionaryRef makeCFDictionaryFrom(const void *data, size_t length) 153{ 154 return makeCFDictionaryFrom(CFTempData(data, length).get()); 155} 156 157 158// 159// Turn a CFString into a UTF8-encoded C++ string. 160// If release==true, the argument will be CFReleased even in case of error. 161// 162string cfString(CFStringRef str) 163{ 164 if (!str) 165 return ""; 166 // quick path first 167 if (const char *s = CFStringGetCStringPtr(str, kCFStringEncodingUTF8)) { 168 return s; 169 } 170 171 // need to extract into buffer 172 string ret; 173 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8); 174 std::vector<char> buffer; 175 buffer.resize(length + 1); 176 if (CFStringGetCString(str, &buffer[0], length + 1, kCFStringEncodingUTF8)) 177 ret = &buffer[0]; 178 return ret; 179} 180 181string cfStringRelease(CFStringRef inStr) 182{ 183 CFRef<CFStringRef> str(inStr); 184 return cfString(str); 185} 186 187string cfString(CFURLRef inUrl) 188{ 189 if (!inUrl) 190 CFError::throwMe(); 191 192 UInt8 buffer[PATH_MAX+1]; 193 if (CFURLGetFileSystemRepresentation(inUrl, true, buffer, sizeof(buffer))) 194 return string(reinterpret_cast<char *>(buffer)); 195 else 196 CFError::throwMe(); 197} 198 199string cfStringRelease(CFURLRef inUrl) 200{ 201 CFRef<CFURLRef> bundle(inUrl); 202 return cfString(bundle); 203} 204 205string cfString(CFBundleRef inBundle) 206{ 207 if (!inBundle) 208 CFError::throwMe(); 209 return cfStringRelease(CFBundleCopyBundleURL(inBundle)); 210} 211 212string cfStringRelease(CFBundleRef inBundle) 213{ 214 CFRef<CFBundleRef> bundle(inBundle); 215 return cfString(bundle); 216} 217 218 219string cfString(CFTypeRef it, OSStatus err) 220{ 221 if (it == NULL) 222 MacOSError::throwMe(err); 223 CFTypeID id = CFGetTypeID(it); 224 if (id == CFStringGetTypeID()) 225 return cfString(CFStringRef(it)); 226 else if (id == CFURLGetTypeID()) 227 return cfString(CFURLRef(it)); 228 else if (id == CFBundleGetTypeID()) 229 return cfString(CFBundleRef(it)); 230 else 231 return cfString(CFCopyDescription(it), true); 232} 233 234 235// 236// CFURLAccess wrappers for specific purposes 237// 238CFDataRef cfLoadFile(CFURLRef url) 239{ 240 assert(url); 241 CFDataRef data; 242 SInt32 error; 243 if (CFURLCreateDataAndPropertiesFromResource(NULL, url, 244 &data, NULL, NULL, &error)) { 245 return data; 246 } else { 247 secdebug("cfloadfile", "failed to fetch %s error=%d", cfString(url).c_str(), int(error)); 248 return NULL; 249 } 250} 251 252CFDataRef cfLoadFile(int fd, size_t bytes) 253{ 254 uint8_t *buffer = (uint8_t *) malloc(bytes); 255 256 if (buffer == NULL) 257 return NULL; 258 259 if (read(fd, buffer, bytes) != bytes) { 260 free(buffer); 261 return NULL; 262 } 263 264 CFDataRef result = CFDataCreateWithBytesNoCopy(kCFAllocatorMalloc, buffer, bytes, kCFAllocatorMalloc); 265 266 // If CFDataCreateWithBytesNoCopy fails, the buffer is not free()-ed 267 if (result == NULL) { 268 free(buffer); 269 return NULL; 270 } 271 272 return result; 273} 274 275// 276// CFArray creators 277// 278CFArrayRef makeCFArray(CFIndex count, ...) 279{ 280 CFTypeRef elements[count]; 281 va_list args; 282 va_start(args, count); 283 for (CFIndex n = 0; n < count; n++) 284 elements[n] = va_arg(args, CFTypeRef); 285 va_end(args); 286 return CFArrayCreate(NULL, elements, count, &kCFTypeArrayCallBacks); 287} 288 289CFMutableArrayRef makeCFMutableArray(CFIndex count, ...) 290{ 291 CFMutableArrayRef array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 292 va_list args; 293 va_start(args, count); 294 for (CFIndex n = 0; n < count; n++) 295 CFArrayAppendValue(array, va_arg(args, CFTypeRef)); 296 va_end(args); 297 return array; 298} 299 300 301} // end namespace Security 302