1/*
2 * Copyright (C) 2006, 2007 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 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 "JSValueRef.h"
28
29#include "APICast.h"
30#include "APIShims.h"
31#include "JSCallbackObject.h"
32
33#include <runtime/JSGlobalObject.h>
34#include <runtime/JSONObject.h>
35#include <runtime/JSString.h>
36#include <runtime/LiteralParser.h>
37#include <runtime/Operations.h>
38#include <runtime/Protect.h>
39#include <runtime/UString.h>
40#include <runtime/JSValue.h>
41
42#include <wtf/Assertions.h>
43#include <wtf/text/StringHash.h>
44
45#include <algorithm> // for std::min
46
47using namespace JSC;
48
49::JSType JSValueGetType(JSContextRef ctx, JSValueRef value)
50{
51    ExecState* exec = toJS(ctx);
52    APIEntryShim entryShim(exec);
53
54    JSValue jsValue = toJS(exec, value);
55
56    if (jsValue.isUndefined())
57        return kJSTypeUndefined;
58    if (jsValue.isNull())
59        return kJSTypeNull;
60    if (jsValue.isBoolean())
61        return kJSTypeBoolean;
62    if (jsValue.isNumber())
63        return kJSTypeNumber;
64    if (jsValue.isString())
65        return kJSTypeString;
66    ASSERT(jsValue.isObject());
67    return kJSTypeObject;
68}
69
70bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value)
71{
72    ExecState* exec = toJS(ctx);
73    APIEntryShim entryShim(exec);
74
75    JSValue jsValue = toJS(exec, value);
76    return jsValue.isUndefined();
77}
78
79bool JSValueIsNull(JSContextRef ctx, JSValueRef value)
80{
81    ExecState* exec = toJS(ctx);
82    APIEntryShim entryShim(exec);
83
84    JSValue jsValue = toJS(exec, value);
85    return jsValue.isNull();
86}
87
88bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value)
89{
90    ExecState* exec = toJS(ctx);
91    APIEntryShim entryShim(exec);
92
93    JSValue jsValue = toJS(exec, value);
94    return jsValue.isBoolean();
95}
96
97bool JSValueIsNumber(JSContextRef ctx, JSValueRef value)
98{
99    ExecState* exec = toJS(ctx);
100    APIEntryShim entryShim(exec);
101
102    JSValue jsValue = toJS(exec, value);
103    return jsValue.isNumber();
104}
105
106bool JSValueIsString(JSContextRef ctx, JSValueRef value)
107{
108    ExecState* exec = toJS(ctx);
109    APIEntryShim entryShim(exec);
110
111    JSValue jsValue = toJS(exec, value);
112    return jsValue.isString();
113}
114
115bool JSValueIsObject(JSContextRef ctx, JSValueRef value)
116{
117    ExecState* exec = toJS(ctx);
118    APIEntryShim entryShim(exec);
119
120    JSValue jsValue = toJS(exec, value);
121    return jsValue.isObject();
122}
123
124bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass)
125{
126    ExecState* exec = toJS(ctx);
127    APIEntryShim entryShim(exec);
128
129    JSValue jsValue = toJS(exec, value);
130
131    if (JSObject* o = jsValue.getObject()) {
132        if (o->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
133            return static_cast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass);
134        if (o->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info))
135            return static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(o)->inherits(jsClass);
136    }
137    return false;
138}
139
140bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* exception)
141{
142    ExecState* exec = toJS(ctx);
143    APIEntryShim entryShim(exec);
144
145    JSValue jsA = toJS(exec, a);
146    JSValue jsB = toJS(exec, b);
147
148    bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown
149    if (exec->hadException()) {
150        if (exception)
151            *exception = toRef(exec, exec->exception());
152        exec->clearException();
153    }
154    return result;
155}
156
157bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b)
158{
159    ExecState* exec = toJS(ctx);
160    APIEntryShim entryShim(exec);
161
162    JSValue jsA = toJS(exec, a);
163    JSValue jsB = toJS(exec, b);
164
165    return JSValue::strictEqual(exec, jsA, jsB);
166}
167
168bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObjectRef constructor, JSValueRef* exception)
169{
170    ExecState* exec = toJS(ctx);
171    APIEntryShim entryShim(exec);
172
173    JSValue jsValue = toJS(exec, value);
174
175    JSObject* jsConstructor = toJS(constructor);
176    if (!jsConstructor->structure()->typeInfo().implementsHasInstance())
177        return false;
178    bool result = jsConstructor->hasInstance(exec, jsValue, jsConstructor->get(exec, exec->propertyNames().prototype)); // false if an exception is thrown
179    if (exec->hadException()) {
180        if (exception)
181            *exception = toRef(exec, exec->exception());
182        exec->clearException();
183    }
184    return result;
185}
186
187JSValueRef JSValueMakeUndefined(JSContextRef ctx)
188{
189    ExecState* exec = toJS(ctx);
190    APIEntryShim entryShim(exec);
191
192    return toRef(exec, jsUndefined());
193}
194
195JSValueRef JSValueMakeNull(JSContextRef ctx)
196{
197    ExecState* exec = toJS(ctx);
198    APIEntryShim entryShim(exec);
199
200    return toRef(exec, jsNull());
201}
202
203JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value)
204{
205    ExecState* exec = toJS(ctx);
206    APIEntryShim entryShim(exec);
207
208    return toRef(exec, jsBoolean(value));
209}
210
211JSValueRef JSValueMakeNumber(JSContextRef ctx, double value)
212{
213    ExecState* exec = toJS(ctx);
214    APIEntryShim entryShim(exec);
215
216    // Our JSValue representation relies on a standard bit pattern for NaN. NaNs
217    // generated internally to JavaScriptCore naturally have that representation,
218    // but an external NaN might not.
219    if (isnan(value))
220        value = NaN;
221
222    return toRef(exec, jsNumber(value));
223}
224
225JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string)
226{
227    ExecState* exec = toJS(ctx);
228    APIEntryShim entryShim(exec);
229
230    return toRef(exec, jsString(exec, string->ustring()));
231}
232
233JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string)
234{
235    ExecState* exec = toJS(ctx);
236    APIEntryShim entryShim(exec);
237    LiteralParser parser(exec, string->ustring(), LiteralParser::StrictJSON);
238    return toRef(exec, parser.tryLiteralParse());
239}
240
241JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsigned indent, JSValueRef* exception)
242{
243    ExecState* exec = toJS(ctx);
244    APIEntryShim entryShim(exec);
245    JSValue value = toJS(exec, apiValue);
246    UString result = JSONStringify(exec, value, indent);
247    if (exception)
248        *exception = 0;
249    if (exec->hadException()) {
250        if (exception)
251            *exception = toRef(exec, exec->exception());
252        exec->clearException();
253        return 0;
254    }
255    return OpaqueJSString::create(result).leakRef();
256}
257
258bool JSValueToBoolean(JSContextRef ctx, JSValueRef value)
259{
260    ExecState* exec = toJS(ctx);
261    APIEntryShim entryShim(exec);
262
263    JSValue jsValue = toJS(exec, value);
264    return jsValue.toBoolean(exec);
265}
266
267double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
268{
269    ExecState* exec = toJS(ctx);
270    APIEntryShim entryShim(exec);
271
272    JSValue jsValue = toJS(exec, value);
273
274    double number = jsValue.toNumber(exec);
275    if (exec->hadException()) {
276        if (exception)
277            *exception = toRef(exec, exec->exception());
278        exec->clearException();
279        number = NaN;
280    }
281    return number;
282}
283
284JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
285{
286    ExecState* exec = toJS(ctx);
287    APIEntryShim entryShim(exec);
288
289    JSValue jsValue = toJS(exec, value);
290
291    RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec)));
292    if (exec->hadException()) {
293        if (exception)
294            *exception = toRef(exec, exec->exception());
295        exec->clearException();
296        stringRef.clear();
297    }
298    return stringRef.release().leakRef();
299}
300
301JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
302{
303    ExecState* exec = toJS(ctx);
304    APIEntryShim entryShim(exec);
305
306    JSValue jsValue = toJS(exec, value);
307
308    JSObjectRef objectRef = toRef(jsValue.toObject(exec));
309    if (exec->hadException()) {
310        if (exception)
311            *exception = toRef(exec, exec->exception());
312        exec->clearException();
313        objectRef = 0;
314    }
315    return objectRef;
316}
317
318void JSValueProtect(JSContextRef ctx, JSValueRef value)
319{
320    ExecState* exec = toJS(ctx);
321    APIEntryShim entryShim(exec);
322
323    JSValue jsValue = toJSForGC(exec, value);
324    gcProtect(jsValue);
325}
326
327void JSValueUnprotect(JSContextRef ctx, JSValueRef value)
328{
329    ExecState* exec = toJS(ctx);
330    APIEntryShim entryShim(exec);
331
332    JSValue jsValue = toJSForGC(exec, value);
333    gcUnprotect(jsValue);
334}
335