]> git.saurik.com Git - apple/javascriptcore.git/blob - bindings/objc/objc_utility.mm
JavaScriptCore-461.tar.gz
[apple/javascriptcore.git] / 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
26 #include "config.h"
27 #include "objc_utility.h"
28
29 #include "objc_instance.h"
30 #include "JSGlobalObject.h"
31 #include "runtime_array.h"
32 #include "runtime_object.h"
33 #include "WebScriptObject.h"
34 #include <wtf/Assertions.h>
35
36 #if !defined(_C_LNG_LNG)
37 #define _C_LNG_LNG 'q'
38 #endif
39
40 #if !defined(_C_ULNG_LNG)
41 #define _C_ULNG_LNG 'Q'
42 #endif
43
44 #if !defined(_C_CONST)
45 #define _C_CONST 'r'
46 #endif
47
48 #if !defined(_C_BYCOPY)
49 #define _C_BYCOPY 'O'
50 #endif
51
52 #if !defined(_C_BYREF)
53 #define _C_BYREF 'R'
54 #endif
55
56 #if !defined(_C_ONEWAY)
57 #define _C_ONEWAY 'V'
58 #endif
59
60 #if !defined(_C_GCINVISIBLE)
61 #define _C_GCINVISIBLE '!'
62 #endif
63
64 namespace KJS {
65 namespace Bindings {
66
67 /*
68 By default, a JavaScript method name is produced by concatenating the
69 components of an ObjectiveC method name, replacing ':' with '_', and
70 escaping '_' and '$' with a leading '$', such that '_' becomes "$_" and
71 '$' becomes "$$". For example:
72
73 ObjectiveC name Default JavaScript name
74 moveTo:: moveTo__
75 moveTo_ moveTo$_
76 moveTo$_ moveTo$$$_
77
78 This function performs the inverse of that operation.
79
80 @result Fills 'buffer' with the ObjectiveC method name that corresponds to 'JSName'.
81 Returns true for success, false for failure. (Failure occurs when 'buffer'
82 is not big enough to hold the result.)
83 */
84 bool convertJSMethodNameToObjc(const char *JSName, char *buffer, size_t bufferSize)
85 {
86 ASSERT(JSName && buffer);
87
88 const char *sp = JSName; // source pointer
89 char *dp = buffer; // destination pointer
90
91 char *end = buffer + bufferSize;
92 while (dp < end) {
93 if (*sp == '$') {
94 ++sp;
95 *dp = *sp;
96 } else if (*sp == '_')
97 *dp = ':';
98 else
99 *dp = *sp;
100
101 // If a future coder puts funny ++ operators above, we might write off the end
102 // of the buffer in the middle of this loop. Let's make sure to check for that.
103 ASSERT(dp < end);
104
105 if (*sp == 0) { // We finished converting JSName
106 ASSERT(strlen(JSName) < bufferSize);
107 return true;
108 }
109
110 ++sp;
111 ++dp;
112 }
113
114 return false; // We ran out of buffer before converting JSName
115 }
116
117 /*
118
119 JavaScript to ObjC
120 Number coerced to char, short, int, long, float, double, or NSNumber, as appropriate
121 String NSString
122 wrapper id
123 Object WebScriptObject
124 null NSNull
125 [], other exception
126
127 */
128 ObjcValue convertValueToObjcValue(ExecState *exec, JSValue *value, ObjcValueType type)
129 {
130 ObjcValue result;
131 double d = 0;
132
133 if (value->isNumber() || value->isString() || value->isBoolean())
134 d = value->toNumber(exec);
135
136 switch (type) {
137 case ObjcObjectType: {
138 JSLock lock;
139
140 JSGlobalObject *originGlobalObject = exec->dynamicGlobalObject();
141 RootObject* originRootObject = findRootObject(originGlobalObject);
142
143 JSGlobalObject* globalObject = 0;
144 if (value->isObject() && static_cast<JSObject*>(value)->isGlobalObject())
145 globalObject = static_cast<JSGlobalObject*>(value);
146
147 if (!globalObject)
148 globalObject = originGlobalObject;
149
150 RootObject* rootObject = findRootObject(globalObject);
151 result.objectValue = rootObject
152 ? [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:originRootObject rootObject:rootObject]
153 : nil;
154 }
155 break;
156
157 case ObjcCharType:
158 case ObjcUnsignedCharType:
159 result.charValue = (char)d;
160 break;
161 case ObjcShortType:
162 case ObjcUnsignedShortType:
163 result.shortValue = (short)d;
164 break;
165 case ObjcIntType:
166 case ObjcUnsignedIntType:
167 result.intValue = (int)d;
168 break;
169 case ObjcLongType:
170 case ObjcUnsignedLongType:
171 result.longValue = (long)d;
172 break;
173 case ObjcLongLongType:
174 case ObjcUnsignedLongLongType:
175 result.longLongValue = (long long)d;
176 break;
177 case ObjcFloatType:
178 result.floatValue = (float)d;
179 break;
180 case ObjcDoubleType:
181 result.doubleValue = (double)d;
182 break;
183 case ObjcVoidType:
184 bzero(&result, sizeof(ObjcValue));
185 break;
186
187 case ObjcInvalidType:
188 default:
189 // FIXME: throw an exception?
190 break;
191 }
192
193 return result;
194 }
195
196 JSValue *convertNSStringToString(NSString *nsstring)
197 {
198 JSLock lock;
199
200 unichar *chars;
201 unsigned int length = [nsstring length];
202 chars = (unichar *)malloc(sizeof(unichar)*length);
203 [nsstring getCharacters:chars];
204 UString u((const UChar*)chars, length);
205 JSValue *aValue = jsString(u);
206 free((void *)chars);
207 return aValue;
208 }
209
210 /*
211 ObjC to JavaScript
212 ---- ----------
213 char number
214 short number
215 int number
216 long number
217 float number
218 double number
219 NSNumber boolean or number
220 NSString string
221 NSArray array
222 NSNull null
223 WebScriptObject underlying JavaScript object
224 WebUndefined undefined
225 id object wrapper
226 other should not happen
227 */
228 JSValue* convertObjcValueToValue(ExecState* exec, void* buffer, ObjcValueType type, RootObject* rootObject)
229 {
230 JSLock lock;
231
232 switch (type) {
233 case ObjcObjectType: {
234 id obj = *(id*)buffer;
235 if ([obj isKindOfClass:[NSString class]])
236 return convertNSStringToString((NSString *)obj);
237 if ([obj isKindOfClass:webUndefinedClass()])
238 return jsUndefined();
239 if ((CFBooleanRef)obj == kCFBooleanTrue)
240 return jsBoolean(true);
241 if ((CFBooleanRef)obj == kCFBooleanFalse)
242 return jsBoolean(false);
243 if ([obj isKindOfClass:[NSNumber class]])
244 return jsNumber([obj doubleValue]);
245 if ([obj isKindOfClass:[NSArray class]])
246 return new RuntimeArray(exec, new ObjcArray(obj, rootObject));
247 if ([obj isKindOfClass:webScriptObjectClass()]) {
248 JSObject* imp = [obj _imp];
249 return imp ? imp : jsUndefined();
250 }
251 if ([obj isKindOfClass:[NSNull class]])
252 return jsNull();
253 if (obj == 0)
254 return jsUndefined();
255 return Instance::createRuntimeObject(Instance::ObjectiveCLanguage, obj, rootObject);
256 }
257 case ObjcCharType:
258 return jsNumber(*(char *)buffer);
259 case ObjcUnsignedCharType:
260 return jsNumber(*(unsigned char *)buffer);
261 case ObjcShortType:
262 return jsNumber(*(short *)buffer);
263 case ObjcUnsignedShortType:
264 return jsNumber(*(unsigned short *)buffer);
265 case ObjcIntType:
266 return jsNumber(*(int *)buffer);
267 case ObjcUnsignedIntType:
268 return jsNumber(*(unsigned int *)buffer);
269 case ObjcLongType:
270 return jsNumber(*(long *)buffer);
271 case ObjcUnsignedLongType:
272 return jsNumber(*(unsigned long *)buffer);
273 case ObjcLongLongType:
274 return jsNumber(*(long long *)buffer);
275 case ObjcUnsignedLongLongType:
276 return jsNumber(*(unsigned long long *)buffer);
277 case ObjcFloatType:
278 return jsNumber(*(float *)buffer);
279 case ObjcDoubleType:
280 return jsNumber(*(double *)buffer);
281 default:
282 // Should never get here. Argument types are filtered.
283 fprintf(stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)type);
284 ASSERT(false);
285 }
286
287 return 0;
288 }
289
290 ObjcValueType objcValueTypeForType(const char *type)
291 {
292 int typeLength = strlen(type);
293 ObjcValueType objcValueType = ObjcInvalidType;
294
295 for (int i = 0; i < typeLength; ++i) {
296 char typeChar = type[i];
297 switch (typeChar) {
298 case _C_CONST:
299 case _C_BYCOPY:
300 case _C_BYREF:
301 case _C_ONEWAY:
302 case _C_GCINVISIBLE:
303 // skip these type modifiers
304 break;
305 case _C_ID:
306 objcValueType = ObjcObjectType;
307 break;
308 case _C_CHR:
309 objcValueType = ObjcCharType;
310 break;
311 case _C_UCHR:
312 objcValueType = ObjcUnsignedCharType;
313 break;
314 case _C_SHT:
315 objcValueType = ObjcShortType;
316 break;
317 case _C_USHT:
318 objcValueType = ObjcUnsignedShortType;
319 break;
320 case _C_INT:
321 objcValueType = ObjcIntType;
322 break;
323 case _C_UINT:
324 objcValueType = ObjcUnsignedIntType;
325 break;
326 case _C_LNG:
327 objcValueType = ObjcLongType;
328 break;
329 case _C_ULNG:
330 objcValueType = ObjcUnsignedLongType;
331 break;
332 case _C_LNG_LNG:
333 objcValueType = ObjcLongLongType;
334 break;
335 case _C_ULNG_LNG:
336 objcValueType = ObjcUnsignedLongLongType;
337 break;
338 case _C_FLT:
339 objcValueType = ObjcFloatType;
340 break;
341 case _C_DBL:
342 objcValueType = ObjcDoubleType;
343 break;
344 case _C_VOID:
345 objcValueType = ObjcVoidType;
346 break;
347 default:
348 // Unhandled type. We don't handle C structs, unions, etc.
349 // FIXME: throw an exception?
350 ASSERT(false);
351 }
352
353 if (objcValueType != ObjcInvalidType)
354 break;
355 }
356
357 return objcValueType;
358 }
359
360 JSObject *throwError(ExecState *exec, ErrorType type, NSString *message)
361 {
362 ASSERT(message);
363 size_t length = [message length];
364 unichar *buffer = new unichar[length];
365 [message getCharacters:buffer];
366 JSObject *error = throwError(exec, type, UString(reinterpret_cast<UChar *>(buffer), length));
367 delete [] buffer;
368 return error;
369 }
370
371 }
372 }