1 | /* |
2 | * Copyright (C) 2010 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. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "NPJSObject.h" |
28 | |
29 | #if ENABLE(NETSCAPE_PLUGIN_API) |
30 | |
31 | #include "JSNPObject.h" |
32 | #include "NPRuntimeObjectMap.h" |
33 | #include "NPRuntimeUtilities.h" |
34 | #include <JavaScriptCore/CatchScope.h> |
35 | #include <JavaScriptCore/JSCInlines.h> |
36 | #include <JavaScriptCore/JSCellInlines.h> |
37 | #include <JavaScriptCore/JSLock.h> |
38 | #include <JavaScriptCore/JSObject.h> |
39 | #include <JavaScriptCore/StrongInlines.h> |
40 | #include <WebCore/Frame.h> |
41 | #include <WebCore/IdentifierRep.h> |
42 | #include <wtf/text/WTFString.h> |
43 | |
44 | namespace WebKit { |
45 | using namespace JSC; |
46 | using namespace WebCore; |
47 | |
48 | NPJSObject* NPJSObject::create(VM& vm, NPRuntimeObjectMap* objectMap, JSObject* jsObject) |
49 | { |
50 | // We should never have a JSNPObject inside an NPJSObject. |
51 | ASSERT(!jsObject->inherits<JSNPObject>(vm)); |
52 | |
53 | NPJSObject* npJSObject = toNPJSObject(createNPObject(0, npClass())); |
54 | npJSObject->initialize(vm, objectMap, jsObject); |
55 | |
56 | return npJSObject; |
57 | } |
58 | |
59 | NPJSObject::NPJSObject() |
60 | : m_objectMap(0) |
61 | { |
62 | } |
63 | |
64 | NPJSObject::~NPJSObject() |
65 | { |
66 | m_objectMap->npJSObjectDestroyed(this); |
67 | } |
68 | |
69 | bool NPJSObject::isNPJSObject(NPObject* npObject) |
70 | { |
71 | return npObject->_class == npClass(); |
72 | } |
73 | |
74 | void NPJSObject::initialize(VM& vm, NPRuntimeObjectMap* objectMap, JSObject* jsObject) |
75 | { |
76 | ASSERT(!m_objectMap); |
77 | ASSERT(!m_jsObject); |
78 | |
79 | m_objectMap = objectMap; |
80 | m_jsObject.set(vm, jsObject); |
81 | } |
82 | |
83 | static Identifier identifierFromIdentifierRep(ExecState* exec, IdentifierRep* identifierRep) |
84 | { |
85 | ASSERT(identifierRep->isString()); |
86 | |
87 | const char* string = identifierRep->string(); |
88 | int length = strlen(string); |
89 | |
90 | return Identifier::fromString(exec, String::fromUTF8WithLatin1Fallback(string, length)); |
91 | } |
92 | |
93 | bool NPJSObject::hasMethod(NPIdentifier methodName) |
94 | { |
95 | IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName); |
96 | |
97 | if (!identifierRep->isString()) |
98 | return false; |
99 | |
100 | ExecState* exec = m_objectMap->globalExec(); |
101 | if (!exec) |
102 | return false; |
103 | |
104 | VM& vm = exec->vm(); |
105 | JSLockHolder lock(vm); |
106 | auto scope = DECLARE_CATCH_SCOPE(vm); |
107 | |
108 | JSValue value = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep)); |
109 | scope.clearException(); |
110 | |
111 | CallData callData; |
112 | return getCallData(vm, value, callData) != CallType::None; |
113 | } |
114 | |
115 | bool NPJSObject::invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) |
116 | { |
117 | IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName); |
118 | |
119 | if (!identifierRep->isString()) |
120 | return false; |
121 | |
122 | ExecState* exec = m_objectMap->globalExec(); |
123 | if (!exec) |
124 | return false; |
125 | |
126 | JSLockHolder lock(exec); |
127 | |
128 | JSValue function = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep)); |
129 | return invoke(exec, m_objectMap->globalObject(), function, arguments, argumentCount, result); |
130 | } |
131 | |
132 | bool NPJSObject::invokeDefault(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) |
133 | { |
134 | ExecState* exec = m_objectMap->globalExec(); |
135 | if (!exec) |
136 | return false; |
137 | |
138 | JSLockHolder lock(exec); |
139 | |
140 | JSValue function = m_jsObject.get(); |
141 | return invoke(exec, m_objectMap->globalObject(), function, arguments, argumentCount, result); |
142 | } |
143 | |
144 | bool NPJSObject::hasProperty(NPIdentifier identifier) |
145 | { |
146 | IdentifierRep* identifierRep = static_cast<IdentifierRep*>(identifier); |
147 | |
148 | ExecState* exec = m_objectMap->globalExec(); |
149 | if (!exec) |
150 | return false; |
151 | |
152 | VM& vm = exec->vm(); |
153 | JSLockHolder lock(vm); |
154 | auto scope = DECLARE_CATCH_SCOPE(vm); |
155 | |
156 | bool result; |
157 | if (identifierRep->isString()) |
158 | result = m_jsObject->hasProperty(exec, identifierFromIdentifierRep(exec, identifierRep)); |
159 | else |
160 | result = m_jsObject->hasProperty(exec, identifierRep->number()); |
161 | |
162 | scope.clearException(); |
163 | return result; |
164 | } |
165 | |
166 | bool NPJSObject::getProperty(NPIdentifier propertyName, NPVariant* result) |
167 | { |
168 | IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName); |
169 | |
170 | ExecState* exec = m_objectMap->globalExec(); |
171 | if (!exec) |
172 | return false; |
173 | |
174 | VM& vm = exec->vm(); |
175 | JSLockHolder lock(vm); |
176 | auto scope = DECLARE_CATCH_SCOPE(vm); |
177 | |
178 | JSValue jsResult; |
179 | if (identifierRep->isString()) |
180 | jsResult = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep)); |
181 | else |
182 | jsResult = m_jsObject->get(exec, identifierRep->number()); |
183 | |
184 | m_objectMap->convertJSValueToNPVariant(exec, jsResult, *result); |
185 | scope.clearException(); |
186 | return true; |
187 | } |
188 | |
189 | bool NPJSObject::setProperty(NPIdentifier propertyName, const NPVariant* value) |
190 | { |
191 | IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName); |
192 | |
193 | ExecState* exec = m_objectMap->globalExec(); |
194 | if (!exec) |
195 | return false; |
196 | |
197 | VM& vm = exec->vm(); |
198 | JSLockHolder lock(vm); |
199 | auto scope = DECLARE_CATCH_SCOPE(vm); |
200 | |
201 | JSValue jsValue = m_objectMap->convertNPVariantToJSValue(exec, m_objectMap->globalObject(), *value); |
202 | if (identifierRep->isString()) { |
203 | PutPropertySlot slot(m_jsObject.get()); |
204 | m_jsObject->methodTable(vm)->put(m_jsObject.get(), exec, identifierFromIdentifierRep(exec, identifierRep), jsValue, slot); |
205 | } else |
206 | m_jsObject->methodTable(vm)->putByIndex(m_jsObject.get(), exec, identifierRep->number(), jsValue, false); |
207 | scope.clearException(); |
208 | |
209 | return true; |
210 | } |
211 | |
212 | bool NPJSObject::removeProperty(NPIdentifier propertyName) |
213 | { |
214 | IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName); |
215 | |
216 | ExecState* exec = m_objectMap->globalExec(); |
217 | if (!exec) |
218 | return false; |
219 | |
220 | VM& vm = exec->vm(); |
221 | JSLockHolder lock(vm); |
222 | auto scope = DECLARE_CATCH_SCOPE(vm); |
223 | |
224 | if (identifierRep->isString()) { |
225 | Identifier identifier = identifierFromIdentifierRep(exec, identifierRep); |
226 | |
227 | if (!m_jsObject->hasProperty(exec, identifier)) { |
228 | scope.clearException(); |
229 | return false; |
230 | } |
231 | |
232 | m_jsObject->methodTable(vm)->deleteProperty(m_jsObject.get(), exec, identifier); |
233 | } else { |
234 | if (!m_jsObject->hasProperty(exec, identifierRep->number())) { |
235 | scope.clearException(); |
236 | return false; |
237 | } |
238 | |
239 | m_jsObject->methodTable(vm)->deletePropertyByIndex(m_jsObject.get(), exec, identifierRep->number()); |
240 | } |
241 | |
242 | scope.clearException(); |
243 | return true; |
244 | } |
245 | |
246 | bool NPJSObject::enumerate(NPIdentifier** identifiers, uint32_t* identifierCount) |
247 | { |
248 | ExecState* exec = m_objectMap->globalExec(); |
249 | if (!exec) |
250 | return false; |
251 | |
252 | VM& vm = exec->vm(); |
253 | JSLockHolder lock(vm); |
254 | |
255 | PropertyNameArray propertyNames(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude); |
256 | m_jsObject->methodTable(vm)->getPropertyNames(m_jsObject.get(), exec, propertyNames, EnumerationMode()); |
257 | |
258 | NPIdentifier* nameIdentifiers = npnMemNewArray<NPIdentifier>(propertyNames.size()); |
259 | |
260 | for (size_t i = 0; i < propertyNames.size(); ++i) |
261 | nameIdentifiers[i] = static_cast<NPIdentifier>(IdentifierRep::get(propertyNames[i].string().utf8().data())); |
262 | |
263 | *identifiers = nameIdentifiers; |
264 | *identifierCount = propertyNames.size(); |
265 | |
266 | return true; |
267 | } |
268 | |
269 | bool NPJSObject::construct(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) |
270 | { |
271 | ExecState* exec = m_objectMap->globalExec(); |
272 | if (!exec) |
273 | return false; |
274 | |
275 | VM& vm = exec->vm(); |
276 | JSLockHolder lock(vm); |
277 | auto scope = DECLARE_CATCH_SCOPE(vm); |
278 | |
279 | ConstructData constructData; |
280 | ConstructType constructType = getConstructData(vm, m_jsObject.get(), constructData); |
281 | if (constructType == ConstructType::None) |
282 | return false; |
283 | |
284 | // Convert the passed in arguments. |
285 | MarkedArgumentBuffer argumentList; |
286 | for (uint32_t i = 0; i < argumentCount; ++i) |
287 | argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, m_objectMap->globalObject(), arguments[i])); |
288 | RELEASE_ASSERT(!argumentList.hasOverflowed()); |
289 | |
290 | JSValue value = JSC::construct(exec, m_jsObject.get(), constructType, constructData, argumentList); |
291 | |
292 | // Convert and return the new object. |
293 | m_objectMap->convertJSValueToNPVariant(exec, value, *result); |
294 | scope.clearException(); |
295 | |
296 | return true; |
297 | } |
298 | |
299 | bool NPJSObject::invoke(ExecState* exec, JSGlobalObject* globalObject, JSValue function, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) |
300 | { |
301 | VM& vm = exec->vm(); |
302 | auto scope = DECLARE_CATCH_SCOPE(vm); |
303 | |
304 | CallData callData; |
305 | CallType callType = getCallData(vm, function, callData); |
306 | if (callType == CallType::None) |
307 | return false; |
308 | |
309 | // Convert the passed in arguments. |
310 | MarkedArgumentBuffer argumentList; |
311 | for (uint32_t i = 0; i < argumentCount; ++i) |
312 | argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, globalObject, arguments[i])); |
313 | RELEASE_ASSERT(!argumentList.hasOverflowed()); |
314 | |
315 | JSValue value = JSC::call(exec, function, callType, callData, m_jsObject.get(), argumentList); |
316 | |
317 | if (UNLIKELY(scope.exception())) { |
318 | scope.clearException(); |
319 | return false; |
320 | } |
321 | |
322 | // Convert and return the result of the function call. |
323 | m_objectMap->convertJSValueToNPVariant(exec, value, *result); |
324 | |
325 | if (UNLIKELY(scope.exception())) { |
326 | scope.clearException(); |
327 | return false; |
328 | } |
329 | |
330 | return true; |
331 | } |
332 | |
333 | NPClass* NPJSObject::npClass() |
334 | { |
335 | static NPClass npClass = { |
336 | NP_CLASS_STRUCT_VERSION, |
337 | NP_Allocate, |
338 | NP_Deallocate, |
339 | 0, |
340 | NP_HasMethod, |
341 | NP_Invoke, |
342 | NP_InvokeDefault, |
343 | NP_HasProperty, |
344 | NP_GetProperty, |
345 | NP_SetProperty, |
346 | NP_RemoveProperty, |
347 | NP_Enumerate, |
348 | NP_Construct |
349 | }; |
350 | |
351 | return &npClass; |
352 | } |
353 | |
354 | NPObject* NPJSObject::NP_Allocate(NPP npp, NPClass*) |
355 | { |
356 | ASSERT_UNUSED(npp, !npp); |
357 | |
358 | return new NPJSObject; |
359 | } |
360 | |
361 | void NPJSObject::NP_Deallocate(NPObject* npObject) |
362 | { |
363 | NPJSObject* npJSObject = toNPJSObject(npObject); |
364 | delete npJSObject; |
365 | } |
366 | |
367 | bool NPJSObject::NP_HasMethod(NPObject* npObject, NPIdentifier methodName) |
368 | { |
369 | return toNPJSObject(npObject)->hasMethod(methodName); |
370 | } |
371 | |
372 | bool NPJSObject::NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) |
373 | { |
374 | return toNPJSObject(npObject)->invoke(methodName, arguments, argumentCount, result); |
375 | } |
376 | |
377 | bool NPJSObject::NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) |
378 | { |
379 | return toNPJSObject(npObject)->invokeDefault(arguments, argumentCount, result); |
380 | } |
381 | |
382 | bool NPJSObject::NP_HasProperty(NPObject* npObject, NPIdentifier propertyName) |
383 | { |
384 | return toNPJSObject(npObject)->hasProperty(propertyName); |
385 | } |
386 | |
387 | bool NPJSObject::NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result) |
388 | { |
389 | return toNPJSObject(npObject)->getProperty(propertyName, result); |
390 | } |
391 | |
392 | bool NPJSObject::NP_SetProperty(NPObject* npObject, NPIdentifier propertyName, const NPVariant* value) |
393 | { |
394 | return toNPJSObject(npObject)->setProperty(propertyName, value); |
395 | } |
396 | |
397 | bool NPJSObject::NP_RemoveProperty(NPObject* npObject, NPIdentifier propertyName) |
398 | { |
399 | return toNPJSObject(npObject)->removeProperty(propertyName); |
400 | } |
401 | |
402 | bool NPJSObject::NP_Enumerate(NPObject* npObject, NPIdentifier** identifiers, uint32_t* identifierCount) |
403 | { |
404 | return toNPJSObject(npObject)->enumerate(identifiers, identifierCount); |
405 | } |
406 | |
407 | bool NPJSObject::NP_Construct(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) |
408 | { |
409 | return toNPJSObject(npObject)->construct(arguments, argumentCount, result); |
410 | } |
411 | |
412 | } // namespace WebKit |
413 | |
414 | #endif // ENABLE(NETSCAPE_PLUGIN_API) |
415 | |