f899fbcb49890a0af294412b74c109ea588ba872
[WebKit-https.git] / Source / WebCore / bridge / objc / objc_utility.mm
1 /*
2  * Copyright (C) 2004, 2013, 2016 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "objc_utility.h"
28
29 #include "WebScriptObjectProtocol.h"
30 #include "objc_instance.h"
31 #include "runtime_array.h"
32 #include "runtime_object.h"
33 #include <runtime/JSGlobalObject.h>
34 #include <runtime/JSLock.h>
35 #include <wtf/Assertions.h>
36
37 #if !defined(_C_LNG_LNG)
38 #define _C_LNG_LNG 'q'
39 #endif
40
41 #if !defined(_C_ULNG_LNG)
42 #define _C_ULNG_LNG 'Q'
43 #endif
44
45 #if !defined(_C_CONST)
46 #define _C_CONST 'r'
47 #endif
48
49 #if !defined(_C_BYCOPY)
50 #define _C_BYCOPY 'O'
51 #endif
52
53 #if !defined(_C_BYREF)
54 #define _C_BYREF 'R'
55 #endif
56
57 #if !defined(_C_ONEWAY)
58 #define _C_ONEWAY 'V'
59 #endif
60
61 #if !defined(_C_GCINVISIBLE)
62 #define _C_GCINVISIBLE '!'
63 #endif
64
65 namespace JSC {
66 namespace Bindings {
67
68 /*
69
70     JavaScript to   ObjC
71     Number          coerced to char, short, int, long, float, double, or NSNumber, as appropriate
72     String          NSString
73     wrapper         id
74     Object          WebScriptObject
75     null            NSNull
76     [], other       exception
77
78 */
79 ObjcValue convertValueToObjcValue(ExecState* exec, JSValue value, ObjcValueType type)
80 {
81     ObjcValue result;
82     double d = 0;
83
84     if (value.isNumber() || value.isString() || value.isBoolean())
85         d = value.toNumber(exec);
86
87     switch (type) {
88         case ObjcObjectType: {
89             JSLockHolder lock(exec);
90             
91             JSGlobalObject *originGlobalObject = exec->vmEntryGlobalObject();
92             RootObject* originRootObject = findRootObject(originGlobalObject);
93
94             JSGlobalObject* globalObject = 0;
95             if (value.isObject() && asObject(value)->isGlobalObject())
96                 globalObject = jsCast<JSGlobalObject*>(asObject(value));
97
98             if (!globalObject)
99                 globalObject = originGlobalObject;
100                 
101             RootObject* rootObject = findRootObject(globalObject);
102             result.objectValue =  rootObject
103                 ? [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:originRootObject rootObject:rootObject]
104                 : nil;
105         }
106         break;
107
108         case ObjcCharType:
109         case ObjcUnsignedCharType:
110             result.charValue = (char)d;
111             break;
112         case ObjcShortType:
113         case ObjcUnsignedShortType:
114             result.shortValue = (short)d;
115             break;
116         case ObjcBoolType:
117             result.booleanValue = (bool)d;
118             break;
119         case ObjcIntType:
120         case ObjcUnsignedIntType:
121             result.intValue = (int)d;
122             break;
123         case ObjcLongType:
124         case ObjcUnsignedLongType:
125             result.longValue = (long)d;
126             break;
127         case ObjcLongLongType:
128         case ObjcUnsignedLongLongType:
129             result.longLongValue = (long long)d;
130             break;
131         case ObjcFloatType:
132             result.floatValue = (float)d;
133             break;
134         case ObjcDoubleType:
135             result.doubleValue = (double)d;
136             break;
137         case ObjcVoidType:
138             bzero(&result, sizeof(ObjcValue));
139             break;
140
141         case ObjcInvalidType:
142         default:
143             // FIXME: throw an exception?
144             break;
145     }
146
147     return result;
148 }
149
150 JSValue convertNSStringToString(ExecState* exec, NSString *nsstring)
151 {
152     JSLockHolder lock(exec);
153     JSValue aValue = jsString(exec, String(nsstring));
154     return aValue;
155 }
156
157 /*
158     ObjC      to    JavaScript
159     ----            ----------
160     char            number
161     short           number
162     int             number
163     long            number
164     float           number
165     double          number
166     NSNumber        boolean or number
167     NSString        string
168     NSArray         array
169     NSNull          null
170     WebScriptObject underlying JavaScript object
171     WebUndefined    undefined
172     id              object wrapper
173     other           should not happen
174 */
175 JSValue convertObjcValueToValue(ExecState* exec, void* buffer, ObjcValueType type, RootObject* rootObject)
176 {
177     JSLockHolder lock(exec);
178     
179     switch (type) {
180         case ObjcObjectType: {
181             id obj = *(id*)buffer;
182             if ([obj isKindOfClass:[NSString class]])
183                 return convertNSStringToString(exec, (NSString *)obj);
184             if ([obj isKindOfClass:webUndefinedClass()])
185                 return jsUndefined();
186             if ((CFBooleanRef)obj == kCFBooleanTrue)
187                 return jsBoolean(true);
188             if ((CFBooleanRef)obj == kCFBooleanFalse)
189                 return jsBoolean(false);
190             if ([obj isKindOfClass:[NSNumber class]])
191                 return jsNumber([obj doubleValue]);
192             if ([obj isKindOfClass:[NSArray class]])
193                 return RuntimeArray::create(exec, new ObjcArray(obj, rootObject));
194             if ([obj isKindOfClass:webScriptObjectClass()]) {
195                 JSObject* imp = [obj _imp];
196                 return imp ? imp : jsUndefined();
197             }
198             if ([obj isKindOfClass:[NSNull class]])
199                 return jsNull();
200             if (obj == 0)
201                 return jsUndefined();
202             return ObjcInstance::create(obj, rootObject)->createRuntimeObject(exec);
203         }
204         case ObjcCharType:
205             return jsNumber(*(char*)buffer);
206         case ObjcUnsignedCharType:
207             return jsNumber(*(unsigned char*)buffer);
208         case ObjcShortType:
209             return jsNumber(*(short*)buffer);
210         case ObjcUnsignedShortType:
211             return jsNumber(*(unsigned short*)buffer);
212         case ObjcBoolType:
213             return jsBoolean(*(bool*)buffer);
214         case ObjcIntType:
215             return jsNumber(*(int*)buffer);
216         case ObjcUnsignedIntType:
217             return jsNumber(*(unsigned int*)buffer);
218         case ObjcLongType:
219             return jsNumber(*(long*)buffer);
220         case ObjcUnsignedLongType:
221             return jsNumber(*(unsigned long*)buffer);
222         case ObjcLongLongType:
223             return jsNumber(*(long long*)buffer);
224         case ObjcUnsignedLongLongType:
225             return jsNumber(*(unsigned long long*)buffer);
226         case ObjcFloatType:
227             return jsNumber(*(float*)buffer);
228         case ObjcDoubleType:
229             return jsNumber(*(double*)buffer);
230         default:
231             // Should never get here. Argument types are filtered.
232             WTFLogAlways("%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)type);
233             ASSERT_NOT_REACHED();
234     }
235     
236     return jsUndefined();
237 }
238
239 ObjcValueType objcValueTypeForType(const char *type)
240 {
241     int typeLength = strlen(type);
242     ObjcValueType objcValueType = ObjcInvalidType;
243
244     for (int i = 0; i < typeLength; ++i) {
245         char typeChar = type[i];
246         switch (typeChar) {
247             case _C_CONST:
248             case _C_BYCOPY:
249             case _C_BYREF:
250             case _C_ONEWAY:
251             case _C_GCINVISIBLE:
252                 // skip these type modifiers
253                 break;
254             case _C_ID:
255                 objcValueType = ObjcObjectType;
256                 break;
257             case _C_CHR:
258                 objcValueType = ObjcCharType;
259                 break;
260             case _C_UCHR:
261                 objcValueType = ObjcUnsignedCharType;
262                 break;
263             case _C_SHT:
264                 objcValueType = ObjcShortType;
265                 break;
266             case _C_USHT:
267                 objcValueType = ObjcUnsignedShortType;
268                 break;
269             case _C_BOOL:
270                 objcValueType = ObjcBoolType;
271                 break;
272             case _C_INT:
273                 objcValueType = ObjcIntType;
274                 break;
275             case _C_UINT:
276                 objcValueType = ObjcUnsignedIntType;
277                 break;
278             case _C_LNG:
279                 objcValueType = ObjcLongType;
280                 break;
281             case _C_ULNG:
282                 objcValueType = ObjcUnsignedLongType;
283                 break;
284             case _C_LNG_LNG:
285                 objcValueType = ObjcLongLongType;
286                 break;
287             case _C_ULNG_LNG:
288                 objcValueType = ObjcUnsignedLongLongType;
289                 break;
290             case _C_FLT:
291                 objcValueType = ObjcFloatType;
292                 break;
293             case _C_DBL:
294                 objcValueType = ObjcDoubleType;
295                 break;
296             case _C_VOID:
297                 objcValueType = ObjcVoidType;
298                 break;
299             default:
300                 // Unhandled type. We don't handle C structs, unions, etc.
301                 // FIXME: throw an exception?
302                 WTFLogAlways("Unhandled ObjC type specifier: \"%c\" used in ObjC bridge.", typeChar);
303                 RELEASE_ASSERT_NOT_REACHED();
304         }
305
306         if (objcValueType != ObjcInvalidType)
307             break;
308     }
309
310     return objcValueType;
311 }
312
313 JSObject *throwError(ExecState *exec, ThrowScope& scope, NSString *message)
314 {
315     ASSERT(message);
316     JSObject *error = throwException(exec, scope, JSC::createError(exec, String(message)));
317     return error;
318 }
319
320 }
321 }