Home | History | Annotate | Download | only in TestNetscapePlugIn.subproj
      1 /*
      2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
      3  * Copyright (C) 2009 Holger Hans Peter Freyther
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "PluginObject.h"
     28 
     29 #include "TestObject.h"
     30 #include <assert.h>
     31 #include <stdarg.h>
     32 #include <stdio.h>
     33 
     34 #include <string.h>
     35 #include <stdlib.h>
     36 
     37 // Helper function which takes in the plugin window object for logging to the console object.
     38 static void pluginLogWithWindowObject(NPObject* windowObject, NPP instance, const char* message)
     39 {
     40     NPVariant consoleVariant;
     41     if (!browser->getproperty(instance, windowObject, browser->getstringidentifier("console"), &consoleVariant)) {
     42         fprintf(stderr, "Failed to retrieve console object while logging: %s\n", message);
     43         return;
     44     }
     45 
     46     NPObject* consoleObject = NPVARIANT_TO_OBJECT(consoleVariant);
     47 
     48     NPVariant messageVariant;
     49     STRINGZ_TO_NPVARIANT(message, messageVariant);
     50 
     51     NPVariant result;
     52     if (!browser->invoke(instance, consoleObject, browser->getstringidentifier("log"), &messageVariant, 1, &result)) {
     53         fprintf(stderr, "Failed to invoke console.log while logging: %s\n", message);
     54         browser->releaseobject(consoleObject);
     55         return;
     56     }
     57 
     58     browser->releasevariantvalue(&result);
     59     browser->releaseobject(consoleObject);
     60 }
     61 
     62 // Helper function which takes in the plugin window object for logging to the console object. This function supports variable
     63 // arguments.
     64 static void pluginLogWithWindowObjectVariableArgs(NPObject* windowObject, NPP instance, const char* format, ...)
     65 {
     66     va_list args;
     67     va_start(args, format);
     68     char message[2048] = "PLUGIN: ";
     69     vsprintf(message + strlen(message), format, args);
     70     va_end(args);
     71 
     72     pluginLogWithWindowObject(windowObject, instance, message);
     73 }
     74 
     75 // Helper function to log to the console object.
     76 void pluginLog(NPP instance, const char* format, ...)
     77 {
     78     va_list args;
     79     va_start(args, format);
     80     char message[2048] = "PLUGIN: ";
     81     vsprintf(message + strlen(message), format, args);
     82     va_end(args);
     83 
     84     NPObject* windowObject = 0;
     85     NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
     86     if (error != NPERR_NO_ERROR) {
     87         fprintf(stderr, "Failed to retrieve window object while logging: %s\n", message);
     88         return;
     89     }
     90 
     91     pluginLogWithWindowObject(windowObject, instance, message);
     92     browser->releaseobject(windowObject);
     93 }
     94 
     95 static void pluginInvalidate(NPObject*);
     96 static bool pluginHasProperty(NPObject*, NPIdentifier name);
     97 static bool pluginHasMethod(NPObject*, NPIdentifier name);
     98 static bool pluginGetProperty(NPObject*, NPIdentifier name, NPVariant*);
     99 static bool pluginSetProperty(NPObject*, NPIdentifier name, const NPVariant*);
    100 static bool pluginInvoke(NPObject*, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result);
    101 static bool pluginInvokeDefault(NPObject*, const NPVariant* args, uint32_t argCount, NPVariant* result);
    102 static NPObject* pluginAllocate(NPP npp, NPClass*);
    103 static void pluginDeallocate(NPObject*);
    104 
    105 NPNetscapeFuncs* browser;
    106 
    107 static NPClass pluginClass = {
    108     NP_CLASS_STRUCT_VERSION,
    109     pluginAllocate,
    110     pluginDeallocate,
    111     pluginInvalidate,
    112     pluginHasMethod,
    113     pluginInvoke,
    114     pluginInvokeDefault,
    115     pluginHasProperty,
    116     pluginGetProperty,
    117     pluginSetProperty,
    118 };
    119 
    120 NPClass *getPluginClass(void)
    121 {
    122     return &pluginClass;
    123 }
    124 
    125 static bool identifiersInitialized = false;
    126 
    127 enum {
    128     ID_PROPERTY_PROPERTY = 0,
    129     ID_PROPERTY_EVENT_LOGGING,
    130     ID_PROPERTY_HAS_STREAM,
    131     ID_PROPERTY_TEST_OBJECT,
    132     ID_PROPERTY_LOG_DESTROY,
    133     ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM,
    134     ID_PROPERTY_PRIVATE_BROWSING_ENABLED,
    135     ID_PROPERTY_CACHED_PRIVATE_BROWSING_ENABLED,
    136     ID_PROPERTY_THROW_EXCEPTION_PROPERTY,
    137     NUM_PROPERTY_IDENTIFIERS
    138 };
    139 
    140 static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS];
    141 static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = {
    142     "property",
    143     "eventLoggingEnabled",
    144     "hasStream",
    145     "testObject",
    146     "logDestroy",
    147     "returnErrorFromNewStream",
    148     "privateBrowsingEnabled",
    149     "cachedPrivateBrowsingEnabled",
    150     "testThrowExceptionProperty"
    151 };
    152 
    153 enum {
    154     ID_TEST_CALLBACK_METHOD = 0,
    155     ID_TEST_GETURL,
    156     ID_REMOVE_DEFAULT_METHOD,
    157     ID_TEST_DOM_ACCESS,
    158     ID_TEST_GET_URL_NOTIFY,
    159     ID_TEST_INVOKE_DEFAULT,
    160     ID_DESTROY_STREAM,
    161     ID_TEST_ENUMERATE,
    162     ID_TEST_GETINTIDENTIFIER,
    163     ID_TEST_GET_PROPERTY,
    164     ID_TEST_HAS_PROPERTY,
    165     ID_TEST_HAS_METHOD,
    166     ID_TEST_EVALUATE,
    167     ID_TEST_GET_PROPERTY_RETURN_VALUE,
    168     ID_TEST_IDENTIFIER_TO_STRING,
    169     ID_TEST_IDENTIFIER_TO_INT,
    170     ID_TEST_POSTURL_FILE,
    171     ID_TEST_CONSTRUCT,
    172     ID_TEST_THROW_EXCEPTION_METHOD,
    173     ID_TEST_FAIL_METHOD,
    174     ID_DESTROY_NULL_STREAM,
    175     ID_TEST_RELOAD_PLUGINS_NO_PAGES,
    176     ID_TEST_RELOAD_PLUGINS_AND_PAGES,
    177     ID_TEST_GET_BROWSER_PROPERTY,
    178     ID_TEST_SET_BROWSER_PROPERTY,
    179     NUM_METHOD_IDENTIFIERS
    180 };
    181 
    182 static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
    183 static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
    184     "testCallback",
    185     "getURL",
    186     "removeDefaultMethod",
    187     "testDOMAccess",
    188     "getURLNotify",
    189     "testInvokeDefault",
    190     "destroyStream",
    191     "testEnumerate",
    192     "testGetIntIdentifier",
    193     "testGetProperty",
    194     "testHasProperty",
    195     "testHasMethod",
    196     "testEvaluate",
    197     "testGetPropertyReturnValue",
    198     "testIdentifierToString",
    199     "testIdentifierToInt",
    200     "testPostURLFile",
    201     "testConstruct",
    202     "testThrowException",
    203     "testFail",
    204     "destroyNullStream",
    205     "reloadPluginsNoPages",
    206     "reloadPluginsAndPages",
    207     "testGetBrowserProperty",
    208     "testSetBrowserProperty"
    209 };
    210 
    211 static NPUTF8* createCStringFromNPVariant(const NPVariant* variant)
    212 {
    213     size_t length = NPVARIANT_TO_STRING(*variant).UTF8Length;
    214     NPUTF8* result = (NPUTF8*)malloc(length + 1);
    215     memcpy(result, NPVARIANT_TO_STRING(*variant).UTF8Characters, length);
    216     result[length] = '\0';
    217     return result;
    218 }
    219 
    220 static void initializeIdentifiers(void)
    221 {
    222     browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers);
    223     browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers);
    224 }
    225 
    226 static bool pluginHasProperty(NPObject *obj, NPIdentifier name)
    227 {
    228     for (int i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++)
    229         if (name == pluginPropertyIdentifiers[i])
    230             return true;
    231     return false;
    232 }
    233 
    234 static bool pluginHasMethod(NPObject *obj, NPIdentifier name)
    235 {
    236     for (int i = 0; i < NUM_METHOD_IDENTIFIERS; i++)
    237         if (name == pluginMethodIdentifiers[i])
    238             return true;
    239     return false;
    240 }
    241 
    242 static bool pluginGetProperty(NPObject* obj, NPIdentifier name, NPVariant* result)
    243 {
    244     PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
    245     if (name == pluginPropertyIdentifiers[ID_PROPERTY_PROPERTY]) {
    246         STRINGZ_TO_NPVARIANT("property", *result);
    247         return true;
    248     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
    249         BOOLEAN_TO_NPVARIANT(plugin->eventLogging, *result);
    250         return true;
    251     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
    252         BOOLEAN_TO_NPVARIANT(plugin->logDestroy, *result);
    253         return true;
    254     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_HAS_STREAM]) {
    255         BOOLEAN_TO_NPVARIANT(plugin->stream != 0, *result);
    256         return true;
    257     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT]) {
    258         NPObject* testObject = plugin->testObject;
    259         browser->retainobject(testObject);
    260         OBJECT_TO_NPVARIANT(testObject, *result);
    261         return true;
    262     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) {
    263         BOOLEAN_TO_NPVARIANT(plugin->returnErrorFromNewStream, *result);
    264         return true;
    265     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_PRIVATE_BROWSING_ENABLED]) {
    266         NPBool privateBrowsingEnabled = FALSE;
    267         browser->getvalue(plugin->npp, NPNVprivateModeBool, &privateBrowsingEnabled);
    268         BOOLEAN_TO_NPVARIANT(privateBrowsingEnabled, *result);
    269         return true;
    270     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_CACHED_PRIVATE_BROWSING_ENABLED]) {
    271         BOOLEAN_TO_NPVARIANT(plugin->cachedPrivateBrowsingMode, *result);
    272         return true;
    273     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) {
    274         browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS");
    275         return true;
    276     }
    277     return false;
    278 }
    279 
    280 static bool pluginSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* variant)
    281 {
    282     PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
    283     if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
    284         plugin->eventLogging = NPVARIANT_TO_BOOLEAN(*variant);
    285         return true;
    286     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
    287         plugin->logDestroy = NPVARIANT_TO_BOOLEAN(*variant);
    288         return true;
    289     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) {
    290         plugin->returnErrorFromNewStream = NPVARIANT_TO_BOOLEAN(*variant);
    291         return true;
    292     } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) {
    293         browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS");
    294         return true;
    295     }
    296 
    297     return false;
    298 }
    299 
    300 static bool testDOMAccess(PluginObject* obj, const NPVariant*, uint32_t, NPVariant* result)
    301 {
    302     // Get plug-in's DOM element
    303     NPObject* elementObject;
    304     if (browser->getvalue(obj->npp, NPNVPluginElementNPObject, &elementObject) == NPERR_NO_ERROR) {
    305         // Get style
    306         NPVariant styleVariant;
    307         NPIdentifier styleIdentifier = browser->getstringidentifier("style");
    308         if (browser->getproperty(obj->npp, elementObject, styleIdentifier, &styleVariant) && NPVARIANT_IS_OBJECT(styleVariant)) {
    309             // Set style.border
    310             NPIdentifier borderIdentifier = browser->getstringidentifier("border");
    311             NPVariant borderVariant;
    312             STRINGZ_TO_NPVARIANT("3px solid red", borderVariant);
    313             browser->setproperty(obj->npp, NPVARIANT_TO_OBJECT(styleVariant), borderIdentifier, &borderVariant);
    314             browser->releasevariantvalue(&styleVariant);
    315         }
    316 
    317         browser->releaseobject(elementObject);
    318     }
    319     VOID_TO_NPVARIANT(*result);
    320     return true;
    321 }
    322 
    323 static NPIdentifier stringVariantToIdentifier(NPVariant variant)
    324 {
    325     assert(NPVARIANT_IS_STRING(variant));
    326     NPUTF8* utf8String = createCStringFromNPVariant(&variant);
    327     NPIdentifier identifier = browser->getstringidentifier(utf8String);
    328     free(utf8String);
    329     return identifier;
    330 }
    331 
    332 static NPIdentifier int32VariantToIdentifier(NPVariant variant)
    333 {
    334     assert(NPVARIANT_IS_INT32(variant));
    335     int32 integer = NPVARIANT_TO_INT32(variant);
    336     return browser->getintidentifier(integer);
    337 }
    338 
    339 static NPIdentifier doubleVariantToIdentifier(NPVariant variant)
    340 {
    341     assert(NPVARIANT_IS_DOUBLE(variant));
    342     double value = NPVARIANT_TO_DOUBLE(variant);
    343     // Sadly there is no "getdoubleidentifier"
    344     int32 integer = static_cast<int32>(value);
    345     return browser->getintidentifier(integer);
    346 }
    347 
    348 static NPIdentifier variantToIdentifier(NPVariant variant)
    349 {
    350     if (NPVARIANT_IS_STRING(variant))
    351         return stringVariantToIdentifier(variant);
    352     else if (NPVARIANT_IS_INT32(variant))
    353         return int32VariantToIdentifier(variant);
    354     else if (NPVARIANT_IS_DOUBLE(variant))
    355         return doubleVariantToIdentifier(variant);
    356     return 0;
    357 }
    358 
    359 static bool testIdentifierToString(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
    360 {
    361     if (argCount != 1)
    362         return true;
    363     NPIdentifier identifier = variantToIdentifier(args[0]);
    364     if (!identifier)
    365         return true;
    366     NPUTF8* utf8String = browser->utf8fromidentifier(identifier);
    367     if (!utf8String)
    368         return true;
    369     STRINGZ_TO_NPVARIANT(utf8String, *result);
    370     return true;
    371 }
    372 
    373 static bool testIdentifierToInt(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
    374 {
    375     if (argCount != 1)
    376         return false;
    377     NPIdentifier identifier = variantToIdentifier(args[0]);
    378     if (!identifier)
    379         return false;
    380     int32 integer = browser->intfromidentifier(identifier);
    381     INT32_TO_NPVARIANT(integer, *result);
    382     return true;
    383 }
    384 
    385 static bool testCallback(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    386 {
    387     if (argCount == 0 || !NPVARIANT_IS_STRING(args[0]))
    388         return false;
    389 
    390     NPObject* windowScriptObject;
    391     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
    392 
    393     NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
    394     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
    395     free(callbackString);
    396 
    397     NPVariant browserResult;
    398     browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult);
    399     browser->releasevariantvalue(&browserResult);
    400 
    401     browser->releaseobject(windowScriptObject);
    402 
    403     VOID_TO_NPVARIANT(*result);
    404     return true;
    405 }
    406 
    407 static bool getURL(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    408 {
    409     if (argCount == 2 && NPVARIANT_IS_STRING(args[0]) && NPVARIANT_IS_STRING(args[1])) {
    410         NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
    411         NPUTF8* targetString = createCStringFromNPVariant(&args[1]);
    412         NPError npErr = browser->geturl(obj->npp, urlString, targetString);
    413         free(urlString);
    414         free(targetString);
    415 
    416         INT32_TO_NPVARIANT(npErr, *result);
    417         return true;
    418     } else if (argCount == 1 && NPVARIANT_IS_STRING(args[0])) {
    419         NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
    420         NPError npErr = browser->geturl(obj->npp, urlString, 0);
    421         free(urlString);
    422 
    423         INT32_TO_NPVARIANT(npErr, *result);
    424         return true;
    425     }
    426     return false;
    427 }
    428 
    429 static bool removeDefaultMethod(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
    430 {
    431     pluginClass.invokeDefault = 0;
    432     VOID_TO_NPVARIANT(*result);
    433     return true;
    434 }
    435 
    436 static bool getURLNotify(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    437 {
    438     if (argCount != 3 || !NPVARIANT_IS_STRING(args[0])
    439         || (!NPVARIANT_IS_STRING(args[1]) && !NPVARIANT_IS_NULL(args[1]))
    440         || !NPVARIANT_IS_STRING(args[2]))
    441         return false;
    442 
    443     NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
    444     NPUTF8* targetString = (NPVARIANT_IS_STRING(args[1]) ? createCStringFromNPVariant(&args[1]) : NULL);
    445     NPUTF8* callbackString = createCStringFromNPVariant(&args[2]);
    446 
    447     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
    448     browser->geturlnotify(obj->npp, urlString, targetString, callbackIdentifier);
    449 
    450     free(urlString);
    451     free(targetString);
    452     free(callbackString);
    453 
    454     VOID_TO_NPVARIANT(*result);
    455     return true;
    456 }
    457 
    458 static bool testInvokeDefault(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    459 {
    460     if (!NPVARIANT_IS_OBJECT(args[0]))
    461         return false;
    462 
    463     NPObject *callback = NPVARIANT_TO_OBJECT(args[0]);
    464 
    465     NPVariant invokeArgs[1];
    466     NPVariant browserResult;
    467 
    468     STRINGZ_TO_NPVARIANT("test", invokeArgs[0]);
    469     bool retval = browser->invokeDefault(obj->npp, callback, invokeArgs, 1, &browserResult);
    470 
    471     if (retval)
    472         browser->releasevariantvalue(&browserResult);
    473 
    474     BOOLEAN_TO_NPVARIANT(retval, *result);
    475     return true;
    476 }
    477 
    478 static bool destroyStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    479 {
    480     NPError npError = browser->destroystream(obj->npp, obj->stream, NPRES_USER_BREAK);
    481     INT32_TO_NPVARIANT(npError, *result);
    482     return true;
    483 }
    484 
    485 static bool destroyNullStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    486 {
    487     NPError npError = browser->destroystream(obj->npp, 0, NPRES_USER_BREAK);
    488     INT32_TO_NPVARIANT(npError, *result);
    489     return true;
    490 }
    491 
    492 static bool testEnumerate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    493 {
    494     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_OBJECT(args[1]))
    495         return false;
    496 
    497     uint32_t count;
    498     NPIdentifier* identifiers;
    499     if (browser->enumerate(obj->npp, NPVARIANT_TO_OBJECT(args[0]), &identifiers, &count)) {
    500         NPObject* outArray = NPVARIANT_TO_OBJECT(args[1]);
    501         NPIdentifier pushIdentifier = browser->getstringidentifier("push");
    502 
    503         for (uint32_t i = 0; i < count; i++) {
    504             NPUTF8* string = browser->utf8fromidentifier(identifiers[i]);
    505 
    506             if (!string)
    507                 continue;
    508 
    509             NPVariant args[1];
    510             STRINGZ_TO_NPVARIANT(string, args[0]);
    511             NPVariant browserResult;
    512             browser->invoke(obj->npp, outArray, pushIdentifier, args, 1, &browserResult);
    513             browser->releasevariantvalue(&browserResult);
    514             browser->memfree(string);
    515         }
    516 
    517         browser->memfree(identifiers);
    518     }
    519 
    520     VOID_TO_NPVARIANT(*result);
    521     return true;
    522 }
    523 
    524 static bool testGetIntIdentifier(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
    525 {
    526     if (argCount != 1 || !NPVARIANT_IS_DOUBLE(args[0]))
    527         return false;
    528 
    529     NPIdentifier identifier = browser->getintidentifier((int)NPVARIANT_TO_DOUBLE(args[0]));
    530     INT32_TO_NPVARIANT((int32)(long long)identifier, *result);
    531     return true;
    532 }
    533 
    534 static bool testGetProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    535 {
    536     if (argCount == 0)
    537         return false;
    538 
    539     NPObject *object;
    540     browser->getvalue(obj->npp, NPNVWindowNPObject, &object);
    541 
    542     for (uint32_t i = 0; i < argCount; i++) {
    543         assert(NPVARIANT_IS_STRING(args[i]));
    544         NPUTF8* propertyString = createCStringFromNPVariant(&args[i]);
    545         NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
    546         free(propertyString);
    547 
    548         NPVariant variant;
    549         bool retval = browser->getproperty(obj->npp, object, propertyIdentifier, &variant);
    550         browser->releaseobject(object);
    551 
    552         if (!retval)
    553             break;
    554 
    555         if (i + 1 < argCount) {
    556             assert(NPVARIANT_IS_OBJECT(variant));
    557             object = NPVARIANT_TO_OBJECT(variant);
    558         } else {
    559             *result = variant;
    560             return true;
    561         }
    562     }
    563 
    564     VOID_TO_NPVARIANT(*result);
    565     return false;
    566 }
    567 
    568 static bool testHasProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    569 {
    570     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
    571         return false;
    572 
    573     NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
    574     NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
    575     free(propertyString);
    576 
    577     bool retval = browser->hasproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier);
    578 
    579     BOOLEAN_TO_NPVARIANT(retval, *result);
    580     return true;
    581 }
    582 
    583 static bool testHasMethod(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    584 {
    585     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
    586         return false;
    587 
    588     NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
    589     NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
    590     free(propertyString);
    591 
    592     bool retval = browser->hasmethod(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier);
    593 
    594     BOOLEAN_TO_NPVARIANT(retval, *result);
    595     return true;
    596 }
    597 
    598 static bool testEvaluate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    599 {
    600     if (argCount != 1 || !NPVARIANT_IS_STRING(args[0]))
    601         return false;
    602     NPObject* windowScriptObject;
    603     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
    604 
    605     NPString s = NPVARIANT_TO_STRING(args[0]);
    606 
    607     bool retval = browser->evaluate(obj->npp, windowScriptObject, &s, result);
    608     browser->releaseobject(windowScriptObject);
    609     return retval;
    610 }
    611 
    612 static bool testGetPropertyReturnValue(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    613 {
    614     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
    615         return false;
    616 
    617     NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
    618     NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
    619     free(propertyString);
    620 
    621     NPVariant variant;
    622     bool retval = browser->getproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier, &variant);
    623     if (retval)
    624         browser->releasevariantvalue(&variant);
    625 
    626     BOOLEAN_TO_NPVARIANT(retval, *result);
    627     return true;
    628 }
    629 
    630 static char* toCString(const NPString& string)
    631 {
    632     char* result = static_cast<char*>(malloc(string.UTF8Length + 1));
    633     memcpy(result, string.UTF8Characters, string.UTF8Length);
    634     result[string.UTF8Length] = '\0';
    635 
    636     return result;
    637 }
    638 
    639 static bool testPostURLFile(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    640 {
    641     if (argCount != 4 || !NPVARIANT_IS_STRING(args[0]) || !NPVARIANT_IS_STRING(args[1]) || !NPVARIANT_IS_STRING(args[2]) || !NPVARIANT_IS_STRING(args[3]))
    642         return false;
    643 
    644     NPString urlString = NPVARIANT_TO_STRING(args[0]);
    645     char* url = toCString(urlString);
    646 
    647     NPString targetString = NPVARIANT_TO_STRING(args[1]);
    648     char* target = toCString(targetString);
    649 
    650     NPString pathString = NPVARIANT_TO_STRING(args[2]);
    651     char* path = toCString(pathString);
    652 
    653     NPString contentsString = NPVARIANT_TO_STRING(args[3]);
    654 
    655     FILE* tempFile = fopen(path, "w");
    656     if (!tempFile)
    657         return false;
    658 
    659     fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile);
    660     fclose(tempFile);
    661 
    662     NPError error = browser->posturl(obj->npp, url, target, pathString.UTF8Length, path, TRUE);
    663 
    664     free(path);
    665     free(target);
    666     free(url);
    667 
    668     BOOLEAN_TO_NPVARIANT(error == NPERR_NO_ERROR, *result);
    669     return true;
    670 }
    671 
    672 static bool testConstruct(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    673 {
    674     if (!argCount || !NPVARIANT_IS_OBJECT(args[0]))
    675         return false;
    676 
    677     return browser->construct(obj->npp, NPVARIANT_TO_OBJECT(args[0]), args + 1, argCount - 1, result);
    678 }
    679 
    680 // Helper function to notify the layout test controller that the test completed.
    681 void notifyTestCompletion(NPP npp, NPObject* object)
    682 {
    683     NPVariant result;
    684     NPString script;
    685     script.UTF8Characters = "javascript:window.layoutTestController.notifyDone();";
    686     script.UTF8Length = strlen("javascript:window.layoutTestController.notifyDone();");
    687     browser->evaluate(npp, object, &script, &result);
    688     browser->releasevariantvalue(&result);
    689 }
    690 
    691 bool testDocumentOpen(NPP npp)
    692 {
    693     NPIdentifier documentId = browser->getstringidentifier("document");
    694     NPIdentifier openId = browser->getstringidentifier("open");
    695 
    696     NPObject *windowObject = NULL;
    697     browser->getvalue(npp, NPNVWindowNPObject, &windowObject);
    698     if (!windowObject)
    699         return false;
    700 
    701     NPVariant docVariant;
    702     browser->getproperty(npp, windowObject, documentId, &docVariant);
    703     if (docVariant.type != NPVariantType_Object)
    704         return false;
    705 
    706     NPObject *documentObject = NPVARIANT_TO_OBJECT(docVariant);
    707 
    708     NPVariant openArgs[2];
    709     STRINGZ_TO_NPVARIANT("text/html", openArgs[0]);
    710     STRINGZ_TO_NPVARIANT("_blank", openArgs[1]);
    711 
    712     NPVariant result;
    713     browser->invoke(npp, documentObject, openId, openArgs, 2, &result);
    714     browser->releaseobject(documentObject);
    715 
    716     if (result.type == NPVariantType_Object) {
    717         pluginLogWithWindowObjectVariableArgs(windowObject, npp, "DOCUMENT OPEN SUCCESS");
    718         notifyTestCompletion(npp, result.value.objectValue);
    719         browser->releaseobject(result.value.objectValue);
    720         return true;
    721     }
    722 
    723     return false;
    724 }
    725 
    726 bool testWindowOpen(NPP npp)
    727 {
    728     NPIdentifier openId = browser->getstringidentifier("open");
    729 
    730     NPObject *windowObject = NULL;
    731     browser->getvalue(npp, NPNVWindowNPObject, &windowObject);
    732     if (!windowObject)
    733         return false;
    734 
    735     NPVariant openArgs[2];
    736     STRINGZ_TO_NPVARIANT("about:blank", openArgs[0]);
    737     STRINGZ_TO_NPVARIANT("_blank", openArgs[1]);
    738 
    739     NPVariant result;
    740     browser->invoke(npp, windowObject, openId, openArgs, 2, &result);
    741     if (result.type == NPVariantType_Object) {
    742         pluginLogWithWindowObjectVariableArgs(windowObject, npp, "WINDOW OPEN SUCCESS");
    743         notifyTestCompletion(npp, result.value.objectValue);
    744         browser->releaseobject(result.value.objectValue);
    745         return true;
    746     }
    747     return false;
    748 }
    749 
    750 static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
    751 {
    752     PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
    753     if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD])
    754         return testCallback(plugin, args, argCount, result);
    755     else if (name == pluginMethodIdentifiers[ID_TEST_GETURL])
    756         return getURL(plugin, args, argCount, result);
    757     else if (name == pluginMethodIdentifiers[ID_REMOVE_DEFAULT_METHOD])
    758         return removeDefaultMethod(plugin, args, argCount, result);
    759     else if (name == pluginMethodIdentifiers[ID_TEST_DOM_ACCESS])
    760         return testDOMAccess(plugin, args, argCount, result);
    761     else if (name == pluginMethodIdentifiers[ID_TEST_GET_URL_NOTIFY])
    762         return getURLNotify(plugin, args, argCount, result);
    763     else if (name == pluginMethodIdentifiers[ID_TEST_INVOKE_DEFAULT])
    764         return testInvokeDefault(plugin, args, argCount, result);
    765     else if (name == pluginMethodIdentifiers[ID_TEST_ENUMERATE])
    766         return testEnumerate(plugin, args, argCount, result);
    767     else if (name == pluginMethodIdentifiers[ID_DESTROY_STREAM])
    768         return destroyStream(plugin, args, argCount, result);
    769     else if (name == pluginMethodIdentifiers[ID_TEST_GETINTIDENTIFIER])
    770         return testGetIntIdentifier(plugin, args, argCount, result);
    771     else if (name == pluginMethodIdentifiers[ID_TEST_EVALUATE])
    772         return testEvaluate(plugin, args, argCount, result);
    773     else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY])
    774         return testGetProperty(plugin, args, argCount, result);
    775     else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY_RETURN_VALUE])
    776         return testGetPropertyReturnValue(plugin, args, argCount, result);
    777     else if (name == pluginMethodIdentifiers[ID_TEST_HAS_PROPERTY])
    778         return testHasProperty(plugin, args, argCount, result);
    779     else if (name == pluginMethodIdentifiers[ID_TEST_HAS_METHOD])
    780         return testHasMethod(plugin, args, argCount, result);
    781     else if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_STRING])
    782         return testIdentifierToString(plugin, args, argCount, result);
    783     else if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_INT])
    784         return testIdentifierToInt(plugin, args, argCount, result);
    785     else if (name == pluginMethodIdentifiers[ID_TEST_POSTURL_FILE])
    786         return testPostURLFile(plugin, args, argCount, result);
    787     else if (name == pluginMethodIdentifiers[ID_TEST_CONSTRUCT])
    788         return testConstruct(plugin, args, argCount, result);
    789     else if (name == pluginMethodIdentifiers[ID_TEST_THROW_EXCEPTION_METHOD]) {
    790         browser->setexception(header, "plugin object testThrowException SUCCESS");
    791         return true;
    792     } else if (name == pluginMethodIdentifiers[ID_TEST_FAIL_METHOD]) {
    793         NPObject* windowScriptObject;
    794         browser->getvalue(plugin->npp, NPNVWindowNPObject, &windowScriptObject);
    795         browser->invoke(plugin->npp, windowScriptObject, name, args, argCount, result);
    796     } else if (name == pluginMethodIdentifiers[ID_DESTROY_NULL_STREAM])
    797         return destroyNullStream(plugin, args, argCount, result);
    798     else if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_NO_PAGES]) {
    799         browser->reloadplugins(false);
    800         return true;
    801     } else if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_AND_PAGES]) {
    802         browser->reloadplugins(true);
    803         return true;
    804     } else if (name == pluginMethodIdentifiers[ID_TEST_GET_BROWSER_PROPERTY]) {
    805         browser->getproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), result);
    806         return true;
    807     } else if (name == pluginMethodIdentifiers[ID_TEST_SET_BROWSER_PROPERTY]) {
    808         browser->setproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), &args[2]);
    809         return true;
    810     }
    811 
    812     return false;
    813 }
    814 
    815 static bool pluginInvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    816 {
    817     INT32_TO_NPVARIANT(1, *result);
    818     return true;
    819 }
    820 
    821 static void pluginInvalidate(NPObject* header)
    822 {
    823     PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
    824     plugin->testObject = 0;
    825 }
    826 
    827 static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
    828 {
    829     PluginObject* newInstance = (PluginObject*)malloc(sizeof(PluginObject));
    830 
    831     if (!identifiersInitialized) {
    832         identifiersInitialized = true;
    833         initializeIdentifiers();
    834     }
    835 
    836     newInstance->npp = npp;
    837     newInstance->testObject = browser->createobject(npp, getTestClass());
    838     newInstance->eventLogging = FALSE;
    839     newInstance->onStreamLoad = 0;
    840     newInstance->onStreamDestroy = 0;
    841     newInstance->onDestroy = 0;
    842     newInstance->onURLNotify = 0;
    843     newInstance->logDestroy = FALSE;
    844     newInstance->logSetWindow = FALSE;
    845     newInstance->returnErrorFromNewStream = FALSE;
    846     newInstance->stream = 0;
    847 
    848     newInstance->firstUrl = NULL;
    849     newInstance->firstHeaders = NULL;
    850     newInstance->lastUrl = NULL;
    851     newInstance->lastHeaders = NULL;
    852 
    853     newInstance->testDocumentOpenInDestroyStream = FALSE;
    854     newInstance->testWindowOpen = FALSE;
    855 
    856     return (NPObject*)newInstance;
    857 }
    858 
    859 static void pluginDeallocate(NPObject* header)
    860 {
    861     PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
    862     if (plugin->testObject)
    863         browser->releaseobject(plugin->testObject);
    864 
    865     free(plugin->firstUrl);
    866     free(plugin->firstHeaders);
    867     free(plugin->lastUrl);
    868     free(plugin->lastHeaders);
    869     free(plugin);
    870 }
    871 
    872 void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData)
    873 {
    874     assert(object);
    875 
    876     NPVariant args[2];
    877 
    878     NPObject *windowScriptObject;
    879     browser->getvalue(object->npp, NPNVWindowNPObject, &windowScriptObject);
    880 
    881     NPIdentifier callbackIdentifier = notifyData;
    882 
    883     INT32_TO_NPVARIANT(reason, args[0]);
    884 
    885     char *strHdr = NULL;
    886     if (object->firstUrl && object->firstHeaders && object->lastUrl && object->lastHeaders) {
    887         // Format expected by JavaScript validator: four fields separated by \n\n:
    888         // First URL; first header block; last URL; last header block.
    889         // Note that header blocks already end with \n due to how NPStream::headers works.
    890         int len = strlen(object->firstUrl) + 2
    891             + strlen(object->firstHeaders) + 1
    892             + strlen(object->lastUrl) + 2
    893             + strlen(object->lastHeaders) + 1;
    894         strHdr = (char*)malloc(len + 1);
    895         snprintf(strHdr, len + 1, "%s\n\n%s\n%s\n\n%s\n",
    896                  object->firstUrl, object->firstHeaders, object->lastUrl, object->lastHeaders);
    897         STRINGN_TO_NPVARIANT(strHdr, len, args[1]);
    898     } else
    899         NULL_TO_NPVARIANT(args[1]);
    900 
    901     NPVariant browserResult;
    902     browser->invoke(object->npp, windowScriptObject, callbackIdentifier, args, 2, &browserResult);
    903     browser->releasevariantvalue(&browserResult);
    904 
    905     free(strHdr);
    906 }
    907 
    908 void notifyStream(PluginObject* object, const char *url, const char *headers)
    909 {
    910     if (object->firstUrl == NULL) {
    911         if (url)
    912             object->firstUrl = strdup(url);
    913         if (headers)
    914             object->firstHeaders = strdup(headers);
    915     } else {
    916         free(object->lastUrl);
    917         free(object->lastHeaders);
    918         object->lastUrl = (url ? strdup(url) : NULL);
    919         object->lastHeaders = (headers ? strdup(headers) : NULL);
    920     }
    921 }
    922 
    923 void testNPRuntime(NPP npp)
    924 {
    925     NPObject* windowScriptObject;
    926     browser->getvalue(npp, NPNVWindowNPObject, &windowScriptObject);
    927 
    928     // Invoke
    929     NPIdentifier testNPInvoke = browser->getstringidentifier("testNPInvoke");
    930     NPVariant args[7];
    931 
    932     VOID_TO_NPVARIANT(args[0]);
    933     NULL_TO_NPVARIANT(args[1]);
    934     BOOLEAN_TO_NPVARIANT(true, args[2]);
    935     INT32_TO_NPVARIANT(242, args[3]);
    936     DOUBLE_TO_NPVARIANT(242.242, args[4]);
    937     STRINGZ_TO_NPVARIANT("Hello, World", args[5]);
    938     OBJECT_TO_NPVARIANT(windowScriptObject, args[6]);
    939 
    940     NPVariant result;
    941     if (browser->invoke(npp, windowScriptObject, testNPInvoke, args, 7, &result))
    942         browser->releasevariantvalue(&result);
    943 
    944     browser->releaseobject(windowScriptObject);
    945 }
    946