2 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "objc_utility.h"
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>
36 #if !defined(_C_LNG_LNG)
37 #define _C_LNG_LNG 'q'
40 #if !defined(_C_ULNG_LNG)
41 #define _C_ULNG_LNG 'Q'
44 #if !defined(_C_CONST)
48 #if !defined(_C_BYCOPY)
52 #if !defined(_C_BYREF)
56 #if !defined(_C_ONEWAY)
60 #if !defined(_C_GCINVISIBLE)
61 #define _C_GCINVISIBLE '!'
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:
73 ObjectiveC name Default JavaScript name
78 This function performs the inverse of that operation.
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.)
84 bool convertJSMethodNameToObjc(const char *JSName, char *buffer, size_t bufferSize)
86 ASSERT(JSName && buffer);
88 const char *sp = JSName; // source pointer
89 char *dp = buffer; // destination pointer
91 char *end = buffer + bufferSize;
96 } else if (*sp == '_')
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.
105 if (*sp == 0) { // We finished converting JSName
106 ASSERT(strlen(JSName) < bufferSize);
114 return false; // We ran out of buffer before converting JSName
120 Number coerced to char, short, int, long, float, double, or NSNumber, as appropriate
123 Object WebScriptObject
128 ObjcValue convertValueToObjcValue(ExecState *exec, JSValue *value, ObjcValueType type)
133 if (value->isNumber() || value->isString() || value->isBoolean())
134 d = value->toNumber(exec);
137 case ObjcObjectType: {
140 JSGlobalObject *originGlobalObject = exec->dynamicGlobalObject();
141 RootObject* originRootObject = findRootObject(originGlobalObject);
143 JSGlobalObject* globalObject = 0;
144 if (value->isObject() && static_cast<JSObject*>(value)->isGlobalObject())
145 globalObject = static_cast<JSGlobalObject*>(value);
148 globalObject = originGlobalObject;
150 RootObject* rootObject = findRootObject(globalObject);
151 result.objectValue = rootObject
152 ? [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:originRootObject rootObject:rootObject]
158 case ObjcUnsignedCharType:
159 result.charValue = (char)d;
162 case ObjcUnsignedShortType:
163 result.shortValue = (short)d;
166 case ObjcUnsignedIntType:
167 result.intValue = (int)d;
170 case ObjcUnsignedLongType:
171 result.longValue = (long)d;
173 case ObjcLongLongType:
174 case ObjcUnsignedLongLongType:
175 result.longLongValue = (long long)d;
178 result.floatValue = (float)d;
181 result.doubleValue = (double)d;
184 bzero(&result, sizeof(ObjcValue));
187 case ObjcInvalidType:
189 // FIXME: throw an exception?
196 JSValue *convertNSStringToString(NSString *nsstring)
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);
219 NSNumber boolean or number
223 WebScriptObject underlying JavaScript object
224 WebUndefined undefined
226 other should not happen
228 JSValue* convertObjcValueToValue(ExecState* exec, void* buffer, ObjcValueType type, RootObject* rootObject)
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();
251 if ([obj isKindOfClass:[NSNull class]])
254 return jsUndefined();
255 return Instance::createRuntimeObject(Instance::ObjectiveCLanguage, obj, rootObject);
258 return jsNumber(*(char *)buffer);
259 case ObjcUnsignedCharType:
260 return jsNumber(*(unsigned char *)buffer);
262 return jsNumber(*(short *)buffer);
263 case ObjcUnsignedShortType:
264 return jsNumber(*(unsigned short *)buffer);
266 return jsNumber(*(int *)buffer);
267 case ObjcUnsignedIntType:
268 return jsNumber(*(unsigned int *)buffer);
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);
278 return jsNumber(*(float *)buffer);
280 return jsNumber(*(double *)buffer);
282 // Should never get here. Argument types are filtered.
283 fprintf(stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)type);
290 ObjcValueType objcValueTypeForType(const char *type)
292 int typeLength = strlen(type);
293 ObjcValueType objcValueType = ObjcInvalidType;
295 for (int i = 0; i < typeLength; ++i) {
296 char typeChar = type[i];
303 // skip these type modifiers
306 objcValueType = ObjcObjectType;
309 objcValueType = ObjcCharType;
312 objcValueType = ObjcUnsignedCharType;
315 objcValueType = ObjcShortType;
318 objcValueType = ObjcUnsignedShortType;
321 objcValueType = ObjcIntType;
324 objcValueType = ObjcUnsignedIntType;
327 objcValueType = ObjcLongType;
330 objcValueType = ObjcUnsignedLongType;
333 objcValueType = ObjcLongLongType;
336 objcValueType = ObjcUnsignedLongLongType;
339 objcValueType = ObjcFloatType;
342 objcValueType = ObjcDoubleType;
345 objcValueType = ObjcVoidType;
348 // Unhandled type. We don't handle C structs, unions, etc.
349 // FIXME: throw an exception?
353 if (objcValueType != ObjcInvalidType)
357 return objcValueType;
360 JSObject *throwError(ExecState *exec, ErrorType type, NSString *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));