Add _ prefix to WKRemoteObjectRegistery and WKRemoteObjectInterface
[WebKit-https.git] / Source / WebKit2 / Shared / API / Cocoa / _WKRemoteObjectInterface.mm
1 /*
2  * Copyright (C) 2013 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 "_WKRemoteObjectInterface.h"
28
29 #if WK_API_ENABLED
30
31 #import <objc/runtime.h>
32 #import <wtf/HashMap.h>
33 #import <wtf/Vector.h>
34 #import <wtf/RetainPtr.h>
35
36 extern "C"
37 const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL sel, BOOL isRequiredMethod, BOOL isInstanceMethod);
38
39 @interface NSMethodSignature (WKDetails)
40 - (Class)_classForObjectAtArgumentIndex:(NSInteger)idx;
41 @end
42
43 @implementation _WKRemoteObjectInterface {
44     HashMap<SEL, Vector<RetainPtr<NSSet>>> _allowedArgumentClasses;
45 }
46
47 static bool isContainerClass(Class objectClass)
48 {
49     // FIXME: Add more classes here if needed.
50     static NSSet *containerClasses = [[NSSet alloc] initWithObjects:[NSArray class], [NSDictionary class], nil];
51
52     return [containerClasses containsObject:objectClass];
53 }
54
55 static NSSet *propertyListClasses()
56 {
57     // FIXME: Add more property list classes if needed.
58     static NSSet *propertyListClasses = [[NSSet alloc] initWithObjects:[NSArray class], [NSDictionary class], [NSNumber class], [NSString class], nil];
59
60     return propertyListClasses;
61 }
62
63 static Vector<RetainPtr<NSSet>> allowedArgumentClassesForMethod(NSMethodSignature *methodSignature)
64 {
65     Vector<RetainPtr<NSSet>> result;
66
67     NSSet *emptySet = [NSSet set];
68
69     // We ignore self and _cmd.
70     NSUInteger argumentCount = methodSignature.numberOfArguments - 2;
71
72     result.reserveInitialCapacity(argumentCount);
73
74     for (NSUInteger i = 0; i < argumentCount; ++i) {
75         const char* type = [methodSignature getArgumentTypeAtIndex:i + 2];
76
77         if (*type != '@') {
78             // This is a non-object type; we won't allow any classes to be decoded for it.
79             result.uncheckedAppend(emptySet);
80             continue;
81         }
82
83         Class objectClass = [methodSignature _classForObjectAtArgumentIndex:i + 2];
84         if (!objectClass) {
85             result.uncheckedAppend(emptySet);
86             continue;
87         }
88
89         if (isContainerClass(objectClass)) {
90             // For container classes, we allow all simple property list classes.
91             result.uncheckedAppend(propertyListClasses());
92             continue;
93         }
94
95         result.uncheckedAppend([NSSet setWithObject:objectClass]);
96     }
97
98     return result;
99 }
100
101 static void initializeAllowedArgumentClasses(_WKRemoteObjectInterface *interface, bool requiredMethods)
102 {
103     unsigned methodCount;
104     struct objc_method_description *methods = protocol_copyMethodDescriptionList(interface->_protocol, requiredMethods, true, &methodCount);
105
106     for (unsigned i = 0; i < methodCount; ++i) {
107         SEL selector = methods[i].name;
108
109         const char* types = _protocol_getMethodTypeEncoding(interface->_protocol, selector, requiredMethods, true);
110         if (!types)
111             [NSException raise:NSInvalidArgumentException format:@"Could not find method type encoding for method \"%s\"", sel_getName(selector)];
112
113         NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:types];
114         interface->_allowedArgumentClasses.set(selector, allowedArgumentClassesForMethod(methodSignature));
115     }
116
117     free(methods);
118 }
119
120 static void initializeAllowedArgumentClasses(_WKRemoteObjectInterface *interface)
121 {
122     initializeAllowedArgumentClasses(interface, true);
123     initializeAllowedArgumentClasses(interface, false);
124 }
125
126 - (id)initWithProtocol:(Protocol *)protocol identifier:(NSString *)identifier
127 {
128     if (!(self = [super init]))
129         return nil;
130
131     _protocol = protocol;
132     _identifier = [identifier copy];
133
134     initializeAllowedArgumentClasses(self);
135
136     return self;
137 }
138
139 + (instancetype)remoteObjectInterfaceWithProtocol:(Protocol *)protocol
140 {
141     return [[[self alloc] initWithProtocol:protocol identifier:NSStringFromProtocol(protocol)] autorelease];
142 }
143
144 - (NSString *)description
145 {
146     return [NSString stringWithFormat:@"<%@: %p; protocol = \"%@\"; identifier = \"%@\">", NSStringFromClass(self.class), self, _identifier, NSStringFromProtocol(_protocol)];
147 }
148
149 static RetainPtr<NSSet>& classesForSelectorArgument(_WKRemoteObjectInterface *interface, SEL selector, NSUInteger argumentIndex)
150 {
151     auto it = interface->_allowedArgumentClasses.find(selector);
152     if (it == interface->_allowedArgumentClasses.end())
153         [NSException raise:NSInvalidArgumentException format:@"Interface does not contain selector \"%s\"", sel_getName(selector)];
154
155     if (argumentIndex >= it->value.size())
156         [NSException raise:NSInvalidArgumentException format:@"Argument index %ld is out of range for selector \"%s\"", (unsigned long)argumentIndex, sel_getName(selector)];
157
158     return it->value[argumentIndex];
159 }
160
161 - (NSSet *)classesForSelector:(SEL)selector argumentIndex:(NSUInteger)argumentIndex
162 {
163     return [[classesForSelectorArgument(self, selector, argumentIndex).get() retain] autorelease];
164 }
165
166 - (void)setClasses:(NSSet *)classes forSelector:(SEL)selector argumentIndex:(NSUInteger)argumentIndex
167 {
168     classesForSelectorArgument(self, selector, argumentIndex) = adoptNS([classes copy]);
169 }
170
171 static const char* methodArgumentTypeEncodingForSelector(Protocol *protocol, SEL selector)
172 {
173     // First look at required methods.
174     struct objc_method_description method = protocol_getMethodDescription(protocol, selector, YES, YES);
175     if (method.name)
176         return method.types;
177
178     // Then look at optional methods.
179     method = protocol_getMethodDescription(protocol, selector, NO, YES);
180     if (method.name)
181         return method.types;
182
183     return nullptr;
184 }
185
186 - (NSMethodSignature *)_methodSignatureForSelector:(SEL)selector
187 {
188     const char* types = methodArgumentTypeEncodingForSelector(_protocol, selector);
189     if (!types)
190         return nil;
191
192     return [NSMethodSignature signatureWithObjCTypes:types];
193 }
194
195 - (const Vector<RetainPtr<NSSet>>&)_allowedArgumentClassesForSelector:(SEL)selector
196 {
197     auto it = _allowedArgumentClasses.find(selector);
198     ASSERT(it != _allowedArgumentClasses.end());
199
200     return it->value;
201 }
202
203 @end
204
205 #endif // WK_API_ENABLED