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