1/* 2 * Copyright (C) 2004, 2013 Apple 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 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 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 65namespace JSC { 66namespace Bindings { 67 68/* 69 70 JavaScript to ObjC 71 Number coerced to char, short, int, long, float, double, or NSNumber, as appropriate 72 String NSString 73 wrapper id 74 Object WebScriptObject 75 null NSNull 76 [], other exception 77 78*/ 79ObjcValue convertValueToObjcValue(ExecState* exec, JSValue value, ObjcValueType type) 80{ 81 ObjcValue result; 82 double d = 0; 83 84 if (value.isNumber() || value.isString() || value.isBoolean()) 85 d = value.toNumber(exec); 86 87 switch (type) { 88 case ObjcObjectType: { 89 JSLockHolder lock(exec); 90 91 JSGlobalObject *originGlobalObject = exec->vmEntryGlobalObject(); 92 RootObject* originRootObject = findRootObject(originGlobalObject); 93 94 JSGlobalObject* globalObject = 0; 95 if (value.isObject() && asObject(value)->isGlobalObject()) 96 globalObject = jsCast<JSGlobalObject*>(asObject(value)); 97 98 if (!globalObject) 99 globalObject = originGlobalObject; 100 101 RootObject* rootObject = findRootObject(globalObject); 102 result.objectValue = rootObject 103 ? [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:originRootObject rootObject:rootObject] 104 : nil; 105 } 106 break; 107 108 case ObjcCharType: 109 case ObjcUnsignedCharType: 110 result.charValue = (char)d; 111 break; 112 case ObjcShortType: 113 case ObjcUnsignedShortType: 114 result.shortValue = (short)d; 115 break; 116 case ObjcBoolType: 117 result.booleanValue = (bool)d; 118 break; 119 case ObjcIntType: 120 case ObjcUnsignedIntType: 121 result.intValue = (int)d; 122 break; 123 case ObjcLongType: 124 case ObjcUnsignedLongType: 125 result.longValue = (long)d; 126 break; 127 case ObjcLongLongType: 128 case ObjcUnsignedLongLongType: 129 result.longLongValue = (long long)d; 130 break; 131 case ObjcFloatType: 132 result.floatValue = (float)d; 133 break; 134 case ObjcDoubleType: 135 result.doubleValue = (double)d; 136 break; 137 case ObjcVoidType: 138 bzero(&result, sizeof(ObjcValue)); 139 break; 140 141 case ObjcInvalidType: 142 default: 143 // FIXME: throw an exception? 144 break; 145 } 146 147 return result; 148} 149 150JSValue convertNSStringToString(ExecState* exec, NSString *nsstring) 151{ 152 JSLockHolder lock(exec); 153 JSValue aValue = jsString(exec, String(nsstring)); 154 return aValue; 155} 156 157/* 158 ObjC to JavaScript 159 ---- ---------- 160 char number 161 short number 162 int number 163 long number 164 float number 165 double number 166 NSNumber boolean or number 167 NSString string 168 NSArray array 169 NSNull null 170 WebScriptObject underlying JavaScript object 171 WebUndefined undefined 172 id object wrapper 173 other should not happen 174*/ 175JSValue convertObjcValueToValue(ExecState* exec, void* buffer, ObjcValueType type, RootObject* rootObject) 176{ 177 JSLockHolder lock(exec); 178 179 switch (type) { 180 case ObjcObjectType: { 181 id obj = *(id*)buffer; 182 if ([obj isKindOfClass:[NSString class]]) 183 return convertNSStringToString(exec, (NSString *)obj); 184 if ([obj isKindOfClass:webUndefinedClass()]) 185 return jsUndefined(); 186 if ((CFBooleanRef)obj == kCFBooleanTrue) 187 return jsBoolean(true); 188 if ((CFBooleanRef)obj == kCFBooleanFalse) 189 return jsBoolean(false); 190 if ([obj isKindOfClass:[NSNumber class]]) 191 return jsNumber([obj doubleValue]); 192 if ([obj isKindOfClass:[NSArray class]]) 193 return RuntimeArray::create(exec, new ObjcArray(obj, rootObject)); 194 if ([obj isKindOfClass:webScriptObjectClass()]) { 195 JSObject* imp = [obj _imp]; 196 return imp ? imp : jsUndefined(); 197 } 198 if ([obj isKindOfClass:[NSNull class]]) 199 return jsNull(); 200 if (obj == 0) 201 return jsUndefined(); 202 return ObjcInstance::create(obj, rootObject)->createRuntimeObject(exec); 203 } 204 case ObjcCharType: 205 return jsNumber(*(char*)buffer); 206 case ObjcUnsignedCharType: 207 return jsNumber(*(unsigned char*)buffer); 208 case ObjcShortType: 209 return jsNumber(*(short*)buffer); 210 case ObjcUnsignedShortType: 211 return jsNumber(*(unsigned short*)buffer); 212 case ObjcBoolType: 213 return jsBoolean(*(bool*)buffer); 214 case ObjcIntType: 215 return jsNumber(*(int*)buffer); 216 case ObjcUnsignedIntType: 217 return jsNumber(*(unsigned int*)buffer); 218 case ObjcLongType: 219 return jsNumber(*(long*)buffer); 220 case ObjcUnsignedLongType: 221 return jsNumber(*(unsigned long*)buffer); 222 case ObjcLongLongType: 223 return jsNumber(*(long long*)buffer); 224 case ObjcUnsignedLongLongType: 225 return jsNumber(*(unsigned long long*)buffer); 226 case ObjcFloatType: 227 return jsNumber(*(float*)buffer); 228 case ObjcDoubleType: 229 return jsNumber(*(double*)buffer); 230 default: 231 // Should never get here. Argument types are filtered. 232 fprintf(stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)type); 233 ASSERT_NOT_REACHED(); 234 } 235 236 return jsUndefined(); 237} 238 239ObjcValueType objcValueTypeForType(const char *type) 240{ 241 int typeLength = strlen(type); 242 ObjcValueType objcValueType = ObjcInvalidType; 243 244 for (int i = 0; i < typeLength; ++i) { 245 char typeChar = type[i]; 246 switch (typeChar) { 247 case _C_CONST: 248 case _C_BYCOPY: 249 case _C_BYREF: 250 case _C_ONEWAY: 251 case _C_GCINVISIBLE: 252 // skip these type modifiers 253 break; 254 case _C_ID: 255 objcValueType = ObjcObjectType; 256 break; 257 case _C_CHR: 258 objcValueType = ObjcCharType; 259 break; 260 case _C_UCHR: 261 objcValueType = ObjcUnsignedCharType; 262 break; 263 case _C_SHT: 264 objcValueType = ObjcShortType; 265 break; 266 case _C_USHT: 267 objcValueType = ObjcUnsignedShortType; 268 break; 269 case _C_BOOL: 270 objcValueType = ObjcBoolType; 271 break; 272 case _C_INT: 273 objcValueType = ObjcIntType; 274 break; 275 case _C_UINT: 276 objcValueType = ObjcUnsignedIntType; 277 break; 278 case _C_LNG: 279 objcValueType = ObjcLongType; 280 break; 281 case _C_ULNG: 282 objcValueType = ObjcUnsignedLongType; 283 break; 284 case _C_LNG_LNG: 285 objcValueType = ObjcLongLongType; 286 break; 287 case _C_ULNG_LNG: 288 objcValueType = ObjcUnsignedLongLongType; 289 break; 290 case _C_FLT: 291 objcValueType = ObjcFloatType; 292 break; 293 case _C_DBL: 294 objcValueType = ObjcDoubleType; 295 break; 296 case _C_VOID: 297 objcValueType = ObjcVoidType; 298 break; 299 default: 300 // Unhandled type. We don't handle C structs, unions, etc. 301 // FIXME: throw an exception? 302 WTFLogAlways("Unhandled ObjC type specifier: \"%c\" used in ObjC bridge.", typeChar); 303 RELEASE_ASSERT_NOT_REACHED(); 304 } 305 306 if (objcValueType != ObjcInvalidType) 307 break; 308 } 309 310 return objcValueType; 311} 312 313JSObject *throwError(ExecState *exec, NSString *message) 314{ 315 ASSERT(message); 316 JSObject *error = exec->vm().throwException(exec, JSC::createError(exec, String(message))); 317 return error; 318} 319 320} 321} 322