Back to index

lightning-sunbird  0.9+nobinonly
ns4xPlugin.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 // TODO: Implement Java callbacks
00039 
00040 #include "prtypes.h"
00041 #include "prmem.h"
00042 #include "ns4xPlugin.h"
00043 #include "ns4xPluginInstance.h"
00044 #include "ns4xPluginStreamListener.h"
00045 #include "nsIServiceManager.h"
00046 
00047 #include "nsIMemory.h"
00048 #include "nsIPluginStreamListener.h"
00049 #include "nsPluginsDir.h"
00050 #include "nsPluginSafety.h"
00051 #include "nsIPrefService.h"
00052 #include "nsIPrefBranch.h"
00053 #include "nsPluginLogging.h"
00054 
00055 #include "nsIPluginInstancePeer2.h"
00056 #include "nsIJSContextStack.h"
00057 
00058 #include "nsPIPluginInstancePeer.h"
00059 #include "nsIDOMElement.h"
00060 #include "nsIDOMDocument.h"
00061 #include "nsIDOMWindow.h"
00062 #include "nsIDocument.h"
00063 #include "nsIScriptGlobalObject.h"
00064 #include "nsIScriptContext.h"
00065 
00066 #include "jscntxt.h"
00067 
00068 #include "nsIXPConnect.h"
00069 
00070 #if defined(XP_MACOSX)
00071 #include <Resources.h>
00072 #endif
00073 
00074 //needed for nppdf plugin
00075 #ifdef MOZ_WIDGET_GTK
00076 #include <gdk/gdk.h>
00077 #include <gdk/gdkx.h>
00078 #include "gtkxtbin.h"
00079 #endif
00080 
00081 #ifdef MOZ_WIDGET_GTK2
00082 #include <gdk/gdk.h>
00083 #include <gdk/gdkx.h>
00084 #include "gtk2xtbin.h"
00085 #endif
00086 
00087 #include "nsJSNPRuntime.h"
00088 
00089 // POST/GET stream type
00090 enum eNPPStreamTypeInternal {
00091   eNPPStreamTypeInternal_Get,
00092   eNPPStreamTypeInternal_Post
00093 };
00094 
00096 // CID's && IID's
00097 static NS_DEFINE_IID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
00098 static NS_DEFINE_IID(kPluginManagerCID, NS_PLUGINMANAGER_CID);
00099 static NS_DEFINE_IID(kMemoryCID, NS_MEMORY_CID);
00100 
00101 PR_BEGIN_EXTERN_C
00102 
00104   // Static stub functions that are exported to the 4.x plugin as entry
00105   // points via the CALLBACKS variable.
00106   //
00107   static NPError NP_EXPORT
00108   _requestread(NPStream *pstream, NPByteRange *rangeList);
00109 
00110   static NPError NP_EXPORT
00111   _geturlnotify(NPP npp, const char* relativeURL, const char* target,
00112                 void* notifyData);
00113 
00114   static NPError NP_EXPORT
00115   _getvalue(NPP npp, NPNVariable variable, void *r_value);
00116 
00117   static NPError NP_EXPORT
00118   _setvalue(NPP npp, NPPVariable variable, void *r_value);
00119 
00120   static NPError NP_EXPORT
00121   _geturl(NPP npp, const char* relativeURL, const char* target);
00122 
00123   static NPError NP_EXPORT
00124   _posturlnotify(NPP npp, const char* relativeURL, const char *target,
00125                  uint32 len, const char *buf, NPBool file, void* notifyData);
00126 
00127   static NPError NP_EXPORT
00128   _posturl(NPP npp, const char* relativeURL, const char *target, uint32 len,
00129               const char *buf, NPBool file);
00130 
00131   static NPError NP_EXPORT
00132   _newstream(NPP npp, NPMIMEType type, const char* window, NPStream** pstream);
00133 
00134   static int32 NP_EXPORT
00135   _write(NPP npp, NPStream *pstream, int32 len, void *buffer);
00136 
00137   static NPError NP_EXPORT
00138   _destroystream(NPP npp, NPStream *pstream, NPError reason);
00139 
00140   static void NP_EXPORT
00141   _status(NPP npp, const char *message);
00142 
00143 #if 0
00144 
00145   static void NP_EXPORT
00146   _registerwindow(NPP npp, void* window);
00147 
00148   static void NP_EXPORT
00149   _unregisterwindow(NPP npp, void* window);
00150 
00151   static int16 NP_EXPORT
00152   _allocateMenuID(NPP npp, NPBool isSubmenu);
00153 
00154 #endif
00155 
00156   static void NP_EXPORT
00157   _memfree (void *ptr);
00158 
00159   static uint32 NP_EXPORT
00160   _memflush(uint32 size);
00161 
00162   static void NP_EXPORT
00163   _reloadplugins(NPBool reloadPages);
00164 
00165   static void NP_EXPORT
00166   _invalidaterect(NPP npp, NPRect *invalidRect);
00167 
00168   static void NP_EXPORT
00169   _invalidateregion(NPP npp, NPRegion invalidRegion);
00170 
00171   static void NP_EXPORT
00172   _forceredraw(NPP npp);
00173 
00174   static void NP_EXPORT
00175   _pushpopupsenabledstate(NPP npp, NPBool enabled);
00176 
00177   static void NP_EXPORT
00178   _poppopupsenabledstate(NPP npp);
00179 
00180   static const char* NP_EXPORT
00181   _useragent(NPP npp);
00182 
00183   static void* NP_EXPORT
00184   _memalloc (uint32 size);
00185 
00186 #ifdef OJI
00187   static JRIEnv* NP_EXPORT
00188   _getJavaEnv(void);
00189 
00190 #if 1
00191 
00192   static jref NP_EXPORT
00193   _getJavaPeer(NPP npp);
00194 
00195 #endif
00196 #endif /* OJI */
00197 
00198 PR_END_EXTERN_C
00199 
00200 #if defined(XP_MACOSX) && defined(__i386__)
00201 
00202 // BROKEN_PLUGIN_HACK works around bugs in the version of the Macromedia
00203 // Flash Player plugin that is supplied with the initial consumer shipment
00204 // of Mac OS X for x86-based Macs.  The plugin is broken in at least
00205 // 10.4.4/x86 and 10.4.5/x86.
00206 #define BROKEN_PLUGIN_HACK
00207 
00208 // brokenPlugin is defined in the scope in which TV2FP is used.  It is
00209 // true when this ns4xPlugin object has loaded a plugin that contains the
00210 // bugs being worked around.
00211 //
00212 // The broken plugin returns entry points that are pointers to function
00213 // pointers, instead of just returning the function pointers.  These must
00214 // be dereferenced, or Mozilla will crash upon attempting to call an address
00215 // that doesn't contain code.  TV2FP is a convenient place to handle this,
00216 // since the macro is already present everywhere it's needed, and is otherwise
00217 // unused on x86.
00218 #define TV2FP(f) (brokenPlugin && f ? *(void**)f : (void*)f)
00219 #define FP2TV(f) (f)
00220 
00221 #elif defined(XP_MACOSX) && defined(__POWERPC__)
00222 
00223 #define TV2FP(tvp) _TV2FP((void *)tvp)
00224 
00225 static void*
00226 _TV2FP(void *tvp)
00227 {
00228     static uint32 glue[6] = {
00229       0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420
00230     };
00231     uint32* newGlue = NULL;
00232 
00233     if (tvp != NULL) {
00234         newGlue = (uint32*) malloc(sizeof(glue));
00235         if (newGlue != NULL) {
00236             memcpy(newGlue, glue, sizeof(glue));
00237             newGlue[0] |= ((UInt32)tvp >> 16);
00238             newGlue[1] |= ((UInt32)tvp & 0xFFFF);
00239             MakeDataExecutable(newGlue, sizeof(glue));
00240         }
00241     }
00242     return newGlue;
00243 }
00244 
00245 #define FP2TV(fp) _FP2TV((void *)fp)
00246 
00247 static void*
00248 _FP2TV(void *fp)
00249 {
00250     void **newGlue = NULL;
00251     if (fp != NULL) {
00252         newGlue = (void**) malloc(2 * sizeof(void *));
00253         if (newGlue != NULL) {
00254             newGlue[0] = fp;
00255             newGlue[1] = NULL;
00256         }
00257     }
00258     return newGlue;
00259 }
00260 
00261 #else
00262 
00263 #define TV2FP(f) (f)
00264 #define FP2TV(f) (f)
00265 
00266 #endif /* XP_MACOSX && __POWERPC__ */
00267 
00269 // Globals
00270 NPNetscapeFuncs ns4xPlugin::CALLBACKS;
00271 
00273 void
00274 ns4xPlugin::CheckClassInitialized(void)
00275 {
00276   static PRBool initialized = FALSE;
00277 
00278   if (initialized)
00279     return;
00280 
00281   // XXX It'd be nice to make this const and initialize it statically...
00282   CALLBACKS.size = sizeof(CALLBACKS);
00283   CALLBACKS.version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
00284 
00285   CALLBACKS.geturl =
00286     NewNPN_GetURLProc(FP2TV(_geturl));
00287 
00288   CALLBACKS.posturl =
00289     NewNPN_PostURLProc(FP2TV(_posturl));
00290 
00291   CALLBACKS.requestread =
00292     NewNPN_RequestReadProc(FP2TV(_requestread));
00293 
00294   CALLBACKS.newstream =
00295     NewNPN_NewStreamProc(FP2TV(_newstream));
00296 
00297   CALLBACKS.write =
00298     NewNPN_WriteProc(FP2TV(_write));
00299 
00300   CALLBACKS.destroystream =
00301     NewNPN_DestroyStreamProc(FP2TV(_destroystream));
00302 
00303   CALLBACKS.status =
00304     NewNPN_StatusProc(FP2TV(_status));
00305 
00306   CALLBACKS.uagent =
00307     NewNPN_UserAgentProc(FP2TV(_useragent));
00308 
00309   CALLBACKS.memalloc =
00310     NewNPN_MemAllocProc(FP2TV(_memalloc));
00311 
00312   CALLBACKS.memfree =
00313     NewNPN_MemFreeProc(FP2TV(_memfree));
00314 
00315   CALLBACKS.memflush =
00316     NewNPN_MemFlushProc(FP2TV(_memflush));
00317 
00318   CALLBACKS.reloadplugins =
00319     NewNPN_ReloadPluginsProc(FP2TV(_reloadplugins));
00320 
00321 #ifdef OJI
00322   CALLBACKS.getJavaEnv =
00323     NewNPN_GetJavaEnvProc(FP2TV(_getJavaEnv));
00324 
00325   CALLBACKS.getJavaPeer =
00326     NewNPN_GetJavaPeerProc(FP2TV(_getJavaPeer));
00327 #endif
00328 
00329   CALLBACKS.geturlnotify =
00330     NewNPN_GetURLNotifyProc(FP2TV(_geturlnotify));
00331 
00332   CALLBACKS.posturlnotify =
00333     NewNPN_PostURLNotifyProc(FP2TV(_posturlnotify));
00334 
00335   CALLBACKS.getvalue =
00336     NewNPN_GetValueProc(FP2TV(_getvalue));
00337 
00338   CALLBACKS.setvalue =
00339     NewNPN_SetValueProc(FP2TV(_setvalue));
00340 
00341   CALLBACKS.invalidaterect =
00342     NewNPN_InvalidateRectProc(FP2TV(_invalidaterect));
00343 
00344   CALLBACKS.invalidateregion =
00345     NewNPN_InvalidateRegionProc(FP2TV(_invalidateregion));
00346 
00347   CALLBACKS.forceredraw =
00348     NewNPN_ForceRedrawProc(FP2TV(_forceredraw));
00349 
00350   CALLBACKS.getstringidentifier =
00351     NewNPN_GetStringIdentifierProc(FP2TV(_getstringidentifier));
00352 
00353   CALLBACKS.getstringidentifiers =
00354     NewNPN_GetStringIdentifiersProc(FP2TV(_getstringidentifiers));
00355 
00356   CALLBACKS.getintidentifier =
00357     NewNPN_GetIntIdentifierProc(FP2TV(_getintidentifier));
00358 
00359   CALLBACKS.identifierisstring =
00360     NewNPN_IdentifierIsStringProc(FP2TV(_identifierisstring));
00361 
00362   CALLBACKS.utf8fromidentifier =
00363     NewNPN_UTF8FromIdentifierProc(FP2TV(_utf8fromidentifier));
00364 
00365   CALLBACKS.intfromidentifier =
00366     NewNPN_IntFromIdentifierProc(FP2TV(_intfromidentifier));
00367 
00368   CALLBACKS.createobject =
00369     NewNPN_CreateObjectProc(FP2TV(_createobject));
00370 
00371   CALLBACKS.retainobject =
00372     NewNPN_RetainObjectProc(FP2TV(_retainobject));
00373 
00374   CALLBACKS.releaseobject =
00375     NewNPN_ReleaseObjectProc(FP2TV(_releaseobject));
00376 
00377   CALLBACKS.invoke =
00378     NewNPN_InvokeProc(FP2TV(_invoke));
00379 
00380   CALLBACKS.invokeDefault =
00381     NewNPN_InvokeDefaultProc(FP2TV(_invokeDefault));
00382 
00383   CALLBACKS.evaluate =
00384     NewNPN_EvaluateProc(FP2TV(_evaluate));
00385 
00386   CALLBACKS.getproperty =
00387     NewNPN_GetPropertyProc(FP2TV(_getproperty));
00388 
00389   CALLBACKS.setproperty =
00390     NewNPN_SetPropertyProc(FP2TV(_setproperty));
00391 
00392   CALLBACKS.removeproperty =
00393     NewNPN_RemovePropertyProc(FP2TV(_removeproperty));
00394 
00395   CALLBACKS.hasproperty =
00396     NewNPN_HasPropertyProc(FP2TV(_hasproperty));
00397 
00398   CALLBACKS.hasmethod =
00399     NewNPN_HasMethodProc(FP2TV(_hasmethod));
00400 
00401   CALLBACKS.releasevariantvalue =
00402     NewNPN_ReleaseVariantValueProc(FP2TV(_releasevariantvalue));
00403 
00404   CALLBACKS.setexception =
00405     NewNPN_SetExceptionProc(FP2TV(_setexception));
00406 
00407   CALLBACKS.pushpopupsenabledstate =
00408     NewNPN_PushPopupsEnabledStateProc(FP2TV(_pushpopupsenabledstate));
00409 
00410   CALLBACKS.poppopupsenabledstate =
00411     NewNPN_PopPopupsEnabledStateProc(FP2TV(_poppopupsenabledstate));
00412 
00413   initialized = TRUE;
00414 
00415   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN callbacks initialized\n"));
00416 }
00417 
00418 
00420 // nsISupports stuff
00421 NS_IMPL_ISUPPORTS2(ns4xPlugin, nsIPlugin, nsIFactory)
00422 
00423 ns4xPlugin::ns4xPlugin(NPPluginFuncs* callbacks, PRLibrary* aLibrary,
00424                        NP_PLUGINSHUTDOWN aShutdown,
00425                        nsIServiceManagerObsolete* serviceMgr)
00426 {
00427   memset((void*) &fCallbacks, 0, sizeof(fCallbacks));
00428   fLibrary = nsnull;
00429 
00430 #if defined(XP_WIN) || defined(XP_OS2)
00431   // On Windows (and Mac) we need to keep a direct reference to the
00432   // fCallbacks and NOT just copy the struct. See Bugzilla 85334
00433 
00434   NP_GETENTRYPOINTS pfnGetEntryPoints =
00435     (NP_GETENTRYPOINTS)PR_FindSymbol(aLibrary, "NP_GetEntryPoints");
00436 
00437   if (!pfnGetEntryPoints)
00438     return;
00439 
00440   fCallbacks.size = sizeof(fCallbacks);
00441 
00442   nsresult result = pfnGetEntryPoints(&fCallbacks);
00443   NS_ASSERTION( NS_OK == result,"Failed to get callbacks");
00444 
00445   NS_ASSERTION(HIBYTE(fCallbacks.version) >= NP_VERSION_MAJOR,
00446                "callback version is less than NP version");
00447 
00448   fShutdownEntry = (NP_PLUGINSHUTDOWN)PR_FindSymbol(aLibrary, "NP_Shutdown");
00449 #elif defined(XP_MACOSX)
00450 #ifdef BROKEN_PLUGIN_HACK
00451 #warning BROKEN_PLUGIN_HACK is in use, enjoy your Flash movies!
00452   // This is a private NSPR struct.  Define it here because it's necessary
00453   // to restrict the hack to plugins that need it, and the only way to do
00454   // that is to examine the bundle that was loaded.  I feel comfortable doing
00455   // this because BROKEN_PLUGIN_HACK is a hack anyway, and it's not intended
00456   // to be long-lived.
00457   struct myPRLibrary {
00458     char*                     name;
00459     PRLibrary*                next;
00460     int                       refCount;
00461     const PRStaticLinkTable*  staticTable;
00462     CFragConnectionID         connection;
00463     CFBundleRef               bundle;
00464     Ptr                       main;
00465     CFMutableDictionaryRef    wrappers;
00466     const struct mach_header* image;
00467   };
00468 
00469   // brokenPlugin indicates whether the plugin needs to be worked around
00470   // because it doesn't adhere to the API used on x86.
00471   PRBool brokenPlugin = PR_FALSE;
00472 
00473   // Identify the broken plugin by a variety of attributes.
00474   // Further inspection will be done before applying any workarounds.
00475   struct myPRLibrary *prLibrary = (struct myPRLibrary*) aLibrary;
00476 
00477   if (prLibrary->name && prLibrary->bundle) {
00478     CFStringRef bundleIdentifier = ::CFBundleGetIdentifier(prLibrary->bundle);
00479     CFStringRef bundleShortVersion =
00480       (CFStringRef) ::CFBundleGetValueForInfoDictionaryKey(prLibrary->bundle,
00481                       CFSTR("CFBundleShortVersionString"));
00482 
00483     if (!strcmp(prLibrary->name,
00484                 "/Library/Internet Plug-Ins/Flash Player.plugin") &&
00485         ::CFBundleGetVersionNumber(prLibrary->bundle) == 0x1018011 &&
00486         bundleIdentifier &&
00487         ::CFStringCompare(bundleIdentifier,
00488                           CFSTR("com.macromedia.Flash Player.plugin"),
00489                           0) == kCFCompareEqualTo &&
00490         bundleShortVersion &&
00491         ::CFStringCompare(bundleShortVersion,
00492                           CFSTR("8.0.17"),
00493                           0) == kCFCompareEqualTo) {
00494       // Macromedia Flash Player plugin, version 8.0.17, bundle version 1.0.1f17
00495       brokenPlugin = PR_TRUE;
00496     }
00497   }
00498 #endif /* BROKEN_PLUGIN_HACK */
00499 
00500   // call into the entry point
00501   NP_MAIN pfnMain = (NP_MAIN) PR_FindSymbol(aLibrary, "main");
00502 
00503   if (pfnMain == NULL)
00504     return;
00505 
00506   NPP_ShutdownUPP pfnShutdown;
00507   NPPluginFuncs np_callbacks;
00508   memset((void*) &np_callbacks, 0, sizeof(np_callbacks));
00509   np_callbacks.size = sizeof(np_callbacks);
00510   NPError error;
00511 
00512   NS_TRY_SAFE_CALL_RETURN(error,
00513                           CallNPP_MainEntryProc(pfnMain,
00514                                                 &(ns4xPlugin::CALLBACKS),
00515                                                 &np_callbacks,
00516                                                 &pfnShutdown),
00517                           aLibrary, nsnull);
00518 
00519 #ifdef BROKEN_PLUGIN_HACK
00520   // The broken plugin has wrapped NPN callback function pointers in PPC
00521   // TVector glue as though they were pointers to CFM TVectors.  When the
00522   // x86 attempts to execute the PPC glue, it will of course fail.
00523   //
00524   // What's done here is a bit unorthodox.  I'm going to locate the
00525   // TVector glue that the plugin created from ns4xPlugin::CALLBACKS by
00526   // peeking into its symbol table, then I'm going to dissect the PPC
00527   // machine code to get the target addresses and produce x86 machine code.
00528   // The x86 code overwrites the PPC code in the plugin's jump table.
00529   // The replacement code is of course executable.  I know I can do this,
00530   // because the broken plugin builds its table of TVector glue based on
00531   // what the sample NPAPI plugin does.
00532   //
00533   // Watch this.
00534   if (brokenPlugin) {
00535     PRUint32 glueFixed = 0;
00536 
00537     // Locate the table that the plugin filled with TVector glue.
00538     PRUint8* pluginsGlueTable = (PRUint8*)
00539       ::CFBundleGetDataPointerForName(prLibrary->bundle,
00540                                       CFSTR("gNetscapeFuncsGlueTable"));
00541 
00542     if (pluginsGlueTable) {
00543       // The table contains 40 entries.  Each entry is TVector glue of 6
00544       // 4-byte words (24 bytes total).  See gPluginFuncsGlueTable in
00545       // mozilla/modules/plugin/samples/default/mac/npmac.cpp .  That table
00546       // accomodates 23 entries, inspection in the debugger teaches that the
00547       // broken plugin's table is 40 entries long.
00548       for (PRUint32 i = 0 ; i < 40 ; i++) {
00549         PRUint32* gluePPC = (PRUint32*) (pluginsGlueTable + 24 * i);
00550 
00551         // Only translate entries that are actually stored as TVector glue.
00552         // There are other ways to write the glue for PPC, but this is the
00553         // de facto standard, and it's what the broken plugin uses.  The
00554         // PPC code means:
00555         //   lis   r12,        hi16(address) ; pointer to tvector embedded
00556         //   ori   r12,   r12, lo16(address) ;   as immediate params in glue
00557         //   lwz    r0, 0(r12)               ; get pc from tvector
00558         //   lwz    r2, 4(r12)               ; get rtoc from tvector
00559         //   mtctr  r0
00560         //   bctr                            ; jump to new pc
00561         if ( (*gluePPC    & 0xffff0000) == 0x3d800000 &&
00562             (*(gluePPC+1) & 0xffff0000) == 0x618c0000 &&
00563              *(gluePPC+2)               == 0x800c0000 &&
00564              *(gluePPC+3)               == 0x804c0004 &&
00565              *(gluePPC+4)               == 0x7c0903a6 &&
00566              *(gluePPC+5)               == 0x4e800420) {
00567           // Determine the actual address of the function by stripping the
00568           // TVector glue.  |address| is a usable function pointer.  Making
00569           // it a pointer to an 8-bit quantity keeps the math below simple.
00570           PRUint8* address = (PRUint8*) ((*gluePPC) << 16 |
00571                                          *(gluePPC+1) & 0xffff);
00572 
00573           // Build an x86 JMP instruction to jump to the desired function,
00574           // and replace the TVector glue with it.  Opcode 0xe9 is a
00575           // jump relative to the next instruction.  Total instruction length
00576           // is 5 bytes (in 32-bit operand-size mode).  If base is address
00577           // 0xfece5 and the target function is at address 0xc0ffee, then
00578           // the instruction placed at base, byte for byte, should be:
00579           //   0xfece5: 0xe9 0x04 0x13 0xb1 0x00: jmp 0xc0ffee
00580           PRUint8* glueX86 = (PRUint8*) gluePPC;
00581           *glueX86 = 0xe9;
00582 
00583           PRInt32* offset = (PRInt32*) (glueX86+1);
00584           *offset = (address - (glueX86 + 5));
00585 
00586           // PPC TVector glue is big compared to the x86 JMP.  Clean up the
00587           // rest of the space in the table entry.  Opcode 0x90 is NOP,
00588           // instruction length 1 byte.  This permits clean disassembly of
00589           // the entire memory region corresponding to the table.
00590           memset(glueX86+5, 0x90, 19);
00591 
00592           glueFixed++;
00593         }
00594       }
00595     }
00596 
00597     if (!glueFixed) {
00598       // This plugin wasn't broken after all.  Avoid applying the callback
00599       // dereferencing workarounds (TV2FP).
00600       brokenPlugin = PR_FALSE;
00601     }
00602   }
00603 #endif /* BROKEN_PLUGIN_HACK */
00604 
00605   NPP_PLUGIN_LOG(PLUGIN_LOG_BASIC,
00606                  ("NPP MainEntryProc called: return=%d\n",error));
00607 
00608   if (error != NPERR_NO_ERROR)
00609     return;
00610 
00611   // version is a uint16 so cast to int to avoid an invalid
00612   // comparison due to limited range of the data type
00613   int cb_version = np_callbacks.version;
00614   if ((cb_version >> 8) < NP_VERSION_MAJOR)
00615     return;
00616 
00617   // wrap all plugin entry points tvectors as mach-o callable function
00618   // pointers.
00619   fCallbacks.size = sizeof(fCallbacks);
00620   fCallbacks.version = np_callbacks.version;
00621   fCallbacks.newp = (NPP_NewUPP) TV2FP(np_callbacks.newp);
00622   fCallbacks.destroy = (NPP_DestroyUPP) TV2FP(np_callbacks.destroy);
00623   fCallbacks.setwindow = (NPP_SetWindowUPP) TV2FP(np_callbacks.setwindow);
00624   fCallbacks.newstream = (NPP_NewStreamUPP) TV2FP(np_callbacks.newstream);
00625   fCallbacks.destroystream =
00626     (NPP_DestroyStreamUPP) TV2FP(np_callbacks.destroystream);
00627   fCallbacks.asfile = (NPP_StreamAsFileUPP) TV2FP(np_callbacks.asfile);
00628   fCallbacks.writeready = (NPP_WriteReadyUPP) TV2FP(np_callbacks.writeready);
00629   fCallbacks.write = (NPP_WriteUPP) TV2FP(np_callbacks.write);
00630   fCallbacks.print = (NPP_PrintUPP) TV2FP(np_callbacks.print);
00631   fCallbacks.event = (NPP_HandleEventUPP) TV2FP(np_callbacks.event);
00632   fCallbacks.urlnotify = (NPP_URLNotifyUPP) TV2FP(np_callbacks.urlnotify);
00633   fCallbacks.getvalue = (NPP_GetValueUPP) TV2FP(np_callbacks.getvalue);
00634   fCallbacks.setvalue = (NPP_SetValueUPP) TV2FP(np_callbacks.setvalue);
00635   fShutdownEntry = (NP_PLUGINSHUTDOWN) TV2FP(pfnShutdown);
00636 #else // for everyone else
00637   memcpy((void*) &fCallbacks, (void*) callbacks, sizeof(fCallbacks));
00638   fShutdownEntry = aShutdown;
00639 #endif
00640 
00641   fLibrary = aLibrary;
00642 }
00643 
00644 
00646 ns4xPlugin::~ns4xPlugin(void)
00647 {
00648   //reset the callbacks list
00649 #if defined(XP_MACOSX) && defined(__POWERPC__)
00650   // release all wrapped plugin entry points.
00651   if (fCallbacks.newp)
00652     free((void *)fCallbacks.newp);
00653   if (fCallbacks.destroy)
00654     free((void *)fCallbacks.destroy);
00655   if (fCallbacks.setwindow)
00656     free((void *)fCallbacks.setwindow);
00657   if (fCallbacks.newstream)
00658     free((void *)fCallbacks.newstream);
00659   if (fCallbacks.asfile)
00660     free((void *)fCallbacks.asfile);
00661   if (fCallbacks.writeready)
00662     free((void *)fCallbacks.writeready);
00663   if (fCallbacks.write)
00664     free((void *)fCallbacks.write);
00665   if (fCallbacks.print)
00666     free((void *)fCallbacks.print);
00667   if (fCallbacks.event)
00668     free((void *)fCallbacks.event);
00669   if (fCallbacks.urlnotify)
00670     free((void *)fCallbacks.urlnotify);
00671   if (fCallbacks.getvalue)
00672     free((void *)fCallbacks.getvalue);
00673   if (fCallbacks.setvalue)
00674     free((void *)fCallbacks.setvalue);
00675 #endif
00676   memset((void*) &fCallbacks, 0, sizeof(fCallbacks));
00677 }
00678 
00679 
00680 #if defined(XP_MACOSX)
00681 
00682 void
00683 ns4xPlugin::SetPluginRefNum(short aRefNum)
00684 {
00685   fPluginRefNum = aRefNum;
00686 }
00687 #endif
00688 
00689 
00691 // Static factory method.
00692 //
00694 //--------------
00695 //Handles the initialization of old, 4x style plugins.  Creates the ns4xPlugin object.
00696 //One ns4xPlugin object exists per Plugin (not instance).
00697 
00698 nsresult
00699 ns4xPlugin::CreatePlugin(nsIServiceManagerObsolete* aServiceMgr,
00700                          const char* aFileName, const char* aFullPath,
00701                          PRLibrary* aLibrary, nsIPlugin** aResult)
00702 {
00703   CheckClassInitialized();
00704 
00705 #if defined(XP_UNIX) && !defined(XP_MACOSX)
00706 
00707   ns4xPlugin *plptr;
00708 
00709   NPPluginFuncs callbacks;
00710   memset((void*) &callbacks, 0, sizeof(callbacks));
00711   callbacks.size = sizeof(callbacks);
00712 
00713   NP_PLUGINSHUTDOWN pfnShutdown =
00714     (NP_PLUGINSHUTDOWN)PR_FindSymbol(aLibrary, "NP_Shutdown");
00715 
00716   // create the new plugin handler
00717   *aResult = plptr =
00718     new ns4xPlugin(&callbacks, aLibrary, pfnShutdown, aServiceMgr);
00719 
00720   if (*aResult == NULL)
00721     return NS_ERROR_OUT_OF_MEMORY;
00722 
00723   NS_ADDREF(*aResult);
00724 
00725   if (!aFileName) //do not call NP_Initialize in this case, bug 74938
00726     return NS_OK;
00727 
00728   // we must init here because the plugin may call NPN functions
00729   // when we call into the NP_Initialize entry point - NPN functions
00730   // require that mBrowserManager be set up
00731   plptr->Initialize();
00732 
00733   NP_PLUGINUNIXINIT pfnInitialize =
00734     (NP_PLUGINUNIXINIT)PR_FindSymbol(aLibrary, "NP_Initialize");
00735 
00736   if (pfnInitialize == NULL)
00737     return NS_ERROR_UNEXPECTED; // XXX Right error?
00738 
00739   if (pfnInitialize(&(ns4xPlugin::CALLBACKS),&callbacks) != NS_OK)
00740     return NS_ERROR_UNEXPECTED;
00741 
00742   // now copy function table back to ns4xPlugin instance
00743   memcpy((void*) &(plptr->fCallbacks), (void*)&callbacks, sizeof(callbacks));
00744 #endif
00745 
00746 #ifdef XP_WIN
00747   // Note: on Windows, we must use the fCallback because plugins may
00748   // change the function table. The Shockwave installer makes changes
00749   // in the table while running
00750   *aResult = new ns4xPlugin(nsnull, aLibrary, nsnull, aServiceMgr);
00751 
00752   if (*aResult == NULL)
00753     return NS_ERROR_OUT_OF_MEMORY;
00754 
00755   NS_ADDREF(*aResult);
00756 
00757   // we must init here because the plugin may call NPN functions
00758   // when we call into the NP_Initialize entry point - NPN functions
00759   // require that mBrowserManager be set up
00760   if (NS_FAILED((*aResult)->Initialize())) {
00761     NS_RELEASE(*aResult);
00762     return NS_ERROR_FAILURE;
00763   }
00764 
00765   // the NP_Initialize entry point was misnamed as NP_PluginInit,
00766   // early in plugin project development.  Its correct name is
00767   // documented now, and new developers expect it to work.  However,
00768   // I don't want to break the plugins already in the field, so
00769   // we'll accept either name
00770 
00771   NP_PLUGININIT pfnInitialize =
00772     (NP_PLUGININIT)PR_FindSymbol(aLibrary, "NP_Initialize");
00773 
00774   if (!pfnInitialize)
00775     pfnInitialize = (NP_PLUGININIT)PR_FindSymbol(aLibrary, "NP_PluginInit");
00776 
00777   if (pfnInitialize == NULL)
00778     return NS_ERROR_UNEXPECTED; // XXX Right error?
00779 
00780   if (pfnInitialize(&(ns4xPlugin::CALLBACKS)) != NS_OK)
00781     return NS_ERROR_UNEXPECTED;
00782 #endif
00783 
00784 #ifdef XP_OS2
00785   // create the new plugin handler
00786   *aResult = new ns4xPlugin(nsnull, aLibrary, nsnull, aServiceMgr);
00787 
00788   if (*aResult == NULL)
00789     return NS_ERROR_OUT_OF_MEMORY;
00790 
00791   NS_ADDREF(*aResult);
00792 
00793   // we must init here because the plugin may call NPN functions
00794   // when we call into the NP_Initialize entry point - NPN functions
00795   // require that mBrowserManager be set up
00796   if (NS_FAILED((*aResult)->Initialize())) {
00797     NS_RELEASE(*aResult);
00798     return NS_ERROR_FAILURE;
00799   }
00800 
00801   // the NP_Initialize entry point was misnamed as NP_PluginInit,
00802   // early in plugin project development.  Its correct name is
00803   // documented now, and new developers expect it to work.  However,
00804   // I don't want to break the plugins already in the field, so
00805   // we'll accept either name
00806 
00807   NP_PLUGININIT pfnInitialize =
00808     (NP_PLUGININIT)PR_FindSymbol(aLibrary, "NP_Initialize");
00809 
00810   if (!pfnInitialize)
00811     pfnInitialize = (NP_PLUGININIT)PR_FindSymbol(aLibrary, "NP_PluginInit");
00812 
00813   if (pfnInitialize == NULL)
00814     return NS_ERROR_UNEXPECTED; // XXX Right error?
00815 
00816   // Fixes problem where the OS/2 native multimedia plugins weren't
00817   // working on mozilla though did work on 4.x.  Problem is that they
00818   // expect the current working directory to be the plugins dir.
00819   // Since these plugins are no longer maintained and they represent
00820   // the majority of the OS/2 plugin contingency, we'll have to make
00821   // them work here.
00822 
00823 #define MAP_DISKNUM_TO_LETTER(n) ('A' + (n - 1))
00824 #define MAP_LETTER_TO_DISKNUM(c) (toupper(c)-'A'+1)
00825 
00826   unsigned long origDiskNum, pluginDiskNum, logicalDisk;
00827 
00828   char pluginPath[CCHMAXPATH], origPath[CCHMAXPATH];
00829   strcpy(pluginPath, aFileName);
00830   char* slash = strrchr(pluginPath, '\\');
00831   *slash = '\0';
00832 
00833   DosQueryCurrentDisk( &origDiskNum, &logicalDisk );
00834   pluginDiskNum = MAP_LETTER_TO_DISKNUM(pluginPath[0]);
00835 
00836   origPath[0] = MAP_DISKNUM_TO_LETTER(origDiskNum);
00837   origPath[1] = ':';
00838   origPath[2] = '\\';
00839 
00840   ULONG len = CCHMAXPATH-3;
00841   APIRET rc = DosQueryCurrentDir(0, &origPath[3], &len);
00842   NS_ASSERTION(NO_ERROR == rc,"DosQueryCurrentDir failed");
00843 
00844   BOOL bChangedDir = FALSE;
00845   BOOL bChangedDisk = FALSE;
00846   if (pluginDiskNum != origDiskNum) {
00847     rc = DosSetDefaultDisk(pluginDiskNum);
00848     NS_ASSERTION(NO_ERROR == rc,"DosSetDefaultDisk failed");
00849     bChangedDisk = TRUE;
00850   }
00851 
00852   if (stricmp(origPath, pluginPath) != 0) {
00853     rc = DosSetCurrentDir(pluginPath);
00854     NS_ASSERTION(NO_ERROR == rc,"DosSetCurrentDir failed");
00855     bChangedDir = TRUE;
00856   }
00857 
00858   nsresult rv = pfnInitialize(&(ns4xPlugin::CALLBACKS));
00859 
00860   if (bChangedDisk) {
00861     rc= DosSetDefaultDisk(origDiskNum);
00862     NS_ASSERTION(NO_ERROR == rc,"DosSetDefaultDisk failed");
00863   }
00864   if (bChangedDir) {
00865     rc = DosSetCurrentDir(origPath);
00866     NS_ASSERTION(NO_ERROR == rc,"DosSetCurrentDir failed");
00867   }
00868 
00869   if (!NS_SUCCEEDED(rv)) {
00870     return NS_ERROR_UNEXPECTED;
00871   }
00872 #endif
00873 
00874 #if defined(XP_MACOSX)
00875   short appRefNum = ::CurResFile();
00876   short pluginRefNum;
00877 
00878   nsCOMPtr<nsILocalFile> pluginPath;
00879   NS_NewNativeLocalFile(nsDependentCString(aFullPath), PR_TRUE,
00880                         getter_AddRefs(pluginPath));
00881 
00882   nsPluginFile pluginFile(pluginPath);
00883   pluginRefNum = pluginFile.OpenPluginResource();
00884   if (pluginRefNum == -1)
00885     return NS_ERROR_FAILURE;
00886 
00887   ns4xPlugin* plugin = new ns4xPlugin(nsnull, aLibrary, nsnull, aServiceMgr);
00888   if (plugin == NULL)
00889     return NS_ERROR_OUT_OF_MEMORY;
00890 
00891   ::UseResFile(appRefNum);
00892   *aResult = plugin;
00893 
00894   NS_ADDREF(*aResult);
00895   if (NS_FAILED((*aResult)->Initialize())) {
00896     NS_RELEASE(*aResult);
00897     return NS_ERROR_FAILURE;
00898   }
00899 
00900   plugin->SetPluginRefNum(pluginRefNum);
00901 #endif  // XP_MACOSX
00902 
00903 #ifdef XP_BEOS
00904   // I just copied UNIX version.
00905   // Makoto Hamanaka <VYA04230@nifty.com>
00906 
00907   ns4xPlugin *plptr;
00908 
00909   NPPluginFuncs callbacks;
00910   memset((void*) &callbacks, 0, sizeof(callbacks));
00911   callbacks.size = sizeof(callbacks);
00912 
00913   NP_PLUGINSHUTDOWN pfnShutdown =
00914     (NP_PLUGINSHUTDOWN)PR_FindSymbol(aLibrary, "NP_Shutdown");
00915 
00916   // create the new plugin handler
00917   *aResult = plptr =
00918     new ns4xPlugin(&callbacks, aLibrary, pfnShutdown, aServiceMgr);
00919 
00920   if (*aResult == NULL)
00921     return NS_ERROR_OUT_OF_MEMORY;
00922 
00923   NS_ADDREF(*aResult);
00924 
00925   // we must init here because the plugin may call NPN functions
00926   // when we call into the NP_Initialize entry point - NPN functions
00927   // require that mBrowserManager be set up
00928   plptr->Initialize();
00929 
00930   NP_PLUGINUNIXINIT pfnInitialize =
00931     (NP_PLUGINUNIXINIT)PR_FindSymbol(aLibrary, "NP_Initialize");
00932 
00933   if (pfnInitialize == NULL)
00934     return NS_ERROR_FAILURE;
00935 
00936   if (pfnInitialize(&(ns4xPlugin::CALLBACKS),&callbacks) != NS_OK)
00937     return NS_ERROR_FAILURE;
00938 
00939   // now copy function table back to ns4xPlugin instance
00940   memcpy((void*) &(plptr->fCallbacks), (void*)&callbacks, sizeof(callbacks));
00941 #endif
00942 
00943   return NS_OK;
00944 }
00945 
00946 
00948 //CreateInstance()
00949 //----------------
00950 //Creates a ns4xPluginInstance object.
00951 
00952 nsresult
00953 ns4xPlugin::CreateInstance(nsISupports *aOuter, const nsIID &aIID,
00954                            void **aResult)
00955 {
00956   if (aResult == NULL)
00957     return NS_ERROR_NULL_POINTER;
00958 
00959   *aResult = NULL;
00960 
00961   // XXX This is suspicuous!
00962   nsRefPtr<ns4xPluginInstance> inst =
00963     new ns4xPluginInstance(&fCallbacks, fLibrary);
00964 
00965   if (!inst)
00966     return NS_ERROR_OUT_OF_MEMORY;
00967 
00968   return inst->QueryInterface(aIID, aResult);
00969 }
00970 
00971 
00973 nsresult
00974 ns4xPlugin::LockFactory(PRBool aLock)
00975 {
00976   // Not implemented in simplest case.
00977   return NS_OK;
00978 }
00979 
00980 
00982 NS_METHOD
00983 ns4xPlugin::CreatePluginInstance(nsISupports *aOuter, REFNSIID aIID,
00984                                  const char *aPluginMIMEType, void **aResult)
00985 {
00986   return CreateInstance(aOuter, aIID, aResult);
00987 }
00988 
00989 
00991 nsresult
00992 ns4xPlugin::Initialize(void)
00993 {
00994   if (nsnull == fLibrary)
00995     return NS_ERROR_FAILURE;
00996   return NS_OK;
00997 }
00998 
00999 
01001 nsresult
01002 ns4xPlugin::Shutdown(void)
01003 {
01004   NPP_PLUGIN_LOG(PLUGIN_LOG_BASIC,
01005                  ("NPP Shutdown to be called: this=%p\n", this));
01006 
01007   if (nsnull != fShutdownEntry) {
01008 #if defined(XP_MACOSX)
01009     CallNPP_ShutdownProc(fShutdownEntry);
01010     ::CloseResFile(fPluginRefNum);
01011 #else
01012     NS_TRY_SAFE_CALL_VOID(fShutdownEntry(), fLibrary, nsnull);
01013 #endif
01014 
01015 #if defined(XP_MACOSX) && defined(__POWERPC__)
01016     // release the wrapped plugin function.
01017     free((void *)fShutdownEntry);
01018 #endif
01019     fShutdownEntry = nsnull;
01020   }
01021 
01022   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01023              ("4xPlugin Shutdown done, this=%p", this));
01024   return NS_OK;
01025 }
01026 
01027 
01029 nsresult
01030 ns4xPlugin::GetMIMEDescription(const char* *resultingDesc)
01031 {
01032   const char* (*npGetMIMEDescription)() =
01033     (const char* (*)()) PR_FindSymbol(fLibrary, "NP_GetMIMEDescription");
01034 
01035   *resultingDesc = npGetMIMEDescription ? npGetMIMEDescription() : "";
01036 
01037   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01038              ("ns4xPlugin::GetMIMEDescription called: this=%p, result=%s\n",
01039               this, *resultingDesc));
01040 
01041   return NS_OK;
01042 }
01043 
01044 
01046 nsresult
01047 ns4xPlugin::GetValue(nsPluginVariable variable, void *value)
01048 {
01049   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01050   ("ns4xPlugin::GetValue called: this=%p, variable=%d\n", this, variable));
01051 
01052   NPError (*npGetValue)(void*, nsPluginVariable, void*) =
01053     (NPError (*)(void*, nsPluginVariable, void*)) PR_FindSymbol(fLibrary,
01054                                                                 "NP_GetValue");
01055 
01056   if (npGetValue && NPERR_NO_ERROR == npGetValue(nsnull, variable, value)) {
01057     return NS_OK;
01058   }
01059 
01060   return NS_ERROR_FAILURE;
01061 }
01062 
01063 // Create a new NPP GET or POST (given in the type argument) url
01064 // stream that may have a notify callback
01065 NPError
01066 MakeNew4xStreamInternal(NPP npp, const char *relativeURL, const char *target,
01067                         eNPPStreamTypeInternal type,
01068                         PRBool bDoNotify = PR_FALSE,
01069                         void *notifyData = nsnull, uint32 len = 0,
01070                         const char *buf = nsnull, NPBool file = PR_FALSE)
01071 {
01072   if (!npp)
01073     return NPERR_INVALID_INSTANCE_ERROR;
01074 
01075   nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
01076 
01077   NS_ASSERTION(inst != NULL, "null instance");
01078   if (inst == NULL)
01079     return NPERR_INVALID_INSTANCE_ERROR;
01080 
01081   nsCOMPtr<nsIPluginManager> pm = do_GetService(kPluginManagerCID);
01082   NS_ASSERTION(pm, "failed to get plugin manager");
01083   if (!pm) return NPERR_GENERIC_ERROR;
01084 
01085   nsIPluginStreamListener* listener = nsnull;
01086   if (target == nsnull)
01087     ((ns4xPluginInstance*)inst)->NewNotifyStream(&listener, notifyData,
01088                                                  bDoNotify, relativeURL);
01089 
01090   switch (type) {
01091   case eNPPStreamTypeInternal_Get:
01092     {
01093       if (NS_FAILED(pm->GetURL(inst, relativeURL, target, listener)))
01094         return NPERR_GENERIC_ERROR;
01095       break;
01096     }
01097   case eNPPStreamTypeInternal_Post:
01098     {
01099       if (NS_FAILED(pm->PostURL(inst, relativeURL, len, buf, file, target,
01100                                 listener)))
01101         return NPERR_GENERIC_ERROR;
01102       break;
01103     }
01104   default:
01105     NS_ASSERTION(0, "how'd I get here");
01106   }
01107 
01108   return NPERR_NO_ERROR;
01109 }
01110 
01112 //
01113 // Static callbacks that get routed back through the new C++ API
01114 //
01115 
01116 NPError NP_EXPORT
01117 _geturl(NPP npp, const char* relativeURL, const char* target)
01118 {
01119   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01120   ("NPN_GetURL: npp=%p, target=%s, url=%s\n", (void *)npp, target,
01121    relativeURL));
01122 
01123   // Block Adobe Acrobat from loading URLs that are not http:, https:,
01124   // or ftp: URLs if the given target is null.
01125   if (target == nsnull && relativeURL &&
01126       (strncmp(relativeURL, "http:", 5) != 0) &&
01127       (strncmp(relativeURL, "https:", 6) != 0) &&
01128       (strncmp(relativeURL, "ftp:", 4) != 0)) {
01129     ns4xPluginInstance *inst = (ns4xPluginInstance *) npp->ndata;
01130 
01131     const char *name = nsPluginHostImpl::GetPluginName(inst);
01132 
01133     if (name && strstr(name, "Adobe") && strstr(name, "Acrobat")) {
01134       return NPERR_NO_ERROR;
01135     }
01136   }
01137 
01138   return MakeNew4xStreamInternal (npp, relativeURL, target,
01139                                   eNPPStreamTypeInternal_Get);
01140 }
01141 
01142 
01144 NPError NP_EXPORT
01145 _geturlnotify(NPP npp, const char* relativeURL, const char* target,
01146               void* notifyData)
01147 {
01148   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01149     ("NPN_GetURLNotify: npp=%p, target=%s, notify=%p, url=%s\n", (void*)npp,
01150      target, notifyData, relativeURL));
01151 
01152   return MakeNew4xStreamInternal (npp, relativeURL, target,
01153                                   eNPPStreamTypeInternal_Get, PR_TRUE,
01154                                   notifyData);
01155 }
01156 
01157 
01159 NPError NP_EXPORT
01160 _posturlnotify(NPP npp, const char *relativeURL, const char *target,
01161                uint32 len, const char *buf, NPBool file, void *notifyData)
01162 {
01163   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01164                  ("NPN_PostURLNotify: npp=%p, target=%s, len=%d, file=%d, "
01165                   "notify=%p, url=%s, buf=%s\n",
01166                   (void*)npp, target, len, file, notifyData, relativeURL,
01167                   buf));
01168 
01169   return MakeNew4xStreamInternal(npp, relativeURL, target,
01170                                  eNPPStreamTypeInternal_Post, PR_TRUE,
01171                                  notifyData, len, buf, file);
01172 }
01173 
01174 
01176 NPError NP_EXPORT
01177 _posturl(NPP npp, const char *relativeURL, const char *target,
01178          uint32 len, const char *buf, NPBool file)
01179 {
01180   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01181                  ("NPN_PostURL: npp=%p, target=%s, file=%d, len=%d, url=%s, "
01182                   "buf=%s\n",
01183                   (void*)npp, target, file, len, relativeURL, buf));
01184 
01185  return MakeNew4xStreamInternal(npp, relativeURL, target,
01186                                 eNPPStreamTypeInternal_Post, PR_FALSE, nsnull,
01187                                 len, buf, file);
01188 }
01189 
01190 
01192 // A little helper class used to wrap up plugin manager streams (that is,
01193 // streams from the plugin to the browser).
01194 
01195 class ns4xStreamWrapper : nsISupports
01196 {
01197 public:
01198   NS_DECL_ISUPPORTS
01199 
01200 protected:
01201   nsIOutputStream *fStream;
01202   NPStream        fNPStream;
01203 
01204 public:
01205   ns4xStreamWrapper(nsIOutputStream* stream);
01206   ~ns4xStreamWrapper();
01207 
01208   void GetStream(nsIOutputStream* &result);
01209   NPStream* GetNPStream(void) { return &fNPStream; };
01210 };
01211 
01212 NS_IMPL_ISUPPORTS1(ns4xStreamWrapper, nsISupports)
01213 
01214 ns4xStreamWrapper::ns4xStreamWrapper(nsIOutputStream* stream)
01215   : fStream(stream)
01216 {
01217   NS_ASSERTION(stream != NULL, "bad stream");
01218 
01219   fStream = stream;
01220   NS_ADDREF(fStream);
01221 
01222   memset(&fNPStream, 0, sizeof(fNPStream));
01223   fNPStream.ndata = (void*) this;
01224 }
01225 
01226 ns4xStreamWrapper::~ns4xStreamWrapper(void)
01227 {
01228   fStream->Close();
01229   NS_IF_RELEASE(fStream);
01230 }
01231 
01232 void
01233 ns4xStreamWrapper::GetStream(nsIOutputStream* &result)
01234 {
01235   result = fStream;
01236   NS_IF_ADDREF(fStream);
01237 }
01238 
01239 
01241 NPError NP_EXPORT
01242 _newstream(NPP npp, NPMIMEType type, const char* target, NPStream* *result)
01243 {
01244   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01245   ("NPN_NewStream: npp=%p, type=%s, target=%s\n", (void*)npp,
01246    (const char *)type, target));
01247 
01248   NPError err = NPERR_INVALID_INSTANCE_ERROR;
01249   if (npp && npp->ndata) {
01250     nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
01251     nsCOMPtr<nsIOutputStream> stream;
01252     nsCOMPtr<nsIPluginInstancePeer> peer;
01253     if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) &&
01254       peer &&
01255       NS_SUCCEEDED(peer->NewStream((const char*) type, target,
01256                                    getter_AddRefs(stream)))) {
01257       ns4xStreamWrapper* wrapper = new ns4xStreamWrapper(stream);
01258       if (wrapper) {
01259         (*result) = wrapper->GetNPStream();
01260         err = NPERR_NO_ERROR;
01261       } else {
01262         err = NPERR_OUT_OF_MEMORY_ERROR;
01263       }
01264     } else {
01265       err = NPERR_GENERIC_ERROR;
01266     }
01267   }
01268   return err;
01269 }
01270 
01271 
01273 int32 NP_EXPORT
01274 _write(NPP npp, NPStream *pstream, int32 len, void *buffer)
01275 {
01276   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01277                  ("NPN_Write: npp=%p, url=%s, len=%d, buffer=%s\n", (void*)npp,
01278                   pstream->url, len, (char*)buffer));
01279 
01280   // negative return indicates failure to the plugin
01281   if (!npp)
01282     return -1;
01283 
01284   ns4xStreamWrapper* wrapper = (ns4xStreamWrapper*) pstream->ndata;
01285   NS_ASSERTION(wrapper != NULL, "null stream");
01286 
01287   if (wrapper == NULL)
01288     return -1;
01289 
01290   nsIOutputStream* stream;
01291   wrapper->GetStream(stream);
01292 
01293   PRUint32 count = 0;
01294   nsresult rv = stream->Write((char *)buffer, len, &count);
01295   NS_RELEASE(stream);
01296 
01297   if (rv != NS_OK)
01298     return -1;
01299 
01300   return (int32)count;
01301 }
01302 
01303 
01305 NPError NP_EXPORT
01306 _destroystream(NPP npp, NPStream *pstream, NPError reason)
01307 {
01308   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01309                  ("NPN_DestroyStream: npp=%p, url=%s, reason=%d\n", (void*)npp,
01310                   pstream->url, (int)reason));
01311 
01312   if (!npp)
01313     return NPERR_INVALID_INSTANCE_ERROR;
01314 
01315   nsCOMPtr<nsIPluginStreamListener> listener =
01316     do_QueryInterface((nsISupports *)pstream->ndata);
01317 
01318   // DestroyStream can kill two kinds of streams: NPP derived and NPN derived.
01319   // check to see if they're trying to kill a NPP stream
01320   if (listener) {
01321     // Tell the stream listner that the stream is now gone.
01322     listener->OnStopBinding(nsnull, NS_BINDING_ABORTED);
01323 
01324     // FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240131
01325     //
01326     // Is it ok to leave pstream->ndata set here, and who releases it
01327     // (or is it even properly ref counted)? And who closes the stream
01328     // etc?
01329   } else {
01330     ns4xStreamWrapper* wrapper = (ns4xStreamWrapper *)pstream->ndata;
01331     NS_ASSERTION(wrapper != NULL, "null wrapper");
01332 
01333     if (wrapper == NULL)
01334       return NPERR_INVALID_PARAM;
01335 
01336     // This will release the wrapped nsIOutputStream.
01337     delete wrapper;
01338     pstream->ndata = nsnull;
01339   }
01340 
01341   return NPERR_NO_ERROR;
01342 }
01343 
01344 
01346 void NP_EXPORT
01347 _status(NPP npp, const char *message)
01348 {
01349   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_Status: npp=%p, message=%s\n",
01350                                      (void*)npp, message));
01351 
01352   if (!npp || !npp->ndata) {
01353     NS_WARNING("_status: npp or npp->ndata == 0");
01354     return;
01355   }
01356 
01357   nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
01358 
01359   nsCOMPtr<nsIPluginInstancePeer> peer;
01360   if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
01361     peer->ShowStatus(message);
01362   }
01363 }
01364 
01365 
01367 void NP_EXPORT
01368 _memfree (void *ptr)
01369 {
01370   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFree: ptr=%p\n", ptr));
01371 
01372   if (ptr)
01373     nsMemory::Free(ptr);
01374 }
01375 
01376 
01378 uint32 NP_EXPORT
01379 _memflush(uint32 size)
01380 {
01381   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFlush: size=%d\n", size));
01382 
01383   nsMemory::HeapMinimize(PR_TRUE);
01384   return 0;
01385 }
01386 
01387 
01389 void NP_EXPORT
01390 _reloadplugins(NPBool reloadPages)
01391 {
01392   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01393                  ("NPN_ReloadPlugins: reloadPages=%d\n", reloadPages));
01394 
01395   nsCOMPtr<nsIPluginManager> pm(do_GetService(kPluginManagerCID));
01396 
01397   pm->ReloadPlugins(reloadPages);
01398 }
01399 
01400 
01402 void NP_EXPORT
01403 _invalidaterect(NPP npp, NPRect *invalidRect)
01404 {
01405   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01406                  ("NPN_InvalidateRect: npp=%p, top=%d, left=%d, bottom=%d, "
01407                   "right=%d\n", (void *)npp, invalidRect->top,
01408                   invalidRect->left, invalidRect->bottom, invalidRect->right));
01409 
01410   if (!npp || !npp->ndata) {
01411     NS_WARNING("_invalidaterect: npp or npp->ndata == 0");
01412     return;
01413   }
01414 
01415   nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
01416 
01417   nsCOMPtr<nsIPluginInstancePeer> peer;
01418   if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
01419     nsCOMPtr<nsIWindowlessPluginInstancePeer> wpeer(do_QueryInterface(peer));
01420     if (wpeer) {
01421       // XXX nsRect & NPRect are structurally equivalent
01422       wpeer->InvalidateRect((nsPluginRect *)invalidRect);
01423     }
01424   }
01425 }
01426 
01427 
01429 void NP_EXPORT
01430 _invalidateregion(NPP npp, NPRegion invalidRegion)
01431 {
01432   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01433                  ("NPN_InvalidateRegion: npp=%p, region=%p\n", (void*)npp,
01434                   (void*)invalidRegion));
01435 
01436   if (!npp || !npp->ndata) {
01437     NS_WARNING("_invalidateregion: npp or npp->ndata == 0");
01438     return;
01439   }
01440 
01441   nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
01442 
01443   nsCOMPtr<nsIPluginInstancePeer> peer;
01444   if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
01445     nsCOMPtr<nsIWindowlessPluginInstancePeer> wpeer(do_QueryInterface(peer));
01446     if (wpeer) {
01447       // XXX nsRegion & NPRegion are typedef'd to the same thing
01448       wpeer->InvalidateRegion((nsPluginRegion)invalidRegion);
01449     }
01450   }
01451 }
01452 
01453 
01455 void NP_EXPORT
01456 _forceredraw(NPP npp)
01457 {
01458   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_ForceDraw: npp=%p\n", (void*)npp));
01459 
01460   if (!npp || !npp->ndata) {
01461     NS_WARNING("_forceredraw: npp or npp->ndata == 0");
01462     return;
01463   }
01464 
01465   nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
01466 
01467   nsCOMPtr<nsIPluginInstancePeer> peer;
01468   if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
01469     nsCOMPtr<nsIWindowlessPluginInstancePeer> wpeer(do_QueryInterface(peer));
01470     if (wpeer) {
01471       wpeer->ForceRedraw();
01472     }
01473   }
01474 }
01475 
01476 static JSContext *
01477 GetJSContextFromNPP(NPP npp)
01478 {
01479   NS_ENSURE_TRUE(npp, nsnull);
01480 
01481   ns4xPluginInstance *inst = (ns4xPluginInstance *)npp->ndata;
01482   NS_ENSURE_TRUE(inst, nsnull);
01483 
01484   nsCOMPtr<nsIPluginInstancePeer> pip;
01485   inst->GetPeer(getter_AddRefs(pip));
01486   nsCOMPtr<nsPIPluginInstancePeer> pp(do_QueryInterface(pip));
01487   NS_ENSURE_TRUE(pp, nsnull);
01488 
01489   nsCOMPtr<nsIPluginInstanceOwner> owner;
01490   pp->GetOwner(getter_AddRefs(owner));
01491   NS_ENSURE_TRUE(owner, nsnull);
01492 
01493   nsCOMPtr<nsIDocument> doc;
01494   owner->GetDocument(getter_AddRefs(doc));
01495   NS_ENSURE_TRUE(doc, nsnull);
01496 
01497   nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
01498   NS_ENSURE_TRUE(sgo, nsnull);
01499 
01500   nsIScriptContext *scx = sgo->GetContext();
01501   NS_ENSURE_TRUE(scx, nsnull);
01502 
01503   return (JSContext *)scx->GetNativeContext();
01504 }
01505 
01506 NPObject* NP_EXPORT
01507 _getwindowobject(NPP npp)
01508 {
01509   JSContext *cx = GetJSContextFromNPP(npp);
01510   NS_ENSURE_TRUE(cx, nsnull);
01511 
01512   // Using ::JS_GetGlobalObject(cx) is ok here since the window we
01513   // want to return here is the outer window, *not* the inner (since
01514   // we don't know what the plugin will do with it).
01515   return nsJSObjWrapper::GetNewOrUsed(npp, cx, ::JS_GetGlobalObject(cx));
01516 }
01517 
01518 NPObject* NP_EXPORT
01519 _getpluginelement(NPP npp)
01520 {
01521   nsIDOMElement *elementp = nsnull;
01522   NPError nperr = _getvalue(npp, NPNVDOMElement, &elementp);
01523 
01524   if (nperr != NPERR_NO_ERROR) {
01525     return nsnull;
01526   }
01527 
01528   // Pass ownership of elementp to element
01529   nsCOMPtr<nsIDOMElement> element;
01530   element.swap(elementp);
01531 
01532   JSContext *cx = GetJSContextFromNPP(npp);
01533   NS_ENSURE_TRUE(cx, nsnull);
01534 
01535   nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
01536   NS_ENSURE_TRUE(xpc, nsnull);
01537 
01538   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
01539   xpc->WrapNative(cx, ::JS_GetGlobalObject(cx), element,
01540                   NS_GET_IID(nsIDOMElement),
01541                   getter_AddRefs(holder));
01542   NS_ENSURE_TRUE(holder, nsnull);
01543 
01544   JSObject* obj = nsnull;
01545   holder->GetJSObject(&obj);
01546   NS_ENSURE_TRUE(obj, nsnull);
01547 
01548   return nsJSObjWrapper::GetNewOrUsed(npp, cx, obj);
01549 }
01550 
01551 static NPIdentifier
01552 doGetIdentifier(JSContext *cx, const NPUTF8* name)
01553 {
01554   NS_ConvertUTF8toUTF16 utf16name(name);
01555 
01556   JSString *str = ::JS_InternUCStringN(cx, (jschar *)utf16name.get(),
01557                                        utf16name.Length());
01558 
01559   if (!str)
01560     return nsnull;
01561 
01562   return (NPIdentifier)STRING_TO_JSVAL(str);
01563 }
01564 
01565 NPIdentifier NP_EXPORT
01566 _getstringidentifier(const NPUTF8* name)
01567 {
01568   nsCOMPtr<nsIThreadJSContextStack> stack =
01569     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
01570   if (!stack)
01571     return NULL;
01572 
01573   JSContext *cx = nsnull;
01574   stack->GetSafeJSContext(&cx);
01575   if (!cx)
01576     return NULL;
01577 
01578   return doGetIdentifier(cx, name);
01579 }
01580 
01581 void NP_EXPORT
01582 _getstringidentifiers(const NPUTF8** names, int32_t nameCount,
01583                       NPIdentifier *identifiers)
01584 {
01585   nsCOMPtr<nsIThreadJSContextStack> stack =
01586     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
01587   if (!stack)
01588     return;
01589 
01590   JSContext *cx = nsnull;
01591   stack->GetSafeJSContext(&cx);
01592   if (!cx)
01593     return;
01594 
01595   for (int32_t i = 0; i < nameCount; ++i) {
01596     identifiers[i] = doGetIdentifier(cx, names[i]);
01597   }
01598 }
01599 
01600 NPIdentifier NP_EXPORT
01601 _getintidentifier(int32_t intid)
01602 {
01603   return (NPIdentifier)INT_TO_JSVAL(intid);
01604 }
01605 
01606 NPUTF8* NP_EXPORT
01607 _utf8fromidentifier(NPIdentifier identifier)
01608 {
01609   if (!identifier)
01610     return NULL;
01611 
01612   jsval v = (jsval)identifier;
01613 
01614   if (!JSVAL_IS_STRING(v)) {
01615     return nsnull;
01616   }
01617 
01618   JSString *str = JSVAL_TO_STRING(v);
01619 
01620   return
01621     ToNewUTF8String(nsDependentString((PRUnichar *)::JS_GetStringChars(str),
01622                                       ::JS_GetStringLength(str)));
01623 }
01624 
01625 int32_t NP_EXPORT
01626 _intfromidentifier(NPIdentifier identifier)
01627 {
01628   jsval v = (jsval)identifier;
01629 
01630   if (!JSVAL_IS_INT(v)) {
01631     return PR_INT32_MIN;
01632   }
01633 
01634   return JSVAL_TO_INT(v);
01635 }
01636 
01637 bool NP_EXPORT
01638 _identifierisstring(NPIdentifier identifier)
01639 {
01640   jsval v = (jsval)identifier;
01641 
01642   return JSVAL_IS_STRING(v);
01643 }
01644 
01645 NPObject* NP_EXPORT
01646 _createobject(NPP npp, NPClass* aClass)
01647 {
01648   if (!npp) {
01649     NS_ERROR("Null npp passed to _createobject()!");
01650 
01651     return nsnull;
01652   }
01653 
01654   if (!aClass) {
01655     NS_ERROR("Null class passed to _createobject()!");
01656 
01657     return nsnull;
01658   }
01659 
01660   NPPAutoPusher nppPusher(npp);
01661 
01662   NPObject *npobj;
01663 
01664   if (aClass->allocate) {
01665     npobj = aClass->allocate(npp, aClass);
01666   } else {
01667     npobj = (NPObject *)PR_Malloc(sizeof(NPObject));
01668   }
01669 
01670   if (npobj) {
01671     npobj->_class = aClass;
01672     npobj->referenceCount = 1;
01673   }
01674 
01675   return npobj;
01676 }
01677 
01678 NPObject* NP_EXPORT
01679 _retainobject(NPObject* npobj)
01680 {
01681   if (npobj) {
01682     PR_AtomicIncrement((PRInt32*)&npobj->referenceCount);
01683   }
01684 
01685   return npobj;
01686 }
01687 
01688 void NP_EXPORT
01689 _releaseobject(NPObject* npobj)
01690 {
01691   if (!npobj)
01692     return;
01693 
01694   int32_t refCnt = PR_AtomicDecrement((PRInt32*)&npobj->referenceCount);
01695 
01696   if (refCnt == 0) {
01697     if (npobj->_class && npobj->_class->deallocate) {
01698       npobj->_class->deallocate(npobj);
01699     } else {
01700       PR_Free(npobj);
01701     }
01702   }
01703 }
01704 
01705 bool NP_EXPORT
01706 _invoke(NPP npp, NPObject* npobj, NPIdentifier method, const NPVariant *args,
01707         uint32_t argCount, NPVariant *result)
01708 {
01709   if (!npp || !npobj || !npobj->_class || !npobj->_class->invoke)
01710     return false;
01711 
01712   NPPExceptionAutoHolder nppExceptionHolder;
01713   NPPAutoPusher nppPusher(npp);
01714 
01715   return npobj->_class->invoke(npobj, method, args, argCount, result);
01716 }
01717 
01718 bool NP_EXPORT
01719 _invokeDefault(NPP npp, NPObject* npobj, const NPVariant *args,
01720                uint32_t argCount, NPVariant *result)
01721 {
01722   if (!npp || !npobj || !npobj->_class || !npobj->_class->invokeDefault)
01723     return false;
01724 
01725   NPPExceptionAutoHolder nppExceptionHolder;
01726   NPPAutoPusher nppPusher(npp);
01727 
01728   return npobj->_class->invokeDefault(npobj, args, argCount, result);
01729 }
01730 
01731 bool NP_EXPORT
01732 _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result)
01733 {
01734   if (!npp)
01735     return false;
01736 
01737   NPPAutoPusher nppPusher(npp);
01738 
01739   JSContext *cx = GetJSContextFromNPP(npp);
01740   NS_ENSURE_TRUE(cx, false);
01741 
01742   JSObject *obj =
01743     nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj);
01744 
01745   if (!obj) {
01746     return false;
01747   }
01748 
01749   // Root obj and the rval (below).
01750   jsval vec[] = { OBJECT_TO_JSVAL(obj), JSVAL_NULL };
01751   JSAutoTempValueRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec);
01752   jsval *rval = &vec[1];
01753 
01754   if (result) {
01755     // Initialize the out param to void
01756     VOID_TO_NPVARIANT(*result);
01757   }
01758 
01759   if (!script || !script->utf8length || !script->utf8characters) {
01760     // Nothing to evaluate.
01761 
01762     return true;
01763   }
01764 
01765   NS_ConvertUTF8toUTF16 utf16script(script->utf8characters,
01766                                     script->utf8length);
01767 
01768   nsCOMPtr<nsIScriptContext> scx = GetScriptContextFromJSContext(cx);
01769   NS_ENSURE_TRUE(scx, false);
01770 
01771   nsIPrincipal *principal = nsnull;
01772   // XXX: Get the principal from the security stack (TBD)
01773 
01774   nsresult rv = scx->EvaluateStringWithValue(utf16script, obj, principal,
01775                                              nsnull, 0, nsnull, rval, nsnull);
01776 
01777   return NS_SUCCEEDED(rv) &&
01778          (!result || JSValToNPVariant(npp, cx, *rval, result));
01779 }
01780 
01781 bool NP_EXPORT
01782 _getproperty(NPP npp, NPObject* npobj, NPIdentifier property,
01783              NPVariant *result)
01784 {
01785   if (!npp || !npobj || !npobj->_class || !npobj->_class->getProperty)
01786     return false;
01787 
01788   NPPExceptionAutoHolder nppExceptionHolder;
01789   NPPAutoPusher nppPusher(npp);
01790 
01791   return npobj->_class->getProperty(npobj, property, result);
01792 }
01793 
01794 bool NP_EXPORT
01795 _setproperty(NPP npp, NPObject* npobj, NPIdentifier property,
01796              const NPVariant *value)
01797 {
01798   if (!npp || !npobj || !npobj->_class || !npobj->_class->setProperty)
01799     return false;
01800 
01801   NPPExceptionAutoHolder nppExceptionHolder;
01802   NPPAutoPusher nppPusher(npp);
01803 
01804   return npobj->_class->setProperty(npobj, property, value);
01805 }
01806 
01807 bool NP_EXPORT
01808 _removeproperty(NPP npp, NPObject* npobj, NPIdentifier property)
01809 {
01810   if (!npp || !npobj || !npobj->_class || !npobj->_class->removeProperty)
01811     return false;
01812 
01813   NPPExceptionAutoHolder nppExceptionHolder;
01814   NPPAutoPusher nppPusher(npp);
01815 
01816   return npobj->_class->removeProperty(npobj, property);
01817 }
01818 
01819 bool NP_EXPORT
01820 _hasproperty(NPP npp, NPObject* npobj, NPIdentifier propertyName)
01821 {
01822   if (!npp || !npobj || !npobj->_class || !npobj->_class->hasProperty)
01823     return false;
01824 
01825   NPPExceptionAutoHolder nppExceptionHolder;
01826   NPPAutoPusher nppPusher(npp);
01827 
01828   return npobj->_class->hasProperty(npobj, propertyName);
01829 }
01830 
01831 bool NP_EXPORT
01832 _hasmethod(NPP npp, NPObject* npobj, NPIdentifier methodName)
01833 {
01834   if (!npp || !npobj || !npobj->_class || !npobj->_class->hasMethod)
01835     return false;
01836 
01837   NPPExceptionAutoHolder nppExceptionHolder;
01838   NPPAutoPusher nppPusher(npp);
01839 
01840   return npobj->_class->hasProperty(npobj, methodName);
01841 }
01842 
01843 void NP_EXPORT
01844 _releasevariantvalue(NPVariant* variant)
01845 {
01846   switch (variant->type) {
01847   case NPVariantType_Void :
01848   case NPVariantType_Null :
01849   case NPVariantType_Bool :
01850   case NPVariantType_Int32 :
01851   case NPVariantType_Double :
01852     break;
01853   case NPVariantType_String :
01854     {
01855       const NPString *s = &NPVARIANT_TO_STRING(*variant);
01856 
01857       if (s->utf8characters)
01858         PR_Free((void *)s->utf8characters);
01859 
01860       break;
01861     }
01862   case NPVariantType_Object:
01863     {
01864       NPObject *npobj = NPVARIANT_TO_OBJECT(*variant);
01865 
01866       if (npobj)
01867         _releaseobject(npobj);
01868 
01869       break;
01870     }
01871   default:
01872     NS_ERROR("Unknown NPVariant type!");
01873   }
01874 
01875   VOID_TO_NPVARIANT(*variant);
01876 }
01877 
01878 bool NP_EXPORT
01879 _tostring(NPObject* npobj, NPVariant *result)
01880 {
01881   NS_ERROR("Write me!");
01882 
01883   return PR_FALSE;
01884 }
01885 
01886 static char *gNPPException;
01887 
01888 void NP_EXPORT
01889 _setexception(NPObject* npobj, const NPUTF8 *message)
01890 {
01891   if (gNPPException) {
01892     // If a plugin throws multiple exceptions, we'll only report the
01893     // last one for now.
01894     free(gNPPException);
01895   }
01896 
01897   gNPPException = strdup(message);
01898 }
01899 
01900 const char *
01901 PeekException()
01902 {
01903   return gNPPException;
01904 }
01905 
01906 void
01907 PopException()
01908 {
01909   NS_ASSERTION(!gNPPException, "Uh, no NPP exception to pop!");
01910 
01911   if (gNPPException) {
01912     free(gNPPException);
01913 
01914     gNPPException = nsnull;
01915   }
01916 }
01917 
01918 NPPExceptionAutoHolder::NPPExceptionAutoHolder()
01919   : mOldException(gNPPException)
01920 {
01921   gNPPException = nsnull;
01922 }
01923 
01924 NPPExceptionAutoHolder::~NPPExceptionAutoHolder()
01925 {
01926   NS_ASSERTION(!gNPPException, "NPP exception not properly cleared!");
01927 
01928   gNPPException = mOldException;
01929 }
01930 
01932 NPError NP_EXPORT
01933 _getvalue(NPP npp, NPNVariable variable, void *result)
01934 {
01935   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetValue: npp=%p, var=%d\n",
01936                                      (void*)npp, (int)variable));
01937 
01938   nsresult res;
01939 
01940   switch(variable) {
01941 #if defined(XP_UNIX) && !defined(XP_MACOSX)
01942   case NPNVxDisplay : {
01943 #ifdef MOZ_WIDGET_GTK2
01944     if (npp) {
01945       ns4xPluginInstance *inst = (ns4xPluginInstance *) npp->ndata;
01946       NPBool rtv = PR_FALSE;
01947       inst->GetValue((nsPluginInstanceVariable)NPPVpluginNeedsXEmbed, &rtv);
01948       if (rtv) {
01949         (*(Display **)result) = GDK_DISPLAY();
01950         return NPERR_NO_ERROR;
01951       }
01952     }
01953 #endif
01954 #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2)
01955     // adobe nppdf calls XtGetApplicationNameAndClass(display,
01956     // &instance, &class) we have to init Xt toolkit before get
01957     // XtDisplay just call gtk_xtbin_new(w,0) once
01958     static GtkWidget *gtkXtBinHolder = 0;
01959     if (!gtkXtBinHolder) {
01960       gtkXtBinHolder = gtk_xtbin_new(GDK_ROOT_PARENT(),0);
01961       // it crashes on destroy, let it leak
01962       // gtk_widget_destroy(gtkXtBinHolder);
01963     }
01964     (*(Display **)result) =  GTK_XTBIN(gtkXtBinHolder)->xtdisplay;
01965     return NPERR_NO_ERROR;
01966 #endif
01967     return NPERR_GENERIC_ERROR;
01968   }
01969 
01970   case NPNVxtAppContext:
01971     return NPERR_GENERIC_ERROR;
01972 #endif
01973 
01974 #if defined(XP_WIN) || defined(XP_OS2)
01975   case NPNVnetscapeWindow: {
01976     if (!npp || !npp->ndata)
01977       return NPERR_INVALID_INSTANCE_ERROR;
01978 
01979     ns4xPluginInstance *inst = (ns4xPluginInstance *) npp->ndata;
01980 
01981     nsCOMPtr<nsIPluginInstancePeer> peer;
01982     if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) &&
01983         peer &&
01984         NS_SUCCEEDED(peer->GetValue(nsPluginInstancePeerVariable_NetscapeWindow,
01985                                     result))) {
01986       return NPERR_NO_ERROR;
01987     }
01988     return NPERR_GENERIC_ERROR;
01989   }
01990 #endif
01991 
01992   case NPNVjavascriptEnabledBool: {
01993     *(NPBool*)result = PR_FALSE;
01994     nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
01995     if (prefs) {
01996       PRBool js = PR_FALSE;;
01997       res = prefs->GetBoolPref("javascript.enabled", &js);
01998       if (NS_SUCCEEDED(res))
01999         *(NPBool*)result = js;
02000     }
02001     return NPERR_NO_ERROR;
02002   }
02003 
02004   case NPNVasdEnabledBool:
02005     *(NPBool*)result = FALSE;
02006     return NPERR_NO_ERROR;
02007 
02008   case NPNVisOfflineBool: {
02009     PRBool offline = PR_FALSE;
02010     nsCOMPtr<nsIIOService> ioservice =
02011       do_GetService(NS_IOSERVICE_CONTRACTID, &res);
02012     if (NS_SUCCEEDED(res))
02013       res = ioservice->GetOffline(&offline);
02014     if (NS_FAILED(res))
02015       return NPERR_GENERIC_ERROR;
02016 
02017     *(NPBool*)result = offline;
02018     return NPERR_NO_ERROR;
02019   }
02020 
02021   case NPNVserviceManager: {
02022     nsIServiceManager * sm;
02023     res = NS_GetServiceManager(&sm);
02024     if (NS_SUCCEEDED(res)) {
02025       *(nsIServiceManager**)result = sm;
02026       return NPERR_NO_ERROR;
02027     } else
02028       return NPERR_GENERIC_ERROR;
02029   }
02030 
02031   case NPNVDOMElement: {
02032     ns4xPluginInstance *inst = (ns4xPluginInstance *) npp->ndata;
02033     NS_ENSURE_TRUE(inst, NPERR_GENERIC_ERROR);
02034 
02035     nsCOMPtr<nsIPluginInstancePeer> pip;
02036     inst->GetPeer(getter_AddRefs(pip));
02037     nsCOMPtr<nsIPluginTagInfo2> pti2 (do_QueryInterface(pip));
02038     if (pti2) {
02039       nsCOMPtr<nsIDOMElement> e;
02040       pti2->GetDOMElement(getter_AddRefs(e));
02041       if (e) {
02042         NS_ADDREF(*(nsIDOMElement**)result = e.get());
02043         return NPERR_NO_ERROR;
02044       }
02045     }
02046     return NPERR_GENERIC_ERROR;
02047   }
02048 
02049   case NPNVDOMWindow: {
02050     ns4xPluginInstance *inst = (ns4xPluginInstance *)npp->ndata;
02051     NS_ENSURE_TRUE(inst, NPERR_GENERIC_ERROR);
02052 
02053     nsIDOMWindow *domWindow = inst->GetDOMWindow().get();
02054 
02055     if (domWindow) {
02056       // Pass over ownership of domWindow to the caller.
02057       (*(nsIDOMWindow**)result) = domWindow;
02058 
02059       return NPERR_NO_ERROR;
02060     }
02061     return NPERR_GENERIC_ERROR;
02062   }
02063 
02064   case NPNVToolkit: {
02065 #ifdef MOZ_WIDGET_GTK
02066     *((NPNToolkitType*)result) = NPNVGtk12;
02067 #endif
02068 
02069 #ifdef MOZ_WIDGET_GTK2
02070     *((NPNToolkitType*)result) = NPNVGtk2;
02071 #endif
02072 
02073     if (result)
02074         return NPERR_NO_ERROR;
02075 
02076     return NPERR_GENERIC_ERROR;
02077   }
02078 
02079   case NPNVSupportsXEmbedBool: {
02080 #ifdef MOZ_WIDGET_GTK2
02081     *(NPBool*)result = PR_TRUE;
02082 #else
02083     *(NPBool*)result = PR_FALSE;
02084 #endif
02085     return NPERR_NO_ERROR;
02086   }
02087 
02088   case NPNVWindowNPObject: {
02089     *(NPObject **)result = _getwindowobject(npp);
02090 
02091     return NPERR_NO_ERROR;
02092   }
02093 
02094   case NPNVPluginElementNPObject: {
02095     *(NPObject **)result = _getpluginelement(npp);
02096 
02097     return NPERR_NO_ERROR;
02098   }
02099 
02100   default : return NPERR_GENERIC_ERROR;
02101   }
02102 }
02103 
02104 
02106 NPError NP_EXPORT
02107 _setvalue(NPP npp, NPPVariable variable, void *result)
02108 {
02109   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_SetValue: npp=%p, var=%d\n",
02110                                      (void*)npp, (int)variable));
02111 
02112   if (!npp)
02113     return NPERR_INVALID_INSTANCE_ERROR;
02114 
02115   ns4xPluginInstance *inst = (ns4xPluginInstance *) npp->ndata;
02116 
02117   NS_ASSERTION(inst != NULL, "null instance");
02118 
02119   if (inst == NULL)
02120     return NPERR_INVALID_INSTANCE_ERROR;
02121 
02122   switch (variable) {
02123 
02124     // we should keep backward compatibility with 4x where the
02125     // actual pointer value is checked rather than its content
02126     // wnen passing booleans
02127     case NPPVpluginWindowBool: {
02128       NPBool bWindowless = (result == nsnull);
02129       return inst->SetWindowless(bWindowless);
02130     }
02131 
02132     case NPPVpluginTransparentBool: {
02133       NPBool bTransparent = (result != nsnull);
02134       return inst->SetTransparent(bTransparent);
02135     }
02136 
02137     case NPPVjavascriptPushCallerBool:
02138       {
02139         nsresult rv;
02140         nsCOMPtr<nsIJSContextStack> contextStack =
02141           do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
02142         if (NS_SUCCEEDED(rv)) {
02143           NPBool bPushCaller = (result != nsnull);
02144 
02145           if (bPushCaller) {
02146             rv = NS_ERROR_FAILURE;
02147 
02148             nsCOMPtr<nsIPluginInstancePeer> peer;
02149             if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
02150               nsCOMPtr<nsIPluginInstancePeer2> peer2 =
02151                 do_QueryInterface(peer);
02152 
02153               if (peer2) {
02154                 JSContext *cx;
02155                 rv = peer2->GetJSContext(&cx);
02156 
02157                 if (NS_SUCCEEDED(rv))
02158                   rv = contextStack->Push(cx);
02159               }
02160             }
02161           } else {
02162             rv = contextStack->Pop(nsnull);
02163           }
02164         }
02165         return NS_SUCCEEDED(rv) ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
02166       }
02167       break;
02168 
02169     case NPPVpluginKeepLibraryInMemory: {
02170       NPBool bCached = (result != nsnull);
02171       return inst->SetCached(bCached);
02172     }
02173 
02174     default:
02175       return NPERR_NO_ERROR;
02176   }
02177 }
02178 
02180 NPError NP_EXPORT
02181 _requestread(NPStream *pstream, NPByteRange *rangeList)
02182 {
02183   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_RequestRead: stream=%p\n",
02184                                      (void*)pstream));
02185 
02186 #ifdef PLUGIN_LOGGING
02187   for(NPByteRange * range = rangeList; range != nsnull; range = range->next)
02188     PR_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY,
02189     ("%i-%i", range->offset, range->offset + range->length - 1));
02190 
02191   PR_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY, ("\n\n"));
02192   PR_LogFlush();
02193 #endif
02194 
02195   if (!pstream || !rangeList || !pstream->ndata)
02196     return NPERR_INVALID_PARAM;
02197 
02198   ns4xPluginStreamListener * streamlistener =
02199     (ns4xPluginStreamListener *)pstream->ndata;
02200 
02201   nsPluginStreamType streamtype = nsPluginStreamType_Normal;
02202 
02203   streamlistener->GetStreamType(&streamtype);
02204 
02205   if (streamtype != nsPluginStreamType_Seek)
02206     return NPERR_STREAM_NOT_SEEKABLE;
02207 
02208   if (streamlistener->mStreamInfo)
02209     streamlistener->mStreamInfo->RequestRead((nsByteRange *)rangeList);
02210 
02211   return NS_OK;
02212 }
02213 
02215 #ifdef OJI
02216 JRIEnv* NP_EXPORT
02217 _getJavaEnv(void)
02218 {
02219   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaEnv\n"));
02220   return NULL;
02221 }
02222 #endif
02223 
02225 const char * NP_EXPORT
02226 _useragent(NPP npp)
02227 {
02228   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_UserAgent: npp=%p\n", (void*)npp));
02229 
02230   char *retstr;
02231 
02232   nsCOMPtr<nsIPluginManager> pm(do_GetService(kPluginManagerCID));
02233 
02234   pm->UserAgent((const char **)&retstr);
02235 
02236   return retstr;
02237 }
02238 
02239 
02241 void * NP_EXPORT
02242 _memalloc (uint32 size)
02243 {
02244   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemAlloc: size=%d\n", size));
02245   return nsMemory::Alloc(size);
02246 }
02247 
02248 #ifdef OJI
02249 
02250 jref NP_EXPORT
02251 _getJavaPeer(NPP npp)
02252 {
02253   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaPeer: npp=%p\n", (void*)npp));
02254   return NULL;
02255 }
02256 
02257 #endif /* OJI */
02258 
02259 void NP_EXPORT
02260 _pushpopupsenabledstate(NPP npp, NPBool enabled)
02261 {
02262   ns4xPluginInstance *inst = (ns4xPluginInstance *)npp->ndata;
02263   if (!inst)
02264     return;
02265 
02266   inst->PushPopupsEnabledState(enabled);
02267 }
02268 
02269 void NP_EXPORT
02270 _poppopupsenabledstate(NPP npp)
02271 {
02272   ns4xPluginInstance *inst = (ns4xPluginInstance *)npp->ndata;
02273   if (!inst)
02274     return;
02275 
02276   inst->PopPopupsEnabledState();
02277 }
02278 
02279 NPP NPPStack::sCurrentNPP = nsnull;