Home | History | Annotate | Download | only in cf
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "ArgumentCodersCF.h"
     28 
     29 #include "ArgumentDecoder.h"
     30 #include "ArgumentEncoder.h"
     31 #include "DataReference.h"
     32 #include <wtf/Vector.h>
     33 
     34 namespace CoreIPC {
     35 
     36 CFTypeRef tokenNullTypeRef()
     37 {
     38     static CFStringRef tokenNullType = CFSTR("WKNull");
     39     return tokenNullType;
     40 }
     41 
     42 enum CFType {
     43     CFArray,
     44     CFBoolean,
     45     CFData,
     46     CFDictionary,
     47     CFNull,
     48     CFNumber,
     49     CFString,
     50     CFURL,
     51 #if PLATFORM(MAC)
     52     SecCertificate,
     53 #endif
     54     Null,
     55     Unknown,
     56 };
     57 
     58 static CFType typeFromCFTypeRef(CFTypeRef type)
     59 {
     60     ASSERT(type);
     61 
     62     if (type == tokenNullTypeRef())
     63         return Null;
     64 
     65     CFTypeID typeID = CFGetTypeID(type);
     66     if (typeID == CFArrayGetTypeID())
     67         return CFArray;
     68     if (typeID == CFBooleanGetTypeID())
     69         return CFBoolean;
     70     if (typeID == CFDataGetTypeID())
     71         return CFData;
     72     if (typeID == CFDictionaryGetTypeID())
     73         return CFDictionary;
     74     if (typeID == CFNullGetTypeID())
     75         return CFNull;
     76     if (typeID == CFNumberGetTypeID())
     77         return CFNumber;
     78     if (typeID == CFStringGetTypeID())
     79         return CFString;
     80     if (typeID == CFURLGetTypeID())
     81         return CFURL;
     82 #if PLATFORM(MAC)
     83     if (typeID == SecCertificateGetTypeID())
     84         return SecCertificate;
     85 #endif
     86 
     87     ASSERT_NOT_REACHED();
     88     return Unknown;
     89 }
     90 
     91 static void encode(ArgumentEncoder* encoder, CFTypeRef typeRef)
     92 {
     93     CFType type = typeFromCFTypeRef(typeRef);
     94     encoder->encodeEnum(type);
     95 
     96     switch (type) {
     97     case CFArray:
     98         encode(encoder, static_cast<CFArrayRef>(typeRef));
     99         return;
    100     case CFBoolean:
    101         encode(encoder, static_cast<CFBooleanRef>(typeRef));
    102         return;
    103     case CFData:
    104         encode(encoder, static_cast<CFDataRef>(typeRef));
    105         return;
    106     case CFDictionary:
    107         encode(encoder, static_cast<CFDictionaryRef>(typeRef));
    108         return;
    109     case CFNull:
    110         return;
    111     case CFNumber:
    112         encode(encoder, static_cast<CFNumberRef>(typeRef));
    113         return;
    114     case CFString:
    115         encode(encoder, static_cast<CFStringRef>(typeRef));
    116         return;
    117     case CFURL:
    118         encode(encoder, static_cast<CFURLRef>(typeRef));
    119         return;
    120 #if PLATFORM(MAC)
    121     case SecCertificate:
    122         encode(encoder, (SecCertificateRef)typeRef);
    123         return;
    124 #endif
    125     case Null:
    126         return;
    127     case Unknown:
    128         break;
    129     }
    130 
    131     ASSERT_NOT_REACHED();
    132 }
    133 
    134 static bool decode(ArgumentDecoder* decoder, RetainPtr<CFTypeRef>& result)
    135 {
    136     CFType type;
    137     if (!decoder->decodeEnum(type))
    138         return false;
    139 
    140     switch (type) {
    141     case CFArray: {
    142         RetainPtr<CFArrayRef> array;
    143         if (!decode(decoder, array))
    144             return false;
    145         result.adoptCF(array.leakRef());
    146         return true;
    147     }
    148     case CFBoolean: {
    149         RetainPtr<CFBooleanRef> boolean;
    150         if (!decode(decoder, boolean))
    151             return false;
    152         result.adoptCF(boolean.leakRef());
    153         return true;
    154     }
    155     case CFData: {
    156         RetainPtr<CFDataRef> data;
    157         if (!decode(decoder, data))
    158             return false;
    159         result.adoptCF(data.leakRef());
    160         return true;
    161     }
    162     case CFDictionary: {
    163         RetainPtr<CFDictionaryRef> dictionary;
    164         if (!decode(decoder, dictionary))
    165             return false;
    166         result.adoptCF(dictionary.leakRef());
    167         return true;
    168     }
    169     case CFNull:
    170         result.adoptCF(kCFNull);
    171         return true;
    172     case CFNumber: {
    173         RetainPtr<CFNumberRef> number;
    174         if (!decode(decoder, number))
    175             return false;
    176         result.adoptCF(number.leakRef());
    177         return true;
    178     }
    179     case CFString: {
    180         RetainPtr<CFStringRef> string;
    181         if (!decode(decoder, string))
    182             return false;
    183         result.adoptCF(string.leakRef());
    184         return true;
    185     }
    186     case CFURL: {
    187         RetainPtr<CFURLRef> url;
    188         if (!decode(decoder, url))
    189             return false;
    190         result.adoptCF(url.leakRef());
    191         return true;
    192     }
    193 #if PLATFORM(MAC)
    194     case SecCertificate: {
    195         RetainPtr<SecCertificateRef> certificate;
    196         if (!decode(decoder, certificate))
    197             return false;
    198         result.adoptCF(certificate.leakRef());
    199         return true;
    200     }
    201 #endif
    202     case Null:
    203         result = tokenNullTypeRef();
    204         return true;
    205     case Unknown:
    206         ASSERT_NOT_REACHED();
    207         return false;
    208     }
    209 
    210     return false;
    211 }
    212 
    213 void encode(ArgumentEncoder* encoder, CFArrayRef array)
    214 {
    215     CFIndex size = CFArrayGetCount(array);
    216     Vector<CFTypeRef, 32> values(size);
    217 
    218     CFArrayGetValues(array, CFRangeMake(0, size), values.data());
    219 
    220     encoder->encodeUInt64(size);
    221     for (CFIndex i = 0; i < size; ++i) {
    222         ASSERT(values[i]);
    223 
    224         encode(encoder, values[i]);
    225     }
    226 }
    227 
    228 bool decode(ArgumentDecoder* decoder, RetainPtr<CFArrayRef>& result)
    229 {
    230     uint64_t size;
    231     if (!decoder->decodeUInt64(size))
    232         return false;
    233 
    234     RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks));
    235 
    236     for (size_t i = 0; i < size; ++i) {
    237         RetainPtr<CFTypeRef> element;
    238         if (!decode(decoder, element))
    239             return false;
    240 
    241         CFArrayAppendValue(array.get(), element.get());
    242     }
    243 
    244     result.adoptCF(array.leakRef());
    245     return true;
    246 }
    247 
    248 void encode(ArgumentEncoder* encoder, CFBooleanRef boolean)
    249 {
    250     encoder->encodeBool(CFBooleanGetValue(boolean));
    251 }
    252 
    253 bool decode(ArgumentDecoder* decoder, RetainPtr<CFBooleanRef>& result)
    254 {
    255     bool boolean;
    256     if (!decoder->decode(boolean))
    257         return false;
    258 
    259     result.adoptCF(boolean ? kCFBooleanTrue : kCFBooleanFalse);
    260     return true;
    261 }
    262 
    263 void encode(ArgumentEncoder* encoder, CFDataRef data)
    264 {
    265     CFIndex length = CFDataGetLength(data);
    266     const UInt8* bytePtr = CFDataGetBytePtr(data);
    267 
    268     encoder->encodeBytes(bytePtr, length);
    269 }
    270 
    271 bool decode(ArgumentDecoder* decoder, RetainPtr<CFDataRef>& result)
    272 {
    273     CoreIPC::DataReference dataReference;
    274     if (!decoder->decode(dataReference))
    275         return false;
    276 
    277     result.adoptCF(CFDataCreate(0, dataReference.data(), dataReference.size()));
    278     return true;
    279 }
    280 
    281 void encode(ArgumentEncoder* encoder, CFDictionaryRef dictionary)
    282 {
    283     CFIndex size = CFDictionaryGetCount(dictionary);
    284     Vector<CFTypeRef, 32> keys(size);
    285     Vector<CFTypeRef, 32> values(size);
    286 
    287     CFDictionaryGetKeysAndValues(dictionary, keys.data(), values.data());
    288 
    289     encoder->encodeUInt64(size);
    290 
    291     for (CFIndex i = 0; i < size; ++i) {
    292         ASSERT(keys[i]);
    293         ASSERT(CFGetTypeID(keys[i]) == CFStringGetTypeID());
    294         ASSERT(values[i]);
    295 
    296         // Ignore values we don't recognize.
    297         if (typeFromCFTypeRef(values[i]) == Unknown)
    298             continue;
    299 
    300         encode(encoder, static_cast<CFStringRef>(keys[i]));
    301         encode(encoder, values[i]);
    302     }
    303 }
    304 
    305 bool decode(ArgumentDecoder* decoder, RetainPtr<CFDictionaryRef>& result)
    306 {
    307     uint64_t size;
    308     if (!decoder->decodeUInt64(size))
    309         return false;
    310 
    311     RetainPtr<CFMutableDictionaryRef> dictionary(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
    312     for (uint64_t i = 0; i < size; ++i) {
    313         // Try to decode the key name.
    314         RetainPtr<CFStringRef> key;
    315         if (!decode(decoder, key))
    316             return false;
    317 
    318         RetainPtr<CFTypeRef> value;
    319         if (!decode(decoder, value))
    320             return false;
    321 
    322         CFDictionarySetValue(dictionary.get(), key.get(), value.get());
    323     }
    324 
    325     result.adoptCF(dictionary.releaseRef());
    326     return true;
    327 }
    328 
    329 void encode(ArgumentEncoder* encoder, CFNumberRef number)
    330 {
    331     CFNumberType numberType = CFNumberGetType(number);
    332 
    333     Vector<uint8_t> buffer(CFNumberGetByteSize(number));
    334     bool result = CFNumberGetValue(number, numberType, buffer.data());
    335     ASSERT_UNUSED(result, result);
    336 
    337     encoder->encodeEnum(numberType);
    338     encoder->encodeBytes(buffer.data(), buffer.size());
    339 }
    340 
    341 static size_t sizeForNumberType(CFNumberType numberType)
    342 {
    343     switch (numberType) {
    344     case kCFNumberSInt8Type:
    345         return sizeof(SInt8);
    346     case kCFNumberSInt16Type:
    347         return sizeof(SInt16);
    348     case kCFNumberSInt32Type:
    349         return sizeof(SInt32);
    350     case kCFNumberSInt64Type:
    351         return sizeof(SInt64);
    352     case kCFNumberFloat32Type:
    353         return sizeof(Float32);
    354     case kCFNumberFloat64Type:
    355         return sizeof(Float64);
    356     case kCFNumberCharType:
    357         return sizeof(char);
    358     case kCFNumberShortType:
    359         return sizeof(short);
    360     case kCFNumberIntType:
    361         return sizeof(int);
    362     case kCFNumberLongType:
    363         return sizeof(long);
    364     case kCFNumberLongLongType:
    365         return sizeof(long long);
    366     case kCFNumberFloatType:
    367         return sizeof(float);
    368     case kCFNumberDoubleType:
    369         return sizeof(double);
    370     case kCFNumberCFIndexType:
    371         return sizeof(CFIndex);
    372     case kCFNumberNSIntegerType:
    373 #ifdef __LP64__
    374         return sizeof(long);
    375 #else
    376         return sizeof(int);
    377 #endif
    378     case kCFNumberCGFloatType:
    379 #ifdef __LP64__
    380         return sizeof(double);
    381 #else
    382         return sizeof(float);
    383 #endif
    384     }
    385 
    386     return 0;
    387 }
    388 
    389 bool decode(ArgumentDecoder* decoder, RetainPtr<CFNumberRef>& result)
    390 {
    391     CFNumberType numberType;
    392     if (!decoder->decodeEnum(numberType))
    393         return false;
    394 
    395     CoreIPC::DataReference dataReference;
    396     if (!decoder->decode(dataReference))
    397         return false;
    398 
    399     size_t neededBufferSize = sizeForNumberType(numberType);
    400     if (!neededBufferSize || dataReference.size() != neededBufferSize)
    401         return false;
    402 
    403     ASSERT(dataReference.data());
    404     CFNumberRef number = CFNumberCreate(0, numberType, dataReference.data());
    405     result.adoptCF(number);
    406 
    407     return true;
    408 }
    409 
    410 void encode(ArgumentEncoder* encoder, CFStringRef string)
    411 {
    412     CFIndex length = CFStringGetLength(string);
    413     CFStringEncoding encoding = CFStringGetFastestEncoding(string);
    414 
    415     CFRange range = CFRangeMake(0, length);
    416     CFIndex bufferLength = 0;
    417 
    418     CFIndex numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, 0, 0, &bufferLength);
    419     ASSERT(numConvertedBytes == length);
    420 
    421     Vector<UInt8, 128> buffer(bufferLength);
    422     numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, buffer.data(), buffer.size(), &bufferLength);
    423     ASSERT(numConvertedBytes == length);
    424 
    425     encoder->encodeEnum(encoding);
    426     encoder->encodeBytes(buffer.data(), bufferLength);
    427 }
    428 
    429 bool decode(ArgumentDecoder* decoder, RetainPtr<CFStringRef>& result)
    430 {
    431     CFStringEncoding encoding;
    432     if (!decoder->decodeEnum(encoding))
    433         return false;
    434 
    435     if (!CFStringIsEncodingAvailable(encoding))
    436         return false;
    437 
    438     CoreIPC::DataReference dataReference;
    439     if (!decoder->decode(dataReference))
    440         return false;
    441 
    442     CFStringRef string = CFStringCreateWithBytes(0, dataReference.data(), dataReference.size(), encoding, false);
    443     if (!string)
    444         return false;
    445 
    446     result.adoptCF(string);
    447     return true;
    448 }
    449 
    450 void encode(ArgumentEncoder* encoder, CFURLRef url)
    451 {
    452     CFURLRef baseURL = CFURLGetBaseURL(url);
    453     encoder->encodeBool(baseURL);
    454     if (baseURL)
    455         encode(encoder, baseURL);
    456 
    457     encode(encoder, CFURLGetString(url));
    458 }
    459 
    460 bool decode(ArgumentDecoder* decoder, RetainPtr<CFURLRef>& result)
    461 {
    462     RetainPtr<CFURLRef> baseURL;
    463     bool hasBaseURL;
    464     if (!decoder->decodeBool(hasBaseURL))
    465         return false;
    466     if (hasBaseURL) {
    467         if (!decode(decoder, baseURL))
    468             return false;
    469     }
    470 
    471     RetainPtr<CFStringRef> string;
    472     if (!decode(decoder, string))
    473         return false;
    474 
    475     CFURLRef url = CFURLCreateWithString(0, string.get(), baseURL.get());
    476     if (!url)
    477         return false;
    478 
    479     result.adoptCF(url);
    480     return true;
    481 }
    482 
    483 #if PLATFORM(MAC)
    484 void encode(ArgumentEncoder* encoder, SecCertificateRef certificate)
    485 {
    486     RetainPtr<CFDataRef> data(AdoptCF, SecCertificateCopyData(certificate));
    487     encode(encoder, data.get());
    488 }
    489 
    490 bool decode(ArgumentDecoder* decoder, RetainPtr<SecCertificateRef>& result)
    491 {
    492     RetainPtr<CFDataRef> data;
    493     if (!decode(decoder, data))
    494         return false;
    495 
    496     result.adoptCF(SecCertificateCreateWithData(0, data.get()));
    497     return true;
    498 }
    499 #endif
    500 
    501 } // namespace CoreIPC
    502