blob: 26776df5fd36d61518446f09bacb10d6a707ec19 [file] [log] [blame]
/*
* Copyright (C) 2010-2018 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
// FIXME: This is a .cpp but has ObjC in it?
#include "config.h"
#include "ArgumentCodersCF.h"
#include "ArgumentCoders.h"
#include "DaemonDecoder.h"
#include "DaemonEncoder.h"
#include "DataReference.h"
#include "Decoder.h"
#include "Encoder.h"
#include "StreamConnectionEncoder.h"
#include <CoreGraphics/CoreGraphics.h>
#include <wtf/EnumTraits.h>
#include <wtf/HashSet.h>
#include <wtf/ProcessPrivilege.h>
#include <wtf/Vector.h>
#include <wtf/cf/CFURLExtras.h>
#include <wtf/spi/cocoa/SecuritySPI.h>
#if USE(FOUNDATION)
#import <Foundation/Foundation.h>
#endif
namespace IPC {
using namespace WebCore;
CFTypeRef tokenNullptrTypeRef()
{
static CFStringRef tokenNullptrType = CFSTR("WKNull");
return tokenNullptrType;
}
enum class CFType : uint8_t {
CFArray,
CFBoolean,
CFData,
CFDate,
CFDictionary,
CFNull,
CFNumber,
CFString,
CFURL,
SecCertificate,
#if HAVE(SEC_KEYCHAIN)
SecKeychainItem,
#endif
#if HAVE(SEC_ACCESS_CONTROL)
SecAccessControl,
#endif
#if HAVE(SEC_TRUST_SERIALIZATION)
SecTrust,
#endif
CGColorSpace,
Nullptr,
Unknown,
};
static CFType typeFromCFTypeRef(CFTypeRef type)
{
ASSERT(type);
if (type == tokenNullptrTypeRef())
return CFType::Nullptr;
CFTypeID typeID = CFGetTypeID(type);
if (typeID == CFArrayGetTypeID())
return CFType::CFArray;
if (typeID == CFBooleanGetTypeID())
return CFType::CFBoolean;
if (typeID == CFDataGetTypeID())
return CFType::CFData;
if (typeID == CFDateGetTypeID())
return CFType::CFDate;
if (typeID == CFDictionaryGetTypeID())
return CFType::CFDictionary;
if (typeID == CFNullGetTypeID())
return CFType::CFNull;
if (typeID == CFNumberGetTypeID())
return CFType::CFNumber;
if (typeID == CFStringGetTypeID())
return CFType::CFString;
if (typeID == CFURLGetTypeID())
return CFType::CFURL;
if (typeID == CGColorSpaceGetTypeID())
return CFType::CGColorSpace;
if (typeID == SecCertificateGetTypeID())
return CFType::SecCertificate;
#if HAVE(SEC_KEYCHAIN)
if (typeID == SecKeychainItemGetTypeID())
return CFType::SecKeychainItem;
#endif
#if HAVE(SEC_ACCESS_CONTROL)
if (typeID == SecAccessControlGetTypeID())
return CFType::SecAccessControl;
#endif
#if HAVE(SEC_TRUST_SERIALIZATION)
if (typeID == SecTrustGetTypeID())
return CFType::SecTrust;
#endif
ASSERT_NOT_REACHED();
return CFType::Unknown;
}
template<typename Encoder>
void ArgumentCoder<CFTypeRef>::encode(Encoder& encoder, CFTypeRef typeRef)
{
auto type = typeFromCFTypeRef(typeRef);
encoder << type;
switch (type) {
case CFType::CFArray:
encoder << static_cast<CFArrayRef>(typeRef);
return;
case CFType::CFBoolean:
encoder << static_cast<CFBooleanRef>(typeRef);
return;
case CFType::CFData:
encoder << static_cast<CFDataRef>(typeRef);
return;
case CFType::CFDate:
encoder << static_cast<CFDateRef>(typeRef);
return;
case CFType::CFDictionary:
encoder << static_cast<CFDictionaryRef>(typeRef);
return;
case CFType::CFNull:
return;
case CFType::CFNumber:
encoder << static_cast<CFNumberRef>(typeRef);
return;
case CFType::CFString:
encoder << static_cast<CFStringRef>(typeRef);
return;
case CFType::CFURL:
encoder << static_cast<CFURLRef>(typeRef);
return;
case CFType::CGColorSpace:
encoder << static_cast<CGColorSpaceRef>(const_cast<void*>(typeRef));
return;
case CFType::SecCertificate:
encoder << static_cast<SecCertificateRef>(const_cast<void*>(typeRef));
return;
#if HAVE(SEC_KEYCHAIN)
case CFType::SecKeychainItem:
encoder << static_cast<SecKeychainItemRef>(const_cast<void*>(typeRef));
return;
#endif
#if HAVE(SEC_ACCESS_CONTROL)
case CFType::SecAccessControl:
encoder << static_cast<SecAccessControlRef>(const_cast<void*>(typeRef));
return;
#endif
#if HAVE(SEC_TRUST_SERIALIZATION)
case CFType::SecTrust:
encoder << static_cast<SecTrustRef>(const_cast<void*>(typeRef));
return;
#endif
case CFType::Nullptr:
return;
case CFType::Unknown:
break;
}
ASSERT_NOT_REACHED();
}
template void ArgumentCoder<CFTypeRef>::encode<Encoder>(Encoder&, CFTypeRef);
template void ArgumentCoder<CFTypeRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, CFTypeRef);
std::optional<RetainPtr<CFTypeRef>> ArgumentCoder<RetainPtr<CFTypeRef>>::decode(Decoder& decoder)
{
std::optional<CFType> type;
decoder >> type;
if (!type)
return std::nullopt;
switch (*type) {
case CFType::CFArray: {
std::optional<RetainPtr<CFArrayRef>> array;
decoder >> array;
if (!array)
return std::nullopt;
return WTFMove(*array);
}
case CFType::CFBoolean: {
std::optional<RetainPtr<CFBooleanRef>> boolean;
decoder >> boolean;
if (!boolean)
return std::nullopt;
return WTFMove(*boolean);
}
case CFType::CFData: {
std::optional<RetainPtr<CFDataRef>> data;
decoder >> data;
if (!data)
return std::nullopt;
return WTFMove(*data);
}
case CFType::CFDate: {
std::optional<RetainPtr<CFDateRef>> date;
decoder >> date;
if (!date)
return std::nullopt;
return WTFMove(*date);
}
case CFType::CFDictionary: {
std::optional<RetainPtr<CFDictionaryRef>> dictionary;
decoder >> dictionary;
if (!dictionary)
return std::nullopt;
return WTFMove(*dictionary);
}
case CFType::CFNull:
return RetainPtr<CFNullRef>(kCFNull);
case CFType::CFNumber: {
std::optional<RetainPtr<CFNumberRef>> number;
decoder >> number;
if (!number)
return std::nullopt;
return WTFMove(*number);
}
case CFType::CFString: {
std::optional<RetainPtr<CFStringRef>> string;
decoder >> string;
if (!string)
return std::nullopt;
return WTFMove(*string);
}
case CFType::CFURL: {
std::optional<RetainPtr<CFURLRef>> url;
decoder >> url;
if (!url)
return std::nullopt;
return WTFMove(*url);
}
case CFType::CGColorSpace: {
std::optional<RetainPtr<CGColorSpaceRef>> colorSpace;
decoder >> colorSpace;
if (!colorSpace)
return std::nullopt;
return WTFMove(*colorSpace);
}
case CFType::SecCertificate: {
std::optional<RetainPtr<SecCertificateRef>> certificate;
decoder >> certificate;
if (!certificate)
return std::nullopt;
return WTFMove(*certificate);
}
#if HAVE(SEC_KEYCHAIN)
case CFType::SecKeychainItem: {
std::optional<RetainPtr<SecKeychainItemRef>> keychainItem;
decoder >> keychainItem;
if (!keychainItem)
return std::nullopt;
return WTFMove(*keychainItem);
}
#endif
#if HAVE(SEC_ACCESS_CONTROL)
case CFType::SecAccessControl: {
std::optional<RetainPtr<SecAccessControlRef>> accessControl;
decoder >> accessControl;
if (!accessControl)
return std::nullopt;
return WTFMove(*accessControl);
}
#endif
#if HAVE(SEC_TRUST_SERIALIZATION)
case CFType::SecTrust: {
std::optional<RetainPtr<SecTrustRef>> trust;
decoder >> trust;
if (!trust)
return std::nullopt;
return WTFMove(*trust);
}
#endif
case CFType::Nullptr:
return tokenNullptrTypeRef();
case CFType::Unknown:
break;
}
ASSERT_NOT_REACHED();
return std::nullopt;
}
template<typename Encoder>
void ArgumentCoder<CFArrayRef>::encode(Encoder& encoder, CFArrayRef array)
{
if (!array) {
encoder << true;
return;
}
encoder << false;
CFIndex size = CFArrayGetCount(array);
Vector<CFTypeRef, 32> values(size);
CFArrayGetValues(array, CFRangeMake(0, size), values.data());
HashSet<CFIndex> invalidIndices;
for (CFIndex i = 0; i < size; ++i) {
// Ignore values we don't support.
ASSERT(typeFromCFTypeRef(values[i]) != CFType::Unknown);
if (typeFromCFTypeRef(values[i]) == CFType::Unknown)
invalidIndices.add(i);
}
encoder << static_cast<uint64_t>(size - invalidIndices.size());
for (CFIndex i = 0; i < size; ++i) {
if (invalidIndices.contains(i))
continue;
encoder << values[i];
}
}
template void ArgumentCoder<CFArrayRef>::encode<Encoder>(Encoder&, CFArrayRef);
template void ArgumentCoder<CFArrayRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, CFArrayRef);
std::optional<RetainPtr<CFArrayRef>> ArgumentCoder<RetainPtr<CFArrayRef>>::decode(Decoder& decoder)
{
std::optional<bool> isNull;
decoder >> isNull;
if (!isNull)
return std::nullopt;
if (*isNull)
return {{ nullptr }};
std::optional<uint64_t> size;
decoder >> size;
if (!size)
return std::nullopt;
auto array = adoptCF(CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks));
for (size_t i = 0; i < *size; ++i) {
std::optional<RetainPtr<CFTypeRef>> element;
decoder >> element;
if (!element)
return std::nullopt;
if (!*element)
continue;
CFArrayAppendValue(array.get(), element->get());
}
return WTFMove(array);
}
template<typename Encoder>
void ArgumentCoder<CFBooleanRef>::encode(Encoder& encoder, CFBooleanRef boolean)
{
encoder << static_cast<bool>(CFBooleanGetValue(boolean));
}
template void ArgumentCoder<CFBooleanRef>::encode<Encoder>(Encoder&, CFBooleanRef);
template void ArgumentCoder<CFBooleanRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, CFBooleanRef);
std::optional<RetainPtr<CFBooleanRef>> ArgumentCoder<RetainPtr<CFBooleanRef>>::decode(Decoder& decoder)
{
std::optional<bool> boolean;
decoder >> boolean;
if (!boolean)
return std::nullopt;
return adoptCF(*boolean ? kCFBooleanTrue : kCFBooleanFalse);
}
template<typename Encoder>
void ArgumentCoder<CFDataRef>::encode(Encoder& encoder, CFDataRef data)
{
encoder << IPC::DataReference(CFDataGetBytePtr(data), CFDataGetLength(data));
}
template void ArgumentCoder<CFDataRef>::encode<Encoder>(Encoder&, CFDataRef);
template void ArgumentCoder<CFDataRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, CFDataRef);
template<typename Decoder>
std::optional<RetainPtr<CFDataRef>> ArgumentCoder<RetainPtr<CFDataRef>>::decode(Decoder& decoder)
{
std::optional<IPC::DataReference> dataReference;
decoder >> dataReference;
if (!dataReference)
return std::nullopt;
return adoptCF(CFDataCreate(0, dataReference->data(), dataReference->size()));
}
template std::optional<RetainPtr<CFDataRef>> ArgumentCoder<RetainPtr<CFDataRef>>::decode<Decoder>(Decoder&);
template std::optional<RetainPtr<CFDataRef>> ArgumentCoder<RetainPtr<CFDataRef>>::decode<WebKit::Daemon::Decoder>(WebKit::Daemon::Decoder&);
template<typename Encoder>
void ArgumentCoder<CFDateRef>::encode(Encoder& encoder, CFDateRef date)
{
encoder << static_cast<double>(CFDateGetAbsoluteTime(date));
}
template void ArgumentCoder<CFDateRef>::encode<Encoder>(Encoder&, CFDateRef);
template void ArgumentCoder<CFDateRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, CFDateRef);
std::optional<RetainPtr<CFDateRef>> ArgumentCoder<RetainPtr<CFDateRef>>::decode(Decoder& decoder)
{
std::optional<double> absoluteTime;
decoder >> absoluteTime;
if (!absoluteTime)
return std::nullopt;
return adoptCF(CFDateCreate(0, *absoluteTime));
}
template<typename Encoder>
void ArgumentCoder<CFDictionaryRef>::encode(Encoder& encoder, CFDictionaryRef dictionary)
{
if (!dictionary) {
encoder << true;
return;
}
encoder << false;
CFIndex size = CFDictionaryGetCount(dictionary);
Vector<CFTypeRef, 32> keys(size);
Vector<CFTypeRef, 32> values(size);
CFDictionaryGetKeysAndValues(dictionary, keys.data(), values.data());
HashSet<CFTypeRef> invalidKeys;
for (CFIndex i = 0; i < size; ++i) {
ASSERT(keys[i]);
ASSERT(values[i]);
// Ignore keys/values we don't support.
ASSERT(typeFromCFTypeRef(keys[i]) != CFType::Unknown);
ASSERT(typeFromCFTypeRef(values[i]) != CFType::Unknown);
if (typeFromCFTypeRef(keys[i]) == CFType::Unknown || typeFromCFTypeRef(values[i]) == CFType::Unknown)
invalidKeys.add(keys[i]);
}
encoder << static_cast<uint64_t>(size - invalidKeys.size());
for (CFIndex i = 0; i < size; ++i) {
if (invalidKeys.contains(keys[i]))
continue;
encoder << keys[i] << values[i];
}
}
template void ArgumentCoder<CFDictionaryRef>::encode<Encoder>(Encoder&, CFDictionaryRef);
template void ArgumentCoder<CFDictionaryRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, CFDictionaryRef);
std::optional<RetainPtr<CFDictionaryRef>> ArgumentCoder<RetainPtr<CFDictionaryRef>>::decode(Decoder& decoder)
{
std::optional<bool> isNull;
decoder >> isNull;
if (!isNull)
return std::nullopt;
if (*isNull)
return {{ nullptr }};
std::optional<uint64_t> size;
decoder >> size;
if (!size)
return std::nullopt;
RetainPtr<CFMutableDictionaryRef> dictionary = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
for (uint64_t i = 0; i < *size; ++i) {
std::optional<RetainPtr<CFTypeRef>> key;
decoder >> key;
if (!key || !*key)
return std::nullopt;
std::optional<RetainPtr<CFTypeRef>> value;
decoder >> value;
if (!value || !*value)
return std::nullopt;
CFDictionarySetValue(dictionary.get(), key->get(), value->get());
}
return WTFMove(dictionary);
}
template<typename Encoder>
void ArgumentCoder<CFNumberRef>::encode(Encoder& encoder, CFNumberRef number)
{
CFNumberType numberType = CFNumberGetType(number);
Vector<uint8_t> buffer(CFNumberGetByteSize(number));
bool result = CFNumberGetValue(number, numberType, buffer.data());
ASSERT_UNUSED(result, result);
encoder << static_cast<uint8_t>(numberType) << IPC::DataReference(buffer);
}
template void ArgumentCoder<CFNumberRef>::encode<Encoder>(Encoder&, CFNumberRef);
template void ArgumentCoder<CFNumberRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, CFNumberRef);
static size_t sizeForNumberType(CFNumberType numberType)
{
switch (numberType) {
case kCFNumberSInt8Type:
return sizeof(SInt8);
case kCFNumberSInt16Type:
return sizeof(SInt16);
case kCFNumberSInt32Type:
return sizeof(SInt32);
case kCFNumberSInt64Type:
return sizeof(SInt64);
case kCFNumberFloat32Type:
return sizeof(Float32);
case kCFNumberFloat64Type:
return sizeof(Float64);
case kCFNumberCharType:
return sizeof(char);
case kCFNumberShortType:
return sizeof(short);
case kCFNumberIntType:
return sizeof(int);
case kCFNumberLongType:
return sizeof(long);
case kCFNumberLongLongType:
return sizeof(long long);
case kCFNumberFloatType:
return sizeof(float);
case kCFNumberDoubleType:
return sizeof(double);
case kCFNumberCFIndexType:
return sizeof(CFIndex);
case kCFNumberNSIntegerType:
return sizeof(long);
case kCFNumberCGFloatType:
return sizeof(double);
}
return 0;
}
std::optional<RetainPtr<CFNumberRef>> ArgumentCoder<RetainPtr<CFNumberRef>>::decode(Decoder& decoder)
{
std::optional<uint8_t> numberTypeFromIPC;
decoder >> numberTypeFromIPC;
if (!numberTypeFromIPC || *numberTypeFromIPC > kCFNumberMaxType)
return std::nullopt;
auto numberType = static_cast<CFNumberType>(*numberTypeFromIPC);
std::optional<IPC::DataReference> dataReference;
decoder >> dataReference;
if (!dataReference)
return std::nullopt;
size_t neededBufferSize = sizeForNumberType(numberType);
if (!neededBufferSize || dataReference->size() != neededBufferSize)
return std::nullopt;
ASSERT(dataReference->data());
return adoptCF(CFNumberCreate(0, numberType, dataReference->data()));
}
template<typename Encoder>
void ArgumentCoder<CFStringRef>::encode(Encoder& encoder, CFStringRef string)
{
CFIndex length = CFStringGetLength(string);
CFStringEncoding encoding = CFStringGetFastestEncoding(string);
CFRange range = CFRangeMake(0, length);
CFIndex bufferLength = 0;
CFIndex numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, 0, 0, &bufferLength);
ASSERT(numConvertedBytes == length);
Vector<UInt8, 128> buffer(bufferLength);
numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, buffer.data(), buffer.size(), &bufferLength);
ASSERT(numConvertedBytes == length);
encoder << static_cast<uint32_t>(encoding) << IPC::DataReference(buffer);
}
template void ArgumentCoder<CFStringRef>::encode<Encoder>(Encoder&, CFStringRef);
template void ArgumentCoder<CFStringRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, CFStringRef);
std::optional<RetainPtr<CFStringRef>> ArgumentCoder<RetainPtr<CFStringRef>>::decode(Decoder& decoder)
{
std::optional<uint32_t> encodingFromIPC;
decoder >> encodingFromIPC;
if (!encodingFromIPC)
return std::nullopt;
auto encoding = static_cast<CFStringEncoding>(*encodingFromIPC);
if (!CFStringIsEncodingAvailable(encoding))
return std::nullopt;
std::optional<IPC::DataReference> dataReference;
decoder >> dataReference;
if (!dataReference)
return std::nullopt;
auto string = adoptCF(CFStringCreateWithBytes(0, dataReference->data(), dataReference->size(), encoding, false));
if (!string)
return std::nullopt;
return WTFMove(string);
}
template<typename Encoder>
void ArgumentCoder<CFURLRef>::encode(Encoder& encoder, CFURLRef url)
{
CFURLRef baseURL = CFURLGetBaseURL(url);
encoder << static_cast<bool>(baseURL);
if (baseURL)
encoder << baseURL;
WTF::URLCharBuffer urlBytes;
WTF::getURLBytes(url, urlBytes);
encoder << IPC::DataReference(reinterpret_cast<const uint8_t*>(urlBytes.data()), urlBytes.size());
}
template void ArgumentCoder<CFURLRef>::encode<Encoder>(Encoder&, CFURLRef);
template void ArgumentCoder<CFURLRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, CFURLRef);
std::optional<RetainPtr<CFURLRef>> ArgumentCoder<RetainPtr<CFURLRef>>::decode(Decoder& decoder)
{
RetainPtr<CFURLRef> baseURL;
std::optional<bool> hasBaseURL;
decoder >> hasBaseURL;
if (!hasBaseURL)
return std::nullopt;
if (*hasBaseURL) {
std::optional<RetainPtr<CFURLRef>> decodedBaseURL;
decoder >> decodedBaseURL;
if (!decodedBaseURL)
return std::nullopt;
baseURL = WTFMove(*decodedBaseURL);
}
std::optional<IPC::DataReference> urlBytes;
decoder >> urlBytes;
if (!urlBytes)
return std::nullopt;
#if USE(FOUNDATION)
// FIXME: Move this to ArgumentCodersCFMac.mm and change this file back to be C++
// instead of Objective-C++.
if (urlBytes->isEmpty()) {
// CFURL can't hold an empty URL, unlike NSURL.
// FIXME: This discards base URL, which seems incorrect.
return {{ (__bridge CFURLRef)[NSURL URLWithString:@""] }};
}
#endif
auto result = adoptCF(CFURLCreateAbsoluteURLWithBytes(nullptr, reinterpret_cast<const UInt8*>(urlBytes->data()), urlBytes->size(), kCFStringEncodingUTF8, baseURL.get(), true));
if (!result)
return std::nullopt;
return WTFMove(result);
}
enum class CGColorSpaceEncodingScheme { Name, PropertyList };
template<typename Encoder>
void ArgumentCoder<CGColorSpaceRef>::encode(Encoder& encoder, CGColorSpaceRef colorSpace)
{
if (auto name = CGColorSpaceGetName(colorSpace)) {
encoder << CGColorSpaceEncodingScheme::Name << name;
return;
}
encoder << CGColorSpaceEncodingScheme::PropertyList << adoptCF(CGColorSpaceCopyPropertyList(colorSpace));
}
template void ArgumentCoder<CGColorSpaceRef>::encode<Encoder>(Encoder&, CGColorSpaceRef);
template void ArgumentCoder<CGColorSpaceRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, CGColorSpaceRef);
std::optional<RetainPtr<CGColorSpaceRef>> ArgumentCoder<RetainPtr<CGColorSpaceRef>>::decode(Decoder& decoder)
{
std::optional<CGColorSpaceEncodingScheme> encodingScheme;
decoder >> encodingScheme;
if (!encodingScheme)
return std::nullopt;
switch (*encodingScheme) {
case CGColorSpaceEncodingScheme::Name: {
std::optional<RetainPtr<CFStringRef>> name;
decoder >> name;
if (!name)
return std::nullopt;
auto colorSpace = adoptCF(CGColorSpaceCreateWithName(name->get()));
if (!colorSpace)
return std::nullopt;
return WTFMove(colorSpace);
}
case CGColorSpaceEncodingScheme::PropertyList: {
std::optional<RetainPtr<CFTypeRef>> propertyList;
decoder >> propertyList;
if (!propertyList)
return std::nullopt;
auto colorSpace = adoptCF(CGColorSpaceCreateWithPropertyList(propertyList->get()));
if (!colorSpace)
return std::nullopt;
return WTFMove(colorSpace);
}
}
ASSERT_NOT_REACHED();
return std::nullopt;
}
template<typename Encoder>
void ArgumentCoder<SecCertificateRef>::encode(Encoder& encoder, SecCertificateRef certificate)
{
encoder << adoptCF(SecCertificateCopyData(certificate));
}
template void ArgumentCoder<SecCertificateRef>::encode<Encoder>(Encoder&, SecCertificateRef);
template void ArgumentCoder<SecCertificateRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, SecCertificateRef);
std::optional<RetainPtr<SecCertificateRef>> ArgumentCoder<RetainPtr<SecCertificateRef>>::decode(Decoder& decoder)
{
std::optional<RetainPtr<CFDataRef>> data;
decoder >> data;
if (!data)
return std::nullopt;
return adoptCF(SecCertificateCreateWithData(0, data->get()));
}
#if HAVE(SEC_KEYCHAIN)
template<typename Encoder>
void ArgumentCoder<SecKeychainItemRef>::encode(Encoder& encoder, SecKeychainItemRef keychainItem)
{
RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials));
CFDataRef data;
if (SecKeychainItemCreatePersistentReference(keychainItem, &data) == errSecSuccess) {
encoder << data;
CFRelease(data);
}
}
template void ArgumentCoder<SecKeychainItemRef>::encode<Encoder>(Encoder&, SecKeychainItemRef);
template void ArgumentCoder<SecKeychainItemRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, SecKeychainItemRef);
std::optional<RetainPtr<SecKeychainItemRef>> ArgumentCoder<RetainPtr<SecKeychainItemRef>>::decode(Decoder& decoder)
{
RELEASE_ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessCredentials));
std::optional<RetainPtr<CFDataRef>> data;
decoder >> data;
if (!data)
return std::nullopt;
CFDataRef dref = data->get();
// SecKeychainItemCopyFromPersistentReference() cannot handle 0-length CFDataRefs.
if (!CFDataGetLength(dref))
return std::nullopt;
SecKeychainItemRef item;
if (SecKeychainItemCopyFromPersistentReference(dref, &item) != errSecSuccess || !item)
return std::nullopt;
return adoptCF(item);
}
#endif
#if HAVE(SEC_ACCESS_CONTROL)
template<typename Encoder>
void ArgumentCoder<SecAccessControlRef>::encode(Encoder& encoder, SecAccessControlRef accessControl)
{
auto data = adoptCF(SecAccessControlCopyData(accessControl));
if (data)
encoder << data;
}
template void ArgumentCoder<SecAccessControlRef>::encode<Encoder>(Encoder&, SecAccessControlRef);
template void ArgumentCoder<SecAccessControlRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, SecAccessControlRef);
std::optional<RetainPtr<SecAccessControlRef>> ArgumentCoder<RetainPtr<SecAccessControlRef>>::decode(Decoder& decoder)
{
std::optional<RetainPtr<CFDataRef>> data;
decoder >> data;
if (!data)
return std::nullopt;
auto result = adoptCF(SecAccessControlCreateFromData(kCFAllocatorDefault, data->get(), nullptr));
if (!result)
return std::nullopt;
return WTFMove(result);
}
#endif
#if HAVE(SEC_TRUST_SERIALIZATION)
template<typename Encoder>
void ArgumentCoder<SecTrustRef>::encode(Encoder& encoder, SecTrustRef trust)
{
auto data = adoptCF(SecTrustSerialize(trust, nullptr));
if (!data) {
encoder << false;
return;
}
encoder << true << data;
}
template void ArgumentCoder<SecTrustRef>::encode<Encoder>(Encoder&, SecTrustRef);
template void ArgumentCoder<SecTrustRef>::encode<WebKit::Daemon::Encoder>(WebKit::Daemon::Encoder&, SecTrustRef);
template void ArgumentCoder<SecTrustRef>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, SecTrustRef);
template<typename Decoder>
std::optional<RetainPtr<SecTrustRef>> ArgumentCoder<RetainPtr<SecTrustRef>>::decode(Decoder& decoder)
{
std::optional<bool> hasTrust;
decoder >> hasTrust;
if (!hasTrust)
return std::nullopt;
if (!*hasTrust)
return { nullptr };
std::optional<RetainPtr<CFDataRef>> trustData;
decoder >> trustData;
if (!trustData)
return std::nullopt;
auto trust = adoptCF(SecTrustDeserialize(trustData->get(), nullptr));
if (!trust)
return std::nullopt;
return WTFMove(trust);
}
template std::optional<RetainPtr<SecTrustRef>> ArgumentCoder<RetainPtr<SecTrustRef>>::decode<Decoder>(Decoder&);
template std::optional<RetainPtr<SecTrustRef>> ArgumentCoder<RetainPtr<SecTrustRef>>::decode<WebKit::Daemon::Decoder>(WebKit::Daemon::Decoder&);
#endif
} // namespace IPC
namespace WTF {
template<> struct EnumTraits<IPC::CFType> {
using values = EnumValues<
IPC::CFType,
IPC::CFType::CFArray,
IPC::CFType::CFBoolean,
IPC::CFType::CFData,
IPC::CFType::CFDate,
IPC::CFType::CFDictionary,
IPC::CFType::CFNull,
IPC::CFType::CFNumber,
IPC::CFType::CFString,
IPC::CFType::CFURL,
IPC::CFType::SecCertificate,
#if HAVE(SEC_KEYCHAIN)
IPC::CFType::SecKeychainItem,
#endif
#if HAVE(SEC_ACCESS_CONTROL)
IPC::CFType::SecAccessControl,
#endif
#if HAVE(SEC_TRUST_SERIALIZATION)
IPC::CFType::SecTrust,
#endif
IPC::CFType::CGColorSpace,
IPC::CFType::Nullptr,
IPC::CFType::Unknown
>;
};
template<> struct EnumTraits<IPC::CGColorSpaceEncodingScheme> {
using values = EnumValues<
IPC::CGColorSpaceEncodingScheme,
IPC::CGColorSpaceEncodingScheme::Name,
IPC::CGColorSpaceEncodingScheme::PropertyList
>;
};
} // namespace WTF