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