diff options
Diffstat (limited to 'Source/WebKit2/Shared/cf/ArgumentCodersCF.cpp')
-rw-r--r-- | Source/WebKit2/Shared/cf/ArgumentCodersCF.cpp | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/Source/WebKit2/Shared/cf/ArgumentCodersCF.cpp b/Source/WebKit2/Shared/cf/ArgumentCodersCF.cpp new file mode 100644 index 0000000..4edf46f --- /dev/null +++ b/Source/WebKit2/Shared/cf/ArgumentCodersCF.cpp @@ -0,0 +1,462 @@ +/* + * Copyright (C) 2010 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. + */ + +#include "ArgumentCodersCF.h" + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include "DataReference.h" +#include <wtf/Vector.h> + +namespace CoreIPC { + +CFTypeRef tokenNullTypeRef() +{ + static CFStringRef tokenNullType = CFSTR("WKNull"); + return tokenNullType; +} + +enum CFType { + CFArray, + CFBoolean, + CFData, + CFDictionary, + CFNull, + CFNumber, + CFString, + CFURL, + Null, + Unknown, +}; + +static CFType typeFromCFTypeRef(CFTypeRef type) +{ + ASSERT(type); + + if (type == tokenNullTypeRef()) + return Null; + + CFTypeID typeID = CFGetTypeID(type); + if (typeID == CFArrayGetTypeID()) + return CFArray; + if (typeID == CFBooleanGetTypeID()) + return CFBoolean; + if (typeID == CFDataGetTypeID()) + return CFData; + if (typeID == CFDictionaryGetTypeID()) + return CFDictionary; + if (typeID == CFNullGetTypeID()) + return CFNull; + if (typeID == CFNumberGetTypeID()) + return CFNumber; + if (typeID == CFStringGetTypeID()) + return CFString; + if (typeID == CFURLGetTypeID()) + return CFURL; + + ASSERT_NOT_REACHED(); + return Unknown; +} + +static void encode(ArgumentEncoder* encoder, CFTypeRef typeRef) +{ + CFType type = typeFromCFTypeRef(typeRef); + encoder->encodeEnum(type); + + switch (type) { + case CFArray: + encode(encoder, static_cast<CFArrayRef>(typeRef)); + return; + case CFBoolean: + encode(encoder, static_cast<CFBooleanRef>(typeRef)); + return; + case CFData: + encode(encoder, static_cast<CFDataRef>(typeRef)); + return; + case CFDictionary: + encode(encoder, static_cast<CFDictionaryRef>(typeRef)); + return; + case CFNull: + return; + case CFNumber: + encode(encoder, static_cast<CFNumberRef>(typeRef)); + return; + case CFString: + encode(encoder, static_cast<CFStringRef>(typeRef)); + return; + case CFURL: + encode(encoder, static_cast<CFURLRef>(typeRef)); + return; + case Null: + return; + case Unknown: + break; + } + + ASSERT_NOT_REACHED(); +} + +static bool decode(ArgumentDecoder* decoder, RetainPtr<CFTypeRef>& result) +{ + CFType type; + if (!decoder->decodeEnum(type)) + return false; + + switch (type) { + case CFArray: { + RetainPtr<CFArrayRef> array; + if (!decode(decoder, array)) + return false; + result.adoptCF(array.leakRef()); + return true; + } + case CFBoolean: { + RetainPtr<CFBooleanRef> boolean; + if (!decode(decoder, boolean)) + return false; + result.adoptCF(boolean.leakRef()); + return true; + } + case CFData: { + RetainPtr<CFDataRef> data; + if (!decode(decoder, data)) + return false; + result.adoptCF(data.leakRef()); + return true; + } + case CFDictionary: { + RetainPtr<CFDictionaryRef> dictionary; + if (!decode(decoder, dictionary)) + return false; + result.adoptCF(dictionary.leakRef()); + return true; + } + case CFNull: + result.adoptCF(kCFNull); + return true; + case CFNumber: { + RetainPtr<CFNumberRef> number; + if (!decode(decoder, number)) + return false; + result.adoptCF(number.leakRef()); + return true; + } + case CFString: { + RetainPtr<CFStringRef> string; + if (!decode(decoder, string)) + return false; + result.adoptCF(string.leakRef()); + return true; + } + case CFURL: { + RetainPtr<CFURLRef> url; + if (!decode(decoder, url)) + return false; + result.adoptCF(url.leakRef()); + return true; + } + case Null: + result = tokenNullTypeRef(); + return true; + case Unknown: + ASSERT_NOT_REACHED(); + return false; + } + + return false; +} + +void encode(ArgumentEncoder* encoder, CFArrayRef array) +{ + CFIndex size = CFArrayGetCount(array); + Vector<CFTypeRef, 32> values(size); + + CFArrayGetValues(array, CFRangeMake(0, size), values.data()); + + encoder->encodeUInt64(size); + for (CFIndex i = 0; i < size; ++i) { + ASSERT(values[i]); + + encode(encoder, values[i]); + } +} + +bool decode(ArgumentDecoder* decoder, RetainPtr<CFArrayRef>& result) +{ + uint64_t size; + if (!decoder->decodeUInt64(size)) + return false; + + RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); + + for (size_t i = 0; i < size; ++i) { + RetainPtr<CFTypeRef> element; + if (!decode(decoder, element)) + return false; + + CFArrayAppendValue(array.get(), element.get()); + } + + result.adoptCF(array.leakRef()); + return true; +} + +void encode(ArgumentEncoder* encoder, CFBooleanRef boolean) +{ + encoder->encodeBool(CFBooleanGetValue(boolean)); +} + +bool decode(ArgumentDecoder* decoder, RetainPtr<CFBooleanRef>& result) +{ + bool boolean; + if (!decoder->decode(boolean)) + return false; + + result.adoptCF(boolean ? kCFBooleanTrue : kCFBooleanFalse); + return true; +} + +void encode(ArgumentEncoder* encoder, CFDataRef data) +{ + CFIndex length = CFDataGetLength(data); + const UInt8* bytePtr = CFDataGetBytePtr(data); + + encoder->encodeBytes(bytePtr, length); +} + +bool decode(ArgumentDecoder* decoder, RetainPtr<CFDataRef>& result) +{ + CoreIPC::DataReference dataReference; + if (!decoder->decode(dataReference)) + return false; + + result.adoptCF(CFDataCreate(0, dataReference.data(), dataReference.size())); + return true; +} + +void encode(ArgumentEncoder* encoder, CFDictionaryRef dictionary) +{ + CFIndex size = CFDictionaryGetCount(dictionary); + Vector<CFTypeRef, 32> keys(size); + Vector<CFTypeRef, 32> values(size); + + CFDictionaryGetKeysAndValues(dictionary, keys.data(), values.data()); + + encoder->encodeUInt64(size); + + for (CFIndex i = 0; i < size; ++i) { + ASSERT(keys[i]); + ASSERT(CFGetTypeID(keys[i]) == CFStringGetTypeID()); + ASSERT(values[i]); + + // Ignore values we don't recognize. + if (typeFromCFTypeRef(values[i]) == Unknown) + continue; + + encode(encoder, static_cast<CFStringRef>(keys[i])); + encode(encoder, values[i]); + } +} + +bool decode(ArgumentDecoder* decoder, RetainPtr<CFDictionaryRef>& result) +{ + uint64_t size; + if (!decoder->decodeUInt64(size)) + return false; + + RetainPtr<CFMutableDictionaryRef> dictionary(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + for (uint64_t i = 0; i < size; ++i) { + // Try to decode the key name. + RetainPtr<CFStringRef> key; + if (!decode(decoder, key)) + return false; + + RetainPtr<CFTypeRef> value; + if (!decode(decoder, value)) + return false; + + CFDictionarySetValue(dictionary.get(), key.get(), value.get()); + } + + result.adoptCF(dictionary.releaseRef()); + return true; +} + +void encode(ArgumentEncoder* 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->encodeEnum(numberType); + encoder->encodeBytes(buffer.data(), buffer.size()); +} + +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: +#ifdef __LP64__ + return sizeof(long); +#else + return sizeof(int); +#endif + case kCFNumberCGFloatType: +#ifdef __LP64__ + return sizeof(double); +#else + return sizeof(float); +#endif + } + + return 0; +} + +bool decode(ArgumentDecoder* decoder, RetainPtr<CFNumberRef>& result) +{ + CFNumberType numberType; + if (!decoder->decodeEnum(numberType)) + return false; + + CoreIPC::DataReference dataReference; + if (!decoder->decode(dataReference)) + return false; + + size_t neededBufferSize = sizeForNumberType(numberType); + if (!neededBufferSize || dataReference.size() != neededBufferSize) + return false; + + ASSERT(dataReference.data()); + CFNumberRef number = CFNumberCreate(0, numberType, dataReference.data()); + result.adoptCF(number); + + return true; +} + +void encode(ArgumentEncoder* 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->encodeEnum(encoding); + encoder->encodeBytes(buffer.data(), bufferLength); +} + +bool decode(ArgumentDecoder* decoder, RetainPtr<CFStringRef>& result) +{ + CFStringEncoding encoding; + if (!decoder->decodeEnum(encoding)) + return false; + + if (!CFStringIsEncodingAvailable(encoding)) + return false; + + CoreIPC::DataReference dataReference; + if (!decoder->decode(dataReference)) + return false; + + CFStringRef string = CFStringCreateWithBytes(0, dataReference.data(), dataReference.size(), encoding, false); + if (!string) + return false; + + result.adoptCF(string); + return true; +} + +void encode(ArgumentEncoder* encoder, CFURLRef url) +{ + CFURLRef baseURL = CFURLGetBaseURL(url); + encoder->encodeBool(baseURL); + if (baseURL) + encode(encoder, baseURL); + + encode(encoder, CFURLGetString(url)); +} + +bool decode(ArgumentDecoder* decoder, RetainPtr<CFURLRef>& result) +{ + RetainPtr<CFURLRef> baseURL; + bool hasBaseURL; + if (!decoder->decodeBool(hasBaseURL)) + return false; + if (hasBaseURL) { + if (!decode(decoder, baseURL)) + return false; + } + + RetainPtr<CFStringRef> string; + if (!decode(decoder, string)) + return false; + + CFURLRef url = CFURLCreateWithString(0, string.get(), baseURL.get()); + if (!url) + return false; + + result.adoptCF(url); + return true; +} + +} // namespace CoreIPC + |