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#import "config.h"
27#import "InjectedBundle.h"
28
29#import "ObjCObjectGraph.h"
30#import "WKBundleAPICast.h"
31#import "WKBundleInitialize.h"
32#import "WKWebProcessPlugInInternal.h"
33#import <Foundation/NSBundle.h>
34#import <stdio.h>
35#import <wtf/RetainPtr.h>
36#import <wtf/text/CString.h>
37#import <wtf/text/WTFString.h>
38
39using namespace WebCore;
40
41@interface NSBundle (WKAppDetails)
42- (CFBundleRef)_cfBundle;
43@end
44
45namespace WebKit {
46
47bool InjectedBundle::load(APIObject* initializationUserData)
48{
49    if (m_sandboxExtension) {
50        if (!m_sandboxExtension->consumePermanently()) {
51            WTFLogAlways("InjectedBundle::load failed - Could not consume bundle sandbox extension for [%s].\n", m_path.utf8().data());
52            return false;
53        }
54
55        m_sandboxExtension = 0;
56    }
57
58    RetainPtr<CFStringRef> injectedBundlePathStr = adoptCF(CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(m_path.characters()), m_path.length()));
59    if (!injectedBundlePathStr) {
60        WTFLogAlways("InjectedBundle::load failed - Could not create the path string.\n");
61        return false;
62    }
63
64    RetainPtr<CFURLRef> bundleURL = adoptCF(CFURLCreateWithFileSystemPath(0, injectedBundlePathStr.get(), kCFURLPOSIXPathStyle, false));
65    if (!bundleURL) {
66        WTFLogAlways("InjectedBundle::load failed - Could not create the url from the path string.\n");
67        return false;
68    }
69
70    m_platformBundle = [[NSBundle alloc] initWithURL:(NSURL *)bundleURL.get()];
71    if (!m_platformBundle) {
72        WTFLogAlways("InjectedBundle::load failed - Could not create the bundle.\n");
73        return false;
74    }
75
76    if (![m_platformBundle load]) {
77        WTFLogAlways("InjectedBundle::load failed - Could not load the executable from the bundle.\n");
78        return false;
79    }
80
81    // First check to see if the bundle has a WKBundleInitialize function.
82    WKBundleInitializeFunctionPtr initializeFunction = reinterpret_cast<WKBundleInitializeFunctionPtr>(CFBundleGetFunctionPointerForName([m_platformBundle _cfBundle], CFSTR("WKBundleInitialize")));
83    if (initializeFunction) {
84        initializeFunction(toAPI(this), toAPI(initializationUserData));
85        return true;
86    }
87
88#if defined(__LP64__) && defined(__clang__)
89    // Otherwise, look to see if the bundle has a principal class
90    Class principalClass = [m_platformBundle principalClass];
91    if (!principalClass) {
92        WTFLogAlways("InjectedBundle::load failed - No initialize function or principal class found in the bundle executable.\n");
93        return false;
94    }
95
96    if (![principalClass conformsToProtocol:@protocol(WKWebProcessPlugIn)]) {
97        WTFLogAlways("InjectedBundle::load failed - Principal class does not conform to the WKWebProcessPlugIn protocol.\n");
98        return false;
99    }
100
101    id<WKWebProcessPlugIn> instance = (id<WKWebProcessPlugIn>)[[principalClass alloc] init];
102    if (!instance) {
103        WTFLogAlways("InjectedBundle::load failed - Could not initialize an instance of the principal class.\n");
104        return false;
105    }
106
107    // Create the shared WKWebProcessPlugInController.
108    [[WKWebProcessPlugInController alloc] _initWithPrincipalClassInstance:instance bundleRef:toAPI(this)];
109
110    if ([instance respondsToSelector:@selector(webProcessPlugIn:initializeWithObject:)]) {
111        RetainPtr<id> objCInitializationUserData;
112        if (initializationUserData && initializationUserData->type() == APIObject::TypeObjCObjectGraph)
113            objCInitializationUserData = static_cast<ObjCObjectGraph*>(initializationUserData)->rootObject();
114        [instance webProcessPlugIn:[WKWebProcessPlugInController _shared] initializeWithObject:objCInitializationUserData.get()];
115    } else if ([instance respondsToSelector:@selector(webProcessPlugInInitialize:)]) {
116        CLANG_PRAGMA("clang diagnostic push")
117        CLANG_PRAGMA("clang diagnostic ignored \"-Wdeprecated-declarations\"")
118        [instance webProcessPlugInInitialize:[WKWebProcessPlugInController _shared]];
119        CLANG_PRAGMA("clang diagnostic pop")
120    }
121
122    return true;
123#else
124    return false;
125#endif
126}
127
128void InjectedBundle::activateMacFontAscentHack()
129{
130}
131
132} // namespace WebKit
133