2009-01-14 Jeremy Moskovich <jeremy@chromium.org>
[WebKit-https.git] / WebKitTools / DumpRenderTree / TestNetscapePlugIn.subproj / PluginObject.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008 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 "PluginObject.h"
27
28 #include "TestObject.h"
29 #include <assert.h>
30 #include <stdio.h>
31
32 #include <string.h>
33 #include <stdlib.h>
34
35 static void pluginInvalidate(NPObject*);
36 static bool pluginHasProperty(NPObject*, NPIdentifier name);
37 static bool pluginHasMethod(NPObject*, NPIdentifier name);
38 static bool pluginGetProperty(NPObject*, NPIdentifier name, NPVariant*);
39 static bool pluginSetProperty(NPObject*, NPIdentifier name, const NPVariant*);
40 static bool pluginInvoke(NPObject*, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result);
41 static bool pluginInvokeDefault(NPObject*, const NPVariant* args, uint32_t argCount, NPVariant* result);
42 static NPObject* pluginAllocate(NPP npp, NPClass*);
43 static void pluginDeallocate(NPObject*);
44
45 NPNetscapeFuncs* browser;
46
47 static NPClass pluginClass = {
48     NP_CLASS_STRUCT_VERSION,
49     pluginAllocate,
50     pluginDeallocate,
51     pluginInvalidate,
52     pluginHasMethod,
53     pluginInvoke,
54     pluginInvokeDefault,
55     pluginHasProperty,
56     pluginGetProperty,
57     pluginSetProperty,
58 };
59
60 NPClass *getPluginClass(void)
61 {
62     return &pluginClass;
63 }
64
65 static bool identifiersInitialized = false;
66
67 #define ID_PROPERTY_PROPERTY                    0
68 #define ID_PROPERTY_EVENT_LOGGING               1
69 #define ID_PROPERTY_HAS_STREAM                  2
70 #define ID_PROPERTY_TEST_OBJECT                 3
71 #define ID_PROPERTY_LOG_DESTROY                 4
72 #define ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM 5
73 #define NUM_PROPERTY_IDENTIFIERS                6
74
75 static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS];
76 static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = {
77     "property",
78     "eventLoggingEnabled",
79     "hasStream",
80     "testObject",
81     "logDestroy",
82     "returnErrorFromNewStream",
83 };
84
85 #define ID_TEST_CALLBACK_METHOD     0
86 #define ID_TEST_GETURL              1
87 #define ID_REMOVE_DEFAULT_METHOD    2
88 #define ID_TEST_DOM_ACCESS          3
89 #define ID_TEST_GET_URL_NOTIFY      4
90 #define ID_TEST_INVOKE_DEFAULT      5
91 #define ID_DESTROY_STREAM           6
92 #define ID_TEST_ENUMERATE           7
93 #define ID_TEST_GETINTIDENTIFIER    8
94 #define ID_TEST_GET_PROPERTY        9
95 #define ID_TEST_EVALUATE            10
96 #define ID_TEST_GET_PROPERTY_RETURN_VALUE 11
97 #define ID_TEST_IDENTIFIER_TO_STRING 12
98 #define ID_TEST_IDENTIFIER_TO_INT   13
99 #define ID_TEST_POSTURL_FILE        14
100 #define ID_TEST_CONSTRUCT           15
101 #define ID_TEST_THROW_EXCEPTION_METHOD 16
102 #define NUM_METHOD_IDENTIFIERS      17
103
104 static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
105 static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
106     "testCallback",
107     "getURL",
108     "removeDefaultMethod",
109     "testDOMAccess",
110     "getURLNotify",
111     "testInvokeDefault",
112     "destroyStream",
113     "testEnumerate",
114     "testGetIntIdentifier",
115     "testGetProperty",
116     "testEvaluate",
117     "testGetPropertyReturnValue",
118     "testIdentifierToString",
119     "testIdentifierToInt",
120     "testPostURLFile",
121     "testConstruct",
122     "testThrowException",
123 };
124
125 static NPUTF8* createCStringFromNPVariant(const NPVariant* variant)
126 {
127     size_t length = NPVARIANT_TO_STRING(*variant).UTF8Length;
128     NPUTF8* result = (NPUTF8*)malloc(length + 1);
129     memcpy(result, NPVARIANT_TO_STRING(*variant).UTF8Characters, length);
130     result[length] = '\0';
131     return result;
132 }
133
134 static void initializeIdentifiers(void)
135 {
136     browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers);
137     browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers);
138 }
139
140 static bool pluginHasProperty(NPObject *obj, NPIdentifier name)
141 {
142     for (int i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++)
143         if (name == pluginPropertyIdentifiers[i])
144             return true;
145     return false;
146 }
147
148 static bool pluginHasMethod(NPObject *obj, NPIdentifier name)
149 {
150     for (int i = 0; i < NUM_METHOD_IDENTIFIERS; i++)
151         if (name == pluginMethodIdentifiers[i])
152             return true;
153     return false;
154 }
155
156 static bool pluginGetProperty(NPObject* obj, NPIdentifier name, NPVariant* result)
157 {
158     PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
159     if (name == pluginPropertyIdentifiers[ID_PROPERTY_PROPERTY]) {
160         STRINGZ_TO_NPVARIANT("property", *result);
161         return true;
162     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
163         BOOLEAN_TO_NPVARIANT(plugin->eventLogging, *result);
164         return true;
165     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
166         BOOLEAN_TO_NPVARIANT(plugin->logDestroy, *result);
167         return true;
168     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_HAS_STREAM]) {
169         BOOLEAN_TO_NPVARIANT(plugin->stream != 0, *result);
170         return true;
171     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT]) {
172         NPObject* testObject = plugin->testObject;
173         browser->retainobject(testObject);
174         OBJECT_TO_NPVARIANT(testObject, *result);
175         return true;
176     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) {
177         BOOLEAN_TO_NPVARIANT(plugin->returnErrorFromNewStream, *result);
178         return true;
179     }
180     return false;
181 }
182
183 static bool pluginSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* variant)
184 {
185     PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
186     if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
187         plugin->eventLogging = NPVARIANT_TO_BOOLEAN(*variant);
188         return true;
189     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
190         plugin->logDestroy = NPVARIANT_TO_BOOLEAN(*variant);
191         return true;
192     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) {
193         plugin->returnErrorFromNewStream = NPVARIANT_TO_BOOLEAN(*variant);
194         return true;
195     }
196
197     return false;
198 }
199
200 static bool testDOMAccess(PluginObject* obj, const NPVariant*, uint32_t, NPVariant* result)
201 {
202     // Get plug-in's DOM element
203     NPObject* elementObject;
204     if (browser->getvalue(obj->npp, NPNVPluginElementNPObject, &elementObject) == NPERR_NO_ERROR) {
205         // Get style
206         NPVariant styleVariant;
207         NPIdentifier styleIdentifier = browser->getstringidentifier("style");
208         if (browser->getproperty(obj->npp, elementObject, styleIdentifier, &styleVariant) && NPVARIANT_IS_OBJECT(styleVariant)) {
209             // Set style.border
210             NPIdentifier borderIdentifier = browser->getstringidentifier("border");
211             NPVariant borderVariant;
212             STRINGZ_TO_NPVARIANT("3px solid red", borderVariant);
213             browser->setproperty(obj->npp, NPVARIANT_TO_OBJECT(styleVariant), borderIdentifier, &borderVariant);
214             browser->releasevariantvalue(&styleVariant);
215         }
216
217         browser->releaseobject(elementObject);
218     }
219     VOID_TO_NPVARIANT(*result);
220     return true;
221 }
222
223 static NPIdentifier stringVariantToIdentifier(NPVariant variant)
224 {
225     assert(NPVARIANT_IS_STRING(variant));
226     NPUTF8* utf8String = createCStringFromNPVariant(&variant);
227     NPIdentifier identifier = browser->getstringidentifier(utf8String);
228     free(utf8String);
229     return identifier;
230 }
231
232 static NPIdentifier int32VariantToIdentifier(NPVariant variant)
233 {
234     assert(NPVARIANT_IS_INT32(variant));
235     int32 integer = NPVARIANT_TO_INT32(variant);
236     return browser->getintidentifier(integer);
237 }
238
239 static NPIdentifier doubleVariantToIdentifier(NPVariant variant)
240 {
241     assert(NPVARIANT_IS_DOUBLE(variant));
242     double value = NPVARIANT_TO_DOUBLE(variant);
243     // Sadly there is no "getdoubleidentifier"
244     int32 integer = static_cast<int32>(value);
245     return browser->getintidentifier(integer);
246 }
247
248 static NPIdentifier variantToIdentifier(NPVariant variant)
249 {
250     if (NPVARIANT_IS_STRING(variant))
251         return stringVariantToIdentifier(variant);
252     else if (NPVARIANT_IS_INT32(variant))
253         return int32VariantToIdentifier(variant);
254     else if (NPVARIANT_IS_DOUBLE(variant))
255         return doubleVariantToIdentifier(variant);
256     return 0;
257 }
258
259 static bool testIdentifierToString(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
260 {
261     if (argCount != 1)
262         return false;
263     NPIdentifier identifier = variantToIdentifier(args[0]);
264     if (!identifier)
265         return false;
266     NPUTF8* utf8String = browser->utf8fromidentifier(identifier);
267     if (!utf8String)
268         return false;
269     STRINGZ_TO_NPVARIANT(utf8String, *result);
270     return true;
271 }
272
273 static bool testIdentifierToInt(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
274 {
275     if (argCount != 1)
276         return false;
277     NPIdentifier identifier = variantToIdentifier(args[0]);
278     if (!identifier)
279         return false;
280     int32 integer = browser->intfromidentifier(identifier);
281     INT32_TO_NPVARIANT(integer, *result);
282     return true;
283 }
284
285 static bool testCallback(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
286 {
287     if (argCount == 0 || !NPVARIANT_IS_STRING(args[0]))
288         return false;
289
290     NPObject* windowScriptObject;
291     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
292
293     NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
294     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
295     free(callbackString);
296
297     NPVariant browserResult;
298     browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult);
299     browser->releasevariantvalue(&browserResult);
300
301     browser->releaseobject(windowScriptObject);
302     
303     VOID_TO_NPVARIANT(*result);
304     return true;
305 }
306
307 static bool getURL(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
308 {
309     if (argCount == 2 && NPVARIANT_IS_STRING(args[0]) && NPVARIANT_IS_STRING(args[1])) {
310         NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
311         NPUTF8* targetString = createCStringFromNPVariant(&args[1]);
312         NPError npErr = browser->geturl(obj->npp, urlString, targetString);
313         free(urlString);
314         free(targetString);
315
316         INT32_TO_NPVARIANT(npErr, *result);
317         return true;
318     } else if (argCount == 1 && NPVARIANT_IS_STRING(args[0])) {
319         NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
320         NPError npErr = browser->geturl(obj->npp, urlString, 0);
321         free(urlString);
322
323         INT32_TO_NPVARIANT(npErr, *result);
324         return true;
325     }
326     return false;
327 }
328
329 static bool removeDefaultMethod(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
330 {
331     pluginClass.invokeDefault = 0;
332     VOID_TO_NPVARIANT(*result);
333     return true;
334 }
335
336 static bool getURLNotify(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
337 {
338     if (argCount != 3 || !NPVARIANT_IS_STRING(args[0])
339         || (!NPVARIANT_IS_STRING(args[1]) && !NPVARIANT_IS_NULL(args[1]))
340         || !NPVARIANT_IS_STRING(args[2]))
341         return false;
342
343     NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
344     NPUTF8* targetString = (NPVARIANT_IS_STRING(args[1]) ? createCStringFromNPVariant(&args[1]) : NULL);
345     NPUTF8* callbackString = createCStringFromNPVariant(&args[2]);
346
347     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
348     browser->geturlnotify(obj->npp, urlString, targetString, callbackIdentifier);
349
350     free(urlString);
351     free(targetString);
352     free(callbackString);
353
354     VOID_TO_NPVARIANT(*result);
355     return true;
356 }
357
358 static bool testInvokeDefault(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
359 {
360     if (!NPVARIANT_IS_OBJECT(args[0]))
361         return false;
362
363     NPObject *callback = NPVARIANT_TO_OBJECT(args[0]);
364
365     NPVariant invokeArgs[1];
366     NPVariant browserResult;
367
368     STRINGZ_TO_NPVARIANT("test", invokeArgs[0]);
369     bool retval = browser->invokeDefault(obj->npp, callback, invokeArgs, 1, &browserResult);
370
371     if (retval)
372         browser->releasevariantvalue(&browserResult);
373
374     BOOLEAN_TO_NPVARIANT(retval, *result);
375     return true;
376 }
377
378 static bool destroyStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
379 {
380     NPError npError = browser->destroystream(obj->npp, obj->stream, NPRES_USER_BREAK);
381     INT32_TO_NPVARIANT(npError, *result);
382     return true;
383 }
384
385 static bool testEnumerate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
386 {
387     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_OBJECT(args[1]))
388         return false;
389
390     uint32_t count;
391     NPIdentifier* identifiers;
392     if (browser->enumerate(obj->npp, NPVARIANT_TO_OBJECT(args[0]), &identifiers, &count)) {
393         NPObject* outArray = NPVARIANT_TO_OBJECT(args[1]);
394         NPIdentifier pushIdentifier = browser->getstringidentifier("push");
395
396         for (uint32_t i = 0; i < count; i++) {
397             NPUTF8* string = browser->utf8fromidentifier(identifiers[i]);
398
399             if (!string)
400                 continue;
401
402             NPVariant args[1];
403             STRINGZ_TO_NPVARIANT(string, args[0]);
404             NPVariant browserResult;
405             browser->invoke(obj->npp, outArray, pushIdentifier, args, 1, &browserResult);
406             browser->releasevariantvalue(&browserResult);
407             browser->memfree(string);
408         }
409
410         browser->memfree(identifiers);
411     }
412
413     VOID_TO_NPVARIANT(*result);
414     return true;
415 }
416
417 static bool testGetIntIdentifier(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
418 {
419     if (argCount != 1 || !NPVARIANT_IS_DOUBLE(args[0]))
420         return false;
421
422     NPIdentifier identifier = browser->getintidentifier((int)NPVARIANT_TO_DOUBLE(args[0]));
423     INT32_TO_NPVARIANT((int32)(long long)identifier, *result);
424     return true;
425 }
426
427 static bool testGetProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
428 {
429     if (argCount == 0)
430         return false;
431
432     NPObject *object;
433     browser->getvalue(obj->npp, NPNVWindowNPObject, &object);
434
435     for (uint32_t i = 0; i < argCount; i++) {
436         assert(NPVARIANT_IS_STRING(args[i]));
437         NPUTF8* propertyString = createCStringFromNPVariant(&args[i]);
438         NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
439         free(propertyString);
440
441         NPVariant variant;
442         bool retval = browser->getproperty(obj->npp, object, propertyIdentifier, &variant);
443         browser->releaseobject(object);
444
445         if (!retval)
446             break;
447
448         if (i + 1 < argCount) {
449             assert(NPVARIANT_IS_OBJECT(variant));
450             object = NPVARIANT_TO_OBJECT(variant);
451         } else {
452             *result = variant;
453             return true;
454         }
455     }
456
457     VOID_TO_NPVARIANT(*result);
458     return false;
459 }
460
461 static bool testEvaluate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
462 {
463     if (argCount != 1 || !NPVARIANT_IS_STRING(args[0]))
464         return false;
465     NPObject* windowScriptObject;
466     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
467
468     NPString s = NPVARIANT_TO_STRING(args[0]);
469
470     bool retval = browser->evaluate(obj->npp, windowScriptObject, &s, result);
471     browser->releaseobject(windowScriptObject);
472     return retval;
473 }
474
475 static bool testGetPropertyReturnValue(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
476 {
477     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
478         return false;
479
480     NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
481     NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
482     free(propertyString);
483
484     NPVariant variant;
485     bool retval = browser->getproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier, &variant);
486     if (retval)
487         browser->releasevariantvalue(&variant);
488
489     BOOLEAN_TO_NPVARIANT(retval, *result);
490     return true;
491 }
492
493 static char* toCString(const NPString& string)
494 {
495     char* result = static_cast<char*>(malloc(string.UTF8Length + 1));
496     memcpy(result, string.UTF8Characters, string.UTF8Length);
497     result[string.UTF8Length] = '\0';
498
499     return result;
500 }
501
502 static bool testPostURLFile(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
503 {
504     if (argCount != 4 || !NPVARIANT_IS_STRING(args[0]) || !NPVARIANT_IS_STRING(args[1]) || !NPVARIANT_IS_STRING(args[2]) || !NPVARIANT_IS_STRING(args[3]))
505         return false;
506
507     NPString urlString = NPVARIANT_TO_STRING(args[0]);
508     char* url = toCString(urlString);
509
510     NPString targetString = NPVARIANT_TO_STRING(args[1]);
511     char* target = toCString(targetString);
512
513     NPString pathString = NPVARIANT_TO_STRING(args[2]);
514     char* path = toCString(pathString);
515
516     NPString contentsString = NPVARIANT_TO_STRING(args[3]);
517
518     FILE* tempFile = fopen(path, "w");
519     if (!tempFile)
520         return false;
521
522     fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile);
523     fclose(tempFile);
524
525     NPError error = browser->posturl(obj->npp, url, target, pathString.UTF8Length, path, TRUE);
526
527     free(path);
528     free(target);
529     free(url);
530
531     BOOLEAN_TO_NPVARIANT(error == NPERR_NO_ERROR, *result);
532     return true;
533 }
534
535 static bool testConstruct(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
536 {
537     if (!argCount || !NPVARIANT_IS_OBJECT(args[0]))
538         return false;
539     
540     return browser->construct(obj->npp, NPVARIANT_TO_OBJECT(args[0]), args + 1, argCount - 1, result);
541 }
542
543 static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
544 {
545     PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
546     if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD])
547         return testCallback(plugin, args, argCount, result);
548     else if (name == pluginMethodIdentifiers[ID_TEST_GETURL])
549         return getURL(plugin, args, argCount, result);
550     else if (name == pluginMethodIdentifiers[ID_REMOVE_DEFAULT_METHOD])
551         return removeDefaultMethod(plugin, args, argCount, result);
552     else if (name == pluginMethodIdentifiers[ID_TEST_DOM_ACCESS])
553         return testDOMAccess(plugin, args, argCount, result);
554     else if (name == pluginMethodIdentifiers[ID_TEST_GET_URL_NOTIFY])
555         return getURLNotify(plugin, args, argCount, result);
556     else if (name == pluginMethodIdentifiers[ID_TEST_INVOKE_DEFAULT])
557         return testInvokeDefault(plugin, args, argCount, result);
558     else if (name == pluginMethodIdentifiers[ID_TEST_ENUMERATE])
559         return testEnumerate(plugin, args, argCount, result);
560     else if (name == pluginMethodIdentifiers[ID_DESTROY_STREAM])
561         return destroyStream(plugin, args, argCount, result);
562     else if (name == pluginMethodIdentifiers[ID_TEST_GETINTIDENTIFIER])
563         return testGetIntIdentifier(plugin, args, argCount, result);
564     else if (name == pluginMethodIdentifiers[ID_TEST_EVALUATE])
565         return testEvaluate(plugin, args, argCount, result);
566     else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY])
567         return testGetProperty(plugin, args, argCount, result);
568     else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY_RETURN_VALUE])
569         return testGetPropertyReturnValue(plugin, args, argCount, result);
570     else if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_STRING])
571         return testIdentifierToString(plugin, args, argCount, result);
572     else if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_INT])
573         return testIdentifierToInt(plugin, args, argCount, result);
574     else if (name == pluginMethodIdentifiers[ID_TEST_POSTURL_FILE])
575         return testPostURLFile(plugin, args, argCount, result);
576     else if (name == pluginMethodIdentifiers[ID_TEST_CONSTRUCT])
577         return testConstruct(plugin, args, argCount, result);
578     else if (name == pluginMethodIdentifiers[ID_TEST_THROW_EXCEPTION_METHOD]) {
579         browser->setexception(header, "plugin object testThrowException SUCCESS");
580         return true;
581     }
582     
583     return false;
584 }
585
586 static bool pluginInvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
587 {
588     INT32_TO_NPVARIANT(1, *result);
589     return true;
590 }
591
592 static void pluginInvalidate(NPObject* obj)
593 {
594 }
595
596 static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
597 {
598     PluginObject* newInstance = (PluginObject*)malloc(sizeof(PluginObject));
599
600     if (!identifiersInitialized) {
601         identifiersInitialized = true;
602         initializeIdentifiers();
603     }
604
605     newInstance->npp = npp;
606     newInstance->testObject = browser->createobject(npp, getTestClass());
607     newInstance->eventLogging = FALSE;
608     newInstance->onStreamLoad = 0;
609     newInstance->onStreamDestroy = 0;
610     newInstance->onURLNotify = 0;
611     newInstance->logDestroy = FALSE;
612     newInstance->logSetWindow = FALSE;
613     newInstance->returnErrorFromNewStream = FALSE;
614     newInstance->stream = 0;
615
616     newInstance->firstUrl = NULL;
617     newInstance->firstHeaders = NULL;
618     newInstance->lastUrl = NULL;
619     newInstance->lastHeaders = NULL;
620
621     return (NPObject*)newInstance;
622 }
623
624 static void pluginDeallocate(NPObject* header)
625 {
626     PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
627     browser->releaseobject(plugin->testObject);
628
629     free(plugin->firstUrl);
630     free(plugin->firstHeaders);
631     free(plugin->lastUrl);
632     free(plugin->lastHeaders);
633     free(plugin);
634 }
635
636 void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData)
637 {
638     assert(object);
639
640     NPVariant args[2];
641
642     NPObject *windowScriptObject;
643     browser->getvalue(object->npp, NPNVWindowNPObject, &windowScriptObject);
644
645     NPIdentifier callbackIdentifier = notifyData;
646
647     INT32_TO_NPVARIANT(reason, args[0]);
648
649     char *strHdr = NULL;
650     if (object->firstUrl && object->firstHeaders && object->lastUrl && object->lastHeaders) {
651         // Format expected by JavaScript validator: four fields separated by \n\n:
652         // First URL; first header block; last URL; last header block.
653         // Note that header blocks already end with \n due to how NPStream::headers works.
654         int len = strlen(object->firstUrl) + 2
655             + strlen(object->firstHeaders) + 1
656             + strlen(object->lastUrl) + 2
657             + strlen(object->lastHeaders) + 1;
658         strHdr = (char*)malloc(len + 1);
659         snprintf(strHdr, len + 1, "%s\n\n%s\n%s\n\n%s\n",
660                  object->firstUrl, object->firstHeaders, object->lastUrl, object->lastHeaders);
661         STRINGN_TO_NPVARIANT(strHdr, len, args[1]);
662     } else
663         NULL_TO_NPVARIANT(args[1]);
664
665     NPVariant browserResult;
666     browser->invoke(object->npp, windowScriptObject, callbackIdentifier, args, 2, &browserResult);
667     browser->releasevariantvalue(&browserResult);
668
669     free(strHdr);
670 }
671
672 void notifyStream(PluginObject* object, const char *url, const char *headers)
673 {
674     if (object->firstUrl == NULL) {
675         if (url)
676             object->firstUrl = strdup(url);
677         if (headers)
678             object->firstHeaders = strdup(headers);
679     } else {
680         free(object->lastUrl);
681         free(object->lastHeaders);
682         object->lastUrl = (url ? strdup(url) : NULL);
683         object->lastHeaders = (headers ? strdup(headers) : NULL);
684     }
685 }
686
687 void testNPRuntime(NPP npp)
688 {
689     NPObject* windowScriptObject;
690     browser->getvalue(npp, NPNVWindowNPObject, &windowScriptObject);
691
692     // Invoke
693     NPIdentifier testNPInvoke = browser->getstringidentifier("testNPInvoke");
694     NPVariant args[7];
695     
696     VOID_TO_NPVARIANT(args[0]);
697     NULL_TO_NPVARIANT(args[1]);
698     BOOLEAN_TO_NPVARIANT(true, args[2]);
699     INT32_TO_NPVARIANT(242, args[3]);
700     DOUBLE_TO_NPVARIANT(242.242, args[4]);
701     STRINGZ_TO_NPVARIANT("Hello, World", args[5]);
702     OBJECT_TO_NPVARIANT(windowScriptObject, args[6]);
703     
704     NPVariant result;
705     browser->invoke(npp, windowScriptObject, testNPInvoke, args, 7, &result);
706     
707     browser->releasevariantvalue(&result);
708     browser->releaseobject(windowScriptObject);
709 }