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 34namespace CoreIPC { 35 36CFTypeRef tokenNullTypeRef() 37{ 38 static CFStringRef tokenNullType = CFSTR("WKNull"); 39 return tokenNullType; 40} 41 42enum 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 58static 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 91static 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 134static 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 213void 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 228bool 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 248void encode(ArgumentEncoder* encoder, CFBooleanRef boolean) 249{ 250 encoder->encodeBool(CFBooleanGetValue(boolean)); 251} 252 253bool 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 263void 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 271bool 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 281void 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 305bool 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 329void 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 341static 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 389bool 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 410void 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 429bool 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 450void 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 460bool 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) 484void encode(ArgumentEncoder* encoder, SecCertificateRef certificate) 485{ 486 RetainPtr<CFDataRef> data(AdoptCF, SecCertificateCopyData(certificate)); 487 encode(encoder, data.get()); 488} 489 490bool 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