netscape-revival
lib/libmocha/lm_plgin.c
/* -*- Mode: C; tab-width: 4; -*- */
/*
** Mocha reflection of Navigator Plugins.
**
** Created: Brendan Eich, 9/8/95
** Implemented: Chris Bingham, 2/16/96
**
** This file contains implementations of several Mocha objects:
**
** + MochaPluginList, a lazily-filled array of all installed
** plug-ins, based on the information exported from lib/plugin
** by the functions in np.h. The plug-in properties in the
** array are named by plug-in name, so you can do an array
** lookup by name, e.g. plugins["Shockwave"].
**
** + MochaMIMETypeList, a lazily-filled array of all handled
** MIME types, based in the information exported from libnet
** by the functions in net.h. The type properties in the
** array are named by type, so you can do an array lookup by
** type, e.g. mimetypes["video/quicktime"].
**
** + MochaPlugin, the reflection of an installed plug-in, with
** static properties for the plug-in's name, file name, etc.
** and dynamic properties for the MIME types supported by
** the plug-in.
**
** + MochaMIMEType, the reflection of an individual MIME type,
** with properties for the type, file extensions, platform-
** specific file type, description of the type, and enabled
** plug-in. The enabled plug-in property is a weak object
** reference marked as MDF_BACKEDGE to break the cycle of
** references from plug-in to mime type to plug-in.
**
*/
#include "lm.h"
#include "prmem.h"
#include "np.h"
#include "net.h"
/*
** -----------------------------------------------------------------------
**
** Data types
**
** -----------------------------------------------------------------------
*/
typedef struct MochaMIMEType
{
MochaDecoder *decoder;
MochaObject *obj;
MochaAtom *type; /* MIME type itself, e.g. "text/html" */
MochaAtom *description; /* English description of MIME type */
MochaAtom *suffixes; /* Comma-separated list of file suffixes */
MochaObject *enabledPluginObj; /* Plug-in enabled for this MIME type */
void *fileType; /* Platform-specific file type */
} MochaMIMEType;
typedef struct MochaPlugin
{
MochaDecoder *decoder;
MochaObject *obj;
MochaAtom *name; /* Name of plug-in */
MochaAtom *filename; /* Name of file on disk */
MochaAtom *description; /* Descriptive HTML (version, etc.) */
NPReference plugref; /* Opaque reference to private plugin object */
uint32 length; /* Total number of mime types we have */
XP_Bool reentrant; /* Flag to halt recursion of get_property */
} MochaPlugin;
typedef struct MochaPluginList
{
MochaDecoder *decoder;
MochaObject *obj;
uint32 length; /* Total number of plug-ins */
XP_Bool reentrant; /* Flag to halt recursion of get_property */
} MochaPluginList;
typedef struct MochaMIMETypeList
{
MochaDecoder *decoder;
MochaObject *obj;
uint32 length; /* Total number of mime types */
XP_Bool reentrant; /* Flag to halt recursion of get_property */
} MochaMIMETypeList;
/*
** -----------------------------------------------------------------------
**
** Function protos (all private to this file)
**
** -----------------------------------------------------------------------
*/
static MochaMIMEType* mimetype_create_self(MochaContext *mc, MochaDecoder* decoder, char* type,
char* description, char** suffixes, uint32 numExtents, void* fileType);
static MochaBoolean mimetype_get_property(MochaContext *mc, MochaObject *obj, MochaSlot slot,
MochaDatum *dp);
static void mimetype_finalize(MochaContext *mc, MochaObject *obj);
static MochaPlugin* plugin_create_self(MochaContext *mc, MochaDecoder* decoder, char* name,
char* filename, char* description, NPReference plugref);
static MochaMIMEType* plugin_create_mimetype(MochaContext* mc, MochaPlugin* plugin,
XP_Bool byName, const char* targetName, MochaSlot targetSlot);
static MochaBoolean plugin_get_property(MochaContext *mc, MochaObject *obj, MochaSlot slot,
MochaDatum *dp);
static MochaBoolean plugin_resolve_name(MochaContext *mc, MochaObject *obj, const char *name);
static void plugin_finalize(MochaContext *mc, MochaObject *obj);
static MochaPluginList* pluginlist_create_self(MochaContext *mc, MochaDecoder* decoder);
static MochaPlugin* pluginlist_create_plugin(MochaContext *mc, MochaPluginList *pluginlist,
XP_Bool byName, const char* targetName, MochaSlot targetSlot);
static MochaBoolean pluginlist_get_property(MochaContext *mc, MochaObject *obj, MochaSlot slot,
MochaDatum *dp);
static MochaBoolean pluginlist_resolve_name(MochaContext *mc, MochaObject *obj, const char *name);
static void pluginlist_finalize(MochaContext *mc, MochaObject *obj);
static MochaBoolean pluginlist_refresh(MochaContext *mc, MochaObject *obj,
uint argc, MochaDatum *argv, MochaDatum *rval);
static MochaMIMETypeList* mimetypelist_create_self(MochaContext *mc, MochaDecoder* decoder);
static MochaMIMEType* mimetypelist_create_mimetype(MochaContext* mc, MochaMIMETypeList* mimetypelist,
XP_Bool byName, const char* targetName, MochaSlot targetSlot);
static MochaBoolean mimetypelist_get_property(MochaContext *mc, MochaObject *obj, MochaSlot slot,
MochaDatum *dp);
static MochaBoolean mimetypelist_resolve_name(MochaContext *mc, MochaObject *obj, const char *name);
static void mimetypelist_finalize(MochaContext *mc, MochaObject *obj);
/*
** -----------------------------------------------------------------------
**
** Reflection of a MIME type.
**
** -----------------------------------------------------------------------
*/
enum mimetype_slot
{
MIMETYPE_TYPE = -1,
MIMETYPE_DESCRIPTION = -2,
MIMETYPE_SUFFIXES = -3,
MIMETYPE_ENABLEDPLUGIN = -4
};
static MochaPropertySpec mimetype_props[] =
{
{"type", MIMETYPE_TYPE, MDF_ENUMERATE | MDF_READONLY |
MDF_TAINTED},
{"description", MIMETYPE_DESCRIPTION, MDF_ENUMERATE | MDF_READONLY |
MDF_TAINTED},
{"suffixes", MIMETYPE_SUFFIXES, MDF_ENUMERATE | MDF_READONLY |
MDF_TAINTED},
{"enabledPlugin", MIMETYPE_ENABLEDPLUGIN, MDF_BACKEDGE | MDF_ENUMERATE |
MDF_READONLY | MDF_TAINTED},
{0}
};
static MochaClass mimetype_class =
{
"MimeType",
mimetype_get_property, mimetype_get_property, MOCHA_ListPropStub,
MOCHA_ResolveStub, MOCHA_ConvertStub, mimetype_finalize
};
/* Constructor method for a MochaMIMEType object */
static MochaMIMEType*
mimetype_create_self(MochaContext *mc, MochaDecoder* decoder,
char* type, char* description, char** suffixes,
uint32 numExtents, void* fileType)
{
MochaObject *obj;
MochaMIMEType *mimetype;
mimetype = MOCHA_malloc(mc, sizeof(MochaMIMEType));
if (!mimetype)
return NULL;
XP_BZERO(mimetype, sizeof *mimetype);
obj = MOCHA_NewObject(mc, &mimetype_class, mimetype, NULL, NULL,
mimetype_props, NULL);
if (!obj)
goto error1;
mimetype->decoder = decoder;
mimetype->obj = obj;
mimetype->fileType = fileType;
mimetype->type = MOCHA_HoldAtom(mc, MOCHA_Atomize(mc, type));
if (! mimetype->type)
goto error2;
mimetype->description = MOCHA_HoldAtom(mc, MOCHA_Atomize(mc, description));
if (! mimetype->description)
goto error3;
/*
* Assemble the list of file extensions into a string.
* The extensions are stored in an array of individual strings, so we
* first traverse the array to see how big the concatenated string will
* be, then allocate the memory and re-traverse the array to build the
* string. Each extension is seperated by trailing comma and space.
*/
{
uint32 index;
uint32 totalSize = 0;
char *extStr;
if (numExtents > 0)
{
for (index = 0; index < numExtents; index++)
totalSize += XP_STRLEN(suffixes[index]);
/* Add space for ', ' after each extension */
totalSize += (2 * (numExtents - 1));
}
/* Total size plus terminator */
extStr = XP_ALLOC(totalSize + 1);
if (! extStr)
goto error4;
extStr[0] = 0;
for (index = 0; index < numExtents; index++)
{
extStr = strcat(extStr, suffixes[index]);
if (index < numExtents - 1)
extStr = strcat(extStr, ", ");
}
mimetype->suffixes = MOCHA_HoldAtom(mc, MOCHA_Atomize(mc, extStr));
XP_FREE(extStr);
if (! mimetype->suffixes)
goto error4;
}
/*
* Conjure up the Mocha object for the plug-in enabled for this
* MIME type. First we get the name of the plug-in from libplugin;
* then we look up the plugin object by name in the global plug-in
* list (it's actually a "resolve", not a "lookup", so that the
* plug-in object will be created if it doesn't already exist).
*/
{
char* pluginName = NPL_FindPluginEnabledForType(type);
if (pluginName)
{
/* Look up the global plugin list object */
MochaDatum datum;
if (MOCHA_LookupName(mc, decoder->navigator, "plugins", &datum))
{
/* Look up the desired plugin by name in the list */
MochaObject* pluginListObj = datum.u.obj;
if (MOCHA_ResolveName(mc, pluginListObj, pluginName, &datum))
mimetype->enabledPluginObj = datum.u.obj;
}
XP_FREE(pluginName);
}
}
LM_LINK_OBJECT(mimetype->decoder, obj,
MOCHA_GetAtomName(mc, mimetype->type));
return mimetype;
/* Early exit */
error4:
MOCHA_DropAtom(mc, mimetype->description);
error3:
MOCHA_DropAtom(mc, mimetype->type);
error2:
MOCHA_DestroyObject(mc, obj);
error1:
MOCHA_free(mc, mimetype);
return 0;
}
static MochaBoolean
mimetype_get_property(MochaContext *mc, MochaObject *obj, MochaSlot slot, MochaDatum *dp)
{
MochaMIMEType *mimetype = obj->data;
switch (slot)
{
case MIMETYPE_TYPE:
MOCHA_INIT_DATUM(mc, dp, MOCHA_STRING, u.atom, mimetype->type);
break;
case MIMETYPE_DESCRIPTION:
MOCHA_INIT_DATUM(mc, dp, MOCHA_STRING, u.atom, mimetype->description);
break;
case MIMETYPE_SUFFIXES:
MOCHA_INIT_DATUM(mc, dp, MOCHA_STRING, u.atom, mimetype->suffixes);
break;
case MIMETYPE_ENABLEDPLUGIN:
MOCHA_INIT_DATUM(mc, dp, MOCHA_OBJECT, u.obj, mimetype->enabledPluginObj);
return MOCHA_TRUE;
break;
default:
/* don't mess with user-defined props. */
return MOCHA_TRUE;
}
if (!dp->u.atom) /* Paranoia */
dp->u.atom = MOCHA_empty.u.atom;
if ((dp->flags & MDF_TAINTED) && dp->taint == MOCHA_TAINT_IDENTITY)
dp->taint = MOCHA_TAINT_MAX;
return MOCHA_TRUE;
}
static void
mimetype_finalize(MochaContext *mc, MochaObject *obj)
{
MochaMIMEType *mimetype = obj->data;
LM_UNLINK_OBJECT(mimetype->decoder, obj);
MOCHA_DropAtom(mc, mimetype->type);
MOCHA_DropAtom(mc, mimetype->description);
MOCHA_DropAtom(mc, mimetype->suffixes);
MOCHA_free(mc, mimetype);
}
/*
** -----------------------------------------------------------------------
**
** Reflection of an installed plug-in.
**
** -----------------------------------------------------------------------
*/
enum plugin_slot
{
PLUGIN_NAME = -1,
PLUGIN_FILENAME = -2,
PLUGIN_DESCRIPTION = -3,
PLUGIN_ARRAY_LENGTH = -4
};
static MochaPropertySpec plugin_props[] =
{
{"name", PLUGIN_NAME, MDF_ENUMERATE | MDF_READONLY |
MDF_TAINTED},
{"filename", PLUGIN_FILENAME, MDF_ENUMERATE | MDF_READONLY |
MDF_TAINTED},
{"description", PLUGIN_DESCRIPTION, MDF_ENUMERATE | MDF_READONLY |
MDF_TAINTED},
{"length", PLUGIN_ARRAY_LENGTH, MDF_ENUMERATE | MDF_READONLY |
MDF_TAINTED},
{0}
};
static MochaClass plugin_class =
{
"Plugin",
plugin_get_property, plugin_get_property, MOCHA_ListPropStub,
plugin_resolve_name, MOCHA_ConvertStub, plugin_finalize
};
/* Constructor method for a MochaPlugin object */
static MochaPlugin*
plugin_create_self(MochaContext *mc, MochaDecoder* decoder, char* name,
char* filename, char* description, NPReference plugref)
{
MochaObject *obj;
MochaPlugin *plugin;
plugin = MOCHA_malloc(mc, sizeof(MochaPlugin));
if (!plugin)
return NULL;
XP_BZERO(plugin, sizeof *plugin);
obj = MOCHA_NewObject(mc, &plugin_class, plugin, NULL, NULL,
plugin_props, NULL);
if (!obj)
goto error1;
/* Fill out static property fields */
plugin->decoder = decoder;
plugin->obj = obj;
plugin->plugref = plugref;
plugin->name = MOCHA_HoldAtom(mc, MOCHA_Atomize(mc, name));
if (! plugin->name)
goto error2;
plugin->filename = MOCHA_HoldAtom(mc, MOCHA_Atomize(mc, filename));
if (! plugin->filename)
goto error3;
plugin->description = MOCHA_HoldAtom(mc, MOCHA_Atomize(mc, description));
if (! plugin->description)
goto error4;
/* Count how many MIME types we have */
{
NPReference typeref = NPRefFromStart;
while (NPL_IteratePluginTypes(&typeref, plugref, NULL, NULL, NULL, NULL))
plugin->length++;
}
LM_LINK_OBJECT(plugin->decoder, obj, MOCHA_GetAtomName(mc, plugin->name));
return plugin;
/* Early exit */
error4:
MOCHA_DropAtom(mc, plugin->filename);
error3:
MOCHA_DropAtom(mc, plugin->name);
error2:
MOCHA_DestroyObject(mc, obj);
error1:
MOCHA_free(mc, plugin);
return 0;
}
/* Create a mimetype property for a plugin for a specified slot or name */
static MochaMIMEType*
plugin_create_mimetype(MochaContext* mc, MochaPlugin* plugin, XP_Bool byName,
const char* targetName, MochaSlot targetSlot)
{
NPMIMEType type = NULL;
char** suffixes = NULL;
char* description = NULL;
void* fileType = NULL;
NPReference typeref = NPRefFromStart;
MochaSlot slot = 0;
XP_Bool found = FALSE;
/* Search for the type (by type name or slot number) */
while (NPL_IteratePluginTypes(&typeref, plugin->plugref, &type,
&suffixes, &description, &fileType))
{
if (byName)
found = (type && (XP_STRCMP(targetName, type) == 0));
else
found = (targetSlot == slot);
if (found)
break;
slot++;
}
/* Found the mime type, so create an object and property */
if (found)
{
MochaMIMEType* mimetype;
uint32 numExtents = 0;
while (suffixes[numExtents])
numExtents++;
mimetype = mimetype_create_self(mc, plugin->decoder, type, description,
suffixes, numExtents, fileType);
if (mimetype)
{
MochaDatum datum;
MOCHA_INIT_FULL_DATUM(mc, &datum, MOCHA_OBJECT,
MDF_ENUMERATE | MDF_READONLY,
MOCHA_TAINT_IDENTITY,
u.obj, mimetype->obj);
MOCHA_SetProperty(mc, plugin->obj,
MOCHA_GetAtomName(mc, mimetype->type),
slot, datum);
}
return mimetype;
}
return NULL;
}
static MochaBoolean
plugin_get_property(MochaContext *mc, MochaObject *obj, MochaSlot slot, MochaDatum *dp)
{
MochaPlugin *plugin = obj->data;
/* Prevent infinite recursion through call to GetSlot below */
if (plugin->reentrant)
return MOCHA_TRUE;
switch (slot)
{
case PLUGIN_NAME:
MOCHA_INIT_DATUM(mc, dp, MOCHA_STRING, u.atom, plugin->name);
break;
case PLUGIN_FILENAME:
MOCHA_INIT_DATUM(mc, dp, MOCHA_STRING, u.atom, plugin->filename);
break;
case PLUGIN_DESCRIPTION:
MOCHA_INIT_DATUM(mc, dp, MOCHA_STRING, u.atom, plugin->description);
break;
case PLUGIN_ARRAY_LENGTH:
MOCHA_INIT_DATUM(mc, dp, MOCHA_NUMBER, u.fval, plugin->length);
return MOCHA_TRUE;
default:
/* Don't mess with a user-defined property. */
if (slot < 0)
break;
/* Ignore requests for slots greater than the number of mime types */
if (slot < plugin->length)
{
/* Search for an existing MochaMIMEType for this slot */
MochaObject* mimetypeObj = NULL;
MochaDatum datum;
plugin->reentrant = TRUE;
if (MOCHA_GetSlot(mc, obj, slot, &datum) && datum.u.obj)
mimetypeObj = datum.u.obj;
else
{
MochaMIMEType* mimetype;
mimetype = plugin_create_mimetype(mc, plugin, FALSE, NULL, slot);
if (mimetype)
mimetypeObj = mimetype->obj;
}
plugin->reentrant = FALSE;
MOCHA_INIT_DATUM(mc, dp, MOCHA_OBJECT, u.obj, mimetypeObj);
return MOCHA_TRUE;
}
else
return MOCHA_FALSE;
}
if (!dp->u.atom) /* Paranoia */
dp->u.atom = MOCHA_empty.u.atom;
if ((dp->flags & MDF_TAINTED) && dp->taint == MOCHA_TAINT_IDENTITY)
dp->taint = MOCHA_TAINT_MAX;
return MOCHA_TRUE;
}
static MochaBoolean
plugin_resolve_name(MochaContext *mc, MochaObject *obj, const char *name)
{
MochaDatum datum;
MochaPlugin* plugin = obj->data;
if (!plugin)
return MOCHA_FALSE;
/* Prevent infinite recursion through call to LookupName below */
if (plugin->reentrant)
return MOCHA_TRUE;
/* Look for a MochaMIMEType object by this name already in our list */
plugin->reentrant = TRUE;
if (MOCHA_LookupName(mc, obj, name, &datum) && datum.u.obj)
{
plugin->reentrant = FALSE;
return MOCHA_TRUE;
}
plugin->reentrant = FALSE;
/* We don't already have the object, so make a new one */
if (plugin_create_mimetype(mc, plugin, TRUE, name, 0))
return MOCHA_TRUE;
/* Still no match for the name? Must be some other property, or invalid. */
return MOCHA_TRUE;
}
static void
plugin_finalize(MochaContext *mc, MochaObject *obj)
{
MochaPlugin* plugin = obj->data;
LM_UNLINK_OBJECT(plugin->decoder, obj);
MOCHA_DropAtom(mc, plugin->name);
MOCHA_DropAtom(mc, plugin->filename);
MOCHA_DropAtom(mc, plugin->description);
MOCHA_free(mc, plugin);
}
/*
** -----------------------------------------------------------------------
**
** Reflection of the list of installed plug-ins.
** The only static property is the array length;
** the array elements (MochaPlugins) are added
** lazily when referenced.
**
** -----------------------------------------------------------------------
*/
enum pluginlist_slot
{
PLUGINLIST_ARRAY_LENGTH = -1
};
static MochaPropertySpec pluginlist_props[] =
{
{"length", PLUGINLIST_ARRAY_LENGTH, MDF_ENUMERATE | MDF_READONLY},
{0}
};
static MochaClass pluginlist_class =
{
"PluginArray",
pluginlist_get_property, pluginlist_get_property, MOCHA_ListPropStub,
pluginlist_resolve_name, MOCHA_ConvertStub, pluginlist_finalize
};
static MochaFunctionSpec pluginlist_methods[] =
{
{"refresh", pluginlist_refresh, 0},
{0}
};
static MochaBoolean
PluginList(MochaContext *mc, MochaObject *obj,
uint argc, MochaDatum *argv, MochaDatum *rval)
{
return MOCHA_TRUE;
}
/* Constructor method for a MochaPluginList object */
static MochaPluginList*
pluginlist_create_self(MochaContext *mc, MochaDecoder* decoder)
{
MochaObject *obj;
MochaPluginList *pluginlist;
pluginlist = MOCHA_malloc(mc, sizeof(MochaPluginList));
if (!pluginlist)
return NULL;
XP_BZERO(pluginlist, sizeof *pluginlist);
obj = MOCHA_InitClass(mc, decoder->window_object, &pluginlist_class, pluginlist,
PluginList, 0, pluginlist_props, pluginlist_methods, 0, 0);
if (!obj)
{
MOCHA_free(mc, pluginlist);
return NULL;
}
pluginlist->decoder = decoder;
pluginlist->obj = obj;
{
/* Compute total number of plug-ins (potential slots) */
NPReference ref = NPRefFromStart;
while (NPL_IteratePluginFiles(&ref, NULL, NULL, NULL))
pluginlist->length++;
}
LM_LINK_OBJECT(pluginlist->decoder, obj, "aPluginList");
return pluginlist;
}
/* Look up the plugin for the specified slot of the plug-in list */
static MochaPlugin*
pluginlist_create_plugin(MochaContext *mc, MochaPluginList *pluginlist, XP_Bool byName,
const char* targetName, MochaSlot targetSlot)
{
char* plugname = NULL;
char* filename = NULL;
char* description = NULL;
NPReference plugref = NPRefFromStart;
MochaSlot slot = 0;
XP_Bool found = FALSE;
/* Search for the plug-in (by name or slot number) */
while (NPL_IteratePluginFiles(&plugref, &plugname, &filename, &description))
{
if (byName)
found = (plugname && (XP_STRCMP(targetName, plugname) == 0));
else
found = (targetSlot == slot);
if (found)
break;
slot++;
}
/* Found the plug-in, so create an object and property */
if (found)
{
MochaPlugin* plugin;
plugin = plugin_create_self(mc, pluginlist->decoder, plugname,
filename, description, plugref);
if (plugin)
{
MochaDatum datum;
MOCHA_INIT_FULL_DATUM(mc, &datum, MOCHA_OBJECT,
MDF_ENUMERATE | MDF_READONLY,
MOCHA_TAINT_IDENTITY,
u.obj, plugin->obj);
MOCHA_SetProperty(mc, pluginlist->obj,
MOCHA_GetAtomName(mc, plugin->name),
slot, datum);
}
return plugin;
}
else
return NULL;
}
static MochaBoolean
pluginlist_get_property(MochaContext *mc, MochaObject *obj, MochaSlot slot, MochaDatum *dp)
{
MochaPluginList *pluginlist = obj->data;
/* Prevent infinite recursion through call to GetSlot below */
if (pluginlist->reentrant)
return MOCHA_TRUE;
switch (slot)
{
case PLUGINLIST_ARRAY_LENGTH:
MOCHA_INIT_DATUM(mc, dp, MOCHA_NUMBER, u.fval, pluginlist->length);
break;
default:
/* Don't mess with a user-defined property. */
if (slot < 0)
break;
/* Ignore requests for slots greater than the number of plug-ins */
if (slot < pluginlist->length)
{
/* Search for an existing MochaPlugin for this slot */
MochaObject* pluginObj = NULL;
MochaDatum datum;
pluginlist->reentrant = TRUE;
if (MOCHA_GetSlot(mc, obj, slot, &datum) && datum.u.obj)
pluginObj = datum.u.obj;
else
{
MochaPlugin* plugin;
plugin = pluginlist_create_plugin(mc, pluginlist, FALSE, NULL, slot);
if (plugin)
pluginObj = plugin->obj;
}
pluginlist->reentrant = FALSE;
MOCHA_INIT_DATUM(mc, dp, MOCHA_OBJECT, u.obj, pluginObj);
return MOCHA_TRUE;
}
break;
}
return MOCHA_TRUE;
}
static MochaBoolean
pluginlist_resolve_name(MochaContext *mc, MochaObject *obj, const char *name)
{
MochaDatum datum;
MochaPluginList* pluginlist = obj->data;
if (!pluginlist)
return MOCHA_FALSE;
/* Prevent infinite recursion through call to LookupName below */
if (pluginlist->reentrant)
return MOCHA_TRUE;
/* Look for a MochaMIMEType object by this name already in our list */
pluginlist->reentrant = TRUE;
if (MOCHA_LookupName(mc, obj, name, &datum) && datum.u.obj)
{
pluginlist->reentrant = FALSE;
return MOCHA_TRUE;
}
pluginlist->reentrant = FALSE;
/* We don't already have the object, so make a new one */
if (pluginlist_create_plugin(mc, pluginlist, TRUE, name, 0))
return MOCHA_TRUE;
/* Still no match for the name? Must be some other property, or invalid. */
return MOCHA_TRUE;
}
static void
pluginlist_finalize(MochaContext *mc, MochaObject *obj)
{
MochaPluginList* pluginlist = obj->data;
LM_UNLINK_OBJECT(pluginlist->decoder, obj);
MOCHA_free(mc, pluginlist);
}
MochaBoolean
pluginlist_refresh(MochaContext *mc, MochaObject *obj,
uint argc, MochaDatum *argv, MochaDatum *rval)
{
MochaBoolean value = MOCHA_FALSE;
MochaPluginList* pluginlist;
MochaObject* navigator;
MochaDecoder* decoder;
NPError error;
if (!MOCHA_InstanceOf(mc, obj, &pluginlist_class, argv[-1].u.fun))
return MOCHA_FALSE;
pluginlist = (MochaPluginList*) obj->data;
decoder = pluginlist->decoder;
/*
* Evaluate the parameter (if any). If the parameter
* is missing or can't be evaluated, default to FALSE.
*/
if (argc > 0)
(void) MOCHA_DatumToBoolean(mc, argv[0], &value);
error = NPL_RefreshPluginList(value);
if (error != NPERR_NO_ERROR)
{
/* XXX should MOCHA_ReportError() here, but can't happen currently */
return MOCHA_FALSE;
}
/*
* Remove references to the existing navigator object,
* and make a new one. If scripts have outstanding
* references to the old objects, they'll still be
* valid, but if they reference navigator.plugins
* anew they'll see any new plug-ins registered by
* NPL_RefreshPlugins.
*/
navigator = decoder->navigator;
decoder->navigator = NULL; /* Prevent lm_DefineNavigator from short-circuiting */
decoder->navigator = lm_DefineNavigator(decoder);
if (!decoder->navigator)
{
/*
* We failed to create a new navigator object, so
* restore the old one (saved in a local variable).
*/
decoder->navigator = navigator;
return MOCHA_FALSE;
}
/*
* We succeeded in creating a new navigator object,
* so we can drop the old one.
*/
MOCHA_DropObject(mc, navigator);
return MOCHA_TRUE;
}
/*
** -----------------------------------------------------------------------
**
** Reflection of the list of handled MIME types.
**
** -----------------------------------------------------------------------
*/
enum mimetypelist_slot
{
MIMETYPELIST_ARRAY_LENGTH = -1
};
static MochaPropertySpec mimetypelist_props[] =
{
{"length", MIMETYPELIST_ARRAY_LENGTH, MDF_ENUMERATE | MDF_READONLY},
{0}
};
static MochaClass mimetypelist_class =
{
"MimeTypeArray",
mimetypelist_get_property, mimetypelist_get_property, MOCHA_ListPropStub,
mimetypelist_resolve_name, MOCHA_ConvertStub, mimetypelist_finalize
};
/* Constructor method for a MochaMIMETypeList object */
static MochaMIMETypeList*
mimetypelist_create_self(MochaContext *mc, MochaDecoder* decoder)
{
MochaObject *obj;
MochaMIMETypeList *mimetypelist;
mimetypelist = MOCHA_malloc(mc, sizeof(MochaMIMETypeList));
if (!mimetypelist)
return NULL;
XP_BZERO(mimetypelist, sizeof *mimetypelist);
obj = MOCHA_NewObject(mc, &mimetypelist_class, mimetypelist, NULL, NULL,
mimetypelist_props, NULL);
if (!obj)
{
MOCHA_free(mc, mimetypelist);
return NULL;
}
mimetypelist->decoder = decoder;
mimetypelist->obj = obj;
/*
* Count the number of types in the list.
* We can't just go by the number of items
* in the list, since it contains encodings, too.
*/
{
XP_List* cinfoList = cinfo_MasterListPointer();
NET_cdataStruct* cdata = NULL;
mimetypelist->length = 0;
while (cinfoList)
{
cdata = cinfoList->object;
if (cdata && cdata->ci.type)
mimetypelist->length++;
cinfoList = cinfoList->next;
}
}
LM_LINK_OBJECT(mimetypelist->decoder, obj, "aMimeTypeList");
return mimetypelist;
}
/* Create a mimetype property for a specified slot or name */
static MochaMIMEType*
mimetypelist_create_mimetype(MochaContext* mc, MochaMIMETypeList* mimetypelist,
XP_Bool byName, const char* targetName, MochaSlot targetSlot)
{
XP_List* cinfoList = cinfo_MasterListPointer();
NET_cdataStruct* cdata = NULL;
XP_Bool found = FALSE;
if (byName)
{
/* Look up by name */
targetSlot = 0;
while (cinfoList)
{
cdata = cinfoList->object;
if (cdata)
{
char* type = cdata->ci.type;
if (type && (XP_STRCMP(type, targetName) == 0))
{
found = TRUE;
break;
}
}
targetSlot++;
cinfoList = cinfoList->next;
}
}
else
{
/*
* Look up by slot.
* The slot number does not directly correspond to list index,
* since not all items in the list correspond to properties
* (encodings are in list list as well as types).
*/
uint32 count = targetSlot + 1;
while (cinfoList)
{
cdata = cinfoList->object;
if (cdata && cdata->ci.type)
count--;
if (count == 0)
{
found = TRUE;
break;
}
cinfoList = cinfoList->next;
}
}
if (found)
{
MochaMIMEType* mimetype;
mimetype = mimetype_create_self(mc, mimetypelist->decoder, cdata->ci.type,
cdata->ci.desc, cdata->exts, cdata->num_exts, NULL);
if (mimetype)
{
MochaDatum datum;
MOCHA_INIT_FULL_DATUM(mc, &datum, MOCHA_OBJECT,
MDF_ENUMERATE | MDF_READONLY,
MOCHA_TAINT_IDENTITY,
u.obj, mimetype->obj);
MOCHA_SetProperty(mc, mimetypelist->obj,
MOCHA_GetAtomName(mc, mimetype->type),
targetSlot, datum);
}
return mimetype;
}
return NULL;
}
static MochaBoolean
mimetypelist_get_property(MochaContext *mc, MochaObject *obj, MochaSlot slot,
MochaDatum *dp)
{
MochaMIMETypeList *mimetypelist = obj->data;
/* Prevent infinite recursion through call to GetSlot below */
if (mimetypelist->reentrant)
return MOCHA_TRUE;
switch (slot)
{
case MIMETYPELIST_ARRAY_LENGTH:
MOCHA_INIT_DATUM(mc, dp, MOCHA_NUMBER, u.fval, mimetypelist->length);
break;
default:
/* Don't mess with a user-defined property. */
if (slot < 0)
break;
/* Ignore requests for slots greater than the number of mime types */
if (slot < mimetypelist->length)
{
/* Search for an existing MochaMIMEType for this slot */
MochaObject* mimetypeObj = NULL;
MochaDatum datum;
mimetypelist->reentrant = TRUE;
if (MOCHA_GetSlot(mc, obj, slot, &datum) && datum.u.obj)
mimetypeObj = datum.u.obj;
else
{
MochaMIMEType* mimetype;
mimetype = mimetypelist_create_mimetype(mc, mimetypelist, FALSE, NULL, slot);
if (mimetype)
mimetypeObj = mimetype->obj;
}
mimetypelist->reentrant = FALSE;
MOCHA_INIT_DATUM(mc, dp, MOCHA_OBJECT, u.obj, mimetypeObj);
return MOCHA_TRUE;
}
break;
}
return MOCHA_TRUE;
}
static MochaBoolean
mimetypelist_resolve_name(MochaContext *mc, MochaObject *obj, const char *name)
{
MochaDatum datum;
MochaMIMETypeList* mimetypelist = obj->data;
if (!mimetypelist)
return MOCHA_FALSE;
/* Prevent infinite recursion through call to LookupName below */
if (mimetypelist->reentrant)
return MOCHA_TRUE;
/* Look for a MochaMIMEType object by this name already in our list */
mimetypelist->reentrant = TRUE;
if (MOCHA_LookupName(mc, obj, name, &datum) && datum.u.obj)
{
mimetypelist->reentrant = FALSE;
return MOCHA_TRUE;
}
mimetypelist->reentrant = FALSE;
/* We don't already have the object, so make a new one */
if (mimetypelist_create_mimetype(mc, mimetypelist, TRUE, name, 0))
return MOCHA_TRUE;
/* Still no match for the name? Must be some other property, or invalid. */
return MOCHA_TRUE;
}
static void
mimetypelist_finalize(MochaContext *mc, MochaObject *obj)
{
MochaMIMETypeList *mimetypelist = obj->data;
LM_UNLINK_OBJECT(mimetypelist->decoder, obj);
MOCHA_free(mc, mimetypelist);
}
/*
* Exported entry point, called from lm_nav.c.
* This function creates the MochaPluginList object. The
* properties for the installed plug-ins are instantiated
* lazily in pluginlist_resolve_name.
*/
MochaObject*
lm_NewPluginList(MochaContext *mc)
{
MochaDecoder* decoder;
MochaPluginList* pluginlist;
decoder = MOCHA_GetGlobalObject(mc)->data;
pluginlist = pluginlist_create_self(mc, decoder);
return (pluginlist ? pluginlist->obj : NULL);
}
/*
* Exported entry point to this file, called from lm_nav.c.
* This function creates the MochaMIMETypeList object. The
* properties for the MIME types are instantiated
* lazily in mimetypelist_resolve_name.
*/
MochaObject*
lm_NewMIMETypeList(MochaContext *mc)
{
MochaDecoder* decoder;
MochaMIMETypeList* mimetypelist;
decoder = MOCHA_GetGlobalObject(mc)->data;
mimetypelist = mimetypelist_create_self(mc, decoder);
return (mimetypelist ? mimetypelist->obj : NULL);
}