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 <WebCore/CFURLExtras.h> 33#include <wtf/Vector.h> 34 35#if PLATFORM(MAC) 36#import <Foundation/Foundation.h> 37#endif 38 39using namespace WebCore; 40 41namespace CoreIPC { 42 43CFTypeRef tokenNullTypeRef() 44{ 45 static CFStringRef tokenNullType = CFSTR("WKNull"); 46 return tokenNullType; 47} 48 49enum CFType { 50 CFArray, 51 CFBoolean, 52 CFData, 53 CFDate, 54 CFDictionary, 55 CFNull, 56 CFNumber, 57 CFString, 58 CFURL, 59#if USE(SECURITY_FRAMEWORK) 60 SecCertificate, 61 SecKeychainItem, 62#endif 63 Null, 64 Unknown, 65}; 66 67static CFType typeFromCFTypeRef(CFTypeRef type) 68{ 69 ASSERT(type); 70 71 if (type == tokenNullTypeRef()) 72 return Null; 73 74 CFTypeID typeID = CFGetTypeID(type); 75 if (typeID == CFArrayGetTypeID()) 76 return CFArray; 77 if (typeID == CFBooleanGetTypeID()) 78 return CFBoolean; 79 if (typeID == CFDataGetTypeID()) 80 return CFData; 81 if (typeID == CFDateGetTypeID()) 82 return CFDate; 83 if (typeID == CFDictionaryGetTypeID()) 84 return CFDictionary; 85 if (typeID == CFNullGetTypeID()) 86 return CFNull; 87 if (typeID == CFNumberGetTypeID()) 88 return CFNumber; 89 if (typeID == CFStringGetTypeID()) 90 return CFString; 91 if (typeID == CFURLGetTypeID()) 92 return CFURL; 93#if USE(SECURITY_FRAMEWORK) 94 if (typeID == SecCertificateGetTypeID()) 95 return SecCertificate; 96 if (typeID == SecKeychainItemGetTypeID()) 97 return SecKeychainItem; 98#endif 99 100 ASSERT_NOT_REACHED(); 101 return Unknown; 102} 103 104void encode(ArgumentEncoder& encoder, CFTypeRef typeRef) 105{ 106 CFType type = typeFromCFTypeRef(typeRef); 107 encoder.encodeEnum(type); 108 109 switch (type) { 110 case CFArray: 111 encode(encoder, static_cast<CFArrayRef>(typeRef)); 112 return; 113 case CFBoolean: 114 encode(encoder, static_cast<CFBooleanRef>(typeRef)); 115 return; 116 case CFData: 117 encode(encoder, static_cast<CFDataRef>(typeRef)); 118 return; 119 case CFDate: 120 encode(encoder, static_cast<CFDateRef>(typeRef)); 121 return; 122 case CFDictionary: 123 encode(encoder, static_cast<CFDictionaryRef>(typeRef)); 124 return; 125 case CFNull: 126 return; 127 case CFNumber: 128 encode(encoder, static_cast<CFNumberRef>(typeRef)); 129 return; 130 case CFString: 131 encode(encoder, static_cast<CFStringRef>(typeRef)); 132 return; 133 case CFURL: 134 encode(encoder, static_cast<CFURLRef>(typeRef)); 135 return; 136#if USE(SECURITY_FRAMEWORK) 137 case SecCertificate: 138 encode(encoder, (SecCertificateRef)typeRef); 139 return; 140 case SecKeychainItem: 141 encode(encoder, (SecKeychainItemRef)typeRef); 142 return; 143#endif 144 case Null: 145 return; 146 case Unknown: 147 break; 148 } 149 150 ASSERT_NOT_REACHED(); 151} 152 153bool decode(ArgumentDecoder& decoder, RetainPtr<CFTypeRef>& result) 154{ 155 CFType type; 156 if (!decoder.decodeEnum(type)) 157 return false; 158 159 switch (type) { 160 case CFArray: { 161 RetainPtr<CFArrayRef> array; 162 if (!decode(decoder, array)) 163 return false; 164 result = adoptCF(array.leakRef()); 165 return true; 166 } 167 case CFBoolean: { 168 RetainPtr<CFBooleanRef> boolean; 169 if (!decode(decoder, boolean)) 170 return false; 171 result = adoptCF(boolean.leakRef()); 172 return true; 173 } 174 case CFData: { 175 RetainPtr<CFDataRef> data; 176 if (!decode(decoder, data)) 177 return false; 178 result = adoptCF(data.leakRef()); 179 return true; 180 } 181 case CFDate: { 182 RetainPtr<CFDateRef> date; 183 if (!decode(decoder, date)) 184 return false; 185 result = adoptCF(date.leakRef()); 186 return true; 187 } 188 case CFDictionary: { 189 RetainPtr<CFDictionaryRef> dictionary; 190 if (!decode(decoder, dictionary)) 191 return false; 192 result = adoptCF(dictionary.leakRef()); 193 return true; 194 } 195 case CFNull: 196 result = adoptCF(kCFNull); 197 return true; 198 case CFNumber: { 199 RetainPtr<CFNumberRef> number; 200 if (!decode(decoder, number)) 201 return false; 202 result = adoptCF(number.leakRef()); 203 return true; 204 } 205 case CFString: { 206 RetainPtr<CFStringRef> string; 207 if (!decode(decoder, string)) 208 return false; 209 result = adoptCF(string.leakRef()); 210 return true; 211 } 212 case CFURL: { 213 RetainPtr<CFURLRef> url; 214 if (!decode(decoder, url)) 215 return false; 216 result = adoptCF(url.leakRef()); 217 return true; 218 } 219#if USE(SECURITY_FRAMEWORK) 220 case SecCertificate: { 221 RetainPtr<SecCertificateRef> certificate; 222 if (!decode(decoder, certificate)) 223 return false; 224 result = adoptCF(certificate.leakRef()); 225 return true; 226 } 227 case SecKeychainItem: { 228 RetainPtr<SecKeychainItemRef> keychainItem; 229 if (!decode(decoder, keychainItem)) 230 return false; 231 result = adoptCF(keychainItem.leakRef()); 232 return true; 233 } 234#endif 235 case Null: 236 result = tokenNullTypeRef(); 237 return true; 238 case Unknown: 239 ASSERT_NOT_REACHED(); 240 return false; 241 } 242 243 return false; 244} 245 246void encode(ArgumentEncoder& encoder, CFArrayRef array) 247{ 248 CFIndex size = CFArrayGetCount(array); 249 Vector<CFTypeRef, 32> values(size); 250 251 CFArrayGetValues(array, CFRangeMake(0, size), values.data()); 252 253 encoder << static_cast<uint64_t>(size); 254 255 for (CFIndex i = 0; i < size; ++i) { 256 ASSERT(values[i]); 257 258 encode(encoder, values[i]); 259 } 260} 261 262bool decode(ArgumentDecoder& decoder, RetainPtr<CFArrayRef>& result) 263{ 264 uint64_t size; 265 if (!decoder.decode(size)) 266 return false; 267 268 RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); 269 270 for (size_t i = 0; i < size; ++i) { 271 RetainPtr<CFTypeRef> element; 272 if (!decode(decoder, element)) 273 return false; 274 275 CFArrayAppendValue(array.get(), element.get()); 276 } 277 278 result = adoptCF(array.leakRef()); 279 return true; 280} 281 282void encode(ArgumentEncoder& encoder, CFBooleanRef boolean) 283{ 284 encoder << static_cast<bool>(CFBooleanGetValue(boolean)); 285} 286 287bool decode(ArgumentDecoder& decoder, RetainPtr<CFBooleanRef>& result) 288{ 289 bool boolean; 290 if (!decoder.decode(boolean)) 291 return false; 292 293 result = adoptCF(boolean ? kCFBooleanTrue : kCFBooleanFalse); 294 return true; 295} 296 297void encode(ArgumentEncoder& encoder, CFDataRef data) 298{ 299 CFIndex length = CFDataGetLength(data); 300 const UInt8* bytePtr = CFDataGetBytePtr(data); 301 302 encoder << CoreIPC::DataReference(bytePtr, length); 303} 304 305bool decode(ArgumentDecoder& decoder, RetainPtr<CFDataRef>& result) 306{ 307 CoreIPC::DataReference dataReference; 308 if (!decoder.decode(dataReference)) 309 return false; 310 311 result = adoptCF(CFDataCreate(0, dataReference.data(), dataReference.size())); 312 return true; 313} 314 315void encode(ArgumentEncoder& encoder, CFDateRef date) 316{ 317 encoder << static_cast<double>(CFDateGetAbsoluteTime(date)); 318} 319 320bool decode(ArgumentDecoder& decoder, RetainPtr<CFDateRef>& result) 321{ 322 double absoluteTime; 323 if (!decoder.decode(absoluteTime)) 324 return false; 325 326 result = adoptCF(CFDateCreate(0, absoluteTime)); 327 return true; 328} 329 330void encode(ArgumentEncoder& encoder, CFDictionaryRef dictionary) 331{ 332 CFIndex size = CFDictionaryGetCount(dictionary); 333 Vector<CFTypeRef, 32> keys(size); 334 Vector<CFTypeRef, 32> values(size); 335 336 CFDictionaryGetKeysAndValues(dictionary, keys.data(), values.data()); 337 338 encoder << static_cast<uint64_t>(size); 339 340 for (CFIndex i = 0; i < size; ++i) { 341 ASSERT(keys[i]); 342 ASSERT(CFGetTypeID(keys[i]) == CFStringGetTypeID()); 343 ASSERT(values[i]); 344 345 // Ignore values we don't recognize. 346 if (typeFromCFTypeRef(values[i]) == Unknown) 347 continue; 348 349 encode(encoder, static_cast<CFStringRef>(keys[i])); 350 encode(encoder, values[i]); 351 } 352} 353 354bool decode(ArgumentDecoder& decoder, RetainPtr<CFDictionaryRef>& result) 355{ 356 uint64_t size; 357 if (!decoder.decode(size)) 358 return false; 359 360 RetainPtr<CFMutableDictionaryRef> dictionary = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 361 for (uint64_t i = 0; i < size; ++i) { 362 // Try to decode the key name. 363 RetainPtr<CFStringRef> key; 364 if (!decode(decoder, key)) 365 return false; 366 367 RetainPtr<CFTypeRef> value; 368 if (!decode(decoder, value)) 369 return false; 370 371 CFDictionarySetValue(dictionary.get(), key.get(), value.get()); 372 } 373 374 result = adoptCF(dictionary.leakRef()); 375 return true; 376} 377 378void encode(ArgumentEncoder& encoder, CFNumberRef number) 379{ 380 CFNumberType numberType = CFNumberGetType(number); 381 382 Vector<uint8_t> buffer(CFNumberGetByteSize(number)); 383 bool result = CFNumberGetValue(number, numberType, buffer.data()); 384 ASSERT_UNUSED(result, result); 385 386 encoder.encodeEnum(numberType); 387 encoder << CoreIPC::DataReference(buffer); 388} 389 390static size_t sizeForNumberType(CFNumberType numberType) 391{ 392 switch (numberType) { 393 case kCFNumberSInt8Type: 394 return sizeof(SInt8); 395 case kCFNumberSInt16Type: 396 return sizeof(SInt16); 397 case kCFNumberSInt32Type: 398 return sizeof(SInt32); 399 case kCFNumberSInt64Type: 400 return sizeof(SInt64); 401 case kCFNumberFloat32Type: 402 return sizeof(Float32); 403 case kCFNumberFloat64Type: 404 return sizeof(Float64); 405 case kCFNumberCharType: 406 return sizeof(char); 407 case kCFNumberShortType: 408 return sizeof(short); 409 case kCFNumberIntType: 410 return sizeof(int); 411 case kCFNumberLongType: 412 return sizeof(long); 413 case kCFNumberLongLongType: 414 return sizeof(long long); 415 case kCFNumberFloatType: 416 return sizeof(float); 417 case kCFNumberDoubleType: 418 return sizeof(double); 419 case kCFNumberCFIndexType: 420 return sizeof(CFIndex); 421 case kCFNumberNSIntegerType: 422#ifdef __LP64__ 423 return sizeof(long); 424#else 425 return sizeof(int); 426#endif 427 case kCFNumberCGFloatType: 428#ifdef __LP64__ 429 return sizeof(double); 430#else 431 return sizeof(float); 432#endif 433 } 434 435 return 0; 436} 437 438bool decode(ArgumentDecoder& decoder, RetainPtr<CFNumberRef>& result) 439{ 440 CFNumberType numberType; 441 if (!decoder.decodeEnum(numberType)) 442 return false; 443 444 CoreIPC::DataReference dataReference; 445 if (!decoder.decode(dataReference)) 446 return false; 447 448 size_t neededBufferSize = sizeForNumberType(numberType); 449 if (!neededBufferSize || dataReference.size() != neededBufferSize) 450 return false; 451 452 ASSERT(dataReference.data()); 453 CFNumberRef number = CFNumberCreate(0, numberType, dataReference.data()); 454 result = adoptCF(number); 455 456 return true; 457} 458 459void encode(ArgumentEncoder& encoder, CFStringRef string) 460{ 461 CFIndex length = CFStringGetLength(string); 462 CFStringEncoding encoding = CFStringGetFastestEncoding(string); 463 464 CFRange range = CFRangeMake(0, length); 465 CFIndex bufferLength = 0; 466 467 CFIndex numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, 0, 0, &bufferLength); 468 ASSERT(numConvertedBytes == length); 469 470 Vector<UInt8, 128> buffer(bufferLength); 471 numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, buffer.data(), buffer.size(), &bufferLength); 472 ASSERT(numConvertedBytes == length); 473 474 encoder.encodeEnum(encoding); 475 encoder << CoreIPC::DataReference(buffer); 476} 477 478bool decode(ArgumentDecoder& decoder, RetainPtr<CFStringRef>& result) 479{ 480 CFStringEncoding encoding; 481 if (!decoder.decodeEnum(encoding)) 482 return false; 483 484 if (!CFStringIsEncodingAvailable(encoding)) 485 return false; 486 487 CoreIPC::DataReference dataReference; 488 if (!decoder.decode(dataReference)) 489 return false; 490 491 CFStringRef string = CFStringCreateWithBytes(0, dataReference.data(), dataReference.size(), encoding, false); 492 if (!string) 493 return false; 494 495 result = adoptCF(string); 496 return true; 497} 498 499void encode(ArgumentEncoder& encoder, CFURLRef url) 500{ 501 CFURLRef baseURL = CFURLGetBaseURL(url); 502 encoder << static_cast<bool>(baseURL); 503 if (baseURL) 504 encode(encoder, baseURL); 505 506 URLCharBuffer urlBytes; 507 getURLBytes(url, urlBytes); 508 CoreIPC::DataReference dataReference(reinterpret_cast<const uint8_t*>(urlBytes.data()), urlBytes.size()); 509 encoder << dataReference; 510} 511 512bool decode(ArgumentDecoder& decoder, RetainPtr<CFURLRef>& result) 513{ 514 RetainPtr<CFURLRef> baseURL; 515 bool hasBaseURL; 516 if (!decoder.decode(hasBaseURL)) 517 return false; 518 if (hasBaseURL) { 519 if (!decode(decoder, baseURL)) 520 return false; 521 } 522 523 CoreIPC::DataReference urlBytes; 524 if (!decoder.decode(urlBytes)) 525 return false; 526 527#if PLATFORM(MAC) 528 // FIXME: Move this to ArgumentCodersCFMac.mm and change this file back to be C++ 529 // instead of Objective-C++. 530 if (urlBytes.isEmpty()) { 531 // CFURL can't hold an empty URL, unlike NSURL. 532 // FIXME: This discards base URL, which seems incorrect. 533 result = reinterpret_cast<CFURLRef>([NSURL URLWithString:@""]); 534 return true; 535 } 536#endif 537 538 result = createCFURLFromBuffer(reinterpret_cast<const char*>(urlBytes.data()), urlBytes.size(), baseURL.get()); 539 return result; 540} 541 542#if USE(SECURITY_FRAMEWORK) 543void encode(ArgumentEncoder& encoder, SecCertificateRef certificate) 544{ 545 RetainPtr<CFDataRef> data = adoptCF(SecCertificateCopyData(certificate)); 546 encode(encoder, data.get()); 547} 548 549bool decode(ArgumentDecoder& decoder, RetainPtr<SecCertificateRef>& result) 550{ 551 RetainPtr<CFDataRef> data; 552 if (!decode(decoder, data)) 553 return false; 554 555 result = adoptCF(SecCertificateCreateWithData(0, data.get())); 556 return true; 557} 558 559void encode(ArgumentEncoder& encoder, SecKeychainItemRef keychainItem) 560{ 561 CFDataRef data; 562 if (SecKeychainItemCreatePersistentReference(keychainItem, &data) == errSecSuccess) { 563 encode(encoder, data); 564 CFRelease(data); 565 } 566} 567 568bool decode(ArgumentDecoder& decoder, RetainPtr<SecKeychainItemRef>& result) 569{ 570 RetainPtr<CFDataRef> data; 571 if (!CoreIPC::decode(decoder, data)) 572 return false; 573 574 SecKeychainItemRef item; 575 if (SecKeychainItemCopyFromPersistentReference(data.get(), &item) != errSecSuccess || !item) 576 return false; 577 578 result = adoptCF(item); 579 return true; 580} 581#endif 582 583} // namespace CoreIPC 584