5ee5f7dcaa44c51f4ad718fb9243164a9341d318
[WebKit-https.git] / JavaScriptCore / bindings / objc / objc_utility.mm
1 /*
2  * Copyright (C) 2004 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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 #include <Foundation/Foundation.h>
26
27 #include <JavascriptCore/internal.h>
28
29 #include <objc_instance.h>
30 #include <objc_utility.h>
31
32 #include <runtime_array.h>
33 #include <runtime_object.h>
34 #include <runtime_root.h>
35
36 #include <WebScriptObjectPrivate.h>
37
38
39 using namespace KJS;
40 using namespace KJS::Bindings;
41
42 /*
43     The default name concatenates the components of the
44     ObjectiveC selector name and replaces ':' with '_'.  '_' characters
45     are escaped with an additional '$', i.e. '_' becomes "$_".  '$' are
46     also escaped, i.e.
47         ObjectiveC name         Default script name
48         moveTo::                move__
49         moveTo_                 moveTo$_
50         moveTo$_                moveTo$$$_
51     @result Returns the name to be used to represent the specificed selector in the
52 */
53 void KJS::Bindings::JSMethodNameToObjCMethodName(const char *name, char *buffer, unsigned int len)
54 {
55     const char *np = name;
56     char *bp;
57
58     if (strlen(name)*2+1 > len){
59         *buffer = 0;
60     }
61
62     bp = buffer;
63     while (*np) {
64         if (*np == '$') {
65             np++;
66             *bp++ = *np++;
67             continue;
68         }
69         
70         if (*np == '_') {
71             np++;
72             *bp++ = ':';
73         }
74         else
75             *bp++ = *np++;
76     }
77     *bp++ = 0;
78 }
79
80 /*
81
82     JavaScript to   ObjC
83     Number          coerced to char, short, int, long, float, double, or NSNumber, as appropriate
84     String          NSString
85     wrapper         id
86     Object          WebScriptObject
87     [], other       exception
88
89 */
90 ObjcValue KJS::Bindings::convertValueToObjcValue (KJS::ExecState *exec, const KJS::Value &value, ObjcValueType type)
91 {
92     ObjcValue result;
93     double d = 0;
94    
95     d = value.toNumber(exec);
96     switch (type){
97         case ObjcObjectType: {
98             const Bindings::RootObject *root = rootForInterpreter(exec->interpreter());
99             if (!root) {
100                 Bindings::RootObject *newRoot = new KJS::Bindings::RootObject(0);
101                 newRoot->setInterpreter (exec->interpreter());
102                 root = newRoot;
103             }
104             result.objectValue = [WebScriptObject _convertValueToObjcValue:value root:root];
105         }
106         break;
107         
108         
109         case ObjcCharType: {
110             result.charValue = (char)d;
111         }
112         break;
113
114         case ObjcShortType: {
115             result.shortValue = (short)d;
116         }
117         break;
118
119         case ObjcIntType: {
120             result.intValue = (int)d;
121         }
122         break;
123
124         case ObjcLongType: {
125             result.longValue = (long)d;
126         }
127         break;
128
129         case ObjcFloatType: {
130             result.floatValue = (float)d;
131         }
132         break;
133
134         case ObjcDoubleType: {
135             result.doubleValue = (double)d;
136         }
137         break;
138             
139         break;
140
141         case ObjcVoidType: {
142             bzero (&result, sizeof(ObjcValue));
143         }
144         break;
145
146         case ObjcInvalidType:
147         default:
148         {
149             // FIXME:  throw an exception
150         }
151         break;
152     }
153     return result;
154 }
155
156 /*
157
158     ObjC      to    JavaScript
159     char            Number
160     short
161     int
162     long
163     float
164     double
165     NSNumber        Number
166     NSString        String
167     NSArray         Array
168     id              Object wrapper
169     other           should not happen
170
171 */
172 Value KJS::Bindings::convertObjcValueToValue (KJS::ExecState *exec, void *buffer, ObjcValueType type)
173 {
174     Value aValue;
175
176     switch (type) {
177         case ObjcObjectType:
178             {
179                 ObjectStructPtr *obj = (ObjectStructPtr *)buffer;
180
181                 /*
182                     NSNumber to Number
183                     NSString to String
184                     NSArray  to Array
185                     id       to Object wrapper
186                 */
187                 if ([*obj isKindOfClass:[NSString class]]){
188                     NSString *string = (NSString *)*obj;
189                     unichar *chars;
190                     unsigned int length = [string length];
191                     chars = (unichar *)malloc(sizeof(unichar)*length);
192                     [string getCharacters:chars];
193                     UString u((const KJS::UChar*)chars, length);
194                     aValue = String (u);
195                     free((void *)chars);
196                 }
197                 else if ([*obj isKindOfClass:[NSNumber class]]) {
198                     aValue = Number([*obj doubleValue]);
199                 }
200                 else if ([*obj isKindOfClass:[NSArray class]]) {
201                     aValue = Object(new RuntimeArrayImp(exec, new ObjcArray (*obj)));
202                 }
203                 else if ([*obj isKindOfClass:[WebScriptObject class]]) {
204                     WebScriptObject *jsobject = (WebScriptObject *)*obj;
205                     aValue = Object([jsobject _imp]);
206                 }
207                 else if (*obj == 0) {
208                     return Undefined();
209                 }
210                 else {
211                     aValue = Object(new RuntimeObjectImp(new ObjcInstance (*obj)));
212                 }
213             }
214             break;
215         case ObjcCharType:
216             {
217                 char *objcVal = (char *)buffer;
218                 aValue = Number ((short)*objcVal);
219             }
220             break;
221         case ObjcShortType:
222             {
223                 short *objcVal = (short *)buffer;
224                 aValue = Number ((short)*objcVal);
225             }
226             break;
227         case ObjcIntType:
228             {
229                 int *objcVal = (int *)buffer;
230                 aValue = Number ((int)*objcVal);
231             }
232             break;
233         case ObjcLongType:
234             {
235                 long *objcVal = (long *)buffer;
236                 aValue = Number ((long)*objcVal);
237             }
238             break;
239         case ObjcFloatType:
240             {
241                 float *objcVal = (float *)buffer;
242                 aValue = Number ((float)*objcVal);
243             }
244             break;
245         case ObjcDoubleType:
246             {
247                 double *objcVal = (double *)buffer;
248                 aValue = Number ((double)*objcVal);
249             }
250             break;
251         default:
252             // Should never get here.  Argument types are filtered (and
253             // the assert above should have fired in the impossible case
254             // of an invalid type anyway).
255             fprintf (stderr, "%s:  invalid type (%d)\n", __PRETTY_FUNCTION__, (int)type);
256             assert (true);
257     }
258     
259     return aValue;
260 }
261
262
263 ObjcValueType KJS::Bindings::objcValueTypeForType (const char *type)
264 {
265     int typeLength = strlen(type);
266     ObjcValueType objcValueType = ObjcInvalidType;
267     
268     if (typeLength == 1) {
269         char typeChar = type[0];
270         switch (typeChar){
271             case _C_ID: {
272                 objcValueType = ObjcObjectType;
273             }
274             break;
275             case _C_CHR: {
276                 objcValueType = ObjcCharType;
277             }
278             break;
279             case _C_SHT: {
280                 objcValueType = ObjcShortType;
281             }
282             break;
283             case _C_INT: {
284                 objcValueType = ObjcIntType;
285             }
286             break;
287             case _C_LNG: {
288                 objcValueType = ObjcLongType;
289             }
290             break;
291             case _C_FLT: {
292                 objcValueType = ObjcFloatType;
293             }
294             break;
295             case _C_DBL: {
296                 objcValueType = ObjcDoubleType;
297             }
298             break;
299             case _C_VOID: {
300                 objcValueType = ObjcVoidType;
301             }
302             break;
303         }
304     }
305     return objcValueType;
306 }
307
308