2023-01-28 04:54:20 +00:00
|
|
|
|
// Copyright 2014 The Crashpad Authors
|
2022-04-02 01:21:55 +00:00
|
|
|
|
//
|
|
|
|
|
// 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"
|
|
|
|
|
#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::mac::CFToNSCast(
|
|
|
|
|
base::mac::CFCastStrict<CFDictionaryRef>(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 =
|
|
|
|
|
implicit_cast<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::mac::CFToNSCast(
|
|
|
|
|
base::mac::CFCastStrict<CFArrayRef>(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 =
|
|
|
|
|
implicit_cast<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::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 = 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::mac::CFCastStrict<CFBooleanRef>(property_cf);
|
|
|
|
|
data_launch = LaunchDataNewBool(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 = LaunchDataNewString([string_ns UTF8String]);
|
|
|
|
|
|
|
|
|
|
} else if (type_id_cf == CFDataGetTypeID()) {
|
|
|
|
|
NSData* data_ns = base::mac::CFToNSCast(
|
|
|
|
|
base::mac::CFCastStrict<CFDataRef>(property_cf));
|
|
|
|
|
data_launch = LaunchDataNewOpaque([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
|