Index: util/mac/launchd.mm |
diff --git a/util/mac/launchd.mm b/util/mac/launchd.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5d9b5481cda25f61e09ce5b7e04babca4c8dd0e4 |
--- /dev/null |
+++ b/util/mac/launchd.mm |
@@ -0,0 +1,141 @@ |
+// Copyright 2014 The Crashpad Authors. All rights reserved. |
+// |
+// 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 <Foundation/Foundation.h> |
+ |
+#include "base/mac/foundation_util.h" |
+#include "base/mac/scoped_launch_data.h" |
+#include "base/mac/scoped_cftyperef.h" |
+#include "base/strings/sys_string_conversions.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 = NULL; |
+ CFTypeID type_id_cf = CFGetTypeID(property_cf); |
+ |
+ if (type_id_cf == CFDictionaryGetTypeID()) { |
+ NSDictionary* dictionary_ns = base::mac::CFToNSCast( |
+ base::mac::CFCastStrict<CFDictionaryRef>(property_cf)); |
+ base::mac::ScopedLaunchData dictionary_launch( |
+ launch_data_alloc(LAUNCH_DATA_DICTIONARY)); |
+ |
+ for (NSString* key in dictionary_ns) { |
+ if (![key isKindOfClass:[NSString class]]) { |
+ return NULL; |
+ } |
+ |
+ CFPropertyListRef value_cf = |
+ static_cast<CFPropertyListRef>([dictionary_ns objectForKey:key]); |
+ launch_data_t value_launch = CFPropertyToLaunchData(value_cf); |
+ if (!value_launch) { |
+ return NULL; |
+ } |
+ |
+ launch_data_dict_insert( |
+ dictionary_launch, value_launch, [key UTF8String]); |
+ } |
+ |
+ data_launch = dictionary_launch.release(); |
+ |
+ } else if (type_id_cf == CFArrayGetTypeID()) { |
+ NSArray* array_ns = base::mac::CFToNSCast( |
+ base::mac::CFCastStrict<CFArrayRef>(property_cf)); |
+ base::mac::ScopedLaunchData array_launch( |
+ launch_data_alloc(LAUNCH_DATA_ARRAY)); |
+ size_t index = 0; |
+ |
+ for (id element_ns in array_ns) { |
+ CFPropertyListRef element_cf = |
+ static_cast<CFPropertyListRef>(element_ns); |
+ launch_data_t element_launch = CFPropertyToLaunchData(element_cf); |
+ if (!element_launch) { |
+ return NULL; |
+ } |
+ |
+ launch_data_array_set_index(array_launch, element_launch, index++); |
+ } |
+ |
+ data_launch = array_launch.release(); |
+ |
+ } else if (type_id_cf == CFNumberGetTypeID()) { |
+ CFNumberRef number_cf = base::mac::CFCastStrict<CFNumberRef>(property_cf); |
+ NSNumber* number_ns = base::mac::CFToNSCast(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 = launch_data_new_integer([number_ns longLongValue]); |
+ break; |
+ } |
+ |
+ case kCFNumberFloat32Type: |
+ case kCFNumberFloat64Type: |
+ case kCFNumberFloatType: |
+ case kCFNumberDoubleType: { |
+ data_launch = launch_data_new_real([number_ns doubleValue]); |
+ break; |
+ } |
+ |
+ default: { return NULL; } |
+ } |
+ |
+ } else if (type_id_cf == CFBooleanGetTypeID()) { |
+ CFBooleanRef boolean_cf = |
+ base::mac::CFCastStrict<CFBooleanRef>(property_cf); |
+ data_launch = launch_data_new_bool(CFBooleanGetValue(boolean_cf)); |
+ |
+ } else if (type_id_cf == CFStringGetTypeID()) { |
+ NSString* string_ns = base::mac::CFToNSCast( |
+ base::mac::CFCastStrict<CFStringRef>(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 = launch_data_new_string([string_ns UTF8String]); |
+ |
+ } else if (type_id_cf == CFDataGetTypeID()) { |
+ NSData* data_ns = base::mac::CFToNSCast( |
+ base::mac::CFCastStrict<CFDataRef>(property_cf)); |
+ data_launch = launch_data_new_opaque([data_ns bytes], [data_ns length]); |
+ } else { |
+ base::ScopedCFTypeRef<CFStringRef> type_name_cf( |
+ CFCopyTypeIDDescription(type_id_cf)); |
+ DLOG(ERROR) << "unable to convert CFTypeID " << type_id_cf << " (" |
+ << base::SysCFStringRefToUTF8(type_name_cf) << ")"; |
+ } |
+ |
+ return data_launch; |
+ } |
+} |
+ |
+} // namespace crashpad |