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"
31 #include "runtime_array.h"
32 #include "runtime_object.h"
34 #include "WebScriptObject.h"
36 #if !defined(_C_BYCOPY)
40 #if !defined(_C_BYREF)
44 #if !defined(_C_ONEWAY)
48 #if !defined(_C_GCINVISIBLE)
49 #define _C_GCINVISIBLE '!'
56 By default, a JavaScript method name is produced by concatenating the
57 components of an ObjectiveC method name, replacing ':' with '_', and
58 escaping '_' and '$' with a leading '$', such that '_' becomes "$_" and
59 '$' becomes "$$". For example:
61 ObjectiveC name Default JavaScript name
66 This function performs the inverse of that operation.
68 @result Fills 'buffer' with the ObjectiveC method name that corresponds to 'JSName'.
69 Returns true for success, false for failure. (Failure occurs when 'buffer'
70 is not big enough to hold the result.)
72 bool convertJSMethodNameToObjc(const char *JSName, char *buffer, size_t bufferSize)
74 assert(JSName && buffer);
76 const char *sp = JSName; // source pointer
77 char *dp = buffer; // destination pointer
79 char *end = buffer + bufferSize;
84 } else if (*sp == '_')
89 // If a future coder puts funny ++ operators above, we might write off the end
90 // of the buffer in the middle of this loop. Let's make sure to check for that.
93 if (*sp == 0) { // We finished converting JSName
94 assert(strlen(JSName) < bufferSize);
102 return false; // We ran out of buffer before converting JSName
108 Number coerced to char, short, int, long, float, double, or NSNumber, as appropriate
111 Object WebScriptObject
116 ObjcValue convertValueToObjcValue(ExecState *exec, JSValue *value, ObjcValueType type)
121 if (value->isNumber() || value->isString() || value->isBoolean())
122 d = value->toNumber(exec);
125 case ObjcObjectType: {
126 Interpreter *originInterpreter = exec->dynamicInterpreter();
127 const RootObject *originExecutionContext = rootForInterpreter(originInterpreter);
129 Interpreter *interpreter = 0;
130 if (originInterpreter->isGlobalObject(value))
131 interpreter = originInterpreter->interpreterForGlobalObject(value);
134 interpreter = originInterpreter;
136 const RootObject *executionContext = rootForInterpreter(interpreter);
137 if (!executionContext) {
138 RootObject *newExecutionContext = new RootObject(0);
139 newExecutionContext->setInterpreter (interpreter);
140 executionContext = newExecutionContext;
143 if (!webScriptObjectClass)
144 webScriptObjectClass = NSClassFromString(@"WebScriptObject");
145 result.objectValue = [webScriptObjectClass _convertValueToObjcValue:value originExecutionContext:originExecutionContext executionContext:executionContext ];
150 case ObjcUnsignedCharType:
151 result.charValue = (char)d;
154 case ObjcUnsignedShortType:
155 result.shortValue = (short)d;
158 case ObjcUnsignedIntType:
159 result.intValue = (int)d;
162 case ObjcUnsignedLongType:
163 result.longValue = (long)d;
165 case ObjcLongLongType:
166 case ObjcUnsignedLongLongType:
167 result.longValue = (long long)d;
170 result.floatValue = (float)d;
173 result.doubleValue = (double)d;
176 bzero(&result, sizeof(ObjcValue));
179 case ObjcInvalidType:
181 // FIXME: throw an exception?
188 JSValue *convertNSStringToString(NSString *nsstring)
191 unsigned int length = [nsstring length];
192 chars = (unichar *)malloc(sizeof(unichar)*length);
193 [nsstring getCharacters:chars];
194 UString u((const UChar*)chars, length);
195 JSValue *aValue = jsString(u);
209 NSNumber boolean or number
213 WebScriptObject underlying JavaScript object
214 WebUndefined undefined
216 other should not happen
218 JSValue* convertObjcValueToValue(ExecState* exec, void* buffer, ObjcValueType type)
220 static ClassStructPtr webUndefinedClass = 0;
221 if (!webUndefinedClass)
222 webUndefinedClass = NSClassFromString(@"WebUndefined");
223 if (!webScriptObjectClass)
224 webScriptObjectClass = NSClassFromString(@"WebScriptObject");
227 case ObjcObjectType: {
228 id obj = *(id*)buffer;
229 if ([obj isKindOfClass:[NSString class]])
230 return convertNSStringToString((NSString *)obj);
231 if ([obj isKindOfClass:webUndefinedClass])
232 return jsUndefined();
233 if ((CFBooleanRef)obj == kCFBooleanTrue)
234 return jsBoolean(true);
235 if ((CFBooleanRef)obj == kCFBooleanFalse)
236 return jsBoolean(false);
237 if ([obj isKindOfClass:[NSNumber class]])
238 return jsNumber([obj doubleValue]);
239 if ([obj isKindOfClass:[NSArray class]])
240 return new RuntimeArray(exec, new ObjcArray(obj));
241 if ([obj isKindOfClass:webScriptObjectClass])
243 if ([obj isKindOfClass:[NSNull class]])
246 return jsUndefined();
247 return Instance::createRuntimeObject(Instance::ObjectiveCLanguage, obj);
250 return jsNumber(*(char *)buffer);
251 case ObjcUnsignedCharType:
252 return jsNumber(*(unsigned char *)buffer);
254 return jsNumber(*(short *)buffer);
255 case ObjcUnsignedShortType:
256 return jsNumber(*(unsigned short *)buffer);
258 return jsNumber(*(int *)buffer);
259 case ObjcUnsignedIntType:
260 return jsNumber(*(unsigned int *)buffer);
262 return jsNumber(*(long *)buffer);
263 case ObjcUnsignedLongType:
264 return jsNumber(*(unsigned long *)buffer);
265 case ObjcLongLongType:
266 return jsNumber(*(long long *)buffer);
267 case ObjcUnsignedLongLongType:
268 return jsNumber(*(unsigned long long *)buffer);
270 return jsNumber(*(float *)buffer);
272 return jsNumber(*(double *)buffer);
274 // Should never get here. Argument types are filtered.
275 fprintf(stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)type);
282 ObjcValueType objcValueTypeForType(const char *type)
284 int typeLength = strlen(type);
285 ObjcValueType objcValueType = ObjcInvalidType;
287 for (int i = 0; i < typeLength; ++i) {
288 char typeChar = type[i];
295 // skip these type modifiers
298 objcValueType = ObjcObjectType;
301 objcValueType = ObjcCharType;
304 objcValueType = ObjcUnsignedCharType;
307 objcValueType = ObjcShortType;
310 objcValueType = ObjcUnsignedShortType;
313 objcValueType = ObjcIntType;
316 objcValueType = ObjcUnsignedIntType;
319 objcValueType = ObjcLongType;
322 objcValueType = ObjcUnsignedLongType;
325 objcValueType = ObjcLongLongType;
328 objcValueType = ObjcUnsignedLongLongType;
331 objcValueType = ObjcFloatType;
334 objcValueType = ObjcDoubleType;
337 objcValueType = ObjcVoidType;
340 // Unhandled type. We don't handle C structs, unions, etc.
341 // FIXME: throw an exception?
345 if (objcValueType != ObjcInvalidType)
349 return objcValueType;
352 void *createObjcInstanceForValue(JSValue *value, const RootObject *origin, const RootObject *current)
354 if (!value->isObject())
356 if (!webScriptObjectClass)
357 webScriptObjectClass = NSClassFromString(@"WebScriptObject");
358 JSObject *object = static_cast<JSObject *>(value);
359 return [[[webScriptObjectClass alloc] _initWithJSObject:object originExecutionContext:origin executionContext:current] autorelease];
362 JSObject *throwError(ExecState *exec, ErrorType type, NSString *message)
365 size_t length = [message length];
366 unichar *buffer = new unichar[length];
367 [message getCharacters:buffer];
368 JSObject *error = throwError(exec, type, UString(reinterpret_cast<UChar *>(buffer), length));