home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmocha / lm_plgin.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  34.9 KB  |  1,263 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*
  19.  * JS reflection of Navigator Plugins.
  20.  *
  21.  * This file contains implementations of several JS objects:
  22.  *
  23.  *     + JSPluginList, a lazily-filled array of all installed
  24.  *       plug-ins, based on the information exported from lib/plugin
  25.  *       by the functions in np.h.  The plug-in properties in the
  26.  *       array are named by plug-in name, so you can do an array
  27.  *       lookup by name, e.g. plugins["Shockwave"].
  28.  *
  29.  *     + JSMIMETypeList, a lazily-filled array of all handled
  30.  *       MIME types, based in the information exported from libnet
  31.  *       by the functions in net.h.  The type properties in the
  32.  *       array are named by type, so you can do an array lookup by
  33.  *       type, e.g. mimetypes["video/quicktime"].
  34.  *
  35.  *     + JSPlugin, the reflection of an installed plug-in, with
  36.  *       static properties for the plug-in's name, file name, etc.
  37.  *       and dynamic properties for the MIME types supported by
  38.  *       the plug-in.
  39.  *
  40.  *     + JSMIMEType, the reflection of an individual MIME type,
  41.  *       with properties for the type, file extensions, platform-
  42.  *       specific file type, description of the type, and enabled
  43.  *         plug-in.  The enabled plug-in property is a weak object
  44.  *         reference marked as JSPROP_BACKEDGE to break the cycle of
  45.  *         references from plug-in to mime type to plug-in.
  46.  *
  47.  */
  48.  
  49. #include "lm.h"
  50. #include "prmem.h"
  51. #include "np.h"
  52. #include "net.h"
  53.  
  54.  
  55. /*
  56.  * -----------------------------------------------------------------------
  57.  *
  58.  * Data types
  59.  *
  60.  * -----------------------------------------------------------------------
  61.  */
  62.  
  63. typedef struct JSMIMEType
  64. {
  65.     MochaDecoder           *decoder;
  66.     JSObject               *obj;
  67.     JSString    *type;                /* MIME type itself, e.g. "text/html" */
  68.     JSString    *description;        /* English description of MIME type */
  69.     JSString    *suffixes;            /* Comma-separated list of file suffixes */
  70.     JSObject               *enabledPluginObj;    /* Plug-in enabled for this MIME type */
  71.     void                   *fileType;            /* Platform-specific file type */
  72. } JSMIMEType;
  73.  
  74. typedef struct JSPlugin
  75. {
  76.     MochaDecoder    *decoder;
  77.     JSObject    *obj;
  78.     JSString    *name;               /* Name of plug-in */
  79.     JSString    *filename;           /* Name of file on disk */
  80.     JSString    *description;        /* Descriptive HTML (version, etc.) */
  81.     NPReference    plugref;            /* Opaque reference to private plugin object */
  82.     uint32    length;             /* Total number of mime types we have */
  83.     XP_Bool    reentrant;            /* Flag to halt recursion of getProperty */
  84. } JSPlugin;
  85.  
  86.  
  87. typedef struct JSPluginList
  88. {
  89.     MochaDecoder       *decoder;
  90.     JSObject           *obj;
  91.     uint32        length;                /* Total number of plug-ins */
  92.     XP_Bool        reentrant;            /* Flag to halt recursion of getProperty */
  93. } JSPluginList;
  94.  
  95.  
  96. typedef struct JSMIMETypeList
  97. {
  98.     MochaDecoder       *decoder;
  99.     JSObject           *obj;
  100.     uint32         length;        /* Total number of mime types */
  101.     PRPackedBool    reentrant;  /* Flag to halt recursion of getProperty */
  102. } JSMIMETypeList;
  103.  
  104.  
  105.  
  106. /*
  107.  * -----------------------------------------------------------------------
  108.  *
  109.  * Function protos (all private to this file)
  110.  *
  111.  * -----------------------------------------------------------------------
  112.  */
  113.  
  114. static JSMIMEType*    mimetype_create_self(JSContext *cx, MochaDecoder* decoder, char* type,
  115.                         char* description, char** suffixes, uint32 numExtents, void* fileType);
  116. JSBool PR_CALLBACK    mimetype_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
  117. void PR_CALLBACK    mimetype_finalize(JSContext *cx, JSObject *obj);
  118.  
  119. static JSPlugin*     plugin_create_self(JSContext *cx, MochaDecoder* decoder, char* name,
  120.                        char* filename, char* description, NPReference plugref);
  121. static JSMIMEType*    plugin_create_mimetype(JSContext* cx, JSPlugin* plugin,
  122.                            XP_Bool byName, const char* targetName, jsint targetSlot);
  123. JSBool PR_CALLBACK    plugin_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
  124. JSBool PR_CALLBACK    plugin_resolve_name(JSContext *cx, JSObject *obj, jsval id);
  125. void PR_CALLBACK     plugin_finalize(JSContext *cx, JSObject *obj);
  126.  
  127. static JSPluginList*    pluginlist_create_self(JSContext *cx, MochaDecoder* decoder, JSObject* parent_obj);
  128. static JSPlugin*    pluginlist_create_plugin(JSContext *cx, JSPluginList *pluginlist,
  129.                          XP_Bool byName, const char* targetName, jsint targetSlot);
  130. JSBool PR_CALLBACK    pluginlist_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
  131. JSBool PR_CALLBACK    pluginlist_resolve_name(JSContext *cx, JSObject *obj, jsval id);
  132. JSBool PR_CALLBACK      pluginlist_enumerate(JSContext *cx, JSObject *obj);
  133. void PR_CALLBACK    pluginlist_finalize(JSContext *cx, JSObject *obj);
  134. JSBool PR_CALLBACK    pluginlist_refresh(JSContext *cx, JSObject *obj,
  135.                        uint argc, jsval *argv, jsval *rval);
  136.  
  137. static JSMIMETypeList*    mimetypelist_create_self(JSContext *cx, MochaDecoder* decoder);
  138. static JSMIMEType*    mimetypelist_create_mimetype(JSContext* cx, JSMIMETypeList* mimetypelist,
  139.                              XP_Bool byName, const char* targetName, jsint targetSlot);
  140. JSBool PR_CALLBACK    mimetypelist_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
  141. JSBool PR_CALLBACK    mimetypelist_resolve_name(JSContext *cx, JSObject *obj, jsval id);
  142. JSBool PR_CALLBACK      mimetypelist_enumerate(JSContext *cx, JSObject *obj);
  143. void PR_CALLBACK    mimetypelist_finalize(JSContext *cx, JSObject *obj);
  144.  
  145. /*
  146.  * -----------------------------------------------------------------------
  147.  *
  148.  * Reflection of a MIME type.
  149.  *
  150.  * -----------------------------------------------------------------------
  151.  */
  152.  
  153. enum mimetype_slot
  154. {
  155.     MIMETYPE_TYPE           = -1,
  156.     MIMETYPE_DESCRIPTION    = -2,
  157.     MIMETYPE_SUFFIXES       = -3,
  158.     MIMETYPE_ENABLEDPLUGIN  = -4
  159. };
  160.  
  161.  
  162. static JSPropertySpec mimetype_props[] =
  163. {
  164.     {"type",          MIMETYPE_TYPE,          JSPROP_ENUMERATE|JSPROP_READONLY},
  165.     {"description",   MIMETYPE_DESCRIPTION,   JSPROP_ENUMERATE|JSPROP_READONLY},
  166.     {"suffixes",      MIMETYPE_SUFFIXES,      JSPROP_ENUMERATE|JSPROP_READONLY},
  167.     {"enabledPlugin", MIMETYPE_ENABLEDPLUGIN, JSPROP_ENUMERATE|JSPROP_READONLY},
  168.     {0}
  169. };
  170.  
  171.  
  172. static JSClass mimetype_class =
  173. {
  174.     "MimeType",    JSCLASS_HAS_PRIVATE,
  175.     JS_PropertyStub, JS_PropertyStub,
  176.     mimetype_getProperty, mimetype_getProperty, JS_EnumerateStub,
  177.     JS_ResolveStub, JS_ConvertStub, mimetype_finalize
  178. };
  179.  
  180. PR_STATIC_CALLBACK(JSBool)
  181. MimeType(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  182. {
  183.     return JS_TRUE;
  184. }
  185.  
  186. /* Constructor method for a JSMIMEType object */
  187. static JSMIMEType*
  188. mimetype_create_self(JSContext *cx, MochaDecoder* decoder,
  189.              char* type, char* description, char ** suffixes,
  190.                      uint32 numExtents, void* fileType)
  191. {
  192.     JSObject *obj;
  193.     JSMIMEType *mimetype;
  194.  
  195.     mimetype = JS_malloc(cx, sizeof(JSMIMEType));
  196.     if (!mimetype)
  197.         return NULL;
  198.     XP_BZERO(mimetype, sizeof *mimetype);
  199.  
  200.     obj = JS_NewObject(cx, &mimetype_class, NULL, NULL);
  201.     if (!obj || !JS_SetPrivate(cx, obj, mimetype)) {
  202.     JS_free(cx, mimetype);
  203.         return NULL;
  204.     }
  205.  
  206.     if (!JS_DefineProperties(cx, obj, mimetype_props))
  207.     return NULL;
  208.  
  209.     mimetype->decoder = HOLD_BACK_COUNT(decoder);
  210.     mimetype->obj = obj;
  211.     mimetype->fileType = fileType;
  212.  
  213.     mimetype->type = JS_NewStringCopyZ(cx, type);
  214.     if (!mimetype->type || !JS_LockGCThing(cx, mimetype->type))
  215.         return NULL;
  216.  
  217.     mimetype->description = JS_NewStringCopyZ(cx, description);
  218.     if (!mimetype->description || !JS_LockGCThing(cx, mimetype->description))
  219.         return NULL;
  220.  
  221.  
  222.     /*
  223.      * Assemble the list of file extensions into a string.
  224.      * The extensions are stored in an array of individual strings, so we
  225.      * first traverse the array to see how big the concatenated string will
  226.      * be, then allocate the memory and re-traverse the array to build the
  227.      * string.  Each extension is seperated by trailing comma and space.
  228.      */
  229.     {
  230.         uint32 index;
  231.         uint32 totalSize = 0;
  232.         char *extStr;
  233.  
  234.         if (numExtents > 0)
  235.         {
  236.             for (index = 0; index < numExtents; index++)
  237.                 totalSize += XP_STRLEN(suffixes[index]);
  238.  
  239.             /* Add space for ', ' after each extension */
  240.             totalSize += (2 * (numExtents - 1));
  241.         }
  242.  
  243.         /* Total size plus terminator */
  244.         extStr = XP_ALLOC(totalSize + 1);
  245.         if (! extStr)
  246.             return NULL;
  247.  
  248.         extStr[0] = 0;
  249.  
  250.         for (index = 0; index < numExtents; index++)
  251.         {
  252.             extStr = strcat(extStr, suffixes[index]);
  253.             if (index < numExtents - 1)
  254.                 extStr = strcat(extStr, ", ");
  255.         }
  256.         mimetype->suffixes = JS_NewStringCopyZ(cx, extStr);
  257.         XP_FREE(extStr);
  258.         if (!mimetype->suffixes || !JS_LockGCThing(cx, mimetype->suffixes))
  259.             return NULL;
  260.     }
  261.  
  262.     /*
  263.      * Conjure up the JS object for the plug-in enabled for this
  264.      * MIME type.  First we get the name of the plug-in from libplugin;
  265.      * then we look up the plugin object by name in the global plug-in
  266.      * list (it's actually a "resolve", not a "lookup", so that the
  267.      * plug-in object will be created if it doesn't already exist).
  268.      */
  269.     if (type) {
  270.     char* pluginName = NPL_FindPluginEnabledForType(type);
  271.     if (pluginName)
  272.     {
  273.         /* Look up the global plugin list object */
  274.         jsval val;
  275.         if (JS_LookupProperty(cx, decoder->navigator, "plugins", &val) &&
  276.         JSVAL_IS_OBJECT(val))
  277.         {
  278.         /* Look up the desired plugin by name in the list */
  279.         JSObject* pluginListObj = JSVAL_TO_OBJECT(val);
  280.         if (JS_GetProperty(cx, pluginListObj, pluginName, &val) &&
  281.             JSVAL_IS_OBJECT(val))
  282.         {
  283.             mimetype->enabledPluginObj = JSVAL_TO_OBJECT(val);
  284.         }
  285.         }
  286.  
  287.         XP_FREE(pluginName);
  288.     }
  289.     }
  290.  
  291.     return mimetype;
  292. }
  293.  
  294.  
  295. JSBool PR_CALLBACK
  296. mimetype_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  297. {
  298.     JSMIMEType *mimetype;
  299.     JSString *str;
  300.     jsint slot;
  301.  
  302.     if (!JSVAL_IS_INT(id))
  303.     return JS_TRUE;
  304.  
  305.     slot = JSVAL_TO_INT(id);
  306.  
  307.     mimetype = JS_GetInstancePrivate(cx, obj, &mimetype_class, NULL);
  308.     if (!mimetype)
  309.     return JS_TRUE;
  310.  
  311.     switch (slot)
  312.     {
  313.         case MIMETYPE_TYPE:
  314.             str = mimetype->type;
  315.             break;
  316.  
  317.         case MIMETYPE_DESCRIPTION:
  318.             str = mimetype->description;
  319.             break;
  320.  
  321.         case MIMETYPE_SUFFIXES:
  322.             str = mimetype->suffixes;
  323.             break;
  324.  
  325.         case MIMETYPE_ENABLEDPLUGIN:
  326.             *vp = OBJECT_TO_JSVAL(mimetype->enabledPluginObj);
  327.             return JS_TRUE;
  328.  
  329.         default:
  330.             /* don't mess with user-defined props. */
  331.             return JS_TRUE;
  332.     }
  333.  
  334.     if (str)
  335.     *vp = STRING_TO_JSVAL(str);
  336.     else
  337.         *vp = JS_GetEmptyStringValue(cx);
  338.     return JS_TRUE;
  339. }
  340.  
  341.  
  342. void PR_CALLBACK
  343. mimetype_finalize(JSContext *cx, JSObject *obj)
  344. {
  345.     JSMIMEType *mimetype;
  346.  
  347.     mimetype = JS_GetPrivate(cx, obj);
  348.     if (!mimetype)
  349.     return;
  350.  
  351.     DROP_BACK_COUNT(mimetype->decoder);
  352.     JS_UnlockGCThing(cx, mimetype->type);
  353.     JS_UnlockGCThing(cx, mimetype->description);
  354.     JS_UnlockGCThing(cx, mimetype->suffixes);
  355.     JS_free(cx, mimetype);
  356. }
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363. /*
  364.  * -----------------------------------------------------------------------
  365.  *
  366.  * Reflection of an installed plug-in.
  367.  *
  368.  * -----------------------------------------------------------------------
  369.  */
  370.  
  371. enum plugin_slot
  372. {
  373.     PLUGIN_NAME         = -1,
  374.     PLUGIN_FILENAME     = -2,
  375.     PLUGIN_DESCRIPTION  = -3,
  376.     PLUGIN_ARRAY_LENGTH = -4
  377. };
  378.  
  379.  
  380. static JSPropertySpec plugin_props[] =
  381. {
  382.     {"name",        PLUGIN_NAME,            JSPROP_ENUMERATE | JSPROP_READONLY},
  383.     {"filename",    PLUGIN_FILENAME,        JSPROP_ENUMERATE | JSPROP_READONLY},
  384.     {"description", PLUGIN_DESCRIPTION,     JSPROP_ENUMERATE | JSPROP_READONLY},
  385.     {"length",      PLUGIN_ARRAY_LENGTH,    JSPROP_ENUMERATE | JSPROP_READONLY},
  386.     {0}
  387. };
  388.  
  389. static JSClass plugin_class =
  390. {
  391.     "Plugin", JSCLASS_HAS_PRIVATE,
  392.     JS_PropertyStub, JS_PropertyStub,
  393.     plugin_getProperty, plugin_getProperty, JS_EnumerateStub,
  394.     plugin_resolve_name, JS_ConvertStub, plugin_finalize
  395. };
  396.  
  397. PR_STATIC_CALLBACK(JSBool)
  398. Plugin(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  399. {
  400.     return JS_TRUE;
  401. }
  402.  
  403. /* Constructor method for a JSPlugin object */
  404. static JSPlugin*
  405. plugin_create_self(JSContext *cx, MochaDecoder* decoder, char* name,
  406.                    char* filename, char* description, NPReference plugref)
  407. {
  408.     JSObject *obj;
  409.     JSPlugin *plugin;
  410.  
  411.     plugin = JS_malloc(cx, sizeof(JSPlugin));
  412.     if (!plugin)
  413.         return NULL;
  414.     XP_BZERO(plugin, sizeof *plugin);
  415.  
  416.     obj = JS_NewObject(cx, &plugin_class, NULL, NULL);
  417.     if (!obj || !JS_SetPrivate(cx, obj, plugin)) {
  418.     JS_free(cx, plugin);
  419.     return NULL;
  420.     }
  421.  
  422.     if (!JS_DefineProperties(cx, obj, plugin_props))
  423.     return NULL;
  424.  
  425.     /* Fill out static property fields */
  426.     plugin->decoder = HOLD_BACK_COUNT(decoder);
  427.     plugin->obj = obj;
  428.     plugin->plugref = plugref;
  429.  
  430.     plugin->name = JS_NewStringCopyZ(cx, name);
  431.     if (!plugin->name || !JS_LockGCThing(cx, plugin->name))
  432.     return NULL;
  433.  
  434.     plugin->filename = JS_NewStringCopyZ(cx, filename);
  435.     if (!plugin->filename || !JS_LockGCThing(cx, plugin->filename))
  436.     return NULL;
  437.  
  438.     plugin->description = JS_NewStringCopyZ(cx, description);
  439.     if (!plugin->description || !JS_LockGCThing(cx, plugin->description))
  440.     return NULL;
  441.  
  442.     /* Count how many MIME types we have */
  443.     {
  444.         NPReference typeref = NPRefFromStart;
  445.         while (NPL_IteratePluginTypes(&typeref, plugref, NULL, NULL, NULL, NULL))
  446.             plugin->length++;
  447.     }
  448.  
  449.     return plugin;
  450. }
  451.  
  452.  
  453. /* Create a mimetype property for a plugin for a specified slot or name */
  454. static JSMIMEType*
  455. plugin_create_mimetype(JSContext* cx, JSPlugin* plugin, XP_Bool byName,
  456.                       const char* targetName, jsint targetSlot)
  457. {
  458.     NPMIMEType type = NULL;
  459.     char** suffixes = NULL;
  460.     char* description = NULL;
  461.     void* fileType = NULL;
  462.     NPReference typeref = NPRefFromStart;
  463.     jsint slot = 0;
  464.     XP_Bool found = FALSE;
  465.  
  466.     /* Search for the type (by type name or slot number) */
  467.     while (NPL_IteratePluginTypes(&typeref, plugin->plugref, &type,
  468.                       &suffixes, &description, &fileType))
  469.     {
  470.         if (byName)
  471.             found = (type && (XP_STRCMP(targetName, type) == 0));
  472.         else
  473.             found = (targetSlot == slot);
  474.  
  475.         if (found)
  476.             break;
  477.  
  478.         slot++;
  479.     }
  480.  
  481.     /* Found the mime type, so create an object and property */
  482.     if (found) {
  483.         JSMIMEType* mimetype;
  484.         uint32 numExtents = 0;
  485.  
  486.         while (suffixes[numExtents])
  487.             numExtents++;
  488.  
  489.         mimetype = mimetype_create_self(cx, plugin->decoder, type, description,
  490.                         suffixes, numExtents, fileType);
  491.     if (mimetype) {
  492.         char *name;
  493.         jsval val;
  494.  
  495.         name = JS_GetStringBytes(mimetype->type);
  496.         val = OBJECT_TO_JSVAL(mimetype->obj);
  497.         JS_DefineProperty(cx, plugin->obj, name, val, NULL, NULL,
  498.                   JSPROP_ENUMERATE | JSPROP_READONLY);
  499.         JS_AliasElement(cx, plugin->obj, name, slot);
  500.     }
  501.  
  502.         return mimetype;
  503.     }
  504.     return NULL;
  505. }
  506.  
  507.  
  508. JSBool PR_CALLBACK
  509. plugin_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  510. {
  511.     JSPlugin *plugin;
  512.     JSString *str;
  513.     jsint slot;
  514.  
  515.     if (!JSVAL_IS_INT(id))
  516.     return JS_TRUE;
  517.  
  518.     slot = JSVAL_TO_INT(id);
  519.  
  520.     plugin = JS_GetInstancePrivate(cx, obj, &plugin_class, NULL);
  521.     if (!plugin)
  522.     return JS_TRUE;
  523.  
  524.     /* Prevent infinite recursion through call to GetSlot below */
  525.     if (plugin->reentrant)
  526.     return JS_TRUE;
  527.  
  528.     switch (slot)
  529.     {
  530.         case PLUGIN_NAME:
  531.             str = plugin->name;
  532.             break;
  533.  
  534.         case PLUGIN_FILENAME:
  535.             str = plugin->filename;
  536.             break;
  537.  
  538.         case PLUGIN_DESCRIPTION:
  539.             str = plugin->description;
  540.             break;
  541.  
  542.         case PLUGIN_ARRAY_LENGTH:
  543.             *vp = INT_TO_JSVAL(plugin->length);
  544.             return JS_TRUE;
  545.  
  546.         default:
  547.             /* Don't mess with a user-defined property. */
  548.             if (slot >= 0 && slot < (jsint) plugin->length) {
  549.         /* Search for an existing JSMIMEType for this slot */
  550.         JSObject* mimetypeObj = NULL;
  551.         jsval val;
  552.  
  553.         plugin->reentrant = TRUE;
  554.         if (JS_GetElement(cx, obj, slot, &val) && JSVAL_IS_OBJECT(val))
  555.             mimetypeObj = JSVAL_TO_OBJECT(val);
  556.         else {
  557.             JSMIMEType* mimetype;
  558.             mimetype = plugin_create_mimetype(cx, plugin, FALSE, NULL, slot);
  559.             if (mimetype)
  560.             mimetypeObj = mimetype->obj;
  561.                 }
  562.         plugin->reentrant = FALSE;
  563.  
  564.         *vp = OBJECT_TO_JSVAL(mimetypeObj);
  565.         return JS_TRUE;
  566.             }
  567.               return JS_FALSE;
  568.     }
  569.  
  570.     if (str)
  571.     *vp = STRING_TO_JSVAL(str);
  572.     else
  573.     *vp = JS_GetEmptyStringValue(cx);
  574.     return JS_TRUE;
  575. }
  576.  
  577.  
  578. JSBool PR_CALLBACK
  579. plugin_resolve_name(JSContext *cx, JSObject *obj, jsval id)
  580. {
  581.     JSPlugin* plugin;
  582.     jsval val;
  583.     const char * name;
  584.  
  585.     if (!JSVAL_IS_STRING(id))
  586.     return JS_TRUE;
  587.  
  588.     name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  589.  
  590.     plugin = JS_GetPrivate(cx, obj);
  591.     if (!plugin)
  592.     return JS_TRUE;
  593.  
  594.     /* Prevent infinite recursion through call to LookupProperty below */
  595.     if (plugin->reentrant)
  596.     return JS_TRUE;
  597.  
  598.     /* Look for a JSMIMEType object by this name already in our list */
  599.     plugin->reentrant = TRUE;
  600.     if (JS_LookupProperty(cx, obj, name, &val) && JSVAL_IS_OBJECT(val)) {
  601.     plugin->reentrant = FALSE;
  602.         return JS_TRUE;
  603.     }
  604.     plugin->reentrant = FALSE;
  605.  
  606.     /* We don't already have the object, so make a new one */
  607.     if (plugin_create_mimetype(cx, plugin, TRUE, name, 0))
  608.     return JS_TRUE;
  609.  
  610.     /* Still no match for the name?  Must be some other property, or invalid. */
  611.     return JS_TRUE;
  612. }
  613.  
  614.  
  615. void PR_CALLBACK
  616. plugin_finalize(JSContext *cx, JSObject *obj)
  617. {
  618.     JSPlugin* plugin;
  619.  
  620.     plugin = JS_GetPrivate(cx, obj);
  621.     if (!plugin)
  622.         return;
  623.     DROP_BACK_COUNT(plugin->decoder);
  624.     JS_UnlockGCThing(cx, plugin->name);
  625.     JS_UnlockGCThing(cx, plugin->filename);
  626.     JS_UnlockGCThing(cx, plugin->description);
  627.     JS_free(cx, plugin);
  628. }
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635. /*
  636.  * -----------------------------------------------------------------------
  637.  *
  638.  * Reflection of the list of installed plug-ins.
  639.  * The only static property is the array length;
  640.  * the array elements (JSPlugins) are added
  641.  * lazily when referenced.
  642.  *
  643.  * -----------------------------------------------------------------------
  644.  */
  645.  
  646. enum pluginlist_slot
  647. {
  648.     PLUGINLIST_ARRAY_LENGTH = -1
  649. };
  650.  
  651.  
  652. static JSPropertySpec pluginlist_props[] =
  653. {
  654.     {"length",  PLUGINLIST_ARRAY_LENGTH,    JSPROP_READONLY},
  655.     {0}
  656. };
  657.  
  658.  
  659. static JSClass pluginlist_class =
  660. {
  661.     "PluginArray", JSCLASS_HAS_PRIVATE,
  662.     JS_PropertyStub, JS_PropertyStub,
  663.     pluginlist_getProperty, pluginlist_getProperty, pluginlist_enumerate,
  664.     pluginlist_resolve_name, JS_ConvertStub, pluginlist_finalize
  665. };
  666.  
  667.  
  668. static JSFunctionSpec pluginlist_methods[] =
  669. {
  670.     {"refresh", pluginlist_refresh, 0},
  671.     {0}
  672. };
  673.  
  674.  
  675. PR_STATIC_CALLBACK(JSBool)
  676. PluginList(JSContext *cx, JSObject *obj,
  677.      uint argc, jsval *argv, jsval *rval)
  678. {
  679.     return JS_TRUE;
  680. }
  681.  
  682.  
  683. /* Constructor method for a JSPluginList object */
  684. static JSPluginList*
  685. pluginlist_create_self(JSContext *cx, MochaDecoder* decoder, JSObject* parent_obj)
  686. {
  687.     JSObject *obj;
  688.     JSPluginList *pluginlist;
  689.  
  690.     pluginlist = JS_malloc(cx, sizeof(JSPluginList));
  691.     if (!pluginlist)
  692.         return NULL;
  693.     XP_BZERO(pluginlist, sizeof *pluginlist);
  694.  
  695.     obj = JS_InitClass(cx, parent_obj, NULL, &pluginlist_class,
  696.                    PluginList, 0, pluginlist_props, 
  697.                pluginlist_methods, NULL, NULL); 
  698.  
  699.     if (!obj || !JS_SetPrivate(cx, obj, pluginlist)) {
  700.         JS_free(cx, pluginlist);
  701.         return NULL;
  702.     }
  703.  
  704.     pluginlist->decoder = HOLD_BACK_COUNT(decoder);
  705.     pluginlist->obj = obj;
  706.  
  707.     {
  708.         /* Compute total number of plug-ins (potential slots) */
  709.         NPReference ref = NPRefFromStart;
  710.         while (NPL_IteratePluginFiles(&ref, NULL, NULL, NULL))
  711.             pluginlist->length++;
  712.     }
  713.  
  714.     return pluginlist;
  715. }
  716.  
  717.  
  718. /* Look up the plugin for the specified slot of the plug-in list */
  719. static JSPlugin*
  720. pluginlist_create_plugin(JSContext *cx, JSPluginList *pluginlist, XP_Bool byName,
  721.                            const char* targetName, jsint targetSlot)
  722. {
  723.     char* plugname = NULL;
  724.     char* filename = NULL;
  725.     char* description = NULL;
  726.     NPReference plugref = NPRefFromStart;
  727.     jsint slot = 0;
  728.     XP_Bool found = FALSE;
  729.  
  730.     /* Search for the plug-in (by name or slot number) */
  731.     while (NPL_IteratePluginFiles(&plugref, &plugname, &filename, &description)) {
  732.         if (byName)
  733.         found = (plugname && (XP_STRCMP(targetName, plugname) == 0));
  734.     else
  735.         found = (targetSlot == slot);
  736.  
  737.     if (found)
  738.         break;
  739.  
  740.         slot++;
  741.     }
  742.  
  743.     /* Found the plug-in, so create an object and property */
  744.     if (found) {
  745.     JSPlugin* plugin;
  746.     plugin = plugin_create_self(cx, pluginlist->decoder, plugname,
  747.                     filename, description, plugref);
  748.         if (plugin) {
  749.         char *name;
  750.         jsval val;
  751.  
  752.         name = JS_GetStringBytes(plugin->name);
  753.         val = OBJECT_TO_JSVAL(plugin->obj);
  754.         JS_DefineProperty(cx, pluginlist->obj, name, val, NULL, NULL,
  755.                   JSPROP_ENUMERATE | JSPROP_READONLY);
  756.         JS_AliasElement(cx, pluginlist->obj, name, slot);
  757.         }
  758.  
  759.         return plugin;
  760.     }
  761.     return NULL;
  762. }
  763.  
  764.  
  765. JSBool PR_CALLBACK
  766. pluginlist_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  767. {
  768.     JSPluginList *pluginlist;
  769.     jsint slot;
  770.  
  771.     if (!JSVAL_IS_INT(id))
  772.     return JS_TRUE;
  773.  
  774.     slot = JSVAL_TO_INT(id);
  775.  
  776.     pluginlist = JS_GetInstancePrivate(cx, obj, &pluginlist_class, NULL);
  777.     if (!pluginlist)
  778.     return JS_TRUE;
  779.  
  780.     /* Prevent infinite recursion through call to GetSlot below */
  781.     if (pluginlist->reentrant)
  782.     return JS_TRUE;
  783.  
  784.     switch (slot) {
  785.         case PLUGINLIST_ARRAY_LENGTH:
  786.             *vp = INT_TO_JSVAL(pluginlist->length);
  787.             break;
  788.  
  789.         default:
  790.             /* Don't mess with a user-defined property. */
  791.             if (slot >= 0 && slot < (jsint) pluginlist->length) {
  792.  
  793.         /* Search for an existing JSPlugin for this slot */
  794.         JSObject* pluginObj = NULL;
  795.         jsval val;
  796.  
  797.         pluginlist->reentrant = TRUE;
  798.         if (JS_GetElement(cx, obj, slot, &val) && JSVAL_IS_OBJECT(val)) {
  799.                 pluginObj = JSVAL_TO_OBJECT(val);
  800.         }
  801.         else {
  802.             JSPlugin* plugin;
  803.             plugin = pluginlist_create_plugin(cx, pluginlist, FALSE, NULL, slot);
  804.             if (plugin)
  805.                 pluginObj = plugin->obj;
  806.         }
  807.         pluginlist->reentrant = FALSE;
  808.  
  809.         *vp = OBJECT_TO_JSVAL(pluginObj);
  810.         return JS_TRUE;
  811.         }
  812.     }
  813.  
  814.     return JS_TRUE;
  815. }
  816.  
  817.  
  818. JSBool PR_CALLBACK
  819. pluginlist_resolve_name(JSContext *cx, JSObject *obj, jsval id)
  820. {
  821.     JSPluginList* pluginlist;
  822.     jsval val;
  823.     const char * name;
  824.  
  825.     if (!JSVAL_IS_STRING(id))
  826.     return JS_TRUE;
  827.  
  828.     name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  829.  
  830.     pluginlist = JS_GetPrivate(cx, obj);
  831.     if (!pluginlist)
  832.     return JS_TRUE;
  833.  
  834.     /* Prevent infinite recursion through call to LookupProperty below */
  835.     if (pluginlist->reentrant)
  836.     return JS_TRUE;
  837.  
  838.     /* Look for a JSMIMEType object by this name already in our list */
  839.     pluginlist->reentrant = TRUE;
  840.     if (JS_LookupProperty(cx, obj, name, &val) && JSVAL_IS_OBJECT(val))
  841.     {
  842.     pluginlist->reentrant = FALSE;
  843.         return JS_TRUE;
  844.     }
  845.     pluginlist->reentrant = FALSE;
  846.  
  847.     /* We don't already have the object, so make a new one */
  848.     if (pluginlist_create_plugin(cx, pluginlist, TRUE, name, 0))
  849.     return JS_TRUE;
  850.  
  851.     /* Still no match for the name?  Must be some other property, or invalid. */
  852.     return JS_TRUE;
  853. }
  854.  
  855. JSBool PR_CALLBACK
  856. pluginlist_enumerate(JSContext *cx, JSObject *obj)
  857. {
  858.     return JS_TRUE;
  859. }
  860.  
  861. void PR_CALLBACK
  862. pluginlist_finalize(JSContext *cx, JSObject *obj)
  863. {
  864.     JSPluginList* pluginlist;
  865.  
  866.     pluginlist = JS_GetPrivate(cx, obj);
  867.     if (!pluginlist)
  868.     return;
  869.     DROP_BACK_COUNT(pluginlist->decoder);
  870.     JS_free(cx, pluginlist);
  871. }
  872.  
  873.  
  874. JSBool PR_CALLBACK
  875. pluginlist_refresh(JSContext *cx, JSObject *obj,
  876.       uint argc, jsval *argv, jsval *rval)
  877. {
  878.     JSBool value = JS_FALSE;
  879.     JSPluginList* pluginlist;
  880.     JSObject* navigator;
  881.     MochaDecoder* decoder;
  882.     NPError error = NPERR_NO_ERROR;
  883.  
  884.     if (!(pluginlist = JS_GetInstancePrivate(cx, obj, &pluginlist_class, argv)))
  885.         return JS_FALSE;
  886.     decoder = pluginlist->decoder;
  887.  
  888.     /*
  889.      * Evaluate the parameter (if any).  If the parameter
  890.      * is missing or can't be evaluated, default to FALSE.
  891.      */
  892.     if (argc > 0)
  893.     (void) JS_ValueToBoolean(cx, argv[0], &value);
  894.  
  895.     /* Synchronously execute this function on the Mozilla thread */
  896.     error = (NPError) ET_npl_RefreshPluginList(decoder->window_context, value);
  897.     if (error != NPERR_NO_ERROR)
  898.     {
  899.     /* XXX should JS_ReportError() here, but can't happen currently */
  900.     return JS_FALSE;
  901.     }
  902.  
  903.     /*
  904.      * Remove references to the existing navigator object,
  905.      * and make a new one.  If scripts have outstanding
  906.      * references to the old objects, they'll still be
  907.      * valid, but if they reference navigator.plugins
  908.      * anew they'll see any new plug-ins registered by
  909.      * NPL_RefreshPlugins.
  910.      */
  911.     navigator = decoder->navigator;
  912.     decoder->navigator = NULL;  /* Prevent lm_DefineNavigator from short-circuiting */
  913.   /*  lm_crippled_decoder = NULL; */
  914.     lm_crippled_decoder->navigator = NULL; 
  915.     lm_crippled_decoder->navigator = lm_DefineNavigator(decoder);
  916.     if (!decoder->navigator)
  917.     {
  918.     /*
  919.      * We failed to create a new navigator object, so
  920.      * restore the old one (saved in a local variable).
  921.      */
  922.     decoder->navigator = navigator;
  923.     return JS_FALSE;
  924.     }
  925.     return JS_TRUE;
  926. }
  927.  
  928.  
  929.  
  930. /*
  931.  * -----------------------------------------------------------------------
  932.  *
  933.  * Reflection of the list of handled MIME types.
  934.  *
  935.  * -----------------------------------------------------------------------
  936.  */
  937.  
  938. enum mimetypelist_slot
  939. {
  940.     MIMETYPELIST_ARRAY_LENGTH   = -1
  941. };
  942.  
  943.  
  944. static JSPropertySpec mimetypelist_props[] =
  945. {
  946.     {"length",  MIMETYPELIST_ARRAY_LENGTH,  JSPROP_READONLY},
  947.     {0}
  948. };
  949.  
  950.  
  951. static JSClass mimetypelist_class =
  952. {
  953.     "MimeTypeArray", JSCLASS_HAS_PRIVATE,
  954.     JS_PropertyStub, JS_PropertyStub,
  955.     mimetypelist_getProperty, mimetypelist_getProperty, mimetypelist_enumerate,
  956.     mimetypelist_resolve_name, JS_ConvertStub, mimetypelist_finalize
  957. };
  958.  
  959.  
  960. /* Constructor method for a JSMIMETypeList object */
  961. static JSMIMETypeList*
  962. mimetypelist_create_self(JSContext *cx, MochaDecoder* decoder)
  963. {
  964.     JSObject *obj;
  965.     JSMIMETypeList *mimetypelist;
  966.  
  967.     mimetypelist = JS_malloc(cx, sizeof(JSMIMETypeList));
  968.     if (!mimetypelist)
  969.         return NULL;
  970.     XP_BZERO(mimetypelist, sizeof *mimetypelist);
  971.  
  972.     obj = JS_NewObject(cx, &mimetypelist_class, NULL, NULL);
  973.  
  974.     if (!obj || !JS_SetPrivate(cx, obj, mimetypelist)) {
  975.         JS_free(cx, mimetypelist);
  976.         return NULL;
  977.     }
  978.  
  979.     if (!JS_DefineProperties(cx, obj, mimetypelist_props))
  980.     return NULL;
  981.  
  982.     mimetypelist->decoder = HOLD_BACK_COUNT(decoder);
  983.     mimetypelist->obj = obj;
  984.  
  985.     /*
  986.      * Count the number of types in the list.
  987.      * We can't just go by the number of items
  988.      * in the list, since it contains encodings, too.
  989.      */
  990.     {
  991.     XP_List* cinfoList = cinfo_MasterListPointer();
  992.     NET_cdataStruct* cdata = NULL;
  993.     mimetypelist->length = 0;
  994.     while (cinfoList)
  995.     {
  996.             cdata = cinfoList->object;
  997.             if (cdata && cdata->ci.type)
  998.             mimetypelist->length++;
  999.         cinfoList = cinfoList->next;
  1000.     }
  1001.     }
  1002.  
  1003.     return mimetypelist;
  1004. }
  1005.  
  1006. /*
  1007.  * Common code to take a cdata and create a mimetype
  1008.  */
  1009. static JSMIMEType*
  1010. define_mimetype(JSContext* cx, JSMIMETypeList* mimetypelist, 
  1011.         NET_cdataStruct* cdata, jsint targetSlot)
  1012. {
  1013.  
  1014.     JSMIMEType* mimetype;
  1015.     mimetype = mimetype_create_self(cx, mimetypelist->decoder, cdata->ci.type,
  1016.                         cdata->ci.desc, cdata->exts, cdata->num_exts, NULL);
  1017.     if (mimetype) {
  1018.     char *name;
  1019.     name = JS_GetStringBytes(mimetype->type);
  1020.     JS_DefineProperty(cx, mimetypelist->obj, name, 
  1021.               OBJECT_TO_JSVAL(mimetype->obj), NULL, NULL,
  1022.               JSPROP_ENUMERATE | JSPROP_READONLY);
  1023.     JS_AliasElement(cx, mimetypelist->obj, name, targetSlot);
  1024.     }
  1025.  
  1026.     return mimetype;
  1027. }
  1028.  
  1029. /* Create a mimetype property for a specified slot or name */
  1030. static JSMIMEType*
  1031. mimetypelist_create_mimetype(JSContext* cx, JSMIMETypeList* mimetypelist,
  1032.                  XP_Bool byName, const char* targetName, jsint targetSlot)
  1033. {
  1034.     XP_List* cinfoList = cinfo_MasterListPointer();
  1035.     NET_cdataStruct* cdata = NULL;
  1036.     XP_Bool found = FALSE;
  1037.  
  1038.     if (byName) {
  1039.     /* Look up by name */
  1040.     targetSlot = 0;
  1041.     while (cinfoList) {
  1042.             cdata = cinfoList->object;
  1043.             if (cdata) {
  1044.         char* type = cdata->ci.type;
  1045.         if (type && (XP_STRCMP(type, targetName) == 0)) {
  1046.             found = TRUE;
  1047.             break;
  1048.         }
  1049.         }
  1050.         targetSlot++;
  1051.         cinfoList = cinfoList->next;
  1052.     }
  1053.     }
  1054.     else {
  1055.         /*
  1056.          * Look up by slot.
  1057.          * The slot number does not directly correspond to list index,
  1058.          * since not all items in the list correspond to properties
  1059.          * (encodings are in list list as well as types).
  1060.          */
  1061.         uint32 count = targetSlot + 1;
  1062.         while (cinfoList) {
  1063.             cdata = cinfoList->object;
  1064.             if (cdata && cdata->ci.type)
  1065.             count--;
  1066.                 
  1067.             if (count == 0) {
  1068.             found = TRUE;
  1069.             break;
  1070.             }
  1071.  
  1072.         cinfoList = cinfoList->next;
  1073.     }
  1074.     }
  1075.  
  1076.     if (found) 
  1077.     return define_mimetype(cx, mimetypelist, cdata, targetSlot);
  1078.  
  1079.     return NULL;
  1080. }
  1081.  
  1082.  
  1083. JSBool PR_CALLBACK
  1084. mimetypelist_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  1085. {
  1086.     JSMIMETypeList *mimetypelist;
  1087.     jsint slot;
  1088.  
  1089.     if (!JSVAL_IS_INT(id))
  1090.     return JS_TRUE;
  1091.  
  1092.     slot = JSVAL_TO_INT(id);
  1093.  
  1094.     mimetypelist = JS_GetInstancePrivate(cx, obj, &mimetypelist_class, NULL);
  1095.     if (!mimetypelist)
  1096.     return JS_TRUE;
  1097.  
  1098.     /* Prevent infinite recursion through call to GetSlot below */
  1099.     if (mimetypelist->reentrant)
  1100.     return JS_TRUE;
  1101.  
  1102.     switch (slot)
  1103.     {
  1104.         case MIMETYPELIST_ARRAY_LENGTH:
  1105.             *vp = INT_TO_JSVAL(mimetypelist->length);
  1106.             break;
  1107.  
  1108.         default:
  1109.             /* Don't mess with a user-defined property. */
  1110.             if (slot >= 0 && slot < (jsint) mimetypelist->length) {
  1111.         /* Search for an existing JSMIMEType for this slot */
  1112.         JSObject* mimetypeObj = NULL;
  1113.         jsval val = JSVAL_VOID;
  1114.  
  1115.         mimetypelist->reentrant = TRUE;
  1116.         if (JS_GetElement(cx, obj, slot, &val) && JSVAL_IS_OBJECT(val)) {
  1117.             mimetypeObj = JSVAL_TO_OBJECT(val);
  1118.         }
  1119.         else {
  1120.             JSMIMEType* mimetype;
  1121.             mimetype = mimetypelist_create_mimetype(cx, mimetypelist, FALSE, NULL, slot);
  1122.             if (mimetype)
  1123.             mimetypeObj = mimetype->obj;
  1124.         }
  1125.         mimetypelist->reentrant = FALSE;
  1126.  
  1127.         *vp = OBJECT_TO_JSVAL(mimetypeObj);
  1128.                 return JS_TRUE;
  1129.             }
  1130.             break;
  1131.     }
  1132.  
  1133.     return JS_TRUE;
  1134. }
  1135.  
  1136.  
  1137. JSBool PR_CALLBACK
  1138. mimetypelist_resolve_name(JSContext *cx, JSObject *obj, jsval id)
  1139. {
  1140.     JSMIMETypeList* mimetypelist;
  1141.     jsval val;
  1142.     const char * name;
  1143.  
  1144.     if (!JSVAL_IS_STRING(id))
  1145.     return JS_TRUE;
  1146.  
  1147.     name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  1148.  
  1149.     mimetypelist = JS_GetPrivate(cx, obj);
  1150.     if (!mimetypelist)
  1151.     return JS_TRUE;
  1152.  
  1153.     /* Prevent infinite recursion through call to LookupProperty below */
  1154.     if (mimetypelist->reentrant)
  1155.     return JS_TRUE;
  1156.  
  1157.     /* Look for a JSMIMEType object by this name already in our list */
  1158.     mimetypelist->reentrant = TRUE;
  1159.     if (JS_LookupProperty(cx, obj, name, &val) && JSVAL_IS_OBJECT(val))
  1160.     {
  1161.     mimetypelist->reentrant = FALSE;
  1162.         return JS_TRUE;
  1163.     }
  1164.     mimetypelist->reentrant = FALSE;
  1165.  
  1166.     /* We don't already have the object, so make a new one */
  1167.     if (mimetypelist_create_mimetype(cx, mimetypelist, TRUE, name, 0))
  1168.     return JS_TRUE;
  1169.  
  1170.     /* Still no match for the name?  Must be some other property, or invalid. */
  1171.     return JS_TRUE;
  1172. }
  1173.  
  1174. JSBool PR_CALLBACK
  1175. mimetypelist_enumerate(JSContext *cx, JSObject *obj)
  1176. {
  1177.     JSMIMETypeList* mimetypelist;
  1178.     XP_List* cinfoList = cinfo_MasterListPointer();
  1179.     NET_cdataStruct* cdata = NULL;
  1180.     jsint targetSlot = 0;
  1181.  
  1182.     mimetypelist = JS_GetPrivate(cx, obj);
  1183.     if (!mimetypelist)
  1184.     return JS_TRUE;
  1185.  
  1186.     while (cinfoList) {
  1187.         cdata = cinfoList->object;
  1188.         if (cdata)
  1189.         define_mimetype(cx, mimetypelist, cdata, targetSlot++);
  1190.     cinfoList = cinfoList->next;
  1191.     }
  1192.  
  1193.     return JS_TRUE;   
  1194. }
  1195.  
  1196. void PR_CALLBACK
  1197. mimetypelist_finalize(JSContext *cx, JSObject *obj)
  1198. {
  1199.     JSMIMETypeList *mimetypelist;
  1200.  
  1201.     mimetypelist = JS_GetPrivate(cx, obj);
  1202.     if (!mimetypelist)
  1203.     return;
  1204.     DROP_BACK_COUNT(mimetypelist->decoder);
  1205.     JS_free(cx, mimetypelist);
  1206. }
  1207.  
  1208.  
  1209.  
  1210.  
  1211. /*
  1212.  * Exported entry point, called from lm_nav.c.
  1213.  * This function creates the JSPluginList object.  The
  1214.  * properties for the installed plug-ins are instantiated
  1215.  * lazily in pluginlist_resolve_name.
  1216.  */
  1217. JSObject*
  1218. lm_NewPluginList(JSContext *cx, JSObject *parent_obj)
  1219. {
  1220.     MochaDecoder* decoder;
  1221.     JSPluginList* pluginlist;
  1222.  
  1223.     decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  1224.     pluginlist = pluginlist_create_self(cx, decoder, parent_obj);
  1225.     return (pluginlist ? pluginlist->obj : NULL);
  1226. }
  1227.  
  1228.  
  1229.  
  1230.  
  1231. /*
  1232.  * Exported entry point to this file, called from lm_nav.c.
  1233.  * This function creates the JSMIMETypeList object.  The
  1234.  * properties for the MIME types are instantiated
  1235.  * lazily in mimetypelist_resolve_name.
  1236.  */
  1237. JSObject*
  1238. lm_NewMIMETypeList(JSContext *cx)
  1239. {
  1240.     MochaDecoder* decoder;
  1241.     JSMIMETypeList* mimetypelist;
  1242.  
  1243.     decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  1244.     mimetypelist = mimetypelist_create_self(cx, decoder);
  1245.     return (mimetypelist ? mimetypelist->obj : NULL);
  1246. }
  1247.  
  1248. JSBool
  1249. lm_DefinePluginClasses(MochaDecoder *decoder)
  1250. {
  1251.     JSContext *cx = decoder->js_context;
  1252.  
  1253.     if (!JS_InitClass(cx, decoder->window_object, NULL, &mimetype_class,
  1254.               MimeType, 0, mimetype_props, NULL, NULL, NULL))
  1255.     return JS_FALSE;
  1256.  
  1257.     if (!JS_InitClass(cx, decoder->window_object, NULL, &plugin_class,
  1258.               Plugin, 0, plugin_props, NULL, NULL, NULL))
  1259.         return JS_FALSE;
  1260.  
  1261.     return JS_TRUE;
  1262. }
  1263.