Update TestNetscapePlugIn to build 64-bit using the Cocoa event model.
[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 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*);
41
42 NPNetscapeFuncs* browser;
43
44 static NPClass pluginClass = {
45     NP_CLASS_STRUCT_VERSION,
46     pluginAllocate,
47     pluginDeallocate,
48     pluginInvalidate,
49     pluginHasMethod,
50     pluginInvoke,
51     pluginInvokeDefault,
52     pluginHasProperty,
53     pluginGetProperty,
54     pluginSetProperty,
55 };
56
57 NPClass *getPluginClass(void)
58 {
59     return &pluginClass;
60 }
61
62 static bool identifiersInitialized = false;
63
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
70
71 static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS];
72 static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = {
73     "property",
74     "eventLoggingEnabled",
75     "hasStream",
76     "testObject",
77     "logDestroy",
78 };
79
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
95
96 static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
97 static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
98     "testCallback",
99     "getURL",
100     "removeDefaultMethod",
101     "testDOMAccess",
102     "getURLNotify",
103     "testInvokeDefault",
104     "destroyStream",
105     "testEnumerate",
106     "testGetIntIdentifier",
107     "testGetProperty",
108     "testEvaluate",
109     "testGetPropertyReturnValue",
110     "testIdentifierToString",
111     "testIdentifierToInt",
112 };
113
114 static NPUTF8* createCStringFromNPVariant(const NPVariant* variant)
115 {
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';
120     return result;
121 }
122
123 static void initializeIdentifiers(void)
124 {
125     browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers);
126     browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers);
127 }
128
129 static bool pluginHasProperty(NPObject *obj, NPIdentifier name)
130 {
131     for (int i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++)
132         if (name == pluginPropertyIdentifiers[i])
133             return true;
134     return false;
135 }
136
137 static bool pluginHasMethod(NPObject *obj, NPIdentifier name)
138 {
139     for (int i = 0; i < NUM_METHOD_IDENTIFIERS; i++)
140         if (name == pluginMethodIdentifiers[i])
141             return true;
142     return false;
143 }
144
145 static bool pluginGetProperty(NPObject* obj, NPIdentifier name, NPVariant* result)
146 {
147     PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
148     if (name == pluginPropertyIdentifiers[ID_PROPERTY_PROPERTY]) {
149         STRINGZ_TO_NPVARIANT("property", *result);
150         return true;
151     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
152         BOOLEAN_TO_NPVARIANT(plugin->eventLogging, *result);
153         return true;
154     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
155         BOOLEAN_TO_NPVARIANT(plugin->logDestroy, *result);
156         return true;
157     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_HAS_STREAM]) {
158         BOOLEAN_TO_NPVARIANT(plugin->stream != 0, *result);
159         return true;
160     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT]) {
161         NPObject* testObject = plugin->testObject;
162         browser->retainobject(testObject);
163         OBJECT_TO_NPVARIANT(testObject, *result);
164         return true;
165     }
166     return false;
167 }
168
169 static bool pluginSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* variant)
170 {
171     PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
172     if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
173         plugin->eventLogging = NPVARIANT_TO_BOOLEAN(*variant);
174         return true;
175     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
176         plugin->logDestroy = NPVARIANT_TO_BOOLEAN(*variant);
177         return true;
178     }
179
180     return false;
181 }
182
183 static bool testDOMAccess(PluginObject* obj, const NPVariant*, uint32_t, NPVariant* result)
184 {
185     // Get plug-in's DOM element
186     NPObject* elementObject;
187     if (browser->getvalue(obj->npp, NPNVPluginElementNPObject, &elementObject) == NPERR_NO_ERROR) {
188         // Get style
189         NPVariant styleVariant;
190         NPIdentifier styleIdentifier = browser->getstringidentifier("style");
191         if (browser->getproperty(obj->npp, elementObject, styleIdentifier, &styleVariant) && NPVARIANT_IS_OBJECT(styleVariant)) {
192             // Set style.border
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);
198         }
199
200         browser->releaseobject(elementObject);
201     }
202     VOID_TO_NPVARIANT(*result);
203     return true;
204 }
205
206 static NPIdentifier stringVariantToIdentifier(NPVariant variant)
207 {
208     assert(NPVARIANT_IS_STRING(variant));
209     NPUTF8* utf8String = createCStringFromNPVariant(&variant);
210     NPIdentifier identifier = browser->getstringidentifier(utf8String);
211     free(utf8String);
212     return identifier;
213 }
214
215 static NPIdentifier int32VariantToIdentifier(NPVariant variant)
216 {
217     assert(NPVARIANT_IS_INT32(variant));
218     int32 integer = NPVARIANT_TO_INT32(variant);
219     return browser->getintidentifier(integer);
220 }
221
222 static NPIdentifier doubleVariantToIdentifier(NPVariant variant)
223 {
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);
229 }
230
231 static NPIdentifier variantToIdentifier(NPVariant variant)
232 {
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);
239     return 0;
240 }
241
242 static bool testIdentifierToString(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
243 {
244     if (argCount != 1)
245         return false;
246     NPIdentifier identifier = variantToIdentifier(args[0]);
247     if (!identifier)
248         return false;
249     NPUTF8* utf8String = browser->utf8fromidentifier(identifier);
250     if (!utf8String)
251         return false;
252     STRINGZ_TO_NPVARIANT(utf8String, *result);
253     return true;
254 }
255
256 static bool testIdentifierToInt(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
257 {
258     if (argCount != 1)
259         return false;
260     NPIdentifier identifier = variantToIdentifier(args[0]);
261     if (!identifier)
262         return false;
263     int32 integer = browser->intfromidentifier(identifier);
264     INT32_TO_NPVARIANT(integer, *result);
265     return true;
266 }
267
268 static bool testCallback(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
269 {
270     if (argCount == 0 || !NPVARIANT_IS_STRING(args[0]))
271         return false;
272
273     NPObject* windowScriptObject;
274     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
275
276     NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
277     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
278     free(callbackString);
279
280     NPVariant browserResult;
281     browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult);
282     browser->releasevariantvalue(&browserResult);
283
284     VOID_TO_NPVARIANT(*result);
285     return true;
286 }
287
288 static bool getURL(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
289 {
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);
294         free(urlString);
295         free(targetString);
296
297         VOID_TO_NPVARIANT(*result);
298         return true;
299     } else if (argCount == 1 && NPVARIANT_IS_STRING(args[0])) {
300         NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
301         browser->geturl(obj->npp, urlString, 0);
302         free(urlString);
303
304         VOID_TO_NPVARIANT(*result);
305         return true;
306     }
307     return false;
308 }
309
310 static bool removeDefaultMethod(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
311 {
312     pluginClass.invokeDefault = 0;
313     VOID_TO_NPVARIANT(*result);
314     return true;
315 }
316
317 static bool getURLNotify(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
318 {
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]))
322         return false;
323
324     NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
325     NPUTF8* targetString = (NPVARIANT_IS_STRING(args[1]) ? createCStringFromNPVariant(&args[1]) : NULL);
326     NPUTF8* callbackString = createCStringFromNPVariant(&args[2]);
327
328     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
329     browser->geturlnotify(obj->npp, urlString, targetString, callbackIdentifier);
330
331     free(urlString);
332     free(targetString);
333     free(callbackString);
334
335     VOID_TO_NPVARIANT(*result);
336     return true;
337 }
338
339 static bool testInvokeDefault(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
340 {
341     if (!NPVARIANT_IS_OBJECT(args[0]))
342         return false;
343
344     NPObject *callback = NPVARIANT_TO_OBJECT(args[0]);
345
346     NPVariant invokeArgs[1];
347     NPVariant browserResult;
348
349     STRINGZ_TO_NPVARIANT("test", invokeArgs[0]);
350     bool retval = browser->invokeDefault(obj->npp, callback, invokeArgs, 1, &browserResult);
351
352     if (retval)
353         browser->releasevariantvalue(&browserResult);
354
355     BOOLEAN_TO_NPVARIANT(retval, *result);
356     return true;
357 }
358
359 static bool destroyStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
360 {
361     NPError npError = browser->destroystream(obj->npp, obj->stream, NPRES_USER_BREAK);
362     INT32_TO_NPVARIANT(npError, *result);
363     return true;
364 }
365
366 static bool testEnumerate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
367 {
368     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_OBJECT(args[1]))
369         return false;
370
371     uint32_t count;
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");
376
377         for (uint32_t i = 0; i < count; i++) {
378             NPUTF8* string = browser->utf8fromidentifier(identifiers[i]);
379
380             if (!string)
381                 continue;
382
383             NPVariant args[1];
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);
389         }
390
391         browser->memfree(identifiers);
392     }
393
394     VOID_TO_NPVARIANT(*result);
395     return true;
396 }
397
398 static bool testGetIntIdentifier(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
399 {
400     if (argCount != 1 || !NPVARIANT_IS_DOUBLE(args[0]))
401         return false;
402
403     NPIdentifier identifier = browser->getintidentifier((int)NPVARIANT_TO_DOUBLE(args[0]));
404     INT32_TO_NPVARIANT((int32)(long long)identifier, *result);
405     return true;
406 }
407
408 static bool testGetProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
409 {
410     if (argCount == 0)
411         return false;
412
413     NPObject *object;
414     browser->getvalue(obj->npp, NPNVWindowNPObject, &object);
415
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);
421
422         NPVariant variant;
423         bool retval = browser->getproperty(obj->npp, object, propertyIdentifier, &variant);
424         browser->releaseobject(object);
425
426         if (!retval)
427             break;
428
429         if (i + 1 < argCount) {
430             assert(NPVARIANT_IS_OBJECT(variant));
431             object = NPVARIANT_TO_OBJECT(variant);
432         } else {
433             *result = variant;
434             return true;
435         }
436     }
437
438     VOID_TO_NPVARIANT(*result);
439     return false;
440 }
441
442 static bool testEvaluate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
443 {
444     if (argCount != 1 || !NPVARIANT_IS_STRING(args[0]))
445         return false;
446     NPObject* windowScriptObject;
447     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
448
449     NPString s = NPVARIANT_TO_STRING(args[0]);
450
451     bool retval = browser->evaluate(obj->npp, windowScriptObject, &s, result);
452     browser->releaseobject(windowScriptObject);
453     return retval;
454 }
455
456 static bool testGetPropertyReturnValue(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
457 {
458     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
459         return false;
460
461     NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
462     NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
463     free(propertyString);
464
465     NPVariant variant;
466     bool retval = browser->getproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier, &variant);
467     if (retval)
468         browser->releasevariantvalue(&variant);
469
470     BOOLEAN_TO_NPVARIANT(retval, *result);
471     return true;
472 }
473
474 static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
475 {
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);
505
506     return false;
507 }
508
509 static bool pluginInvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
510 {
511     INT32_TO_NPVARIANT(1, *result);
512     return true;
513 }
514
515 static void pluginInvalidate(NPObject* obj)
516 {
517 }
518
519 static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
520 {
521     PluginObject* newInstance = (PluginObject*)malloc(sizeof(PluginObject));
522
523     if (!identifiersInitialized) {
524         identifiersInitialized = true;
525         initializeIdentifiers();
526     }
527
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;
535
536     newInstance->firstUrl = NULL;
537     newInstance->firstHeaders = NULL;
538     newInstance->lastUrl = NULL;
539     newInstance->lastHeaders = NULL;
540
541     return (NPObject*)newInstance;
542 }
543
544 static void pluginDeallocate(NPObject* header)
545 {
546     PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
547     browser->releaseobject(plugin->testObject);
548
549     free(plugin->firstUrl);
550     free(plugin->firstHeaders);
551     free(plugin->lastUrl);
552     free(plugin->lastHeaders);
553     free(plugin);
554 }
555
556 void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData)
557 {
558     assert(object);
559
560     NPVariant args[2];
561
562     NPObject *windowScriptObject;
563     browser->getvalue(object->npp, NPNVWindowNPObject, &windowScriptObject);
564
565     NPIdentifier callbackIdentifier = notifyData;
566
567     INT32_TO_NPVARIANT(reason, args[0]);
568
569     char *strHdr = NULL;
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]);
582     } else
583         NULL_TO_NPVARIANT(args[1]);
584
585     NPVariant browserResult;
586     browser->invoke(object->npp, windowScriptObject, callbackIdentifier, args, 2, &browserResult);
587     browser->releasevariantvalue(&browserResult);
588
589     free(strHdr);
590 }
591
592 void notifyStream(PluginObject* object, const char *url, const char *headers)
593 {
594     if (object->firstUrl == NULL) {
595         if (url)
596             object->firstUrl = strdup(url);
597         if (headers)
598             object->firstHeaders = strdup(headers);
599     } else {
600         free(object->lastUrl);
601         free(object->lastHeaders);
602         object->lastUrl = (url ? strdup(url) : NULL);
603         object->lastHeaders = (headers ? strdup(headers) : NULL);
604     }
605 }