// Copyright 2014 The Crashpad Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "util/mac/launchd.h" #import #include "base/apple/bridging.h" #include "base/apple/foundation_util.h" #include "base/apple/scoped_cftyperef.h" #include "base/mac/scoped_launch_data.h" #include "base/strings/sys_string_conversions.h" #include "util/misc/implicit_cast.h" namespace crashpad { launch_data_t CFPropertyToLaunchData(CFPropertyListRef property_cf) { @autoreleasepool { // This function mixes Foundation and Core Foundation access to property // list elements according to which is more convenient and correct for any // specific task. launch_data_t data_launch = nullptr; CFTypeID type_id_cf = CFGetTypeID(property_cf); if (type_id_cf == CFDictionaryGetTypeID()) { NSDictionary* dictionary_ns = base::apple::CFToNSPtrCast( base::apple::CFCastStrict(property_cf)); base::mac::ScopedLaunchData dictionary_launch( LaunchDataAlloc(LAUNCH_DATA_DICTIONARY)); for (NSString* key in dictionary_ns) { if (![key isKindOfClass:[NSString class]]) { return nullptr; } CFPropertyListRef value_cf = (__bridge CFPropertyListRef)dictionary_ns[key]; launch_data_t value_launch = CFPropertyToLaunchData(value_cf); if (!value_launch) { return nullptr; } LaunchDataDictInsert( dictionary_launch.get(), value_launch, [key UTF8String]); } data_launch = dictionary_launch.release(); } else if (type_id_cf == CFArrayGetTypeID()) { NSArray* array_ns = base::apple::CFToNSPtrCast( base::apple::CFCastStrict(property_cf)); base::mac::ScopedLaunchData array_launch( LaunchDataAlloc(LAUNCH_DATA_ARRAY)); size_t index = 0; for (id element_ns in array_ns) { CFPropertyListRef element_cf = (__bridge CFPropertyListRef)element_ns; launch_data_t element_launch = CFPropertyToLaunchData(element_cf); if (!element_launch) { return nullptr; } LaunchDataArraySetIndex(array_launch.get(), element_launch, index++); } data_launch = array_launch.release(); } else if (type_id_cf == CFNumberGetTypeID()) { CFNumberRef number_cf = base::apple::CFCastStrict(property_cf); NSNumber* number_ns = base::apple::CFToNSPtrCast(number_cf); switch (CFNumberGetType(number_cf)) { case kCFNumberSInt8Type: case kCFNumberSInt16Type: case kCFNumberSInt32Type: case kCFNumberSInt64Type: case kCFNumberCharType: case kCFNumberShortType: case kCFNumberIntType: case kCFNumberLongType: case kCFNumberLongLongType: case kCFNumberCFIndexType: case kCFNumberNSIntegerType: { data_launch = LaunchDataNewInteger([number_ns longLongValue]); break; } case kCFNumberFloat32Type: case kCFNumberFloat64Type: case kCFNumberFloatType: case kCFNumberDoubleType: { data_launch = LaunchDataNewReal([number_ns doubleValue]); break; } default: { return nullptr; } } } else if (type_id_cf == CFBooleanGetTypeID()) { CFBooleanRef boolean_cf = base::apple::CFCastStrict(property_cf); data_launch = LaunchDataNewBool(CFBooleanGetValue(boolean_cf)); } else if (type_id_cf == CFStringGetTypeID()) { NSString* string_ns = base::apple::CFToNSPtrCast( base::apple::CFCastStrict(property_cf)); // -fileSystemRepresentation might be more correct than -UTF8String, // because these strings can hold paths. The analogous function in // launchctl, CF2launch_data() (10.9.4 // launchd-842.92.1/support/launchctl.c), uses UTF-8 instead of filesystem // encoding, so do the same here. Note that there’s another occurrence of // -UTF8String above, used for dictionary keys. data_launch = LaunchDataNewString([string_ns UTF8String]); } else if (type_id_cf == CFDataGetTypeID()) { NSData* data_ns = base::apple::CFToNSPtrCast( base::apple::CFCastStrict(property_cf)); data_launch = LaunchDataNewOpaque([data_ns bytes], [data_ns length]); } else { base::apple::ScopedCFTypeRef type_name_cf( CFCopyTypeIDDescription(type_id_cf)); DLOG(ERROR) << "unable to convert CFTypeID " << type_id_cf << " (" << base::SysCFStringRefToUTF8(type_name_cf.get()) << ")"; } return data_launch; } } } // namespace crashpad