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