/* * Copyright (c) 1999-2002, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * cfutil.c * - CF utility functions */ /* * Modification History * * February 15, 2002 Dieter Siegmund (dieter@apple.com) * - broken out of ipconfigd.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "cfutil.h" #include "symbol_scope.h" PRIVATE_EXTERN void my_CFRelease(void * t) { void * * obj = (void * *)t; if (obj && *obj) { CFRelease(*obj); *obj = NULL; } return; } static void * read_file(const char * filename, size_t * data_length) { void * data = NULL; size_t len = 0; int fd = -1; struct stat sb; *data_length = 0; if (stat(filename, &sb) < 0) goto done; len = sb.st_size; if (len == 0) goto done; data = malloc(len); if (data == NULL) goto done; fd = open(filename, O_RDONLY); if (fd < 0) goto done; if (read(fd, data, len) != len) { goto done; } done: if (fd >= 0) close(fd); if (data) { *data_length = len; } return (data); } static int write_file(const char * filename, const void * data, size_t data_length) { char path[MAXPATHLEN]; int fd = -1; int ret = 0; snprintf(path, sizeof(path), "%s-", filename); fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0644); if (fd < 0) { ret = -1; goto done; } if (write(fd, data, data_length) != data_length) { ret = -1; goto done; } rename(path, filename); done: if (fd >= 0) { close(fd); } return (ret); } PRIVATE_EXTERN CFPropertyListRef my_CFPropertyListCreateFromFile(const char * filename) { void * buf; size_t bufsize; CFDataRef data = NULL; CFPropertyListRef plist = NULL; buf = read_file(filename, &bufsize); if (buf == NULL) { return (NULL); } data = CFDataCreateWithBytesNoCopy(NULL, buf, bufsize, kCFAllocatorNull); if (data == NULL) { goto done; } plist = CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL); done: if (data) CFRelease(data); if (buf) free(buf); return (plist); } PRIVATE_EXTERN int my_CFPropertyListWriteFile(CFPropertyListRef plist, const char * filename) { CFDataRef data; int ret; if (plist == NULL) return (0); data = CFPropertyListCreateXMLData(NULL, plist); if (data == NULL) { return (0); } ret = write_file(filename, (const void *)CFDataGetBytePtr(data), CFDataGetLength(data)); CFRelease(data); return (ret); } PRIVATE_EXTERN int my_CFStringToCStringAndLengthExt(CFStringRef cfstr, char * str, int len, boolean_t is_external) { CFIndex ret_len = 0; CFStringGetBytes(cfstr, CFRangeMake(0, CFStringGetLength(cfstr)), kCFStringEncodingUTF8, 0, is_external, (UInt8 *)str, len - 1, &ret_len); if (str != NULL) { str[ret_len] = '\0'; } return (ret_len + 1); /* leave 1 byte for nul-termination */ } PRIVATE_EXTERN Boolean my_CFStringArrayToCStringArray(CFArrayRef arr, void * buffer, int * buffer_size, int * ret_count) { int count = CFArrayGetCount(arr); int i; char * offset = NULL; int space; char * * strlist = NULL; space = count * sizeof(char *); if (buffer != NULL) { if (*buffer_size < space) { /* not enough space for even the pointer list */ return (FALSE); } strlist = (char * *)buffer; offset = buffer + space; /* the start of the 1st string */ } for (i = 0; i < count; i++) { CFIndex len = 0; CFStringRef str; str = CFArrayGetValueAtIndex(arr, i); if (isA_CFString(str) == NULL) { return (FALSE); } if (buffer != NULL) { len = *buffer_size - space; if (len < 0) { return (FALSE); } } len = my_CFStringToCStringAndLength(str, offset, len); if (buffer != NULL) { strlist[i] = offset; offset += len; } space += len; } *buffer_size = roundup(space, sizeof(char *)); *ret_count = count; return (TRUE); } PRIVATE_EXTERN Boolean my_CFStringArrayToEtherArray(CFArrayRef array, char * buffer, int * buffer_size, int * ret_count) { int count = CFArrayGetCount(array); int i; struct ether_addr * list = NULL; int space; space = roundup(count * sizeof(*list), sizeof(char *)); if (buffer != NULL) { if (*buffer_size < space) { /* not enough space for all elements */ return (FALSE); } list = (struct ether_addr *)buffer; } for (i = 0; i < count; i++) { struct ether_addr * eaddr; CFStringRef str = CFArrayGetValueAtIndex(array, i); char val[64]; if (isA_CFString(str) == NULL) { return (FALSE); } if (CFStringGetCString(str, val, sizeof(val), kCFStringEncodingASCII) == FALSE) { return (FALSE); } eaddr = ether_aton((char *)val); if (eaddr == NULL) { return (FALSE); } if (list != NULL) { list[i] = *eaddr; } } *buffer_size = space; *ret_count = count; return (TRUE); } PRIVATE_EXTERN bool my_CFStringToIPAddress(CFStringRef str, struct in_addr * ret_ip) { char buf[64]; ret_ip->s_addr = 0; if (isA_CFString(str) == NULL) { return (FALSE); } if (CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingASCII) == FALSE) { return (FALSE); } if (inet_aton(buf, ret_ip) == 1) { return (TRUE); } return (FALSE); } PRIVATE_EXTERN bool my_CFStringToNumber(CFStringRef str, uint32_t * ret_val) { char buf[64]; unsigned long val; my_CFStringToCStringAndLength(str, buf, sizeof(buf)); val = strtoul(buf, NULL, 0); if (val != ULONG_MAX && errno != ERANGE) { *ret_val = (uint32_t)val; return (TRUE); } return (FALSE); } PRIVATE_EXTERN bool my_CFTypeToNumber(CFTypeRef element, uint32_t * l_p) { if (isA_CFString(element) != NULL) { if (my_CFStringToNumber(element, l_p) == FALSE) { return (FALSE); } } else if (isA_CFBoolean(element) != NULL) { *l_p = CFBooleanGetValue(element); } else if (isA_CFNumber(element) != NULL) { if (CFNumberGetValue(element, kCFNumberSInt32Type, l_p) == FALSE) { return (FALSE); } } else { return (FALSE); } return (TRUE); } PRIVATE_EXTERN void my_CFDictionarySetTypeAsArrayValue(CFMutableDictionaryRef dict, CFStringRef prop, CFTypeRef val) { CFArrayRef array; array = CFArrayCreate(NULL, (const void **)&val, 1, &kCFTypeArrayCallBacks); if (array != NULL) { CFDictionarySetValue(dict, prop, array); CFRelease(array); } return; } PRIVATE_EXTERN void my_CFDictionarySetIPAddressAsArrayValue(CFMutableDictionaryRef dict, CFStringRef prop, struct in_addr ip_addr) { CFStringRef str; str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&ip_addr)); my_CFDictionarySetTypeAsArrayValue(dict, prop, str); CFRelease(str); return; } PRIVATE_EXTERN void my_CFArrayAppendUniqueValue(CFMutableArrayRef arr, CFTypeRef new) { int count; int i; count = CFArrayGetCount(arr); for (i = 0; i < count; i++) { CFStringRef element = CFArrayGetValueAtIndex(arr, i); if (CFEqual(element, new)) { return; } } CFArrayAppendValue(arr, new); return; } PRIVATE_EXTERN Boolean my_CFEqual(CFTypeRef val1, CFTypeRef val2) { if (val1 == NULL) { if (val2 == NULL) { return (TRUE); } return (FALSE); } if (val2 == NULL) { return (FALSE); } if (CFGetTypeID(val1) != CFGetTypeID(val2)) { return (FALSE); } return (CFEqual(val1, val2)); } /* * Function: my_CFStringCopyComponent * Purpose: * Separates the given string using the given separator, and returns * the component at the specified index. * Returns: * NULL if no such component exists, non-NULL component otherwise */ PRIVATE_EXTERN CFStringRef my_CFStringCopyComponent(CFStringRef path, CFStringRef separator, CFIndex component_index) { CFArrayRef arr; CFStringRef component = NULL; arr = CFStringCreateArrayBySeparatingStrings(NULL, path, separator); if (arr == NULL) { goto done; } if (CFArrayGetCount(arr) <= component_index) { goto done; } component = CFRetain(CFArrayGetValueAtIndex(arr, component_index)); done: my_CFRelease(&arr); return (component); } CFStringRef my_CFStringCreateWithIPAddress(const struct in_addr ip) { return (CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&ip))); } CFStringRef my_CFStringCreateWithIPv6Address(const void * ip6_addr) { char ntopbuf[INET6_ADDRSTRLEN]; const char * c_str; c_str = inet_ntop(AF_INET6, ip6_addr, ntopbuf, sizeof(ntopbuf)); return (CFStringCreateWithCString(NULL, c_str, kCFStringEncodingASCII)); } void my_CFStringAppendBytesAsHex(CFMutableStringRef str, const uint8_t * bytes, int length, char separator) { int i; for (i = 0; i < length; i++) { char sep[3]; if (i == 0) { sep[0] = '\0'; } else { if ((i % 8) == 0 && separator == ' ') { sep[0] = sep[1] = ' '; sep[2] = '\0'; } else { sep[0] = separator; sep[1] = '\0'; } } CFStringAppendFormat(str, NULL, CFSTR("%s%02x"), sep, bytes[i]); } return; } char * my_CFStringToCString(CFStringRef cfstr, CFStringEncoding encoding) { CFIndex l; CFRange range; uint8_t * str; range = CFRangeMake(0, CFStringGetLength(cfstr)); CFStringGetBytes(cfstr, range, encoding, 0, FALSE, NULL, 0, &l); if (l <= 0) { return (NULL); } str = (uint8_t *)malloc(l + 1); CFStringGetBytes(cfstr, range, encoding, 0, FALSE, str, l, &l); str[l] = '\0'; return ((char *)str); }