2 * Copyright (C) 2006, 2007, 2008 Apple 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 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.
26 #include "PluginObject.h"
28 #include "TestObject.h"
32 static void pluginInvalidate(NPObject*);
33 static bool pluginHasProperty(NPObject*, NPIdentifier name);
34 static bool pluginHasMethod(NPObject*, NPIdentifier name);
35 static bool pluginGetProperty(NPObject*, NPIdentifier name, NPVariant*);
36 static bool pluginSetProperty(NPObject*, NPIdentifier name, const NPVariant*);
37 static bool pluginInvoke(NPObject*, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result);
38 static bool pluginInvokeDefault(NPObject*, const NPVariant* args, uint32_t argCount, NPVariant* result);
39 static NPObject* pluginAllocate(NPP npp, NPClass*);
40 static void pluginDeallocate(NPObject*);
42 NPNetscapeFuncs* browser;
44 static NPClass pluginClass = {
45 NP_CLASS_STRUCT_VERSION,
57 NPClass *getPluginClass(void)
62 static bool identifiersInitialized = false;
64 #define ID_PROPERTY_PROPERTY 0
65 #define ID_PROPERTY_EVENT_LOGGING 1
66 #define ID_PROPERTY_HAS_STREAM 2
67 #define ID_PROPERTY_TEST_OBJECT 3
68 #define ID_PROPERTY_LOG_DESTROY 4
69 #define NUM_PROPERTY_IDENTIFIERS 5
71 static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS];
72 static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = {
74 "eventLoggingEnabled",
80 #define ID_TEST_CALLBACK_METHOD 0
81 #define ID_TEST_GETURL 1
82 #define ID_REMOVE_DEFAULT_METHOD 2
83 #define ID_TEST_DOM_ACCESS 3
84 #define ID_TEST_GET_URL_NOTIFY 4
85 #define ID_TEST_INVOKE_DEFAULT 5
86 #define ID_DESTROY_STREAM 6
87 #define ID_TEST_ENUMERATE 7
88 #define ID_TEST_GETINTIDENTIFIER 8
89 #define ID_TEST_GET_PROPERTY 9
90 #define ID_TEST_EVALUATE 10
91 #define ID_TEST_GET_PROPERTY_RETURN_VALUE 11
92 #define ID_TEST_IDENTIFIER_TO_STRING 12
93 #define ID_TEST_IDENTIFIER_TO_INT 13
94 #define NUM_METHOD_IDENTIFIERS 14
96 static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
97 static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
100 "removeDefaultMethod",
106 "testGetIntIdentifier",
109 "testGetPropertyReturnValue",
110 "testIdentifierToString",
111 "testIdentifierToInt",
114 static NPUTF8* createCStringFromNPVariant(const NPVariant* variant)
116 size_t length = NPVARIANT_TO_STRING(*variant).UTF8Length;
117 NPUTF8* result = (NPUTF8*)malloc(length + 1);
118 memcpy(result, NPVARIANT_TO_STRING(*variant).UTF8Characters, length);
119 result[length] = '\0';
123 static void initializeIdentifiers(void)
125 browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers);
126 browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers);
129 static bool pluginHasProperty(NPObject *obj, NPIdentifier name)
131 for (int i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++)
132 if (name == pluginPropertyIdentifiers[i])
137 static bool pluginHasMethod(NPObject *obj, NPIdentifier name)
139 for (int i = 0; i < NUM_METHOD_IDENTIFIERS; i++)
140 if (name == pluginMethodIdentifiers[i])
145 static bool pluginGetProperty(NPObject* obj, NPIdentifier name, NPVariant* result)
147 PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
148 if (name == pluginPropertyIdentifiers[ID_PROPERTY_PROPERTY]) {
149 STRINGZ_TO_NPVARIANT("property", *result);
151 } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
152 BOOLEAN_TO_NPVARIANT(plugin->eventLogging, *result);
154 } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
155 BOOLEAN_TO_NPVARIANT(plugin->logDestroy, *result);
157 } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_HAS_STREAM]) {
158 BOOLEAN_TO_NPVARIANT(plugin->stream != 0, *result);
160 } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT]) {
161 NPObject* testObject = plugin->testObject;
162 browser->retainobject(testObject);
163 OBJECT_TO_NPVARIANT(testObject, *result);
169 static bool pluginSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* variant)
171 PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
172 if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
173 plugin->eventLogging = NPVARIANT_TO_BOOLEAN(*variant);
175 } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
176 plugin->logDestroy = NPVARIANT_TO_BOOLEAN(*variant);
183 static bool testDOMAccess(PluginObject* obj, const NPVariant*, uint32_t, NPVariant* result)
185 // Get plug-in's DOM element
186 NPObject* elementObject;
187 if (browser->getvalue(obj->npp, NPNVPluginElementNPObject, &elementObject) == NPERR_NO_ERROR) {
189 NPVariant styleVariant;
190 NPIdentifier styleIdentifier = browser->getstringidentifier("style");
191 if (browser->getproperty(obj->npp, elementObject, styleIdentifier, &styleVariant) && NPVARIANT_IS_OBJECT(styleVariant)) {
193 NPIdentifier borderIdentifier = browser->getstringidentifier("border");
194 NPVariant borderVariant;
195 STRINGZ_TO_NPVARIANT("3px solid red", borderVariant);
196 browser->setproperty(obj->npp, NPVARIANT_TO_OBJECT(styleVariant), borderIdentifier, &borderVariant);
197 browser->releasevariantvalue(&styleVariant);
200 browser->releaseobject(elementObject);
202 VOID_TO_NPVARIANT(*result);
206 static NPIdentifier stringVariantToIdentifier(NPVariant variant)
208 assert(NPVARIANT_IS_STRING(variant));
209 NPUTF8* utf8String = createCStringFromNPVariant(&variant);
210 NPIdentifier identifier = browser->getstringidentifier(utf8String);
215 static NPIdentifier int32VariantToIdentifier(NPVariant variant)
217 assert(NPVARIANT_IS_INT32(variant));
218 int32 integer = NPVARIANT_TO_INT32(variant);
219 return browser->getintidentifier(integer);
222 static NPIdentifier doubleVariantToIdentifier(NPVariant variant)
224 assert(NPVARIANT_IS_DOUBLE(variant));
225 double value = NPVARIANT_TO_DOUBLE(variant);
226 // Sadly there is no "getdoubleidentifier"
227 int32 integer = static_cast<int32>(value);
228 return browser->getintidentifier(integer);
231 static NPIdentifier variantToIdentifier(NPVariant variant)
233 if (NPVARIANT_IS_STRING(variant))
234 return stringVariantToIdentifier(variant);
235 else if (NPVARIANT_IS_INT32(variant))
236 return int32VariantToIdentifier(variant);
237 else if (NPVARIANT_IS_DOUBLE(variant))
238 return doubleVariantToIdentifier(variant);
242 static bool testIdentifierToString(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
246 NPIdentifier identifier = variantToIdentifier(args[0]);
249 NPUTF8* utf8String = browser->utf8fromidentifier(identifier);
252 STRINGZ_TO_NPVARIANT(utf8String, *result);
256 static bool testIdentifierToInt(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
260 NPIdentifier identifier = variantToIdentifier(args[0]);
263 int32 integer = browser->intfromidentifier(identifier);
264 INT32_TO_NPVARIANT(integer, *result);
268 static bool testCallback(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
270 if (argCount == 0 || !NPVARIANT_IS_STRING(args[0]))
273 NPObject* windowScriptObject;
274 browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
276 NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
277 NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
278 free(callbackString);
280 NPVariant browserResult;
281 browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult);
282 browser->releasevariantvalue(&browserResult);
284 VOID_TO_NPVARIANT(*result);
288 static bool getURL(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
290 if (argCount == 2 && NPVARIANT_IS_STRING(args[0]) && NPVARIANT_IS_STRING(args[1])) {
291 NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
292 NPUTF8* targetString = createCStringFromNPVariant(&args[1]);
293 browser->geturl(obj->npp, urlString, targetString);
297 VOID_TO_NPVARIANT(*result);
299 } else if (argCount == 1 && NPVARIANT_IS_STRING(args[0])) {
300 NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
301 browser->geturl(obj->npp, urlString, 0);
304 VOID_TO_NPVARIANT(*result);
310 static bool removeDefaultMethod(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
312 pluginClass.invokeDefault = 0;
313 VOID_TO_NPVARIANT(*result);
317 static bool getURLNotify(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
319 if (argCount != 3 || !NPVARIANT_IS_STRING(args[0])
320 || (!NPVARIANT_IS_STRING(args[1]) && !NPVARIANT_IS_NULL(args[1]))
321 || !NPVARIANT_IS_STRING(args[2]))
324 NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
325 NPUTF8* targetString = (NPVARIANT_IS_STRING(args[1]) ? createCStringFromNPVariant(&args[1]) : NULL);
326 NPUTF8* callbackString = createCStringFromNPVariant(&args[2]);
328 NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
329 browser->geturlnotify(obj->npp, urlString, targetString, callbackIdentifier);
333 free(callbackString);
335 VOID_TO_NPVARIANT(*result);
339 static bool testInvokeDefault(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
341 if (!NPVARIANT_IS_OBJECT(args[0]))
344 NPObject *callback = NPVARIANT_TO_OBJECT(args[0]);
346 NPVariant invokeArgs[1];
347 NPVariant browserResult;
349 STRINGZ_TO_NPVARIANT("test", invokeArgs[0]);
350 bool retval = browser->invokeDefault(obj->npp, callback, invokeArgs, 1, &browserResult);
353 browser->releasevariantvalue(&browserResult);
355 BOOLEAN_TO_NPVARIANT(retval, *result);
359 static bool destroyStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
361 NPError npError = browser->destroystream(obj->npp, obj->stream, NPRES_USER_BREAK);
362 INT32_TO_NPVARIANT(npError, *result);
366 static bool testEnumerate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
368 if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_OBJECT(args[1]))
372 NPIdentifier* identifiers;
373 if (browser->enumerate(obj->npp, NPVARIANT_TO_OBJECT(args[0]), &identifiers, &count)) {
374 NPObject* outArray = NPVARIANT_TO_OBJECT(args[1]);
375 NPIdentifier pushIdentifier = browser->getstringidentifier("push");
377 for (uint32_t i = 0; i < count; i++) {
378 NPUTF8* string = browser->utf8fromidentifier(identifiers[i]);
384 STRINGZ_TO_NPVARIANT(string, args[0]);
385 NPVariant browserResult;
386 browser->invoke(obj->npp, outArray, pushIdentifier, args, 1, &browserResult);
387 browser->releasevariantvalue(&browserResult);
388 browser->memfree(string);
391 browser->memfree(identifiers);
394 VOID_TO_NPVARIANT(*result);
398 static bool testGetIntIdentifier(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
400 if (argCount != 1 || !NPVARIANT_IS_DOUBLE(args[0]))
403 NPIdentifier identifier = browser->getintidentifier((int)NPVARIANT_TO_DOUBLE(args[0]));
404 INT32_TO_NPVARIANT((int32)(long long)identifier, *result);
408 static bool testGetProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
414 browser->getvalue(obj->npp, NPNVWindowNPObject, &object);
416 for (uint32_t i = 0; i < argCount; i++) {
417 assert(NPVARIANT_IS_STRING(args[i]));
418 NPUTF8* propertyString = createCStringFromNPVariant(&args[i]);
419 NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
420 free(propertyString);
423 bool retval = browser->getproperty(obj->npp, object, propertyIdentifier, &variant);
424 browser->releaseobject(object);
429 if (i + 1 < argCount) {
430 assert(NPVARIANT_IS_OBJECT(variant));
431 object = NPVARIANT_TO_OBJECT(variant);
438 VOID_TO_NPVARIANT(*result);
442 static bool testEvaluate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
444 if (argCount != 1 || !NPVARIANT_IS_STRING(args[0]))
446 NPObject* windowScriptObject;
447 browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
449 NPString s = NPVARIANT_TO_STRING(args[0]);
451 bool retval = browser->evaluate(obj->npp, windowScriptObject, &s, result);
452 browser->releaseobject(windowScriptObject);
456 static bool testGetPropertyReturnValue(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
458 if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
461 NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
462 NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
463 free(propertyString);
466 bool retval = browser->getproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier, &variant);
468 browser->releasevariantvalue(&variant);
470 BOOLEAN_TO_NPVARIANT(retval, *result);
474 static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
476 PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
477 if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD])
478 return testCallback(plugin, args, argCount, result);
479 else if (name == pluginMethodIdentifiers[ID_TEST_GETURL])
480 return getURL(plugin, args, argCount, result);
481 else if (name == pluginMethodIdentifiers[ID_REMOVE_DEFAULT_METHOD])
482 return removeDefaultMethod(plugin, args, argCount, result);
483 else if (name == pluginMethodIdentifiers[ID_TEST_DOM_ACCESS])
484 return testDOMAccess(plugin, args, argCount, result);
485 else if (name == pluginMethodIdentifiers[ID_TEST_GET_URL_NOTIFY])
486 return getURLNotify(plugin, args, argCount, result);
487 else if (name == pluginMethodIdentifiers[ID_TEST_INVOKE_DEFAULT])
488 return testInvokeDefault(plugin, args, argCount, result);
489 else if (name == pluginMethodIdentifiers[ID_TEST_ENUMERATE])
490 return testEnumerate(plugin, args, argCount, result);
491 else if (name == pluginMethodIdentifiers[ID_DESTROY_STREAM])
492 return destroyStream(plugin, args, argCount, result);
493 else if (name == pluginMethodIdentifiers[ID_TEST_GETINTIDENTIFIER])
494 return testGetIntIdentifier(plugin, args, argCount, result);
495 else if (name == pluginMethodIdentifiers[ID_TEST_EVALUATE])
496 return testEvaluate(plugin, args, argCount, result);
497 else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY])
498 return testGetProperty(plugin, args, argCount, result);
499 else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY_RETURN_VALUE])
500 return testGetPropertyReturnValue(plugin, args, argCount, result);
501 else if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_STRING])
502 return testIdentifierToString(plugin, args, argCount, result);
503 else if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_INT])
504 return testIdentifierToInt(plugin, args, argCount, result);
509 static bool pluginInvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
511 INT32_TO_NPVARIANT(1, *result);
515 static void pluginInvalidate(NPObject* obj)
519 static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
521 PluginObject* newInstance = (PluginObject*)malloc(sizeof(PluginObject));
523 if (!identifiersInitialized) {
524 identifiersInitialized = true;
525 initializeIdentifiers();
528 newInstance->npp = npp;
529 newInstance->testObject = browser->createobject(npp, getTestClass());
530 newInstance->eventLogging = FALSE;
531 newInstance->logDestroy = FALSE;
532 newInstance->logSetWindow = FALSE;
533 newInstance->returnErrorFromNewStream = FALSE;
534 newInstance->stream = 0;
536 newInstance->firstUrl = NULL;
537 newInstance->firstHeaders = NULL;
538 newInstance->lastUrl = NULL;
539 newInstance->lastHeaders = NULL;
541 return (NPObject*)newInstance;
544 static void pluginDeallocate(NPObject* header)
546 PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
547 browser->releaseobject(plugin->testObject);
549 free(plugin->firstUrl);
550 free(plugin->firstHeaders);
551 free(plugin->lastUrl);
552 free(plugin->lastHeaders);
556 void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData)
562 NPObject *windowScriptObject;
563 browser->getvalue(object->npp, NPNVWindowNPObject, &windowScriptObject);
565 NPIdentifier callbackIdentifier = notifyData;
567 INT32_TO_NPVARIANT(reason, args[0]);
570 if (object->firstUrl && object->firstHeaders && object->lastUrl && object->lastHeaders) {
571 // Format expected by JavaScript validator: four fields separated by \n\n:
572 // First URL; first header block; last URL; last header block.
573 // Note that header blocks already end with \n due to how NPStream::headers works.
574 int len = strlen(object->firstUrl) + 2
575 + strlen(object->firstHeaders) + 1
576 + strlen(object->lastUrl) + 2
577 + strlen(object->lastHeaders) + 1;
578 strHdr = (char*)malloc(len + 1);
579 snprintf(strHdr, len + 1, "%s\n\n%s\n%s\n\n%s\n",
580 object->firstUrl, object->firstHeaders, object->lastUrl, object->lastHeaders);
581 STRINGN_TO_NPVARIANT(strHdr, len, args[1]);
583 NULL_TO_NPVARIANT(args[1]);
585 NPVariant browserResult;
586 browser->invoke(object->npp, windowScriptObject, callbackIdentifier, args, 2, &browserResult);
587 browser->releasevariantvalue(&browserResult);
592 void notifyStream(PluginObject* object, const char *url, const char *headers)
594 if (object->firstUrl == NULL) {
596 object->firstUrl = strdup(url);
598 object->firstHeaders = strdup(headers);
600 free(object->lastUrl);
601 free(object->lastHeaders);
602 object->lastUrl = (url ? strdup(url) : NULL);
603 object->lastHeaders = (headers ? strdup(headers) : NULL);