home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / layout / layobj.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  33.3 KB  |  1,326 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.  
  20. #include "xp.h"
  21. #include "net.h"
  22. #include "pa_parse.h"
  23. #include "layout.h"
  24. #include "np.h"
  25. #ifdef JAVA
  26. #include "java.h"
  27. #endif
  28.  
  29. #ifdef    ANTHRAX /* 9.23.97    amusil */
  30. #include "prefapi.h"
  31. #endif    /* ANTHRAX */
  32.  
  33. /* Internal prototypes */
  34. void lo_FetchObjectData(MWContext*, lo_DocState*, lo_ObjectStack*);
  35. void lo_ObjectURLExit(URL_Struct*, int, MWContext*);
  36. void lo_ClearObjectBlock(MWContext*, LO_ObjectStruct*);
  37. lo_ObjectStack* lo_PushObject(MWContext*, lo_DocState*, PA_Tag*);
  38. void lo_PopObject(lo_DocState*);
  39. Bool lo_CheckObjectBlockage(MWContext*, lo_DocState*, lo_ObjectStack*);
  40.  
  41. #ifdef    ANTHRAX        /* 9.23.97    amusil */
  42. static void lo_SetClassID(PA_Tag* tag, char* appletName);
  43. static char* lo_GetNextName(char** index);
  44. static char* lo_GetNextValue(char** index);
  45. static void lo_SetJavaArgs(char* tag, LO_JavaAppStruct* current_java);
  46. static void lo_itoa(uint32 n, char* s);
  47. static void lo_ReverseString(char* s);
  48. #endif    /* ANTHRAX */
  49.  
  50. void
  51. lo_FormatObject(MWContext* context, lo_DocState* state, PA_Tag* tag)
  52. {
  53.     lo_TopState* top_state = state->top_state;
  54.     lo_ObjectStack* top;
  55.     LO_ObjectStruct* object;
  56.     PA_Block buff;
  57.     int16 type = LO_NONE;
  58.     char* str;
  59.  
  60. #ifdef    ANTHRAX
  61.     XP_Bool javaMimetypeHandler = FALSE;
  62.     char* appletName;
  63.     NET_cinfo* fileInfo;
  64. #endif /* ANTHRAX */
  65.     
  66.     /*
  67.      * Make a new default object.  Passing LO_OBJECT will create an
  68.      * LO_Element, which being a union of all other layout element types
  69.      * is guaranteed to be big enough to transmogrify into one of these
  70.      * specific types later if necessary.
  71.      */
  72.     object = (LO_ObjectStruct*) lo_NewElement(context, state, LO_OBJECT, NULL, 0);
  73.     if (object == NULL)
  74.     {
  75.         state->top_state->out_of_memory = TRUE;
  76.         return;
  77.     }
  78.     
  79.     top = top_state->object_stack;
  80.     top->object = object;
  81.  
  82.     /*
  83.      * Set up default fields for this object that are common
  84.      * to all possible object types.
  85.      */
  86.     object->lo_element.type = LO_NONE;
  87.     object->lo_element.lo_any.ele_id = NEXT_ELEMENT;
  88.     object->lo_element.lo_any.x = state->x;
  89.     object->lo_element.lo_any.x_offset = 0;
  90.     object->lo_element.lo_any.y = state->y;
  91.     object->lo_element.lo_any.y_offset = 0;
  92.     object->lo_element.lo_any.width = 0;
  93.     object->lo_element.lo_any.height = 0;
  94.     object->lo_element.lo_any.next = NULL;
  95.     object->lo_element.lo_any.prev = NULL;
  96.  
  97.     
  98.     /*
  99.      * Now attempt to figure out what type of object we have.
  100.      * If the type can be determined here, great; otherwise
  101.      * we have to block until the type can be determined by
  102.      * reading in additional data.
  103.      *
  104.      * Initially the type of the object is LO_NONE.  When
  105.      * we figure out enough to know the type, we set it to
  106.      * LO_EMBED, LO_JAVA, or LO_IMAGE.  If the type had
  107.      * already been changed to a different incompatible type,
  108.      * then the tag is malformed and we should ignore it, so
  109.      * set the type to LO_UNKNOWN.
  110.      */
  111.     
  112. #if 0 
  113.     /*
  114.      * Check the "codetype" attribute, which optionally determines
  115.      * the MIME type of the object code itself (as opposed to its
  116.      * data).  The only code type we know about right now is
  117.      * application/java-vm for Java applets.
  118.      */
  119.     buff = lo_FetchParamValue(context, tag, PARAM_CODETYPE);
  120.     if (buff != NULL)
  121.     {
  122.         PA_LOCK(str, char *, buff);
  123.         if (pa_TagEqual(APPLICATION_JAVAVM, str))
  124.         {
  125.             /* It's a Java applet */
  126.             if (type == LO_NONE)
  127.                 type = LO_JAVA;
  128.             else if (type != LO_JAVA)
  129.                 type = LO_UNKNOWN;
  130.         }
  131.         else if (pa_TagEqual(APPLICATION_OLEOBJECT, str) ||
  132.                  pa_TagEqual(APPLICATION_OLEOBJECT2, str))
  133.         {
  134.             /* It's an OLE object */
  135.             if (type == LO_NONE)
  136.                 type = LO_EMBED;
  137.             else if (type != LO_EMBED)
  138.                 type = LO_UNKNOWN;
  139.         }
  140.         PA_UNLOCK(buff);
  141.         XP_FREE(buff);
  142.     }
  143. #endif
  144.  
  145.     /*
  146.      * Check the "classid" attribute, which optionally determines
  147.      * the specific implementation of the object.  The classid
  148.      * could be a normal URL, in which case we have to retrieve
  149.      * that URL and match it against a known code type (see above).
  150.      * There are also two "magic" URL types supported for classid:
  151.      * "clsid:", which indicates a COM 376-hex-digit class ID,
  152.      * and "java:", which indicates a specific java class to run.
  153.      * Note that the "java:" URL is different from the APPLET
  154.      * "code" attribute: the "java:" URL specifies a particular
  155.      * method (e.g. "java:program.run"), while the APPLET CODE
  156.      * attribute specifies an applet subclass (e.g. "MyApplet.class").
  157.      *
  158.      * Further notes about "java:"
  159.      * We are adding two related "magic" protocol selectors to
  160.      * augment "java:". These are "javaprogram:" and "javabean:".
  161.      * They are used with embedded applications and application
  162.      * objects. "javaprogram:" identifies an object as being a
  163.      * subclass of netscape.application.Application, and is used
  164.      * to start an instance of such application. "javabean:" is
  165.      * used to add an embedded object to an application.
  166.      */
  167.     buff = lo_FetchParamValue(context, tag, PARAM_CLASSID);
  168.     if (buff != NULL)
  169.     {
  170.         PA_LOCK(str, char *, buff);
  171.         if (XP_STRNCASECMP(str, "clsid:", 6) == 0)
  172.         {
  173.             /*
  174.              * It's a COM class ID, so make sure we have an
  175.              * appropriate plug-in to handle ActiveX controls.
  176.              */
  177.             if (NPL_FindPluginEnabledForType(APPLICATION_OLEOBJECT) != NULL)
  178.             {
  179.                 if (type == LO_NONE)
  180.                     type = LO_EMBED;
  181.                 else if (type != LO_EMBED)
  182.                     type = LO_UNKNOWN;
  183.             }
  184.         }
  185.         else if ( (XP_STRNCASECMP(str, "java:", 5) == 0) ||
  186.                   (XP_STRNCASECMP(str, "javaprogram:", 12) == 0) ||
  187.                   (XP_STRNCASECMP(str, "javabean:", 9) == 0) )
  188.         {
  189.             /* It's a Java class */
  190.             if (type == LO_NONE)
  191.                 type = LO_JAVA;
  192.             else if (type != LO_JAVA)
  193.                 type = LO_UNKNOWN;
  194.         }
  195.         else
  196.         {
  197.             /*
  198.              * Must be a URL to the code; we'll need to fetch it to
  199.              * determine the type.  bing: How should we do this?
  200.              */
  201.         }
  202.         PA_UNLOCK(buff);
  203.         XP_FREE(buff);
  204.     }
  205.  
  206.     /*
  207.      * Check the "type" attribute, which optionally determines
  208.      * the type of the data for the object.  The data type
  209.      * can be used to infer the object implementation type if
  210.      * the implementation hasn't been specified via "classid"
  211.      * or "codetype" (see above).  The two kinds of objects
  212.      * we currently support with typed data are plug-ins and
  213.      * images; for plug-ins we can ask libplug if the type is
  214.      * currently handled by a plug-in; for images we just check
  215.      * against a hard-coded list of image types we natively
  216.      * support (yuck).
  217.      */
  218.     buff = lo_FetchParamValue(context, tag, PARAM_TYPE);
  219.     if (buff != NULL)
  220.     {
  221.         PA_LOCK(str, char *, buff);
  222.         if (NPL_FindPluginEnabledForType(str) != NULL)
  223.         {
  224.             /* It's a plug-in */
  225.             if (type == LO_NONE)
  226.                 type = LO_EMBED;
  227.             else if (type != LO_EMBED)
  228.                 type = LO_UNKNOWN;
  229.         }
  230.  
  231.         /*  
  232.             Adding a check for applets that handle mimetypes.
  233.             The pref is stored based on the particular mimetype.
  234.             We do a lookup and if there is an association, the name
  235.             of the applet is placed into "appletName".  
  236.             
  237.             NOTE: PREF_CopyCharPref() allocates memory for appletName
  238.                     and we must free it.
  239.                     
  240.             9.23.97        amusil
  241.         */
  242. #ifdef    ANTHRAX
  243.         if((appletName = NPL_FindAppletEnabledForMimetype(str)) != NULL)
  244.             {
  245.             /* Set the type */
  246.             type = LO_JAVA;
  247.             
  248.             /* set the CLASSID to whatever was put into "appletName" */
  249.             lo_SetClassID(tag, appletName);
  250.             
  251.             /* set this so that we know later to translate the DATA/SRC param to a Java arg */
  252.             javaMimetypeHandler = TRUE;
  253.             XP_FREE(appletName);
  254.             }
  255. #endif    /* ANTHRAX */    
  256.         
  257. #if 0
  258.         else if (XP_STRNCASECMP(str, "image/", 6) == 0)
  259.         {
  260.             if (XP_STRCASECMP(str, IMAGE_GIF) ||
  261.                 XP_STRCASECMP(str, IMAGE_JPG) ||
  262.                 XP_STRCASECMP(str, IMAGE_PJPG) ||
  263.                 XP_STRCASECMP(str, IMAGE_XBM) ||
  264.                 XP_STRCASECMP(str, IMAGE_XBM2) ||
  265.                 XP_STRCASECMP(str, IMAGE_XBM3))
  266.             {
  267.                 /* It's an image */
  268.                 if (type == LO_NONE)
  269.                     type = LO_IMAGE;
  270.                 else if (type != LO_IMAGE)
  271.                     type = LO_UNKNOWN;
  272.             }
  273.         }
  274. #endif /* if 0 */
  275.  
  276. #ifdef SHACK
  277.         if (XP_STRNCASECMP(str, "builtin", 7) == 0)
  278.         {
  279.             if (type == LO_NONE)
  280.                 type = LO_EMBED;
  281.             else if (type != LO_EMBED)
  282.                 type = LO_UNKNOWN;
  283.         }
  284. #endif /* SHACK */
  285.  
  286.         PA_UNLOCK(buff);
  287.         XP_FREE(buff);
  288.     }
  289. #ifdef    ANTHRAX
  290.     else /* we didn't find a TYPE param, so check the filename to get the type - amusil */
  291.         {
  292.         buff = lo_FetchParamValue(context, tag, PARAM_SRC);
  293.         /* if no src, check if there's a DATA param */
  294.         if(buff == NULL)
  295.             buff = lo_FetchParamValue(context, tag, PARAM_DATA);
  296.             
  297.         
  298.         /* extract the mimetype info */
  299.         PA_LOCK(str, char *, buff);
  300.         fileInfo = NET_cinfo_find_type(str);
  301.         
  302.         str = fileInfo->type;
  303.         if((appletName = NPL_FindAppletEnabledForMimetype(str)) != NULL)
  304.             {
  305.             /* Set the type */
  306.             type = LO_JAVA;
  307.             
  308.             /* set the CLASSID to whatever was put into "appletName" */
  309.             lo_SetClassID(tag, appletName);
  310.             
  311.             /* set this so that we know later to translate the DATA/SRC param to a Java arg */
  312.             javaMimetypeHandler = TRUE;
  313.             XP_FREE(appletName);            /* do we need to free this regardless? */    
  314.             }
  315.         if(buff)
  316.             XP_FREE(buff);
  317.         }
  318. #endif    /* ANTRHAX */
  319.  
  320.  
  321.     if (type == LO_EMBED)
  322.     {
  323.         object->lo_element.type = LO_EMBED;
  324.     }
  325. #ifdef JAVA
  326.     else if (type == LO_JAVA)
  327.     {
  328.         if (LJ_GetJavaEnabled() != FALSE)
  329.         {
  330.             /*
  331.              * Close out the current applet if necessary
  332.              * (people tend to forget "</APPLET>").
  333.              */
  334.             if (state->current_java != NULL)
  335.                 lo_CloseJavaApp(context, state, state->current_java);
  336.                 
  337.             object->lo_element.type = LO_JAVA;
  338.             lo_FormatJavaObject(context, state, tag, (LO_JavaAppStruct*) object);
  339.             
  340.             /* 
  341.                 If we determined previously that this is an applet to mimetype
  342.                 association, we must set up the SRC or DATA as an arg for the 
  343.                 applet.
  344.                 
  345.                 9.8.97        amusil
  346.             */
  347. #ifdef    ANTHRAX
  348.             if(javaMimetypeHandler)
  349.                 lo_SetJavaArgs((char*)tag->data, state->current_java);
  350. #endif    /* ANTHRAX */
  351.         }
  352.     }
  353. #endif /* JAVA */
  354. #if 0
  355.     else if (type == LO_IMAGE)
  356.     {
  357.         object->type = LO_IMAGE;
  358.         lo_FormatImageObject(context, state, tag, (LO_ImageStruct*) object);
  359.     }
  360. #endif /* if 0 */
  361.     else
  362.     {
  363.         /*
  364.          * Check for a "data" attribute; if it exists, we can get
  365.          * the URL later to see what the type of the object should be.
  366.          */
  367.         buff = lo_FetchParamValue(context, tag, PARAM_DATA);
  368.         if (buff != NULL)
  369.         {
  370.             PA_LOCK(str, char *, buff);
  371.             if (XP_STRNCASECMP(str, "data:", 5) == 0)
  372.             {
  373.                 /* bing: deal with magic data URLs here */
  374.                 PA_UNLOCK(buff);
  375.                 XP_FREE(buff);
  376.             }
  377.             else
  378.             {
  379.                 
  380.                 /*
  381.                  * Block layout until we can read the PARAM tags
  382.                  * and closing </OBJECT> tag, go get the data URL,
  383.                  * and determine its type.  At that point (in
  384.                  * either LO_NewObjectStream, or lo_ObjectURLExit),
  385.                  * we know the object type and can unblock.
  386.                  */
  387.                 top->data_url = str;
  388.                 state->top_state->layout_blocking_element = (LO_Element*) object;
  389.                 PA_UNLOCK(buff);
  390.                 /* Don't free buff; we stored it in the object stack */
  391.             }
  392.         }
  393.         else
  394.         {
  395.             /*
  396.              * Otherwise we just don't know what to do with this!
  397.              */
  398.             object->lo_element.type = LO_UNKNOWN;
  399.         }
  400.     }
  401. }
  402.  
  403.  
  404.  
  405.  
  406. /* 
  407.  * Takes a "PARAM" tag and pointers to the object's attribute
  408.  * count, attribute name array, and attribute value array.
  409.  * Parses the name and value of the PARAM and adjusts the
  410.  * attribute count, names, and values accordingly.
  411.  */
  412. void
  413. lo_ObjectParam(MWContext* context, lo_DocState* state, PA_Tag* tag,
  414.                uint32* count, char*** names, char*** values)
  415. {
  416.     PA_Block buff;
  417.     char *str;
  418.     char *param_name = NULL;
  419.     char *param_value = NULL;
  420.     char **name_list;
  421.     char **value_list;
  422.     
  423.     /*
  424.      * Get the name of this parameter.
  425.      */
  426.     buff = lo_FetchParamValue(context, tag, PARAM_NAME);
  427.     if (buff != NULL)
  428.     {
  429.         PA_LOCK(str, char *, buff);
  430.         if (str != NULL)
  431.         {
  432.             int32 len;
  433.             char *new_str;
  434.  
  435.             len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  436.             new_str = (char *)XP_ALLOC(len + 1);
  437.             if (new_str != NULL)
  438.             {
  439.                 XP_STRCPY(new_str, str);
  440.             }
  441.             param_name = new_str;
  442.         }
  443.         PA_UNLOCK(buff);
  444.         PA_FREE(buff);
  445.     }
  446.     else
  447.     {
  448.         /* If we don't have a parameter name, it's useless */
  449.         return;
  450.     }
  451.  
  452.     /*
  453.      * Get the value of this parameter.
  454.      */
  455.     buff = lo_FetchParamValue(context, tag, PARAM_VALUE);
  456.     if (buff != NULL)
  457.     {
  458.         PA_LOCK(str, char *, buff);
  459.         if (str != NULL)
  460.         {
  461.             int32 len;
  462.             char *new_str;
  463.  
  464.             len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  465.             new_str = (char *)XP_ALLOC(len + 1);
  466.             if (new_str != NULL)
  467.             {
  468.                 XP_STRCPY(new_str, str);
  469.             }
  470.             param_value = new_str;
  471.         }
  472.         PA_UNLOCK(buff);
  473.         PA_FREE(buff);
  474.     }
  475.  
  476.     /*
  477.      * Add the parameter to the name/value list.
  478.      */
  479.     if (*names == NULL)
  480.         name_list = (char **)XP_ALLOC(sizeof(char *));
  481.     else
  482.         name_list = (char **)XP_REALLOC(*names,
  483.                         ((*count + 1) * sizeof(char *)));
  484.     
  485.     /*
  486.      * If we run out of memory here, free up what
  487.      * we can and return.
  488.      */
  489.     if (name_list == NULL)
  490.     {
  491.         state->top_state->out_of_memory = TRUE;
  492.         XP_FREE(param_name);
  493.         if (param_value != NULL)
  494.             XP_FREE(param_value);
  495.         return;
  496.     }
  497.  
  498.     if (*values == NULL)
  499.         value_list = (char **)XP_ALLOC(sizeof(char *));
  500.     else
  501.         value_list = (char **)XP_REALLOC(*values,
  502.                         ((*count + 1) * sizeof(char *)));
  503.  
  504.     /*
  505.      * If we run out of memory here, free up what
  506.      * we can and return.
  507.      */
  508.     if (value_list == NULL)
  509.     {
  510.         state->top_state->out_of_memory = TRUE;
  511.         XP_FREE(param_name);
  512.         if (param_value != NULL)
  513.             XP_FREE(param_value);
  514.         return;
  515.     }
  516.     
  517.     *names = name_list;
  518.     *values = value_list;
  519.     (*names)[*count] = param_name;
  520.     (*values)[*count] = param_value;
  521.     (*count)++;
  522.  
  523. }
  524.  
  525.  
  526. /*
  527.  * Appends the name/value list in count2, names2, and values2 on
  528.  * to the name/value list in count1, names1, and values1.
  529.  */
  530. void
  531. lo_AppendParamList(uint32* count1, char*** names1, char*** values1,
  532.                    uint32 count2, char** names2, char** values2)
  533. {        
  534.     char** names = NULL;
  535.     char** values = NULL;
  536.     
  537.     if (*names1 != NULL)
  538.     {
  539.         if (names2 != NULL)
  540.         {
  541.             names = (char**) XP_REALLOC(*names1, ((*count1 + count2) * sizeof(char*)));
  542.             if (names != NULL)
  543.                 XP_MEMCPY(&(names[*count1]), names2, count2 * sizeof(char*));
  544.         }
  545.         else
  546.             names = *names1;
  547.     }
  548.     else
  549.         names = names2;
  550.         
  551.     if (*values1 != NULL)
  552.     {
  553.         if (values2 != NULL)
  554.         {
  555.             values = (char**) XP_REALLOC(*values1, ((*count1 + count2) * sizeof(char*)));
  556.             if (values != NULL)
  557.                 XP_MEMCPY(&(values[*count1]), values2, count2 * sizeof(char*));
  558.         }
  559.         else
  560.             values = *values1;
  561.     }
  562.     else
  563.         values = values2;
  564.         
  565.     if (names != NULL && values != NULL)
  566.     {
  567.         *count1 = *count1 + count2;
  568.         *names1 = names;
  569.         *values1 = values;
  570.     }
  571. }
  572.  
  573.  
  574.  
  575. lo_ObjectStack*
  576. lo_PushObject(MWContext* context, lo_DocState* state, PA_Tag* tag)
  577. {
  578.     /*
  579.      * If possible, reuse an object stack entry created in
  580.      * a previous pass over this tag (i.e. while blocked, by
  581.      * lo_BlockObjectTag).  If there's no previously-created
  582.      * object, make a new one.
  583.      */
  584.     lo_TopState* top_state = state->top_state;
  585.     lo_ObjectStack* new_top = top_state->object_cache;
  586.  
  587.     if (new_top != NULL)
  588.     {
  589.         /* Find and remove the matching item, if any */
  590.         if (new_top->real_tag == tag)
  591.             top_state->object_cache = new_top->next;
  592.         else
  593.         {
  594.             while (new_top->next != NULL)
  595.             {
  596.                 if (new_top->next->real_tag == tag)
  597.                 {
  598.                     lo_ObjectStack* temp = new_top->next;
  599.                     new_top->next = new_top->next->next;
  600.                     new_top = temp;
  601.                     break;
  602.                 }
  603.                 new_top = new_top->next;
  604.             }
  605.         }
  606.     }
  607.     
  608.     if (new_top == NULL || new_top->real_tag != tag)
  609.     {
  610.         new_top = XP_NEW_ZAP(lo_ObjectStack);
  611.         if (new_top == NULL)
  612.         {
  613.             state->top_state->out_of_memory = TRUE;
  614.             return NULL;
  615.         }
  616.     }
  617.     
  618.     new_top->next = top_state->object_stack;
  619.     top_state->object_stack = new_top;
  620.  
  621.     new_top->context = context;
  622.     new_top->state = state;
  623.     
  624.     /*
  625.      * Clone the tag since the tag passed in may be freed
  626.      * by the parser before we're ready for it.
  627.      */
  628.     if (new_top->real_tag != tag)
  629.     {
  630.         new_top->real_tag = tag;
  631.  
  632.         if (new_top->clone_tag != NULL)
  633.             PA_FreeTag(new_top->clone_tag);
  634.  
  635.         new_top->clone_tag = XP_NEW(PA_Tag);
  636.         if (new_top->clone_tag != NULL)
  637.         {
  638.             XP_MEMCPY(new_top->clone_tag, tag, sizeof(PA_Tag));
  639.             new_top->clone_tag->data = PA_ALLOC((tag->data_len + 1) * sizeof (char)); 
  640.             if (new_top->clone_tag->data != NULL)
  641.             {
  642.                 char* source;
  643.                 char* dest;
  644.                 PA_LOCK(source, char*, tag->data);
  645.                 PA_LOCK(dest, char*, new_top->clone_tag->data);
  646.                 XP_MEMCPY(dest, source, tag->data_len + 1);
  647.                 PA_UNLOCK(dest);
  648.                 PA_UNLOCK(source);
  649.             }
  650.         }
  651.     }
  652.     
  653.     return new_top;
  654. }
  655.  
  656.  
  657. void
  658. lo_PopObject(lo_DocState* state)
  659. {
  660.     lo_TopState* top_state = state->top_state;
  661.     lo_ObjectStack* top = top_state->object_stack;
  662.     if (top == NULL)
  663.         return;
  664.  
  665.     /* Unlink from stack */
  666.     top_state->object_stack = top->next;
  667.  
  668.     /* Add to cache */
  669.     top->next = top_state->object_cache;
  670.     top_state->object_cache = top;
  671. }
  672.  
  673.  
  674. void
  675. lo_DeleteObjectStack(lo_ObjectStack* top)
  676. {
  677.     /* Delete parameters */
  678.     if (top->param_count > 0)
  679.     {
  680.         uint32 index;
  681.         
  682.         if (top->param_values != NULL)
  683.         {
  684.             for (index = 0; index < top->param_count; index++)
  685.             {
  686.                 if (top->param_names[index] != NULL)
  687.                     XP_FREE(top->param_names[index]);
  688.             }
  689.             XP_FREE(top->param_names);
  690.         }
  691.         
  692.         if (top->param_values != NULL)
  693.         {
  694.             for (index = 0; index < top->param_count; index++)
  695.             {
  696.                 if (top->param_values[index] != NULL)
  697.                     XP_FREE(top->param_values[index]);
  698.             }
  699.             XP_FREE(top->param_values);
  700.         }
  701.     }
  702.     
  703.     /* Delete tag copy */
  704.     if (top->clone_tag != NULL)
  705.         PA_FreeTag(top->clone_tag);
  706.         
  707.     /* Delete object */
  708.     XP_FREE(top);
  709. }
  710.  
  711.  
  712.  
  713. Bool
  714. lo_CheckObjectBlockage(MWContext* context, lo_DocState* state, lo_ObjectStack* top)
  715. {
  716.     LO_ObjectStruct* object = top->object;
  717.     
  718.     if (object != NULL &&
  719.         state->top_state->layout_blocking_element == (LO_Element*) object)
  720.     {
  721.         /*
  722.          * We're blocked on this object, and we need to start
  723.          * a data stream to figure out the object type. Now
  724.          * that we've read the PARAMs, it's OK to start the
  725.          * stream.
  726.          */
  727.         if (top->data_url != NULL)
  728.         {
  729.             XP_ASSERT(object->lo_element.type == LO_NONE);
  730.             lo_FetchObjectData(context, state, top);
  731.         }
  732.         else
  733.         {
  734.             XP_ASSERT(FALSE);
  735.             object->lo_element.type = LO_UNKNOWN;
  736.         }
  737.         
  738.         return TRUE;    /* Yes, we're the cause of the blockage */
  739.     }
  740.     
  741.     return FALSE;        /* No, some enclosing object is the block point */
  742. }
  743.  
  744.  
  745.  
  746. void
  747. lo_ProcessObjectTag(MWContext* context, lo_DocState* state, PA_Tag* tag, XP_Bool blocked)
  748. {
  749.     lo_TopState* top_state = state->top_state;
  750.     lo_ObjectStack* top = top_state->object_stack;
  751.     LO_ObjectStruct* object = top ? top->object : NULL;
  752.  
  753.     if (tag->is_end == FALSE)
  754.     {
  755.         lo_ObjectStack* new_top;
  756.  
  757.         /*
  758.          * If we have started loading an OBJECT we are
  759.          * out if the HEAD section of the HTML
  760.          * and into the BODY
  761.          */
  762.         if (blocked == FALSE)
  763.         {
  764.             state->top_state->in_head = FALSE;
  765.             state->top_state->in_body = TRUE;
  766.         }
  767.  
  768.         /*
  769.          * Push a new entry onto the stack.  If blocked,
  770.          * also stash it in the tag's lo_data so we can
  771.          * reuse it later when not blocked.
  772.          */
  773.         new_top = lo_PushObject(context, state, tag);
  774.         if (blocked)
  775.         {
  776.             XP_ASSERT(tag->lo_data == NULL);
  777.             tag->lo_data = (void*) new_top;
  778.         }
  779.         
  780.         /*
  781.          * If we're not blocked, and not in the middle of a handled
  782.          * object, go process this object tag. Otherwise ignore the
  783.          * the tag (we don't just filter it out in lo_FilterTag
  784.          * because we need to keep track of the object nesting to
  785.          * match up with the right </OBJECT>).
  786.          */
  787.         if (blocked == FALSE)
  788.         {
  789.             if (object == NULL || object->lo_element.type == LO_UNKNOWN)
  790.             {
  791.                 lo_FormatObject(context, state, tag);
  792.  
  793.                 /*
  794.                  * If we've already read the PARAMs, we can try deal
  795.                  * with the blockage now (in fact, we must).  If we
  796.                  * haven't read the params yet, we have to wait until
  797.                  * our matching </OBJECT> tag (this will be handled
  798.                  * by the code below).
  799.                  */
  800.                 if (new_top->read_params)
  801.                     lo_CheckObjectBlockage(context, state, new_top);
  802.             }
  803.         }
  804.     }
  805.     else
  806.     {
  807.         if (top != NULL)
  808.         {
  809.             if (blocked)
  810.             {
  811.                 /*
  812.                  * Set a flag indicating that we've already read
  813.                  * this object's params while blocked so we won't
  814.                  * have to do it again later when unblocked.
  815.                  */
  816.                 top->read_params = TRUE;
  817.                 
  818.                 if (lo_CheckObjectBlockage(context, state, top))
  819.                 {
  820.                     /*
  821.                      * If we're blocked on this object, don't pop the
  822.                      * stack. When the blockage is cleared we want to
  823.                      * still be at the top of the stack, because layout
  824.                      * will proceed immediately after the block point, 
  825.                      * which was our opening <OBJECT> tag.
  826.                      */
  827.                 }
  828.                 else
  829.                 {
  830.                     /*
  831.                      * If blocked on some other (enclosing) object,
  832.                      * pop the stack.
  833.                      */
  834.                     lo_PopObject(state);
  835.                 }
  836.             }
  837.             else
  838.             {
  839.                 /*
  840.                  * If not blocked, just close out the object
  841.                  * as appropriate.
  842.                  */
  843.                  if (object != NULL && top->formatted_object == FALSE)
  844.                  {
  845.                     if (object->lo_element.type == LO_EMBED)
  846.                     {
  847.                         lo_FormatEmbedObject(context,
  848.                                              state,
  849.                                              top->clone_tag,
  850.                                              (LO_EmbedStruct*) object,
  851.                                              FALSE, /* Stream not started */
  852.                                              top->param_count,
  853.                                              top->param_names,
  854.                                              top->param_values);
  855.                         top->formatted_object = TRUE;
  856.                         top->param_count = 0;
  857.                         top->param_names = NULL;
  858.                         top->param_values = NULL;
  859.                     }
  860. #ifdef JAVA
  861.                     else if (object->lo_element.type == LO_JAVA)
  862.                     {
  863.                         lo_CloseJavaApp(context, state, (LO_JavaAppStruct*) object);
  864.                     }
  865. #endif
  866.                  }
  867.  
  868.                 /* Pop stack entry */
  869.                 lo_PopObject(state);
  870.             }
  871.         }
  872.     }
  873. }
  874.  
  875.  
  876.  
  877. void
  878. lo_ProcessParamTag(MWContext* context, lo_DocState* state, PA_Tag* tag, XP_Bool blocked)
  879. {
  880.     if (tag->is_end == FALSE)
  881.     {
  882.         lo_TopState* top_state = state->top_state;
  883.         lo_ObjectStack* top = top_state->object_stack;
  884.  
  885.         /*
  886.          * PARAMs can be used inside both APPLETs and OBJECTs.
  887.          * Since applets can be inside objects but objects can't
  888.          * be inside applets, give the current applet priority
  889.          * for ownership of the parameter.
  890.          */
  891. #ifdef JAVA
  892.         if (state->current_java != NULL && blocked == FALSE)
  893.         {
  894.             LO_JavaAppStruct* java_app = state->current_java;
  895.             lo_ObjectParam(context, state, tag,
  896.                            (uint32*) &(java_app->param_cnt),
  897.                            &(java_app->param_names),
  898.                            &(java_app->param_values));
  899.         }
  900.         else 
  901. #endif
  902.         if (top != NULL && top->read_params == FALSE)
  903.         {
  904.             lo_ObjectParam(context, state, tag,
  905.                            &(top->param_count),
  906.                            &(top->param_names),
  907.                            &(top->param_values));
  908.         }
  909.     }
  910. }
  911.  
  912.  
  913.  
  914. /*
  915.  * This function gets the URL for the "data" attribute
  916.  * for an object, so we can determine the MIME type of
  917.  * the data and thus the type of object.  If libnet can
  918.  * get the data, LO_NewObjectStream will be called (see
  919.  * below).  If it can't, lo_ObjectURLExit will be called
  920.  * (also see below).
  921.  */
  922. void
  923. lo_FetchObjectData(MWContext* context, lo_DocState* state,
  924.                    lo_ObjectStack* top)
  925. {
  926.     char* address = NULL;
  927.     URL_Struct* urls = NULL;
  928.     
  929.     address = NET_MakeAbsoluteURL(
  930.                 state->top_state->base_url, top->data_url);
  931.  
  932.     if (address != NULL)
  933.     {
  934.         urls = NET_CreateURLStruct(address, NET_DONT_RELOAD);
  935.         if (urls != NULL)
  936.         {
  937.             urls->fe_data = (void*) top;
  938.             (void) NET_GetURL(urls, FO_CACHE_AND_OBJECT,
  939.                               context, lo_ObjectURLExit);
  940.         }
  941.     }
  942.     
  943.     if (address != NULL)
  944.         XP_FREE(address);
  945.         
  946.     if (urls == NULL)
  947.     {
  948.         state->top_state->out_of_memory = TRUE;
  949.         return;
  950.     }
  951. }
  952.  
  953.  
  954.  
  955. /*
  956.  * Create a new stream handler for dealing with a stream of
  957.  * object data.  We don't really want to do anything with
  958.  * the data, we just need to check the type to see if this
  959.  * is some kind of object we can handle.  If it is, we can
  960.  * format the right kind of object, clear the layout blockage,
  961.  * and connect this stream up to its rightful owner.
  962.  * NOTE: Plug-ins are the only object type supported here now.
  963.  */
  964. NET_StreamClass*
  965. LO_NewObjectStream(FO_Present_Types format_out, void* type,
  966.                    URL_Struct* urls, MWContext* context)
  967. {
  968.     NET_StreamClass* stream = NULL;
  969.     lo_ObjectStack* top = (lo_ObjectStack*) urls->fe_data;
  970.     
  971.     if (top != NULL && top->object != NULL)
  972.     {    
  973.         if (NPL_FindPluginEnabledForType(urls->content_type) != NULL)
  974.         {
  975.             /* bing: Internal reference to libplug! */
  976.             extern void NPL_EmbedURLExit(URL_Struct*, int, MWContext*);
  977.  
  978.             /* Now we know the object type */
  979.             top->object->lo_element.type = LO_EMBED;
  980.             
  981.             lo_FormatEmbedObject(top->context,
  982.                                  top->state,
  983.                                  top->clone_tag,
  984.                                  (LO_EmbedStruct*) top->object,
  985.                                  TRUE,
  986.                                  top->param_count,
  987.                                  top->param_names,
  988.                                  top->param_values);
  989.             top->param_count = 0;
  990.             top->param_names = NULL;
  991.             top->param_values = NULL;
  992.             top->formatted_object = TRUE;
  993.  
  994.             /* Set the FE data that libplug expects */
  995.             urls->fe_data = top->object->lo_element.lo_embed.FE_Data;
  996.  
  997.             /* Set the exit routine that libplug expects */
  998.             NET_SetNewContext(urls, context, NPL_EmbedURLExit);
  999.  
  1000.             /* Get the stream handler that libplug registered */
  1001.             stream = NET_StreamBuilder(FO_CACHE_AND_EMBED, urls, context);
  1002.  
  1003.             lo_ClearObjectBlock(top->context, top->object);
  1004.         }
  1005.     }
  1006.     
  1007.     return stream;
  1008. }
  1009.  
  1010.  
  1011.  
  1012. /*
  1013.  * This routine is called when a data stream we requested 
  1014.  * failed (either because libnet couldn't get the data, or
  1015.  * because we returned a NULL stream in LO_NewObjectStream
  1016.  * because the MIME type of the stream didn't translate into
  1017.  * a handlable object type).  In this case we need to get
  1018.  * the object out of the URL, set its type to "unknown", and
  1019.  * unblock layout.  This routine is also called when we
  1020.  * successfully handed off the stream to its new owner and
  1021.  * reset the exit routine (in LO_NewObjectStream; the status
  1022.  * will be MK_CHANGING_CONTEXT in the latter case).  In this
  1023.  * case, we don't need to do anything here.
  1024.  */
  1025. void
  1026. lo_ObjectURLExit(URL_Struct* urls, int status, MWContext* context)
  1027. {
  1028.     if (urls != NULL && status != MK_CHANGING_CONTEXT)
  1029.     {
  1030.         if (urls->fe_data != NULL)
  1031.         {
  1032.             lo_ObjectStack* stack = (lo_ObjectStack*) urls->fe_data;
  1033.             LO_ObjectStruct* object = stack->object;
  1034.             if (object != NULL)
  1035.             {
  1036.                 object->lo_element.type = LO_UNKNOWN;
  1037.                 lo_ClearObjectBlock(context, object);
  1038.             }
  1039.         }
  1040.  
  1041.         XP_FREE(urls);
  1042.     }
  1043. }
  1044.  
  1045.  
  1046.  
  1047. void
  1048. lo_ClearObjectBlock(MWContext* context, LO_ObjectStruct* object)
  1049. {
  1050.     int32 doc_id = XP_DOCID(context);
  1051.     lo_TopState* top_state = lo_FetchTopState(doc_id);
  1052.  
  1053.     if (top_state != NULL &&
  1054.         top_state->doc_state != NULL &&
  1055.         top_state->layout_blocking_element == (LO_Element*) object)
  1056.     {
  1057.         lo_DocState* main_doc_state = top_state->doc_state;
  1058.         lo_DocState* state = lo_CurrentSubState(main_doc_state);
  1059.         lo_FlushBlockage(context, state, main_doc_state);
  1060.     }
  1061. }
  1062.  
  1063. /*     
  1064.     lo_SetClassID
  1065.     -------------
  1066.     This inserts a CLASSID attribute into the tag->data string with its value set
  1067.     to "appletName".
  1068.  
  1069.     9.8.97        created        amusil
  1070. */
  1071.  
  1072. #ifdef    ANTHRAX
  1073.  
  1074. static void lo_SetClassID(PA_Tag* tag, char* appletName)
  1075. {
  1076.     uint32 appletNameLen, oldTagLen, newTagLen;
  1077.     char* tagData;
  1078.     char foo;
  1079.     
  1080.     appletNameLen = XP_STRLEN(appletName);
  1081.     oldTagLen = XP_STRLEN((char*)tag->data);
  1082.     newTagLen = oldTagLen + 15 + appletNameLen;
  1083.     
  1084.     tag->data = XP_REALLOC(tag->data, newTagLen+1);
  1085.  
  1086.     /* remove the '>' character */
  1087.     tagData = (char*) (tag->data);
  1088.     tagData[oldTagLen-1] = 0;
  1089.  
  1090.     /* add " CLASSID = appletName" */
  1091.     XP_STRCAT((char*)tag->data, " CLASSID=java:");
  1092.     XP_STRCAT((char*)tag->data, appletName);
  1093.     XP_STRCAT((char*)tag->data, " >");
  1094.     tag->data_len = newTagLen;
  1095. }
  1096.  
  1097. /*
  1098.     lo_GetNextName()
  1099.     ----------------
  1100.     This function parses a tag and returns a newly allocated string containing the first encountered
  1101.     NAME.  An example of what would get passed to this function is (basically a tag without the preceding
  1102.     <OBJECT) :
  1103.         
  1104.         "foo = VALUE    bar = VALUE2 >"
  1105.     
  1106.     This would return foo.  The tag pointer also gets incremented past the just-read NAME.  The example above
  1107.     would exit with *tag equal to:
  1108.     
  1109.         " = VALUE        bar = VALUE2 >"
  1110.     
  1111.     NULL is returned if a '>' character is encountered.
  1112.     
  1113.     10.7.97        amusil
  1114. */
  1115.  
  1116. static char* lo_GetNextName(char** tag)
  1117. {
  1118.     uint32 nameLength = 0;
  1119.     char* newName;
  1120.     char* start;
  1121.  
  1122.     XP_ASSERT(tag);
  1123.     XP_ASSERT(*tag);
  1124.     XP_ASSERT(**tag);    
  1125.  
  1126.     while(**tag == ' ')
  1127.         ++(*tag);
  1128.         
  1129.     if(**tag == '>')
  1130.         return NULL;
  1131.         
  1132.     start = *tag;
  1133.     while((**tag != ' ') && (**tag != '='))
  1134.         {
  1135.         ++nameLength;
  1136.         ++(*tag);
  1137.         }
  1138.         
  1139.     newName = XP_ALLOC((nameLength+1)*sizeof(char));
  1140.     
  1141.     newName = strncpy(newName, start, nameLength);
  1142.     XP_ASSERT(newName);
  1143.     
  1144.     newName[nameLength] = 0;
  1145.     
  1146.     return newName;
  1147. }
  1148.  
  1149. /*
  1150.     lo_GetNextValue()
  1151.     ----------------
  1152.     This function parses a tag and returns a newly allocated string containing the first encountered
  1153.     VALUE.  An example of what would get passed to this function is (basically a tag without the preceding
  1154.     <OBJECT) :
  1155.         
  1156.         "= foo    NAME = bar >"
  1157.     
  1158.     This would return foo.  The tag pointer also gets incremented past the just-read VALUE.  The example above
  1159.     would exit with *tag equal to:
  1160.     
  1161.         "    NAME = bar >"
  1162.  
  1163.  
  1164.     In the case that the value is enclosed in quotes, the entire string within the quotes, including spaces,
  1165.     is returned.
  1166.  
  1167.     NOTE: This function expects that lo_GetNextName() was called before it.
  1168.     
  1169.     10.7.97        amusil
  1170. */
  1171.  
  1172. static char* lo_GetNextValue(char** tag)
  1173. {
  1174.     uint32 valueLength = 0;
  1175.     char* newValue;
  1176.     char* start;
  1177.  
  1178.     XP_ASSERT(tag);
  1179.     XP_ASSERT(*tag);
  1180.     XP_ASSERT(**tag);    
  1181.  
  1182.     while(**tag == ' ' || **tag == '=')
  1183.         ++(*tag);
  1184.         
  1185.     if(**tag == '>')
  1186.         return NULL;
  1187.         
  1188.     /* if the value is enclosed in quotes, we capture the entire string up to the closing quote */
  1189.     if(**tag == '\"')
  1190.         {
  1191.             ++(*tag);
  1192.             start = *tag;
  1193.             while(**tag != '\"')
  1194.                 {
  1195.                 ++valueLength;
  1196.                 ++(*tag);
  1197.                 }
  1198.             ++(*tag);  /* skip over the enclosing " */
  1199.         }
  1200.     else    /* otherwise, we just get up to the first space */
  1201.         {
  1202.             start = *tag;
  1203.             while((**tag != ' '))
  1204.                 {
  1205.                 ++valueLength;
  1206.                 ++(*tag);
  1207.                 }
  1208.         }    
  1209.     
  1210.     newValue = XP_ALLOC((valueLength+1)*sizeof(char));
  1211.     
  1212.     newValue = strncpy(newValue, start, valueLength);
  1213.     XP_ASSERT(newValue);
  1214.     
  1215.     newValue[valueLength] = 0;
  1216.     
  1217.     return newValue;
  1218. }
  1219.  
  1220.  
  1221. /*    
  1222.     lo_SetJavaArgs
  1223.     --------------
  1224.     Extracts every param and passes them as arguements to the Java applet.  
  1225.     Here is the mapping: <... X=Y ...> becomes equivalent to <PARAM NAME=x VALUE=y>
  1226.     
  1227.     NOTE: lo_GetNextName() lo_GetNextValue() and allocates new memory for the return values.
  1228.     
  1229.     10.7.97        amusil
  1230. */
  1231. #ifdef JAVA
  1232. static void lo_SetJavaArgs(char* tag, LO_JavaAppStruct* current_java)
  1233. {
  1234.     char* paramName;
  1235.     char* paramValue;
  1236.     char* index;
  1237.     Bool is_percent;
  1238.     int32 val;
  1239.         
  1240.     index = tag;
  1241.     while(TRUE)
  1242.         {
  1243.             paramName = lo_GetNextName(&index);
  1244.             if(paramName == NULL)
  1245.                 break;
  1246.  
  1247.             /* always map data to src */
  1248.             if(!strcasecomp(paramName, "data"))
  1249.                 {
  1250.                 XP_FREE(paramName);
  1251.                 paramName = XP_STRDUP("src");
  1252.                 }                
  1253.  
  1254.             paramValue  = lo_GetNextValue(&index);
  1255.  
  1256.             /* Check if the user specified a % for height and width */
  1257.             if(!strcasecmp(paramName, "height"))
  1258.                 {
  1259.                 val = lo_ValueOrPercent(paramValue, &is_percent);
  1260.                 if(is_percent)
  1261.                     {
  1262.                     XP_FREE(paramValue);
  1263.                     /* int32 cannot exceed 10 digits */
  1264.                     paramValue = XP_ALLOC(11 * sizeof(char));
  1265.                     lo_itoa(current_java->height, paramValue);
  1266.                     }
  1267.                 }
  1268.         
  1269.             if(!strcasecmp(paramName, "width"))
  1270.                 {
  1271.                 val = lo_ValueOrPercent(paramValue, &is_percent);
  1272.                 if(is_percent)
  1273.                     {
  1274.                     XP_FREE(paramValue);
  1275.                     /* int32 cannot exceed 10 digits */
  1276.                     paramValue = XP_ALLOC(11 * sizeof(char));
  1277.                     lo_itoa(current_java->width, paramValue);
  1278.                     }
  1279.                 }
  1280.                 
  1281.             /* increment and resize array */
  1282.             ++(current_java->param_cnt);
  1283.             current_java->param_names = XP_REALLOC(current_java->param_names, current_java->param_cnt*sizeof(char*));
  1284.             XP_ASSERT(current_java->param_names);
  1285.             current_java->param_values = XP_REALLOC(current_java->param_values, current_java->param_cnt*sizeof(char*));
  1286.             XP_ASSERT(current_java->param_values);
  1287.             
  1288.             /* point the new array elements to the newly allocated paramName and paramValue */
  1289.             current_java->param_names[current_java->param_cnt-1] = paramName;
  1290.             current_java->param_values[current_java->param_cnt-1] = paramValue;
  1291.         }
  1292. }
  1293. #endif
  1294.  
  1295. static void lo_itoa(uint32 n, char* s)
  1296. {
  1297.     int i, sign;
  1298.     if((sign = n) < 0)
  1299.         n = -n;
  1300.     i = 0;
  1301.     
  1302.     do
  1303.         {
  1304.         s[i++] = n%10 + '0';
  1305.         } while ((n/=10) > 0);
  1306.         
  1307.     if(sign < 0)
  1308.         s[i++] = '-';
  1309.     s[i]  = '\0';
  1310.     lo_ReverseString(s);
  1311. }
  1312.  
  1313. static void lo_ReverseString(char* s)
  1314. {
  1315.     int c, i, j;
  1316.     
  1317.     for(i=0, j=strlen(s)-1; i<j; i++, j--)
  1318.         {
  1319.         c = s[i];
  1320.         s[i] = s[j];
  1321.         s[j] = c;
  1322.         }
  1323. }
  1324.  
  1325. #endif    /* ANTHRAX */
  1326.