Mozilla/mozilla/modules/plugin/nglsrc/nsPluginHostImpl.cpp
michaelp%netscape.com 8674ae2b1c cleanup. now supports stream "as file" and "as file only." added support
for pluginmanager2 methods (largely stubs). now correctly handles URLNotify().
we noew report our user agent as 5.0. can now load 5.0 style plugins from DLLs
and instantiate them properly.


git-svn-id: svn://10.0.0.236/trunk@11185 18797224-902f-48f8-a5cc-f745e15eee43
1998-09-27 22:21:39 +00:00

1587 lines
38 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsPluginHostImpl.h"
#include <stdio.h>
#include "prio.h"
#include "prmem.h"
#include "ns4xPlugin.h"
#include "nsMalloc.h" //this is evil...
#include "nsPluginInstancePeer.h"
#include "nsPluginStreamPeer.h"
#include "nsIStreamListener.h"
#include "nsIURL.h"
#include "nsIInputStream.h"
#include "prprf.h"
#include "gui.h"
#ifdef XP_PC
#include "windows.h"
#include "winbase.h"
#endif
static NS_DEFINE_IID(kIPluginInstanceIID, NS_IPLUGININSTANCE_IID);
static NS_DEFINE_IID(kIPluginInstancePeerIID, NS_IPLUGININSTANCEPEER_IID);
static NS_DEFINE_IID(kIPluginManagerIID, NS_IPLUGINMANAGER_IID);
static NS_DEFINE_IID(kIPluginManager2IID, NS_IPLUGINMANAGER2_IID);
static NS_DEFINE_IID(kIPluginHostIID, NS_IPLUGINHOST_IID);
static NS_DEFINE_IID(kIPluginStreamPeerIID, NS_IPLUGINSTREAMPEER_IID);
static NS_DEFINE_IID(kIPluginIID, NS_IPLUGIN_IID);
static NS_DEFINE_IID(kIMallocIID, NS_IMALLOC_IID);
static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIStreamListenerIID, NS_ISTREAMLISTENER_IID);
static NS_DEFINE_IID(kIStreamObserverIID, NS_ISTREAMOBSERVER_IID);
nsPluginTag :: nsPluginTag()
{
mNext = nsnull;
mName = nsnull;
mDescription = nsnull;
mMimeType = nsnull;
mMimeDescription = nsnull;
mExtensions = nsnull;
mVariants = 0;
mMimeTypeArray = nsnull;
mMimeDescriptionArray = nsnull;
mExtensionsArray = nsnull;
mLibrary = nsnull;
mEntryPoint = nsnull;
mFlags = NS_PLUGIN_FLAG_ENABLED;
}
nsPluginTag :: ~nsPluginTag()
{
NS_IF_RELEASE(mEntryPoint);
if (nsnull != mName)
{
PR_Free(mName);
mName = nsnull;
}
if (nsnull != mDescription)
{
PR_Free(mDescription);
mDescription = nsnull;
}
if (nsnull != mMimeType)
{
PR_Free(mMimeType);
mMimeType = nsnull;
}
if (nsnull != mMimeDescription)
{
PR_Free(mMimeDescription);
mMimeDescription = nsnull;
}
if (nsnull != mExtensions)
{
PR_Free(mExtensions);
mExtensions = nsnull;
}
if (nsnull != mMimeTypeArray)
{
PR_Free(mMimeTypeArray);
mMimeTypeArray = nsnull;
}
if (nsnull != mMimeDescriptionArray)
{
PR_Free(mMimeDescriptionArray);
mMimeDescriptionArray = nsnull;
}
if (nsnull != mExtensionsArray)
{
PR_Free(mExtensionsArray);
mExtensionsArray = nsnull;
}
if (nsnull != mLibrary)
{
PR_UnloadLibrary(mLibrary);
mLibrary = nsnull;
}
}
class nsPluginStreamListener : public nsIStreamListener
{
public:
nsPluginStreamListener();
~nsPluginStreamListener();
NS_DECL_ISUPPORTS
//nsIStreamObserver interface
NS_IMETHOD OnStartBinding(nsIURL* aURL, const char *aContentType);
NS_IMETHOD OnProgress(nsIURL* aURL, PRInt32 aProgress, PRInt32 aProgressMax);
NS_IMETHOD OnStatus(nsIURL* aURL, const nsString &aMsg);
NS_IMETHOD OnStopBinding(nsIURL* aURL, PRInt32 aStatus, const nsString &aMsg);
//nsIStreamListener interface
NS_IMETHOD GetBindInfo(nsIURL* aURL);
NS_IMETHOD OnDataAvailable(nsIURL* aURL, nsIInputStream *aIStream,
PRInt32 aLength);
//locals
nsresult Initialize(nsIURL *aURL, nsIPluginInstance *aInstance, void *aNotifyData);
nsresult Initialize(nsIURL *aURL, nsIPluginInstanceOwner *aOwner,
nsIPluginHost *aHost, void *aNotifyData);
nsresult Initialize(nsIPluginInstance *aInstance, void *aNotifyData);
private:
nsIURL *mURL;
nsPluginStreamPeer *mPeer;
nsIPluginInstanceOwner *mOwner;
nsIPluginInstance *mInstance;
PRBool mBound;
nsIPluginStream *mStream;
char *mMIMEType;
PRUint8 *mBuffer;
PRUint32 mBufSize;
void *mNotifyData;
nsIPluginHost *mHost;
PRInt32 mLength;
PRBool mGotProgress;
nsPluginStreamType mStreamType;
FILE *mStreamFile;
};
nsPluginStreamListener :: nsPluginStreamListener()
{
NS_INIT_REFCNT();
mURL = nsnull;
mPeer = nsnull;
mOwner = nsnull;
mInstance = nsnull;
mBound = PR_FALSE;
mStream = nsnull;
mMIMEType = nsnull;
mBuffer = nsnull;
mBufSize = 0;
mNotifyData = nsnull;
mHost = nsnull;
mLength = 0;
mGotProgress = PR_FALSE;
mStreamType = nsPluginStreamType_Normal;
mStreamFile = nsnull;
}
nsPluginStreamListener :: ~nsPluginStreamListener()
{
#ifdef NS_DEBUG
printf("killing stream for %s\n", mURL ? mURL->GetSpec() : "(unknown URL)");
#endif
NS_IF_RELEASE(mURL);
NS_IF_RELEASE(mOwner);
NS_IF_RELEASE(mInstance);
NS_IF_RELEASE(mStream);
NS_IF_RELEASE(mPeer);
if (nsnull != mMIMEType)
{
PR_Free(mMIMEType);
mMIMEType = nsnull;
}
if (nsnull != mBuffer)
{
PR_Free(mBuffer);
mBuffer = nsnull;
}
mNotifyData = nsnull;
NS_IF_RELEASE(mHost);
if (nsnull != mStreamFile)
{
fclose(mStreamFile);
mStreamFile = nsnull;
}
}
NS_IMPL_ADDREF(nsPluginStreamListener)
NS_IMPL_RELEASE(nsPluginStreamListener)
nsresult nsPluginStreamListener :: QueryInterface(const nsIID& aIID,
void** aInstancePtrResult)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
if (nsnull == aInstancePtrResult)
return NS_ERROR_NULL_POINTER;
if (aIID.Equals(kIStreamListenerIID))
{
*aInstancePtrResult = (void *)((nsIStreamListener *)this);
AddRef();
return NS_OK;
}
if (aIID.Equals(kIStreamObserverIID))
{
*aInstancePtrResult = (void *)((nsIStreamObserver *)this);
AddRef();
return NS_OK;
}
if (aIID.Equals(kISupportsIID))
{
*aInstancePtrResult = (void *)((nsISupports *)((nsIStreamListener *)this));
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
nsresult nsPluginStreamListener :: Initialize(nsIURL *aURL, nsIPluginInstance *aInstance, void *aNotifyData)
{
#ifdef NS_DEBUG
printf("created stream for %s\n", aURL->GetSpec());
#endif
mURL = aURL;
NS_ADDREF(mURL);
mInstance = aInstance;
NS_ADDREF(mInstance);
mNotifyData = aNotifyData;
return NS_OK;
}
nsresult nsPluginStreamListener :: Initialize(nsIURL *aURL, nsIPluginInstanceOwner *aOwner,
nsIPluginHost *aHost, void *aNotifyData)
{
#ifdef NS_DEBUG
printf("created stream for %s\n", aURL->GetSpec());
#endif
mURL = aURL;
NS_ADDREF(mURL);
mOwner = aOwner;
NS_ADDREF(mOwner);
mHost = aHost;
NS_IF_ADDREF(mHost);
return NS_OK;
}
nsresult nsPluginStreamListener :: Initialize(nsIPluginInstance *aInstance, void *aNotifyData)
{
#ifdef NS_DEBUG
printf("created stream for (unknown URL)\n");
#endif
mInstance = aInstance;
NS_ADDREF(mInstance);
mNotifyData = aNotifyData;
return NS_OK;
}
NS_IMETHODIMP nsPluginStreamListener :: OnStartBinding(nsIURL* aURL, const char *aContentType)
{
nsresult rv = NS_OK;
if (nsnull != aContentType)
{
PRInt32 len = PL_strlen(aContentType);
mMIMEType = (char *)PR_Malloc(len + 1);
if (nsnull != mMIMEType)
PL_strcpy(mMIMEType, aContentType);
else
rv = NS_ERROR_OUT_OF_MEMORY;
}
//now that we have the mime type, see if we need
//to load a plugin...
nsIPluginInstance *instance = nsnull;
nsPluginWindow *window = nsnull;
if ((nsnull == mInstance) && (nsnull != mOwner))
{
mOwner->GetInstance(instance);
mOwner->GetWindow(window);
if ((nsnull == instance) && (nsnull != mHost) && (nsnull != window))
{
rv = mHost->InstantiatePlugin(aContentType, aURL, mOwner);
if (NS_OK == rv)
{
mOwner->GetInstance(instance);
if (nsnull != instance)
{
instance->Start();
mOwner->CreateWidget();
instance->SetWindow(window);
}
}
}
}
else
{
instance = mInstance;
NS_ADDREF(instance);
}
if ((PR_TRUE == mGotProgress) && (nsnull == mPeer) &&
(nsnull != instance) && (PR_FALSE == mBound))
{
//need to create new peer and tell plugin that we have new stream...
mPeer = (nsPluginStreamPeer *)new nsPluginStreamPeer();
NS_ADDREF(mPeer);
mPeer->Initialize(aURL, mLength, 0, aContentType, mNotifyData);
instance->NewStream(mPeer, &mStream);
if (nsnull != mStream)
mStream->GetStreamType(&mStreamType);
if ((mStreamType == nsPluginStreamType_AsFile) ||
(mStreamType == nsPluginStreamType_AsFileOnly))
{
char buf[400], tpath[300];
#ifdef XP_PC
::GetTempPath(sizeof(tpath), tpath);
PRInt32 len = PL_strlen(tpath);
if ((len > 0) && (tpath[len - 1] != '\\'))
{
tpath[len] = '\\';
tpath[len + 1] = 0;
}
#elif defined (XP_UNIX)
PL_strcpy(tpath, "/tmp/");
#else
tpath[0] = 0;
#endif
PR_snprintf(buf, sizeof(buf), "%s%08X.ngl", tpath, mStream);
mStreamFile = fopen(buf, "wb");
}
}
NS_IF_RELEASE(instance);
mBound = PR_TRUE;
return rv;
}
NS_IMETHODIMP nsPluginStreamListener :: OnProgress(nsIURL* aURL, PRInt32 aProgress, PRInt32 aProgressMax)
{
if ((aProgress == 0) && (nsnull == mPeer))
{
nsIPluginInstance *instance = nsnull;
if (nsnull == mInstance)
mOwner->GetInstance(instance);
else
{
instance = mInstance;
NS_ADDREF(instance);
}
if (nsnull != instance)
{
//need to create new peer and and tell plugin that we have new stream...
mPeer = (nsPluginStreamPeer *)new nsPluginStreamPeer();
NS_ADDREF(mPeer);
mPeer->Initialize(aURL, aProgressMax, 0, mMIMEType, mNotifyData);
instance->NewStream(mPeer, &mStream);
if (nsnull != mStream)
mStream->GetStreamType(&mStreamType);
if ((mStreamType == nsPluginStreamType_AsFile) ||
(mStreamType == nsPluginStreamType_AsFileOnly))
{
char buf[400], tpath[300];
#ifdef XP_PC
::GetTempPath(sizeof(tpath), tpath);
PRInt32 len = PL_strlen(tpath);
if ((len > 0) && (tpath[len - 1] != '\\'))
{
tpath[len] = '\\';
tpath[len + 1] = 0;
}
#elif defined (XP_UNIX)
PL_strcpy(tpath, "/tmp/");
#else
tpath[0] = 0;
#endif
PR_snprintf(buf, sizeof(buf), "%s%08X.ngl", tpath, mStream);
mStreamFile = fopen(buf, "wb");
}
NS_RELEASE(instance);
}
}
mLength = aProgressMax;
mGotProgress = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP nsPluginStreamListener :: OnStatus(nsIURL* aURL, const nsString &aMsg)
{
return NS_OK;
}
NS_IMETHODIMP nsPluginStreamListener :: OnStopBinding(nsIURL* aURL, PRInt32 aStatus, const nsString &aMsg)
{
nsresult rv;
nsPluginReason reason = nsPluginReason_NoReason;
//XXX this is incomplete... MMP
if (nsnull != mPeer)
{
if (aStatus == NS_BINDING_SUCCEEDED)
reason = nsPluginReason_Done;
else
reason = nsPluginReason_UserBreak;
mPeer->SetReason(reason);
rv = NS_OK;
}
else
rv = NS_ERROR_UNEXPECTED;
if (nsnull != mStream)
{
if ((mStreamType == nsPluginStreamType_AsFile) ||
(mStreamType == nsPluginStreamType_AsFileOnly))
{
if (nsnull != mStreamFile)
{
fclose(mStreamFile);
mStreamFile = nsnull;
char buf[400], tpath[300];
#ifdef XP_PC
::GetTempPath(sizeof(tpath), tpath);
PRInt32 len = PL_strlen(tpath);
if ((len > 0) && (tpath[len - 1] != '\\'))
{
tpath[len] = '\\';
tpath[len + 1] = 0;
}
#elif defined (XP_UNIX)
PL_strcpy(tpath, "/tmp/");
#else
tpath[0] = 0;
#endif
PR_snprintf(buf, sizeof(buf), "%s%08X.ngl", tpath, mStream);
mStream->AsFile(buf);
}
}
nsIPluginInstance *instance = nsnull;
if (nsnull == mInstance)
mOwner->GetInstance(instance);
else
{
instance = mInstance;
NS_ADDREF(instance);
}
mStream->Close();
if (nsnull != instance)
{
const char *url;
if (nsnull != mURL)
url = mURL->GetSpec();
else
url = "";
//XXX target is bad. MMP
instance->URLNotify(url, "", reason, mNotifyData);
NS_RELEASE(instance);
}
}
return rv;
}
NS_IMETHODIMP nsPluginStreamListener :: GetBindInfo(nsIURL* aURL)
{
return NS_OK;
}
NS_IMETHODIMP nsPluginStreamListener :: OnDataAvailable(nsIURL* aURL, nsIInputStream *aIStream,
PRInt32 aLength)
{
if ((PRUint32)aLength > mBufSize)
{
if (nsnull != mBuffer)
PR_Free((void *)mBuffer);
mBuffer = (PRUint8 *)PR_Malloc(aLength);
mBufSize = aLength;
}
if ((nsnull != mBuffer) && (nsnull != mStream))
{
PRInt32 readlen;
aIStream->Read((char *)mBuffer, 0, aLength, &readlen);
if (nsnull != mStreamFile)
fwrite(mBuffer, 1, aLength, mStreamFile);
if (mStreamType != nsPluginStreamType_AsFileOnly)
mStream->Write((char *)mBuffer, 0, aLength, &readlen);
}
return NS_OK;
}
nsPluginHostImpl :: nsPluginHostImpl()
{
NS_INIT_REFCNT();
}
nsPluginHostImpl :: ~nsPluginHostImpl()
{
#ifdef NS_DEBUG
printf("killing plugin host\n");
#endif
if (nsnull != mPluginPath)
{
PR_Free(mPluginPath);
mPluginPath = nsnull;
}
while (nsnull != mPlugins)
{
nsPluginTag *temp = mPlugins->mNext;
delete mPlugins;
mPlugins = temp;
}
NS_IF_RELEASE(mMalloc);
}
NS_IMPL_ADDREF(nsPluginHostImpl)
NS_IMPL_RELEASE(nsPluginHostImpl)
nsresult nsPluginHostImpl :: QueryInterface(const nsIID& aIID,
void** aInstancePtrResult)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
if (nsnull == aInstancePtrResult)
return NS_ERROR_NULL_POINTER;
if (aIID.Equals(kIPluginManagerIID))
{
*aInstancePtrResult = (void *)((nsIPluginManager *)this);
AddRef();
return NS_OK;
}
if (aIID.Equals(kIPluginManager2IID))
{
*aInstancePtrResult = (void *)((nsIPluginManager2 *)this);
AddRef();
return NS_OK;
}
if (aIID.Equals(kIPluginHostIID))
{
*aInstancePtrResult = (void *)((nsIPluginHost *)this);
AddRef();
return NS_OK;
}
if (aIID.Equals(kIFactoryIID))
{
*aInstancePtrResult = (void *)((nsIFactory *)this);
AddRef();
return NS_OK;
}
if (aIID.Equals(kIMallocIID))
{
*aInstancePtrResult = mMalloc;
NS_IF_ADDREF(mMalloc);
return NS_OK;
}
if (aIID.Equals(kISupportsIID))
{
*aInstancePtrResult = (void *)((nsISupports *)((nsIPluginHost *)this));
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
NS_IMETHODIMP nsPluginHostImpl :: GetValue(nsPluginManagerVariable variable, void *value)
{
printf("manager getvalue %d called\n", variable);
return NS_OK;
}
nsresult nsPluginHostImpl :: ReloadPlugins(PRBool reloadPages)
{
return LoadPlugins();
}
//XXX need to find out score on this one... MMP
nsresult nsPluginHostImpl :: UserAgent(const char **retstring)
{
*retstring = (const char *)"Mozilla/5.0 [en] (Windows;I)";
return NS_OK;
}
NS_IMETHODIMP nsPluginHostImpl :: GetURL(nsISupports* inst, const char* url,
const char* target,
void* notifyData, const char* altHost,
const char* referrer, PRBool forceJSEnabled)
{
nsAutoString string = nsAutoString(url);
nsIPluginInstance *instance;
nsresult rv;
rv = inst->QueryInterface(kIPluginInstanceIID, (void **)&instance);
if (NS_OK == rv)
{
if (nsnull != target)
{
nsPluginInstancePeerImpl *peer;
rv = instance->GetPeer((nsIPluginInstancePeer **)&peer);
if (NS_OK == rv)
{
nsIPluginInstanceOwner *owner;
rv = peer->GetOwner(owner);
if (NS_OK == rv)
{
if ((0 == PL_strcmp(target, "newwindow")) ||
(0 == PL_strcmp(target, "_new")))
target = "_blank";
else if (0 == PL_strcmp(target, "_current"))
target = "_self";
rv = owner->GetURL(url, target, nsnull);
NS_RELEASE(owner);
}
NS_RELEASE(peer);
}
}
if ((nsnull != notifyData) || (nsnull == target))
rv = NewPluginStream(string, instance, notifyData);
NS_RELEASE(instance);
}
return rv;
}
NS_IMETHODIMP nsPluginHostImpl :: PostURL(nsISupports* inst,
const char* url, const char* target,
PRUint32 postDataLen, const char* postData,
PRBool isFile, void* notifyData,
const char* altHost, const char* referrer,
PRBool forceJSEnabled,
PRUint32 postHeadersLength, const char* postHeaders)
{
printf("plugin manager posturl called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: BeginWaitCursor(void)
{
printf("plugin manager2 beginwaitcursor called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: EndWaitCursor(void)
{
printf("plugin manager2 posturl called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: SupportsURLProtocol(const char* protocol, PRBool *result)
{
printf("plugin manager2 supportsurlprotocol called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: NotifyStatusChange(nsIPlugin* plugin, nsresult errorStatus)
{
printf("plugin manager2 notifystatuschange called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: FindProxyForURL(const char* url, char* *result)
{
printf("plugin manager2 findproxyforurl called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: RegisterWindow(nsIEventHandler* handler, nsPluginPlatformWindowRef window)
{
printf("plugin manager2 registerwindow called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: UnregisterWindow(nsIEventHandler* handler, nsPluginPlatformWindowRef window)
{
printf("plugin manager2 unregisterwindow called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: AllocateMenuID(nsIEventHandler* handler, PRBool isSubmenu, PRInt16 *result)
{
printf("plugin manager2 allocatemenuid called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: DeallocateMenuID(nsIEventHandler* handler, PRInt16 menuID)
{
printf("plugin manager2 deallocatemenuid called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: HasAllocatedMenuID(nsIEventHandler* handler, PRInt16 menuID, PRBool *result)
{
printf("plugin manager2 hasallocatedmenuid called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginHostImpl :: ProcessNextEvent(PRBool *bEventHandled)
{
printf("plugin manager2 processnextevent called\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult nsPluginHostImpl :: Init(void)
{
nsresult rv;
nsISupports *object;
// rv = nsMalloc::Create(nsnull, kIMallocIID, (void **)&mMalloc);
rv = nsMalloc::Create(nsnull, kIMallocIID, (void **)&object);
//it should be possible to kill this now... MMP
if (NS_OK == rv)
{
rv = object->QueryInterface(kIMallocIID, (void **)&mMalloc);
NS_RELEASE(object);
}
return rv;
}
nsresult nsPluginHostImpl :: Destroy(void)
{
nsPluginTag *plug = mPlugins;
while (nsnull != plug)
{
if (nsnull != plug->mEntryPoint)
plug->mEntryPoint->Shutdown();
plug = plug->mNext;
}
return NS_OK;
}
nsresult nsPluginHostImpl :: LoadPlugins(void)
{
#ifdef XP_PC
long result;
HKEY keyloc;
DWORD type, pathlen;
char path[2000];
PRDir *dir = nsnull;
if (::GetModuleFileName(NULL, path, sizeof(path)) > 0)
{
pathlen = PL_strlen(path) - 1;
while (pathlen > 0)
{
if (path[pathlen] == '\\')
break;
pathlen--;
}
if (pathlen > 0)
{
PL_strcpy(&path[pathlen + 1], "plugins");
dir = PR_OpenDir(path);
}
}
if (nsnull == dir)
{
path[0] = 0;
result = ::RegOpenKeyEx(HKEY_CURRENT_USER,
"Software\\Netscape\\Netscape Navigator\\Main",
0, KEY_READ, &keyloc);
if (result == ERROR_SUCCESS)
{
pathlen = sizeof(path);
result = ::RegQueryValueEx(keyloc, "Install Directory",
NULL, &type, (LPBYTE)&path, &pathlen);
if (result == ERROR_SUCCESS)
{
PL_strcat(path, "\\Program\\Plugins");
}
::RegCloseKey(keyloc);
}
dir = PR_OpenDir(path);
}
#ifdef NS_DEBUG
if (path[0] != 0)
printf("plugins at: %s\n", path);
#endif
if (nsnull != dir)
{
PRDirEntry *dent;
char *verbuf = NULL;
DWORD verbufsize = 0;
pathlen = PL_strlen(path);
mPluginPath = (char *)PR_Malloc(pathlen + 2);
if (nsnull != mPluginPath)
{
PL_strcpy(mPluginPath, path);
mPluginPath[pathlen] = '\\';
mPluginPath[pathlen + 1] = 0;
}
while (nsnull != mPlugins)
{
nsPluginTag *temp = mPlugins->mNext;
delete mPlugins;
mPlugins = temp;
}
while (dent = PR_ReadDir(dir, PR_SKIP_BOTH))
{
PRInt32 len = PL_strlen(dent->name);
if (len > 6) //np*.dll
{
if ((0 == stricmp(&dent->name[len - 4], ".dll")) && //ends in '.dll'
(0 == PL_strncasecmp(dent->name, "np", 2))) //starts with 'np'
{
PRLibrary *plugin;
PL_strcpy(path, mPluginPath);
PL_strcat(path, dent->name);
plugin = PR_LoadLibrary(path);
if (NULL != plugin)
{
DWORD zerome, versionsize;
versionsize = ::GetFileVersionInfoSize(path, &zerome);
if (versionsize > 0)
{
if (versionsize > verbufsize)
{
if (nsnull != verbuf)
PR_Free(verbuf);
verbuf = (char *)PR_Malloc(versionsize);
verbufsize = versionsize;
}
if ((nsnull != verbuf) && ::GetFileVersionInfo(path, NULL, verbufsize, verbuf))
{
char *buf = NULL;
UINT blen;
nsPluginTag *plugintag;
PRBool completetag = PR_FALSE;
PRInt32 variants;
plugintag = new nsPluginTag();
while (nsnull != plugintag)
{
plugintag->mName = (char *)PR_Malloc(PL_strlen(dent->name) + 1);
if (nsnull == plugintag->mName)
break;
else
PL_strcpy(plugintag->mName, dent->name);
::VerQueryValue(verbuf,
TEXT("\\StringFileInfo\\040904E4\\FileDescription"),
(void **)&buf, &blen);
if (NULL == buf)
break;
else
{
plugintag->mDescription = (char *)PR_Malloc(blen + 1);
if (nsnull == plugintag->mDescription)
break;
else
PL_strcpy(plugintag->mDescription, buf);
}
::VerQueryValue(verbuf,
TEXT("\\StringFileInfo\\040904E4\\MIMEType"),
(void **)&buf, &blen);
if (NULL == buf)
break;
else
{
plugintag->mMimeType = (char *)PR_Malloc(blen + 1);
if (nsnull == plugintag->mMimeType)
break;
else
PL_strcpy(plugintag->mMimeType, buf);
buf = plugintag->mMimeType;
variants = 1;
while (*buf)
{
if (*buf == '|')
variants++;
buf++;
}
plugintag->mVariants = variants;
plugintag->mMimeTypeArray = (char **)PR_Malloc(variants * sizeof(char *));
if (nsnull == plugintag->mMimeTypeArray)
break;
else
{
variants = 0;
plugintag->mMimeTypeArray[variants++] = plugintag->mMimeType;
buf = plugintag->mMimeType;
while (*buf)
{
if (*buf == '|')
{
plugintag->mMimeTypeArray[variants++] = buf + 1;
*buf = 0;
}
buf++;
}
}
}
::VerQueryValue(verbuf,
TEXT("\\StringFileInfo\\040904E4\\FileOpenName"),
(void **)&buf, &blen);
if (NULL == buf)
break;
else
{
plugintag->mMimeDescription = (char *)PR_Malloc(blen + 1);
if (nsnull == plugintag->mMimeDescription)
break;
else
PL_strcpy(plugintag->mMimeDescription, buf);
buf = plugintag->mMimeDescription;
variants = 1;
while (*buf)
{
if (*buf == '|')
variants++;
buf++;
}
if (variants != plugintag->mVariants)
break;
plugintag->mMimeDescriptionArray = (char **)PR_Malloc(variants * sizeof(char *));
if (nsnull == plugintag->mMimeDescriptionArray)
break;
else
{
variants = 0;
plugintag->mMimeDescriptionArray[variants++] = plugintag->mMimeDescription;
buf = plugintag->mMimeDescription;
while (*buf)
{
if (*buf == '|')
{
plugintag->mMimeDescriptionArray[variants++] = buf + 1;
*buf = 0;
}
buf++;
}
}
}
::VerQueryValue(verbuf,
TEXT("\\StringFileInfo\\040904E4\\FileExtents"),
(void **)&buf, &blen);
if (NULL == buf)
break;
else
{
plugintag->mExtensions = (char *)PR_Malloc(blen + 1);
if (nsnull == plugintag->mExtensions)
break;
else
PL_strcpy(plugintag->mExtensions, buf);
buf = plugintag->mExtensions;
variants = 1;
while (*buf)
{
if (*buf == '|')
variants++;
buf++;
}
if (variants != plugintag->mVariants)
break;
plugintag->mExtensionsArray = (char **)PR_Malloc(variants * sizeof(char *));
if (nsnull == plugintag->mExtensionsArray)
break;
else
{
variants = 0;
plugintag->mExtensionsArray[variants++] = plugintag->mExtensions;
buf = plugintag->mExtensions;
while (*buf)
{
if (*buf == '|')
{
plugintag->mExtensionsArray[variants++] = buf + 1;
*buf = 0;
}
buf++;
}
}
}
completetag = PR_TRUE;
break;
}
if (PR_FALSE == completetag)
delete plugintag;
else
{
if (nsnull == PR_FindSymbol(plugin, "NSGetFactory"))
plugintag->mFlags |= NS_PLUGIN_FLAG_OLDSCHOOL;
#ifdef NS_DEBUG
printf("plugin %s added to list %s\n", plugintag->mName, (plugintag->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL) ? "(old school)" : "");
#endif
plugintag->mNext = mPlugins;
mPlugins = plugintag;
}
}
}
PR_UnloadLibrary(plugin);
}
}
}
}
if (nsnull != verbuf)
PR_Free(verbuf);
PR_CloseDir(dir);
}
#else
#ifdef NS_DEBUG
printf("Don't know how to locate plugins directory on Unix yet...\n");
#endif
#endif
return NS_OK;
}
nsresult nsPluginHostImpl :: InstantiatePlugin(const char *aMimeType, nsIURL *aURL,
nsIPluginInstanceOwner *aOwner)
{
nsPluginTag *plugins = nsnull;
PRInt32 variants, cnt;
if (nsnull != aMimeType)
{
plugins = mPlugins;
while (nsnull != plugins)
{
variants = plugins->mVariants;
for (cnt = 0; cnt < variants; cnt++)
{
if (0 == strcmp(plugins->mMimeTypeArray[cnt], aMimeType))
break;
}
if (cnt < variants)
break;
plugins = plugins->mNext;
}
}
if ((nsnull == plugins) && (nsnull != aURL))
{
const char *name = aURL->GetSpec();
PRInt32 len = PL_strlen(name);
//find the plugin by filename extension.
if ((nsnull != name) && (len > 1))
{
len--;
while ((name[len] != 0) && (name[len] != '.'))
len--;
if (name[len] == '.')
{
const char *ext = name + len + 1;
len = PL_strlen(ext);
plugins = mPlugins;
while (nsnull != plugins)
{
variants = plugins->mVariants;
for (cnt = 0; cnt < variants; cnt++)
{
char *extensions = plugins->mExtensionsArray[cnt];
char *nextexten;
PRInt32 extlen;
while (nsnull != extensions)
{
nextexten = strchr(extensions, ',');
if (nsnull != nextexten)
extlen = nextexten - extensions;
else
extlen = PL_strlen(extensions);
if (extlen == len)
{
if (PL_strncasecmp(extensions, ext, extlen) == 0)
break;
}
if (nsnull != nextexten)
extensions = nextexten + 1;
else
extensions = nsnull;
}
if (nsnull != extensions)
break;
}
if (cnt < variants)
{
aMimeType = plugins->mMimeTypeArray[cnt];
#ifdef NS_DEBUG
printf("found plugin via extension %s\n", ext);
#endif
break;
}
plugins = plugins->mNext;
}
}
}
}
if (nsnull != plugins)
{
if (nsnull == plugins->mLibrary)
{
char path[2000];
PL_strcpy(path, mPluginPath);
PL_strcat(path, plugins->mName);
plugins->mLibrary = PR_LoadLibrary(path);
#ifdef NS_DEBUG
printf("loaded plugin %s for mime type %s\n", plugins->mName, aMimeType);
#endif
}
if (nsnull != plugins->mLibrary)
{
if (nsnull == plugins->mEntryPoint)
{
//create the plugin object
if (plugins->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL)
{
nsresult rv = ns4xPlugin::CreatePlugin(plugins->mLibrary, (nsIPlugin **)&plugins->mEntryPoint);
#ifdef NS_DEBUG
printf("result of creating plugin adapter: %d\n", rv);
#endif
}
else
{
nsFactoryProc fact = (nsFactoryProc)PR_FindSymbol(plugins->mLibrary, "NSGetFactory");
if (nsnull != fact)
{
nsIFactory *factory;
if (NS_OK == (fact)(kIFactoryIID, &factory))
{
factory->QueryInterface(kIPluginIID, (void **)&plugins->mEntryPoint);
NS_RELEASE(factory);
}
}
}
if (nsnull != plugins->mEntryPoint)
plugins->mEntryPoint->Initialize((nsISupports *)(nsIPluginManager *)this);
}
if (nsnull != plugins->mEntryPoint)
{
nsIPluginInstance *instance;
//create an instance
if (NS_OK == plugins->mEntryPoint->CreateInstance(nsnull, kIPluginInstanceIID, (void **)&instance))
{
#ifdef NS_DEBUG
printf("successfully created plugin instance %08x for %s, mimetype %s\n", instance, plugins->mName, aMimeType ? aMimeType : "(none)");
#endif
aOwner->SetInstance(instance);
nsPluginInstancePeerImpl *peer = new nsPluginInstancePeerImpl();
peer->Initialize(aOwner, aMimeType); //this will not add a ref to the instance (or owner). MMP
instance->Initialize(peer);
NS_RELEASE(instance);
}
}
}
else
return NS_ERROR_UNEXPECTED;
return NS_OK;
}
else
{
if ((nsnull != aURL) || (nsnull != aMimeType))
#ifdef NS_DEBUG
printf("unable to find plugin to handle %s\n", aMimeType ? aMimeType : "(mime type unspecified)")
#endif
;
return NS_ERROR_FAILURE;
}
}
nsresult nsPluginHostImpl :: InstantiatePlugin(const char *aMimeType, nsString& aURLSpec,
nsIPluginInstanceOwner *aOwner)
{
nsresult rv;
rv = InstantiatePlugin(aMimeType, nsnull, aOwner);
if ((rv != NS_OK) || (nsnull == aMimeType))
{
//either the plugin could not be identified based
//on the mime type or there was no mime type
if (aURLSpec.Length() > 0)
{
//we need to stream in enough to get the mime type...
rv = NewPluginStream(aURLSpec, aOwner, nsnull);
}
else
rv = NS_ERROR_FAILURE;
}
else
{
nsIPluginInstance *instance = nsnull;
nsPluginWindow *window = nsnull;
//we got a plugin built, now stream
aOwner->GetInstance(instance);
aOwner->GetWindow(window);
if (nsnull != instance)
{
instance->Start();
aOwner->CreateWidget();
instance->SetWindow(window);
rv = NewPluginStream(aURLSpec, instance, nsnull);
NS_RELEASE(instance);
}
}
return rv;
}
nsresult nsPluginHostImpl :: InstantiatePlugin(const char *aMimeType, nsString& aURLSpec,
nsIStreamListener *&aStreamListener,
nsIPluginInstanceOwner *aOwner)
{
nsresult rv;
nsIURL *url;
//create a URL so that the instantiator can do file ext.
//based plugin lookups...
rv = NS_NewURL(&url, aURLSpec);
if (rv != NS_OK)
url = nsnull;
rv = InstantiatePlugin(aMimeType, url, aOwner);
NS_IF_RELEASE(url);
if (NS_OK == rv)
{
nsIPluginInstance *instance = nsnull;
nsPluginWindow *window = nsnull;
//we got a plugin built, now stream
aOwner->GetInstance(instance);
aOwner->GetWindow(window);
if (nsnull != instance)
{
instance->Start();
aOwner->CreateWidget();
instance->SetWindow(window);
rv = NewPluginStream(aStreamListener, instance, nsnull);
NS_RELEASE(instance);
}
}
return rv;
}
NS_IMETHODIMP nsPluginHostImpl :: NewPluginStream(const nsString& aURL,
nsIPluginInstance *aInstance,
void *aNotifyData)
{
nsIURL *url;
nsPluginStreamListener *listener = (nsPluginStreamListener *)new nsPluginStreamListener();
nsresult rv;
if (aURL.Length() <= 0)
return NS_OK;
rv = NS_NewURL(&url, aURL);
if (NS_OK == rv)
{
rv = listener->Initialize(url, aInstance, aNotifyData);
if (NS_OK == rv)
rv = url->Open(listener);
NS_RELEASE(url);
}
return rv;
}
NS_IMETHODIMP nsPluginHostImpl :: NewPluginStream(const nsString& aURL,
nsIPluginInstanceOwner *aOwner,
void *aNotifyData)
{
nsIURL *url;
nsPluginStreamListener *listener = (nsPluginStreamListener *)new nsPluginStreamListener();
nsresult rv;
if (aURL.Length() <= 0)
return NS_OK;
rv = NS_NewURL(&url, aURL);
if (NS_OK == rv)
{
rv = listener->Initialize(url, aOwner, (nsIPluginHost *)this, aNotifyData);
if (NS_OK == rv)
rv = url->Open(listener);
NS_RELEASE(url);
}
return rv;
}
NS_IMETHODIMP nsPluginHostImpl :: NewPluginStream(nsIStreamListener *&aStreamListener,
nsIPluginInstance *aInstance,
void *aNotifyData)
{
nsPluginStreamListener *listener = (nsPluginStreamListener *)new nsPluginStreamListener();
nsresult rv;
rv = listener->Initialize(aInstance, aNotifyData);
aStreamListener = (nsIStreamListener *)listener;
NS_IF_ADDREF(listener);
return rv;
}
nsresult nsPluginHostImpl :: CreateInstance(nsISupports *aOuter,
const nsIID &aIID,
void **aResult)
{
if (aResult == NULL)
return NS_ERROR_NULL_POINTER;
nsISupports *inst = nsnull;
if (aIID.Equals(kIPluginStreamPeerIID))
inst = (nsISupports *)(nsIPluginStreamPeer *)new nsPluginStreamPeer();
if (inst == NULL)
return NS_ERROR_OUT_OF_MEMORY;
nsresult res = inst->QueryInterface(aIID, aResult);
if (res != NS_OK) {
// We didn't get the right interface, so clean up
delete inst;
}
return res;
}
nsresult nsPluginHostImpl :: LockFactory(PRBool aLock)
{
// Not implemented in simplest case.
return NS_OK;
}