1/* 2 * Copyright (C) 2012 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#import "config.h" 27#import "ObjCObjectGraphCoders.h" 28 29#import "ArgumentCodersMac.h" 30#import "WKTypeRefWrapper.h" 31 32// For UIProcess side encoding/decoding 33#import "WKAPICast.h" 34#import "WKBrowsingContextControllerInternal.h" 35#import "WebContextUserMessageCoders.h" 36#import "WebPageProxy.h" 37#import "WebProcessProxy.h" 38 39// For WebProcess side encoding/decoding 40#import "InjectedBundleUserMessageCoders.h" 41#import "WKBundleAPICast.h" 42#import "WKWebProcessPlugInBrowserContextControllerInternal.h" 43#import "WKWebProcessPlugInInternal.h" 44#import "WebPage.h" 45#import "WebProcess.h" 46 47namespace WebKit { 48 49enum WebKitNSType { 50 NullType, 51 NSDictionaryType, 52 NSArrayType, 53 NSStringType, 54 NSNumberType, 55 NSDateType, 56 NSDataType, 57#if WK_API_ENABLED 58 WKBrowsingContextControllerType, 59 WKTypeRefWrapperType, 60#endif 61 UnknownType, 62}; 63 64static WebKitNSType typeFromObject(id object) 65{ 66 ASSERT(object); 67 68 if ([object isKindOfClass:[NSDictionary class]]) 69 return NSDictionaryType; 70 if ([object isKindOfClass:[NSString class]]) 71 return NSStringType; 72 if ([object isKindOfClass:[NSArray class]]) 73 return NSArrayType; 74 if ([object isKindOfClass:[NSNumber class]]) 75 return NSNumberType; 76 if ([object isKindOfClass:[NSDate class]]) 77 return NSDateType; 78 if ([object isKindOfClass:[NSData class]]) 79 return NSDataType; 80#if WK_API_ENABLED 81 if ([object isKindOfClass:[WKBrowsingContextController class]] || [object isKindOfClass:[WKWebProcessPlugInBrowserContextController class]]) 82 return WKBrowsingContextControllerType; 83 if ([object isKindOfClass:[WKTypeRefWrapper class]]) 84 return WKTypeRefWrapperType; 85#endif 86 87 return UnknownType; 88} 89 90template<typename Owner> 91class ObjCObjectGraphEncoder { 92public: 93 bool baseEncode(IPC::ArgumentEncoder& encoder, const Owner& coder, WebKitNSType& type) const 94 { 95 if (!m_root) { 96 encoder << static_cast<uint32_t>(NullType); 97 return true; 98 } 99 100 type = typeFromObject(m_root); 101 if (type == UnknownType) { 102 [NSException raise:NSInvalidArgumentException format:@"Can not encode objects of class type '%@'", static_cast<NSString *>(NSStringFromClass([m_root class]))]; 103 } 104 105 encoder << static_cast<uint32_t>(type); 106 107 switch (type) { 108 case NSStringType: { 109 IPC::encode(encoder, static_cast<NSString *>(m_root)); 110 return true; 111 } 112 case NSArrayType: { 113 NSArray *array = static_cast<NSArray *>(m_root); 114 115 NSUInteger size = [array count]; 116 encoder << static_cast<uint64_t>(size); 117 118 for (NSUInteger i = 0; i < size; ++i) 119 encoder << Owner(coder, [array objectAtIndex:i]); 120 return true; 121 } 122 case NSDictionaryType: { 123 NSDictionary* dictionary = static_cast<NSDictionary *>(m_root); 124 125 NSUInteger size = [dictionary count]; 126 encoder << static_cast<uint64_t>(size); 127 128 NSArray *keys = [dictionary allKeys]; 129 NSArray *values = [dictionary allValues]; 130 for (NSUInteger i = 0; i < size; ++i) { 131 encoder << Owner(coder, [keys objectAtIndex:i]); 132 encoder << Owner(coder, [values objectAtIndex:i]); 133 } 134 135 return true; 136 } 137 case NSNumberType: { 138 IPC::encode(encoder, static_cast<NSNumber *>(m_root)); 139 return true; 140 } 141 case NSDateType: { 142 IPC::encode(encoder, static_cast<NSDate *>(m_root)); 143 return true; 144 } 145 case NSDataType: { 146 IPC::encode(encoder, static_cast<NSData *>(m_root)); 147 return true; 148 } 149 default: 150 break; 151 } 152 153 return false; 154 } 155 156protected: 157 ObjCObjectGraphEncoder(id root) 158 : m_root(root) 159 { 160 } 161 162 id m_root; 163}; 164 165template<typename Owner> 166class ObjCObjectGraphDecoder { 167public: 168 static bool baseDecode(IPC::ArgumentDecoder& decoder, Owner& coder, WebKitNSType& type) 169 { 170 uint32_t typeAsUInt32; 171 if (!decoder.decode(typeAsUInt32)) 172 return false; 173 174 type = static_cast<WebKitNSType>(typeAsUInt32); 175 176 switch (type) { 177 case NSStringType: { 178 RetainPtr<NSString> string; 179 if (!IPC::decode(decoder, string)) 180 return false; 181 coder.m_root = string; 182 break; 183 } 184 case NSArrayType: { 185 uint64_t size; 186 if (!decoder.decode(size)) 187 return false; 188 189 RetainPtr<NSMutableArray> array = adoptNS([[NSMutableArray alloc] initWithCapacity:size]); 190 for (uint64_t i = 0; i < size; ++i) { 191 RetainPtr<id> value; 192 Owner messageCoder(coder, value); 193 if (!decoder.decode(messageCoder)) 194 return false; 195 196 [array addObject:value.get()]; 197 } 198 199 coder.m_root = array; 200 break; 201 } 202 case NSDictionaryType: { 203 uint64_t size; 204 if (!decoder.decode(size)) 205 return false; 206 207 RetainPtr<NSMutableDictionary> dictionary = adoptNS([[NSMutableDictionary alloc] initWithCapacity:size]); 208 for (uint64_t i = 0; i < size; ++i) { 209 // Try to decode the key name. 210 RetainPtr<id> key; 211 Owner keyMessageCoder(coder, key); 212 if (!decoder.decode(keyMessageCoder)) 213 return false; 214 215 RetainPtr<id> value; 216 Owner valueMessageCoder(coder, value); 217 if (!decoder.decode(valueMessageCoder)) 218 return false; 219 220 [dictionary setObject:value.get() forKey:key.get()]; 221 } 222 223 coder.m_root = dictionary; 224 break; 225 } 226 case NSNumberType: { 227 RetainPtr<NSNumber> number; 228 if (!IPC::decode(decoder, number)) 229 return false; 230 coder.m_root = number; 231 break; 232 } 233 case NSDateType: { 234 RetainPtr<NSDate> date; 235 if (!IPC::decode(decoder, date)) 236 return false; 237 coder.m_root = date; 238 break; 239 } 240 case NSDataType: { 241 RetainPtr<NSData> data; 242 if (!IPC::decode(decoder, data)) 243 return false; 244 coder.m_root = data; 245 break; 246 } 247 default: 248 break; 249 } 250 251 return true; 252 } 253 254protected: 255 ObjCObjectGraphDecoder(RetainPtr<id>& root) 256 : m_root(root) 257 { 258 } 259 260 RetainPtr<id>& m_root; 261}; 262 263 264// WebContext Additions 265 266class WebContextObjCObjectGraphEncoderImpl : public ObjCObjectGraphEncoder<WebContextObjCObjectGraphEncoderImpl> { 267public: 268 typedef ObjCObjectGraphEncoder<WebContextObjCObjectGraphEncoderImpl> Base; 269 270 explicit WebContextObjCObjectGraphEncoderImpl(id root, WebProcessProxy& process) 271 : Base(root) 272 , m_process(process) 273 { 274 } 275 276 WebContextObjCObjectGraphEncoderImpl(const WebContextObjCObjectGraphEncoderImpl& userMessageEncoder, id root) 277 : Base(root) 278 , m_process(userMessageEncoder.m_process) 279 { 280 } 281 282 void encode(IPC::ArgumentEncoder& encoder) const 283 { 284 WebKitNSType type = NullType; 285 if (baseEncode(encoder, *this, type)) 286 return; 287 288 switch (type) { 289#if WK_API_ENABLED 290 case WKBrowsingContextControllerType: { 291 WKBrowsingContextController *browsingContextController = static_cast<WKBrowsingContextController *>(m_root); 292 293 encoder << toImpl(browsingContextController._pageRef)->pageID(); 294 break; 295 } 296 case WKTypeRefWrapperType: { 297 WKTypeRefWrapper *wrapper = static_cast<WKTypeRefWrapper *>(m_root); 298 encoder << WebContextUserMessageEncoder(toImpl(wrapper.object), m_process); 299 break; 300 } 301#endif 302 default: 303 ASSERT_NOT_REACHED(); 304 break; 305 } 306 } 307 308private: 309 WebProcessProxy& m_process; 310}; 311 312 313class WebContextObjCObjectGraphDecoderImpl : public ObjCObjectGraphDecoder<WebContextObjCObjectGraphDecoderImpl> { 314public: 315 typedef ObjCObjectGraphDecoder<WebContextObjCObjectGraphDecoderImpl> Base; 316 317 WebContextObjCObjectGraphDecoderImpl(RetainPtr<id>& root, WebProcessProxy& process) 318 : Base(root) 319 , m_process(process) 320 { 321 } 322 323 WebContextObjCObjectGraphDecoderImpl(WebContextObjCObjectGraphDecoderImpl& userMessageDecoder, RetainPtr<id>& root) 324 : Base(root) 325 , m_process(userMessageDecoder.m_process) 326 { 327 } 328 329 static bool decode(IPC::ArgumentDecoder& decoder, WebContextObjCObjectGraphDecoderImpl& coder) 330 { 331 WebKitNSType type = NullType; 332 if (!Base::baseDecode(decoder, coder, type)) 333 return false; 334 335 if (coder.m_root) 336 return true; 337 338 if (type == NullType || type == UnknownType) { 339 coder.m_root = [NSNull null]; 340 return true; 341 } 342 343 switch (type) { 344#if WK_API_ENABLED 345 case WKBrowsingContextControllerType: { 346 uint64_t pageID; 347 if (!decoder.decode(pageID)) 348 return false; 349 350 WebPageProxy* webPage = coder.m_process.webPage(pageID); 351 if (!webPage) 352 coder.m_root = [NSNull null]; 353 else 354 coder.m_root = [WKBrowsingContextController _browsingContextControllerForPageRef:toAPI(webPage)]; 355 break; 356 } 357 case WKTypeRefWrapperType: { 358 RefPtr<API::Object> object; 359 WebContextUserMessageDecoder objectDecoder(object, coder.m_process); 360 if (!decoder.decode(objectDecoder)) 361 return false; 362 coder.m_root = adoptNS([[WKTypeRefWrapper alloc] initWithObject:toAPI(object.get())]); 363 break; 364 } 365#endif 366 default: 367 return false; 368 } 369 370 return true; 371 } 372 373private: 374 WebProcessProxy& m_process; 375}; 376 377 378// InjectedBundle Additions 379 380class InjectedBundleObjCObjectGraphEncoderImpl : public ObjCObjectGraphEncoder<InjectedBundleObjCObjectGraphEncoderImpl> { 381public: 382 typedef ObjCObjectGraphEncoder<InjectedBundleObjCObjectGraphEncoderImpl> Base; 383 384 explicit InjectedBundleObjCObjectGraphEncoderImpl(id root, WebProcess& process) 385 : Base(root) 386 , m_process(process) 387 { 388 } 389 390 explicit InjectedBundleObjCObjectGraphEncoderImpl(const InjectedBundleObjCObjectGraphEncoderImpl& encoder, id root) 391 : Base(root) 392 , m_process(encoder.m_process) 393 { 394 } 395 396 void encode(IPC::ArgumentEncoder& encoder) const 397 { 398 WebKitNSType type = NullType; 399 if (baseEncode(encoder, *this, type)) 400 return; 401 402 switch (type) { 403#if WK_API_ENABLED 404 case WKBrowsingContextControllerType: { 405 WKWebProcessPlugInBrowserContextController *browserContextController = static_cast<WKWebProcessPlugInBrowserContextController *>(m_root); 406 407 encoder << toImpl(browserContextController._bundlePageRef)->pageID(); 408 break; 409 } 410 case WKTypeRefWrapperType: { 411 WKTypeRefWrapper *wrapper = static_cast<WKTypeRefWrapper *>(m_root); 412 encoder << InjectedBundleUserMessageEncoder(toImpl(wrapper.object)); 413 break; 414 } 415#endif 416 default: 417 ASSERT_NOT_REACHED(); 418 break; 419 } 420 } 421 422private: 423 WebProcess& m_process; 424}; 425 426class InjectedBundleObjCObjectGraphDecoderImpl : public ObjCObjectGraphDecoder<InjectedBundleObjCObjectGraphDecoderImpl> { 427public: 428 typedef ObjCObjectGraphDecoder<InjectedBundleObjCObjectGraphDecoderImpl> Base; 429 430 InjectedBundleObjCObjectGraphDecoderImpl(RetainPtr<id>& root, WebProcess& process) 431 : Base(root) 432 , m_process(process) 433 { 434 } 435 436 InjectedBundleObjCObjectGraphDecoderImpl(InjectedBundleObjCObjectGraphDecoderImpl& userMessageDecoder, RetainPtr<id>& root) 437 : Base(root) 438 , m_process(userMessageDecoder.m_process) 439 { 440 } 441 442 static bool decode(IPC::ArgumentDecoder& decoder, InjectedBundleObjCObjectGraphDecoderImpl& coder) 443 { 444 WebKitNSType type = NullType; 445 if (!Base::baseDecode(decoder, coder, type)) 446 return false; 447 448 if (coder.m_root) 449 return true; 450 451 if (type == NullType || type == UnknownType) { 452 coder.m_root = [NSNull null]; 453 return true; 454 } 455 456 switch (type) { 457#if WK_API_ENABLED 458 case WKBrowsingContextControllerType: { 459 uint64_t pageID; 460 if (!decoder.decode(pageID)) 461 return false; 462 463 WebPage* webPage = coder.m_process.webPage(pageID); 464 if (!webPage) 465 coder.m_root = [NSNull null]; 466 else 467 coder.m_root = wrapper(*webPage); 468 break; 469 } 470 case WKTypeRefWrapperType: { 471 RefPtr<API::Object> object; 472 InjectedBundleUserMessageDecoder objectDecoder(object); 473 if (!decoder.decode(objectDecoder)) 474 return false; 475 coder.m_root = adoptNS([[WKTypeRefWrapper alloc] initWithObject:toAPI(object.get())]); 476 break; 477 } 478#endif 479 default: 480 return false; 481 } 482 483 return true; 484 } 485 486private: 487 WebProcess& m_process; 488}; 489 490 491// Adaptors 492 493WebContextObjCObjectGraphEncoder::WebContextObjCObjectGraphEncoder(ObjCObjectGraph* objectGraph, WebProcessProxy& process) 494 : m_objectGraph(objectGraph) 495 , m_process(process) 496{ 497} 498 499void WebContextObjCObjectGraphEncoder::encode(IPC::ArgumentEncoder& encoder) const 500{ 501 encoder << WebContextObjCObjectGraphEncoderImpl(m_objectGraph->rootObject(), m_process); 502} 503 504WebContextObjCObjectGraphDecoder::WebContextObjCObjectGraphDecoder(RefPtr<ObjCObjectGraph>& objectGraph, WebProcessProxy& process) 505 : m_objectGraph(objectGraph) 506 , m_process(process) 507{ 508} 509 510bool WebContextObjCObjectGraphDecoder::decode(IPC::ArgumentDecoder& decoder, WebContextObjCObjectGraphDecoder& coder) 511{ 512 RetainPtr<id> root; 513 WebContextObjCObjectGraphDecoderImpl coderImpl(root, coder.m_process); 514 if (!decoder.decode(coderImpl)) 515 return false; 516 517 coder.m_objectGraph = ObjCObjectGraph::create(root.get()); 518 return true; 519} 520 521InjectedBundleObjCObjectGraphEncoder::InjectedBundleObjCObjectGraphEncoder(ObjCObjectGraph* objectGraph, WebProcess& process) 522 : m_objectGraph(objectGraph) 523 , m_process(process) 524{ 525} 526 527void InjectedBundleObjCObjectGraphEncoder::encode(IPC::ArgumentEncoder& encoder) const 528{ 529 encoder << InjectedBundleObjCObjectGraphEncoderImpl(m_objectGraph->rootObject(), m_process); 530} 531 532InjectedBundleObjCObjectGraphDecoder::InjectedBundleObjCObjectGraphDecoder(RefPtr<ObjCObjectGraph>& objectGraph, WebProcess& process) 533 : m_objectGraph(objectGraph) 534 , m_process(process) 535{ 536} 537 538bool InjectedBundleObjCObjectGraphDecoder::decode(IPC::ArgumentDecoder& decoder, InjectedBundleObjCObjectGraphDecoder& coder) 539{ 540 RetainPtr<id> root; 541 InjectedBundleObjCObjectGraphDecoderImpl coderImpl(root, coder.m_process); 542 if (!decoder.decode(coderImpl)) 543 return false; 544 545 coder.m_objectGraph = ObjCObjectGraph::create(root.get()); 546 return true; 547} 548 549} // namespace WebKit 550