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

  1. /* -*- Mode: C++; tab-width: 8; 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.  
  22. /*
  23.  * SCRIPT tag support.
  24.  */
  25.  
  26. #include "libmocha.h"
  27. #include "lo_ele.h"
  28. #include "net.h"
  29. #include "pa_parse.h"
  30. #include "pa_tags.h"
  31. #include "layout.h"
  32. #include "libevent.h"
  33. #include "css.h"
  34. #include "laystyle.h"
  35. #include "mcom_db.h"
  36. #include "laylayer.h"
  37. #include "prefapi.h"
  38.  
  39. static char lo_jsAllowFileSrcFromNonFile[]
  40.     = "javascript.allow.file_src_from_non_file";
  41.  
  42. /*
  43.  * XXX Should dynamic layer resize-reload really rerun scripts, potentially
  44.  * XXX destroying and reinitializing JS state?  An onResize event handler
  45.  * XXX would be consistent with how windows and static layers resize-reload.
  46.  */
  47. #define SCRIPT_EXEC_OK(top_state, state, type, script_type)                   \
  48.         (top_state->resize_reload == FALSE ||                                 \
  49.          type != script_type ||                                               \
  50.          (lo_InsideLayer(state) && (lo_IsAnyCurrentAncestorDynamic(state) ||  \
  51.                                     lo_IsAnyCurrentAncestorSourced(state))))
  52.  
  53. static void
  54. lo_ParseScriptLanguage(MWContext * context, PA_Tag * tag, int8 * type,
  55.                JSVersion * version)
  56. {
  57.     PA_Block buff;
  58.     char * str;
  59.  
  60.     buff = lo_FetchParamValue(context, tag, PARAM_LANGUAGE);
  61.     if (buff != NULL) {
  62.         PA_LOCK(str, char *, buff);
  63.         if ((XP_STRCASECMP(str, js_language_name) == 0) ||
  64.             (XP_STRCASECMP(str, "LiveScript") == 0) ||
  65.             (XP_STRCASECMP(str, "Mocha") == 0)) {
  66.             *type = SCRIPT_TYPE_MOCHA;
  67.             *version = JSVERSION_DEFAULT;
  68.         } 
  69.         else if (XP_STRCASECMP(str, "JavaScript1.1") == 0) {
  70.             *type = SCRIPT_TYPE_MOCHA;
  71.             *version = JSVERSION_1_1;
  72.         } 
  73.         else if (XP_STRCASECMP(str, "JavaScript1.2") == 0) {
  74.             *type = SCRIPT_TYPE_MOCHA;
  75.             *version = JSVERSION_1_2;
  76.         } 
  77.         else if (XP_STRCASECMP(str, "JavaScript1.3") == 0) {
  78.             *type = SCRIPT_TYPE_MOCHA;
  79.             *version = JSVERSION_1_3;
  80.         } 
  81.  
  82.         else {
  83.             *type = SCRIPT_TYPE_UNKNOWN;
  84.         }
  85.         PA_FREE(buff);
  86.     }
  87. }
  88.  
  89. void
  90. lo_BlockScriptTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  91. {
  92.     lo_TopState *top_state;
  93.     pa_DocData *doc_data;
  94.  
  95.     if (!LM_CanDoJS(context))
  96.     return;
  97.  
  98.     /*
  99.      * Find the parser stream from its private data, doc_data, pointed at by
  100.      * a top_state member for just this situation.
  101.      */
  102.     top_state = state->top_state;
  103.     doc_data = top_state->doc_data;
  104.     XP_ASSERT(doc_data != NULL && doc_data->url_struct != NULL);
  105.     if (doc_data == NULL || doc_data->url_struct == NULL)   /* XXX paranoia */
  106.         return;
  107.  
  108.     /*
  109.      * The parser must not parse ahead after a script or style end-tag, or
  110.      * it could get into a brute_tag state (XMP, PRE, etc.) and enter a mode
  111.      * that would mess up document.writes coming from the script or style.
  112.      * So we put it into overflow mode here, and decrement overflow when we
  113.      * unblock.
  114.      *
  115.      * We test tag first to handle the call from lo_ProcessScriptTag, which
  116.      * wants us to create an input state if needed, but not to count comment
  117.      * bytes via lo_data.  Sad to say, this means lo_ProcessScriptTag must
  118.      * also increment doc_data->overflow, but only if tag->is_end == 1 (a.k.a.
  119.      * PR_TRUE), meaning the script tag was not blocked by an earlier blocking
  120.      * tag that caused it to go through here and set is_end to 2.  XXX we can
  121.      * do this only because all layout and libparse tests of is_end are of the
  122.      * form "tag->is_end == FALSE".
  123.      */
  124.     if (tag) {
  125.         /* Tag non-null means we're called from lo_BlockTag in layout.c. */
  126.         if (tag->is_end == FALSE) {
  127.             int8 script_type;
  128.             JSVersion ver;
  129.  
  130.             /* Keep track of whether we're in a script or style container... */
  131.             script_type = SCRIPT_TYPE_UNKNOWN;
  132.             lo_ParseScriptLanguage(context, tag, &script_type, &ver);
  133.             if (tag->type == P_STYLE || tag->type == P_LINK || 
  134.                 script_type != SCRIPT_TYPE_UNKNOWN)
  135.                 top_state->in_blocked_script = TRUE;
  136.         }
  137.         else if (top_state->in_blocked_script) {
  138.             /* ...so we can avoid overflowing the parser on superfluous end
  139.              * tags, such as those emitted by libmime.
  140.              */
  141.             top_state->in_blocked_script = FALSE;
  142.  
  143.             if (SCRIPT_EXEC_OK(top_state, state, tag->type, P_SCRIPT)) {
  144.                 tag->is_end = (PRPackedBool)2;
  145.                 PA_PushOverflow(doc_data);
  146.                 doc_data->overflow_depth ++;
  147.             }
  148.         }
  149.     }
  150.  
  151.     /*
  152.      * Count the bytes of HTML comments and heuristicly "lost" newlines in
  153.      * tag so lo_ProcessScriptTag can recover it there later, in preference
  154.      * to the (then far-advanced) value of doc_data->comment_bytes.  Ensure
  155.      * that this hack is not confused for NULL by adding 1 here and taking
  156.      * it away later.  Big XXX for future cleanup, needless to say.
  157.      */
  158.     if (tag)
  159.         tag->lo_data = (void *)(doc_data->comment_bytes + 1);
  160.     
  161.     if (top_state->script_tag_count++ == 0)
  162.         ET_SetDecoderStream(context, doc_data->parser_stream,
  163.                             doc_data->url_struct, JS_FALSE);
  164. }
  165.  
  166.  
  167. typedef struct {
  168.     MWContext *context;
  169.     lo_DocState *state;
  170.     PA_Tag *tag;
  171.     char *url, *archiveSrc, *id, *codebase;
  172.     char *buffer;
  173.     uint32 bufferSize;
  174.     JSVersion version;
  175.     JSBool inlineSigned;
  176. } ScriptData;
  177.  
  178. void 
  179. lo_DestroyScriptData(void *arg)
  180. {
  181.     ScriptData *data = arg;
  182.  
  183.     if (data == NULL)
  184.     return;
  185.     XP_FREEIF(data->url);
  186.     XP_FREEIF(data->archiveSrc);
  187.     XP_FREEIF(data->id);
  188.     XP_FREEIF(data->codebase);
  189.     XP_FREEIF(data->buffer);
  190.     if (data->tag)
  191.     PA_FreeTag(data->tag);
  192.     XP_FREE(data);
  193. }
  194.  
  195. static void
  196. lo_script_src_exit_fn(URL_Struct *url_struct, int status, MWContext *context);
  197.  
  198. static void
  199. lo_script_archive_exit_fn(URL_Struct *url_struct, int status, MWContext *context);
  200.  
  201. static Bool
  202. lo_create_script_blockage(MWContext *context, lo_DocState *state, int type)
  203. {
  204.     lo_TopState *top_state;
  205.     LO_Element *block_ele;
  206.  
  207.     top_state = state->top_state;
  208.     if (!top_state) {
  209.         XP_ASSERT(0);
  210.         return FALSE;
  211.     }
  212.     
  213.     block_ele = lo_NewElement(context, state, LO_SCRIPT, NULL, 0);
  214.     if (block_ele == NULL) {
  215.         top_state->out_of_memory = TRUE;
  216.     return FALSE;
  217.     }
  218.  
  219.     block_ele->type = type;
  220.     block_ele->lo_any.ele_id = NEXT_ELEMENT;
  221.     top_state->layout_blocking_element = block_ele;
  222.     if (type == LO_SCRIPT)
  223.     top_state->current_script = block_ele;
  224.  
  225.     return TRUE;
  226. }
  227.  
  228. /*
  229.  * used for ARCHIVE= and SRC= 
  230.  * Create name of form "archive.jar/src.js" 
  231.  */
  232. static char *
  233. lo_BuildJSArchiveURL( char *archive_name, char *filename )
  234. {
  235.     uint32 len = XP_STRLEN(archive_name) + XP_STRLEN(filename) + 2;
  236.     char *path = XP_ALLOC(len);
  237.     if (path)
  238.     {
  239.         XP_STRCPY(path, archive_name);
  240.         XP_STRCAT(path, "/");
  241.         XP_STRCAT(path, filename);
  242.     }
  243.     return path;
  244. }
  245.  
  246. /*
  247.  * Load a document from an external URL.  Assumes that layout is
  248.  *   already blocked
  249.  */
  250. static void
  251. lo_GetScriptFromURL(ScriptData *data, int script_type) 
  252. {
  253.     URL_Struct *url_struct;
  254.     lo_TopState *top_state = data->state->top_state;
  255.     PA_Tag *tag = data->tag;
  256.  
  257.     url_struct = NET_CreateURLStruct(data->url, top_state->force_reload);
  258.     if (url_struct == NULL) {
  259.         top_state->out_of_memory = TRUE;
  260.     lo_DestroyScriptData(data);
  261.     return;
  262.     }
  263.  
  264.     url_struct->must_cache = TRUE;
  265.     url_struct->preset_content_type = TRUE;
  266.     if (script_type == SCRIPT_TYPE_CSS) {
  267.         StrAllocCopy(url_struct->content_type, TEXT_CSS);
  268.     } else {
  269.     if (tag->type == P_STYLE || tag->type == P_LINK) {
  270.         StrAllocCopy(url_struct->content_type, TEXT_JSSS);
  271.     } else {
  272.         StrAllocCopy(url_struct->content_type, js_content_type);
  273.     }
  274.     }
  275.  
  276.     XP_ASSERT(top_state->layout_blocking_element);
  277.  
  278.     if (!url_struct->content_type)
  279.     goto out;
  280.  
  281.     if (!data->inlineSigned) {
  282.         if (data->archiveSrc) {
  283.             /* ARCHIVE= and SRC= */
  284.             /*
  285.              * Need to set nesting url. Create name of form
  286.              * "archive.jar/src.js" 
  287.              */
  288.              
  289.             char *path = lo_BuildJSArchiveURL(url_struct->address,
  290.                                               data->archiveSrc);    
  291.             if (!path)
  292.                 goto out;
  293.             ET_SetNestingUrl(data->context, path);
  294.             /* version taken care of in lo_script_archive_exit_fn */
  295.             XP_FREE(path);
  296.         } else {
  297.             /* SRC= but no ARCHIVE= */
  298.             ET_SetNestingUrl(data->context, url_struct->address);
  299.             ET_SetVersion(data->context, data->version);
  300.         }
  301.     }
  302.  
  303.     url_struct->fe_data = data;
  304.  
  305.     if (data->archiveSrc != NULL || data->inlineSigned) {
  306.         NET_GetURL(url_struct, 
  307.                    FO_CACHE_ONLY,
  308.                    data->context,
  309.                    lo_script_archive_exit_fn);
  310.     } else {
  311.         NET_GetURL(url_struct, 
  312.                    FO_CACHE_AND_PRESENT, 
  313.                    data->context,
  314.                    lo_script_src_exit_fn);
  315.     }
  316.  
  317.     return;
  318.   out:
  319.     top_state->out_of_memory = TRUE;
  320.     NET_FreeURLStruct(url_struct);
  321.     lo_DestroyScriptData(data);
  322.     return;
  323. }
  324.  
  325. /*
  326.  * A script has just completed.  If we are blocked on that script
  327.  *   free the blockage
  328.  */
  329. static void
  330. lo_unblock_script_tag(MWContext * context, Bool messWithParser)
  331. {
  332.     lo_TopState *top_state;
  333.     lo_DocState *state;
  334.     LO_Element * block_ele;
  335.     LO_Element * current_script;
  336.     PA_Tag * tag;
  337.     NET_StreamClass stream;
  338.  
  339.     top_state = lo_FetchTopState(XP_DOCID(context));
  340.     if (!top_state || !top_state->doc_state)
  341.         return;
  342.     state = top_state->doc_state;
  343.     
  344.     /* 
  345.      * Remember the fake element we created but clear the current
  346.      *   script flag of the top_state since the FlushBlockage call
  347.      *   might just turn around and block us on another script
  348.      */
  349.     current_script = top_state->current_script;
  350.     top_state->current_script = NULL;
  351.  
  352.     /* 
  353.      * if we are finishing a nested script make sure the current_script
  354.      *   points to our parent script
  355.      */
  356.     for (tag = top_state->tags; tag; tag = tag->next) {
  357.         if (tag->type == P_NSCP_REBLOCK) {
  358.         top_state->current_script = tag->lo_data;
  359.         break;
  360.         }
  361.     }
  362.  
  363.  
  364.     /* Flush tags blocked by this <SCRIPT SRC="URL"> tag. */
  365.     block_ele = top_state->layout_blocking_element;
  366.  
  367.     /* no longer in a script */
  368.     top_state->in_script = SCRIPT_TYPE_NOT;
  369.  
  370.     /* 
  371.      * we must be blocked on something either the script that just ended or
  372.      *   some other object
  373.      */
  374.     if (!block_ele)
  375.         goto done;
  376.  
  377.     if (messWithParser && top_state->doc_data &&
  378.         SCRIPT_EXEC_OK(top_state, state, block_ele->type, LO_SCRIPT)) {
  379.       top_state->doc_data->overflow_depth --;
  380.     XP_ASSERT(top_state->doc_data->overflow_depth >= 0);
  381.     }
  382.  
  383.     lo_FlushLineBuffer(context, top_state->doc_state);
  384.  
  385.     /* 
  386.      * unblock on UNKNOWN's as well since that's the type for
  387.      * style attribute scripts
  388.      */
  389.     if (block_ele->type == LO_SCRIPT || block_ele->type == LO_UNKNOWN) {
  390.         lo_UnblockLayout(context, top_state);
  391.     }
  392.     else {
  393.         /* 
  394.          * we're still blocked on something else - make sure
  395.          *   there are no reblock tags that are going to hose
  396.          *   us.  Find the reblock tags that point to our script
  397.          *   tag and render them hermless
  398.          */
  399.         PA_Tag * tag;
  400.         for (tag = top_state->tags; tag; tag = tag->next) {
  401.             if (tag->type == P_NSCP_REBLOCK) {
  402.                 LO_Element * lo_ele = tag->lo_data;
  403.                 if (lo_ele == current_script) {
  404.                     tag->lo_data = NULL;
  405.                 }
  406.             }
  407.         }
  408.     }
  409.  
  410.     /* free the fake element we created earlier */
  411.     lo_FreeElement(context, current_script, FALSE);
  412.  
  413. done:
  414.     
  415.     /* the parser is now able to receive new data from netlib */
  416.     stream.data_object=(pa_DocData *)top_state->doc_data;
  417.     pa_FlushOverflow(&stream);
  418.  
  419.     /*
  420.      * The initial call to lo_UnblockLayout() might have not torn
  421.      *   everything down because we were waiting for the last
  422.      *   chunk of data to come out of the doc_data->overflow_buf
  423.      * We need to get to lo_FlushedBlockedTags() and lo_FinishLayout()
  424.      *   at the bottom of lo_FlushBlockage().
  425.      */
  426.     if (!top_state->layout_blocking_element)
  427.     lo_FlushBlockage(context, top_state->doc_state, top_state->doc_state);
  428.  
  429. }
  430.  
  431.  
  432. static void
  433. lo_script_src_exit_fn(URL_Struct *url_struct, int status, MWContext *context)
  434. {
  435.     lo_DestroyScriptData(url_struct->fe_data);
  436.     NET_FreeURLStruct(url_struct);
  437.  
  438.     /*
  439.      * If our status is negative that means there was an error and the
  440.      *   script won't be executed.  Therefore the MochaDecoder's nesting
  441.      *   url must be cleared, and layout must be unblocked.
  442.      */
  443.     if (status < 0) {
  444.         ET_SetNestingUrl(context, NULL);
  445.         lo_unblock_script_tag(context, TRUE);
  446.     }
  447. }
  448.  
  449. static void
  450. lo_script_archive_exit_fn(URL_Struct *url_struct, int status, MWContext *context)
  451. {
  452.     ScriptData *data = NULL;
  453.     char *name;
  454.     JSPrincipals *principals;
  455.     ETEvalStuff * stuff;
  456.  
  457.     data = (ScriptData *) url_struct->fe_data;
  458.     stuff = (ETEvalStuff *) XP_NEW_ZAP(ETEvalStuff);
  459.     if (!stuff)
  460.     return;
  461.  
  462.     stuff->line_no = 1;
  463.     stuff->scope_to = NULL;
  464.     stuff->want_result = JS_FALSE;
  465.     stuff->version = data->version;
  466.     stuff->data = context;
  467.  
  468. #ifndef JAVA
  469.     /* No Java; execute without principals. */
  470.     if (data->buffer) {
  471.     stuff->principals = NULL;
  472.         ET_EvaluateScript(context, data->buffer, stuff, lo_ScriptEvalExitFn);
  473.     }
  474.     else {
  475.     XP_FREE(stuff);
  476.     }
  477. #else
  478.     name = data->archiveSrc ? data->archiveSrc : data->id;
  479.     principals = LM_NewJSPrincipals(url_struct, name, data->codebase);
  480.     if (principals != NULL) {
  481.         char *src;
  482.         uint srcSize;
  483.  
  484.         if (data->archiveSrc) {
  485.             /* Extract from archive using "SRC=" value */
  486.             src = LM_ExtractFromPrincipalsArchive(principals, data->archiveSrc, 
  487.                                                   &srcSize);
  488.                                                   
  489. #ifdef JSDEBUGGER
  490.         if( src != NULL && LM_GetJSDebugActive() )
  491.         {
  492.             char *path = lo_BuildJSArchiveURL(url_struct->address,
  493.             data->archiveSrc);
  494.             if (path)
  495.             {
  496.                 LM_JamSourceIntoJSDebug( path, src, srcSize, context );
  497.                 XP_FREE(path);
  498.             }
  499.         }
  500. #endif /* JSDEBUGGER */
  501.  
  502.             if (src == NULL) {
  503.                 /* Unsuccessful extracting from archive. Now try normal SRC= lookup. */
  504.                 (*principals->destroy)(NULL, principals);
  505.                 data->url = NET_MakeAbsoluteURL(data->state->top_state->base_url, 
  506.                                                 data->archiveSrc);
  507.                 XP_FREEIF(data->archiveSrc);
  508.                 data->archiveSrc = NULL;
  509.                 lo_GetScriptFromURL(data, data->state->top_state->in_script);
  510.                 goto out;
  511.         }
  512.         } else {
  513.             /* Should be an inline script */
  514.             src = data->buffer;
  515.             srcSize = data->bufferSize;
  516.         }
  517.  
  518.     stuff->len = srcSize;
  519.     stuff->principals = principals;
  520.         ET_EvaluateScript(context, src, stuff, lo_ScriptEvalExitFn);
  521.  
  522.         if (data->archiveSrc){
  523.             ET_SetNestingUrl(context, NULL);
  524.             XP_FREE(src);
  525.         }            
  526.     }
  527.     else {
  528.     XP_FREE(stuff);
  529.     }
  530.      
  531. #endif /* ifdef JAVA */
  532.  
  533.     lo_DestroyScriptData(data);
  534.  
  535. out:
  536.     /* Always free (or drop a ref on) the url_struct before returning. */
  537.     NET_FreeURLStruct(url_struct);
  538. }    
  539.  
  540. /*
  541.  * This function gets called when the LM_EvaluateBuffer() operation
  542.  *   completes (in the mocha thread, but we run in the mozilla thread
  543.  *   here)
  544.  */
  545. void
  546. lo_ScriptEvalExitFn(void * data, char * str, size_t len, char * wysiwyg_url, 
  547.                     char * base_href, Bool valid)
  548. {
  549.  
  550.     /* we don't care about the strings here just kill them */
  551.     XP_FREEIF(str);
  552.     XP_FREEIF(wysiwyg_url);
  553.     XP_FREEIF(base_href);
  554.  
  555.     lo_unblock_script_tag(data, TRUE);
  556.  
  557. }
  558.  
  559. /*
  560.  * This function gets called when the LM_EvaluateBuffer() operation
  561.  *   completes (in the mocha thread, but we run in the mozilla thread
  562.  *   here)
  563.  */
  564. PRIVATE
  565. void
  566. lo_StyleEvalExitFn(void * data, char * str, size_t len, char * wysiwyg_url, 
  567.                     char * base_href, Bool valid)
  568. {
  569.  
  570.     /* we don't care about the strings here just kill them */
  571.     XP_FREEIF(str);
  572.     XP_FREEIF(wysiwyg_url);
  573.     XP_FREEIF(base_href);
  574.  
  575.     lo_unblock_script_tag(data, FALSE);
  576.  
  577. }
  578.  
  579.  
  580. void
  581. lo_UnblockLayout(MWContext *context, lo_TopState *top_state)
  582. {
  583.     XP_ASSERT(top_state && top_state->doc_state);
  584.     if (!top_state || !top_state->doc_state)
  585.         return;
  586.  
  587.     top_state->layout_blocking_element = NULL;
  588.     lo_FlushBlockage(context, top_state->doc_state, top_state->doc_state);
  589. }
  590.  
  591.  
  592. Bool
  593. lo_CloneTagAndBlockLayout(MWContext *context, lo_DocState *state, PA_Tag *tag)
  594. {
  595.  
  596.     PA_Tag *new_tag;
  597.     lo_TopState * top_state = state->top_state;
  598.  
  599.     /*
  600.      * Since we're adding tags to the blocked tags list without going through
  601.      * lo_BlockTag, we need to see if this is a flushed to block transition
  602.      * and, if so, add to the doc_data's ref count. We don't want to do this
  603.      * if we're in the process of flushing blockage - in that case, the count
  604.      *  has already been incremented.
  605.      */
  606.     if (top_state->tags == NULL && top_state->flushing_blockage == FALSE)
  607.     PA_HoldDocData(top_state->doc_data);
  608.  
  609.     /* 
  610.      * stick the current tag onto the front of the tag list
  611.      */
  612.     new_tag = PA_CloneMDLTag(tag);
  613.     if (!new_tag) {
  614.         top_state->out_of_memory = TRUE;
  615.         return FALSE;
  616.     }
  617.  
  618.     new_tag->next = top_state->tags;
  619.     top_state->tags = new_tag;
  620.     if (top_state->tags_end == &top_state->tags)
  621.         top_state->tags_end = &new_tag->next;
  622.  
  623.     return lo_create_script_blockage(context, state, LO_UNKNOWN);
  624. }
  625.  
  626. /* evaluate the buffer encompassed by the style attribute on any tag.
  627.  * this will be JSS or CSS 
  628.  *
  629.  * Returns TRUE if it needs to block layout
  630.  * Returns FALSE if not.
  631.  */
  632. XP_Bool
  633. lo_ProcessStyleAttribute(MWContext *context, lo_DocState *state, PA_Tag *tag, char *script_buff)
  634. {
  635.     lo_TopState *top_state;
  636.     char *scope_to = NULL;
  637.     int32 script_buff_len;
  638.     char *new_id;
  639.     XP_Bool in_double_quote=FALSE, in_single_quote=FALSE;
  640.     char *ptr, *end;
  641.     ETEvalStuff * stuff;
  642.  
  643.     if (!state)
  644.       {
  645.        XP_FREEIF(script_buff);
  646.        return FALSE;
  647.     }
  648.  
  649.  
  650.     if (!script_buff)
  651.         return FALSE;
  652.  
  653.     /* @@@ A bit of a hack.
  654.      * Get rid of the style attribute in the tag->data so that we don't
  655.      * go circular
  656.      *
  657.      * get rid of STYLE by rewriting it as SYTLE so that the parser 
  658.      * ignores it :)
  659.      */
  660.     for (ptr=(char*)tag->data, end = ptr+tag->data_len; ptr < end; ptr++) {
  661.         if (*ptr == '"') {
  662.             in_double_quote = !in_double_quote;
  663.         }
  664.         else if (*ptr == '\'') {
  665.             in_single_quote = !in_single_quote;
  666.         }
  667.         else if (!in_single_quote &&
  668.                  !in_double_quote &&
  669.                  !strncasecomp(ptr, PARAM_STYLE, sizeof(PARAM_STYLE)-1)) {
  670.             *ptr = 'T';    /* ttyle NOT style */
  671.             break;
  672.         }
  673.     }
  674.  
  675.     script_buff_len = XP_STRLEN(script_buff);
  676.  
  677.     top_state = state->top_state;
  678.  
  679.     /* get the tag ID if it has one */
  680.     new_id = (char *)lo_FetchParamValue(context, tag, PARAM_ID);
  681.  
  682.     if (!new_id)
  683.         new_id = PR_smprintf(NSIMPLICITID"%ld", top_state->tag_count);
  684.  
  685.     if (!new_id)
  686.         return FALSE;
  687.  
  688.     if (top_state->default_style_script_type == SCRIPT_TYPE_JSSS ||
  689.     top_state->default_style_script_type == SCRIPT_TYPE_MOCHA) {
  690.  
  691.         StrAllocCopy(scope_to, "document.ids.");
  692.         StrAllocCat(scope_to, new_id);
  693.  
  694.         if (!scope_to) {
  695.             XP_FREE(new_id);
  696.         return(FALSE);
  697.     }
  698.     }
  699.     else if (top_state->default_style_script_type == SCRIPT_TYPE_CSS) {
  700.         char *new_jss_buff;
  701.         int32 new_jss_buff_len;
  702.         char *new_css_buff;
  703.         int32 new_css_buff_len;
  704.  
  705.         /* scope the css to the ns implicit ID */
  706.         new_css_buff = PR_smprintf("#%s { %s }", new_id, script_buff);
  707.  
  708.         XP_FREE(script_buff);
  709.  
  710.         if (!new_css_buff) {
  711.         XP_FREE(new_id);
  712.         return FALSE;
  713.     }
  714.  
  715.         new_css_buff_len = XP_STRLEN(new_css_buff);
  716.         
  717.         /* convert to JSS */
  718.         CSS_ConvertToJS(new_css_buff,
  719.                         new_css_buff_len,
  720.                         &new_jss_buff,
  721.                         &new_jss_buff_len);
  722.  
  723.         XP_FREE(new_css_buff);
  724.  
  725.         if (!new_jss_buff) {
  726.         XP_FREE(new_id);
  727.         return FALSE;
  728.     }
  729.  
  730.         script_buff = new_jss_buff;
  731.         script_buff_len = new_jss_buff_len;
  732.     }
  733.     else {
  734.         /* unknown script type, punt */
  735.         XP_FREE(script_buff);
  736.     XP_FREE(new_id);
  737.         return FALSE;
  738.     }
  739.  
  740.     /* not needed anymore */
  741.     XP_FREE(new_id);
  742.  
  743.     stuff = (ETEvalStuff *) XP_NEW_ZAP(ETEvalStuff);
  744.     if (!stuff) {
  745.     /* what do we free here? */
  746.     XP_FREE(new_id);
  747.         return FALSE;
  748.     }
  749.  
  750.     if (lo_CloneTagAndBlockLayout(context, state, tag)) {
  751.         tag->type = P_UNKNOWN;
  752.     stuff->len = XP_STRLEN(script_buff);
  753.     stuff->line_no = top_state->script_lineno;
  754.     stuff->scope_to = scope_to;
  755.     stuff->want_result = JS_FALSE;
  756.     stuff->data = context;
  757.     stuff->version = top_state->version;
  758.     stuff->principals = NULL;
  759.  
  760.         ET_EvaluateScript(context, script_buff, stuff, lo_StyleEvalExitFn);
  761.  
  762.     /* don't free scope_to, ET_EvaluateScript has taken possession */
  763.         XP_FREE(script_buff);
  764.  
  765.         return TRUE;
  766.     }
  767.  
  768.     XP_FREEIF(scope_to);
  769.     XP_FREE(script_buff);
  770.     
  771.     return FALSE;
  772. }
  773.  
  774. #ifdef DEBUG_ScriptPlugin
  775. #include "np.h"
  776.  
  777. PA_Tag *
  778. LO_CreateHiddenEmbedTag(PA_Tag *old_tag, char * newTagStr)
  779. {
  780.     PA_Tag *new_tag = PA_CloneMDLTag(old_tag);
  781.     if(new_tag)
  782.     {
  783.         char * buf = NULL;
  784.         new_tag->type = P_EMBED;
  785.         XP_FREE(new_tag->data);
  786.         new_tag->data = NULL;
  787.         StrAllocCopy(buf,newTagStr);
  788.         XP_ASSERT(buf != NULL);
  789.         new_tag->data = (PA_Block)buf;
  790.         new_tag->data_len = XP_STRLEN((char*)new_tag->data);
  791.         XP_ASSERT(new_tag->data_len != 0);
  792.     }
  793.  
  794.     return(new_tag);
  795. }
  796.  
  797. /* Generate mimetype string corresponding to this script language.  
  798.    Specifically, <SCRIPT language = blah> should yield a mimetype
  799.    of "script/blah"
  800.  */
  801. char * npl_Script2mimeType(MWContext *context, PA_Tag *tag)
  802. {
  803.     PA_Block buff;
  804.     char * language;
  805.     char * preface = "script/";
  806.     uint32 prefLen = XP_STRLEN(preface);
  807.     char * mimebuf = NULL;
  808.     uint32 len;
  809.  
  810.     buff = lo_FetchParamValue(context, tag, PARAM_LANGUAGE);
  811.     if (buff != NULL) {
  812.         PA_LOCK(language, char *, buff);
  813.         len = prefLen + XP_STRLEN(language);
  814.         mimebuf = XP_ALLOC(len+1);
  815.         if (mimebuf)
  816.         {
  817.             XP_STRCPY(mimebuf, preface);
  818.             XP_STRCAT(mimebuf, language);
  819.         }
  820.         PA_FREE(buff);
  821.     }
  822.     return mimebuf;
  823. }
  824.     
  825. /* A plugin wants to handle this (otherwise unhandled) script language.
  826.    Now we redirect it to the plugin using the following steps:
  827.  
  828.     1.  Create a cachefile w/ the appropriate extension and store the contents of the script delims
  829.     2.  Build a hidden, semi-internal embed tag pointing to the cachefile. 
  830.     3.  Cause Layout to initiate the hidden embed tag, which further starts netlib and other plugin
  831.         initialization.
  832.  
  833.  */
  834. #define ALLOC_CHECK(a,id,abnormal_exit)   {id++; if (!a) goto abnormal_exit;}
  835. void npl_ScriptPlugin(MWContext *context, lo_DocState *state, PA_Tag *tag, size_t line_buf_len, char * mimebuf)
  836. {
  837.     char * suffix                = NULL;
  838.     char * fname                = NULL;
  839.     char * embedtagstr            = NULL;
  840.     char * NET_suffix            = NULL;
  841.     PA_Tag * newTag                = NULL;
  842.     NET_StreamClass* viewstream = NULL;
  843.     URL_Struct* urls            = NULL;
  844.     int streamStatus            = 0;
  845.     int id                        = 0;
  846.  
  847.     if (!context || !state || !tag || (line_buf_len <= 0) || !mimebuf){
  848.         XP_Trace("npl_ScriptPlugin:  Invalid input(s).");
  849.         return; /* no need to goto clean_exit, since havn't alloc'd anything */
  850.     }
  851.  
  852.     urls = NET_CreateURLStruct("internal_url.", NET_DONT_RELOAD);
  853.             ALLOC_CHECK(urls,id,abnormal_exit);
  854.  
  855.     /* NETLib gives me a pointer here instead of a copy of the string, so I have to make
  856.        my own, make checks, etc. 
  857.      */
  858.     NET_suffix = NET_cinfo_find_ext(mimebuf);
  859.     if (!NET_suffix)
  860.         goto abnormal_exit;
  861.  
  862.     suffix = PR_smprintf("internal_url.%s", NET_suffix);
  863.             ALLOC_CHECK(suffix,id,abnormal_exit);
  864.  
  865.             XP_FREEIF(urls->address);
  866.     StrAllocCopy(urls->address     , suffix);
  867.             ALLOC_CHECK(urls->address,id,abnormal_exit);
  868.  
  869.             XP_FREEIF(urls->content_name);
  870.     StrAllocCopy(urls->content_name, suffix);
  871.             ALLOC_CHECK(urls->content_name,id,abnormal_exit);
  872.  
  873.             XP_FREEIF(urls->content_type);
  874.     StrAllocCopy(urls->content_type, mimebuf);
  875.             ALLOC_CHECK(urls->content_type,id,abnormal_exit);
  876.  
  877.     urls->must_cache = 1;      /* ugly flag for mailto and saveas */
  878.  
  879.     viewstream = NET_StreamBuilder(FO_CACHE_ONLY, urls, context);
  880.             ALLOC_CHECK(viewstream,id,abnormal_exit);
  881.  
  882.     streamStatus =
  883.         (*viewstream->put_block)(viewstream,(CONST char*)state->line_buf, line_buf_len);
  884.     if (streamStatus <= 0)
  885.         goto abnormal_exit;
  886.     (*viewstream->complete)(viewstream);
  887.  
  888.     /* Now build internal embed tag pointing to this source:  */
  889.     fname = WH_FileName(urls->cache_file, xpCache);
  890.             ALLOC_CHECK(fname,id,abnormal_exit);
  891.     embedtagstr = PR_smprintf("<EMBED SRC=file:///%s HIDDEN=TRUE>", fname);
  892.             ALLOC_CHECK(embedtagstr,id,abnormal_exit);
  893.  
  894.     newTag = LO_CreateHiddenEmbedTag(tag,embedtagstr);
  895.             ALLOC_CHECK(newTag,id,abnormal_exit);
  896.  
  897.     lo_FormatEmbed(context,state,newTag);     
  898.     goto normal_exit;
  899.  
  900. abnormal_exit:
  901.     XP_Trace("npl_ScriptPlugin:  Abnormal termination, id = %d",id);
  902.     if (urls) {
  903.         XP_FREEIF(urls->content_type);
  904.         XP_FREEIF(urls->content_name);
  905.         XP_FREEIF(urls->address);
  906.         XP_FREE(  urls);
  907.     }
  908.  
  909. normal_exit:
  910.     XP_FREEIF(newTag);
  911.     XP_FREEIF(embedtagstr);
  912.     XP_FREEIF(fname);
  913.     XP_FREEIF(viewstream);
  914.     XP_FREEIF(suffix);
  915.     return;
  916.  
  917. }
  918. #endif /* DEBUG_ScriptPlugin */
  919.  
  920. void
  921. lo_ProcessScriptTag(MWContext *context, lo_DocState *state, PA_Tag *tag, JSObject *obj)
  922. {
  923.     lo_TopState *top_state;
  924.     pa_DocData *doc_data;
  925.     XP_Bool type_explicitly_set=FALSE;
  926.     XP_Bool saw_archive=FALSE;
  927. #ifdef DEBUG_ScriptPlugin
  928.     char * mimebuf = NULL;
  929. #endif
  930.  
  931.     top_state = state->top_state;
  932.     doc_data = (pa_DocData *)top_state->doc_data;
  933.     XP_ASSERT(doc_data != NULL || state->in_relayout || tag->lo_data);
  934.  
  935.     if (tag->is_end == FALSE) {
  936.         PA_Block buff;
  937.         char *str, *url, *archiveSrc, *id, *codebase;
  938.  
  939.         /* Controversial default language value. */
  940.         top_state->version = JSVERSION_DEFAULT;
  941.         if (tag->type == P_STYLE || tag->type == P_LINK) {
  942.             top_state->in_script = top_state->default_style_script_type;
  943.         }
  944.         else {
  945.             /* in order to get old script behaviour, pretend
  946.              * that the content-type is explicitly set for all scripts
  947.              */
  948.             type_explicitly_set = TRUE;
  949.             top_state->in_script = SCRIPT_TYPE_MOCHA;
  950.         }
  951.  
  952.         /* XXX account for HTML comment bytes and  "lost" newlines */
  953.         if (lo_IsAnyCurrentAncestorSourced(state))
  954.             top_state->script_bytes = top_state->layout_bytes;
  955.         else
  956.             top_state->script_bytes = top_state->layout_bytes - tag->true_len;
  957.         if (tag->lo_data != NULL) {
  958.             top_state->script_bytes += (int32)tag->lo_data - 1;
  959.             tag->lo_data = NULL;
  960.         } 
  961.         else if (doc_data != NULL) {
  962.             top_state->script_bytes += doc_data->comment_bytes;
  963.         } 
  964.         else {
  965.             XP_ASSERT(state->in_relayout);
  966.         }
  967.  
  968.     lo_ParseScriptLanguage(context, tag, &top_state->in_script,
  969.                    &top_state->version);
  970. #ifdef DEBUG_ScriptPlugin
  971.         if (top_state->in_script == SCRIPT_TYPE_UNKNOWN)
  972.         {
  973.             mimebuf = npl_Script2mimeType(context,tag);
  974.             if (mimebuf){
  975.                 if (NPL_FindPluginEnabledForType(mimebuf)){
  976.                     top_state->in_script = SCRIPT_TYPE_PLUGIN;
  977.                     XP_ASSERT(top_state->mimetype == NULL);
  978.                     StrAllocCopy((char *)top_state->mimetype,mimebuf);
  979.                     XP_FREE(mimebuf);
  980.                     mimebuf = NULL;
  981.                 }
  982.                 else{
  983.                     XP_FREE(mimebuf);
  984.                     mimebuf = NULL;
  985.                 }
  986.             }
  987.         }
  988. #endif /* DEBUG_ScriptPlugin */
  989.  
  990.         buff = lo_FetchParamValue(context, tag, PARAM_TYPE);
  991.         if (buff != NULL) {
  992.             PA_LOCK(str, char *, buff);
  993.             if ((XP_STRCASECMP(str, js_content_type) == 0) ||
  994.                 (!XP_STRCASECMP(str, "text/javascript"))) {
  995.         if(tag->type == P_STYLE || tag->type == P_LINK)
  996.         {
  997.             top_state->in_script = SCRIPT_TYPE_JSSS;
  998.             top_state->default_style_script_type = SCRIPT_TYPE_JSSS;
  999.         }
  1000.         else
  1001.         {
  1002.             top_state->in_script = SCRIPT_TYPE_MOCHA;                    
  1003.         }
  1004.                 type_explicitly_set = TRUE;
  1005.             } 
  1006.             else if ((XP_STRCASECMP(str, TEXT_CSS) == 0)) {
  1007.                 top_state->in_script = SCRIPT_TYPE_CSS;
  1008.                 top_state->default_style_script_type = SCRIPT_TYPE_CSS;
  1009.                 type_explicitly_set = TRUE;
  1010.             } 
  1011.             else {
  1012.                 top_state->in_script = SCRIPT_TYPE_UNKNOWN;
  1013.                 top_state->default_style_script_type = SCRIPT_TYPE_UNKNOWN;
  1014.             }
  1015.             PA_UNLOCK(buff);
  1016.             PA_FREE(buff);
  1017.         } 
  1018.  
  1019.     /* check for media=screen
  1020.      * don't load the style sheet if there 
  1021.      * is a media not equal to screen
  1022.      */
  1023.     buff = lo_FetchParamValue(context, tag, PARAM_MEDIA);
  1024.     if (buff) {
  1025.         if (strcasecomp((char*)buff, "screen")) {
  1026.         /* set the script type to UNKNOWN
  1027.          * so that it will get thrown away
  1028.          */
  1029.         top_state->in_script = SCRIPT_TYPE_UNKNOWN;
  1030.         }
  1031.         PA_FREE(buff);
  1032.     }
  1033.  
  1034.         /*
  1035.          * Flush the line buffer so we can start storing Mocha script
  1036.          * source lines in there.
  1037.          */
  1038.         lo_FlushLineBuffer(context, state);
  1039.  
  1040.         url = archiveSrc = id = codebase = NULL;
  1041.         if (top_state->in_script != SCRIPT_TYPE_NOT) {
  1042.             /*
  1043.              * Check for the archive parameter for known languages.
  1044.              */
  1045.             buff = lo_FetchParamValue(context, tag, PARAM_ARCHIVE);
  1046.             if (buff != NULL) {
  1047.                 saw_archive = TRUE;
  1048.                 PA_LOCK(str, char *, buff);
  1049.                 url = NET_MakeAbsoluteURL(top_state->base_url, str);
  1050.                 PA_UNLOCK(buff);
  1051.                 PA_FREE(buff);
  1052.         if (url == NULL) {
  1053.                     top_state->out_of_memory = TRUE;
  1054.                     return;
  1055.         }
  1056.             }
  1057.  
  1058.             /* 
  1059.              * Look for ID attribute. If it's there we have may have
  1060.              * an inline signed script.
  1061.              */
  1062.             buff = lo_FetchParamValue(context, tag, PARAM_ID);
  1063.             if (buff != NULL) {
  1064.                 PA_LOCK(str, char *, buff);
  1065.                 StrAllocCopy(id, str);
  1066.                 PA_UNLOCK(buff);
  1067.                 PA_FREE(buff);
  1068.         if (id == NULL) {
  1069.                     top_state->out_of_memory = TRUE;
  1070.             XP_FREEIF(url);
  1071.                     return;
  1072.         }
  1073.             }
  1074.  
  1075.             /*
  1076.              * Now look for a SRC="url" attribute for known languages.
  1077.              * If found, synchronously load the url.
  1078.              */
  1079.         buff = lo_FetchParamValue(context, tag, PARAM_SRC);  /* XXX overloaded rv */
  1080.             if (buff != NULL) {
  1081.         XP_Bool allowFileSrc = FALSE;
  1082.                 char *absUrl;
  1083.  
  1084.                 PA_LOCK(str, char *, buff);
  1085.  
  1086.         PREF_GetBoolPref(lo_jsAllowFileSrcFromNonFile, &allowFileSrc);
  1087.                 absUrl = NET_MakeAbsoluteURL(top_state->base_url, str);
  1088.         if (absUrl == NULL) {
  1089.             top_state->out_of_memory = TRUE;
  1090.             XP_FREEIF(id);
  1091.                 } else if (allowFileSrc == FALSE &&
  1092.                    NET_URL_Type(absUrl) == FILE_TYPE_URL &&
  1093.                    NET_URL_Type(top_state->url) != FILE_TYPE_URL) {
  1094.             /*
  1095.              * Deny access from http: to file: via SCRIPT SRC=...
  1096.              * XXX silently
  1097.              */
  1098.                     top_state->in_script = SCRIPT_TYPE_UNKNOWN;
  1099.                     XP_FREE(absUrl);
  1100.                     XP_FREEIF(url);
  1101.             XP_FREEIF(id);
  1102.         } else if (url != NULL) {
  1103.                     XP_FREE(absUrl);
  1104.                     StrAllocCopy(archiveSrc, str);
  1105.             if (archiveSrc == NULL) {
  1106.             top_state->out_of_memory = TRUE;
  1107.             XP_FREE(url);
  1108.             XP_FREEIF(id);
  1109.             }
  1110.                 } else {
  1111.                     url = absUrl;
  1112.                 }
  1113.                 PA_UNLOCK(buff);
  1114.                 PA_FREE(buff);
  1115.         if (top_state->out_of_memory)
  1116.             return;
  1117.  
  1118.                 /*
  1119.                  * If we are doing a <script src=""> mocha script but JS
  1120.                  *   is turned off just ignore the tag
  1121.                  */
  1122.         if (!LM_CanDoJS(context)) {
  1123.                     top_state->in_script = SCRIPT_TYPE_UNKNOWN;
  1124.                     XP_FREE(url);
  1125.             XP_FREEIF(id);
  1126.             XP_FREEIF(archiveSrc);
  1127.                     return;
  1128.                 }
  1129.             }
  1130.         }
  1131.  
  1132.         /*
  1133.          * Set text_divert so we know to accumulate text in line_buf
  1134.          * without interpretation.
  1135.          */
  1136.         state->text_divert = tag->type;
  1137.  
  1138.         /*
  1139.          * XXX need to stack these to handle blocked SCRIPT tags
  1140.          */
  1141.         top_state->script_lineno = tag->newline_count + 1;
  1142.  
  1143.         /* if we got here as a result of a LINK tag
  1144.          * check to make sure rel=stylesheet and then
  1145.          * check for an HREF and if one does not exist
  1146.          * fail
  1147.          */
  1148.         if (tag->type == P_LINK) {
  1149.             char *cbuff = (char*)lo_FetchParamValue(context, tag, PARAM_REL);
  1150.                         
  1151.             if (cbuff && !strcasecomp(cbuff, "stylesheet")) {
  1152.                 XP_FREE(cbuff);
  1153.  
  1154.                 cbuff = (char*)lo_FetchParamValue(context, tag, PARAM_HREF);
  1155.  
  1156.                 if (cbuff) {
  1157.                     if (saw_archive && url) {
  1158.                         archiveSrc = XP_STRDUP(cbuff);
  1159.                     } else {
  1160.                 XP_FREEIF(url);
  1161.                         url = NET_MakeAbsoluteURL(top_state->base_url, cbuff);
  1162.                     }
  1163.         }
  1164.             }
  1165.  
  1166.             XP_FREEIF(cbuff);
  1167.         }
  1168.  
  1169.         if (url != NULL || id != NULL || codebase != NULL) {
  1170.             if ((doc_data != NULL) &&
  1171.                 (state->in_relayout == FALSE) &&
  1172.                 SCRIPT_EXEC_OK(top_state, state, tag->type, P_SCRIPT)) {
  1173.                 ScriptData *data;
  1174.  
  1175.                 data = XP_ALLOC(sizeof(ScriptData));
  1176.                 if (data == NULL) {
  1177.                     top_state->out_of_memory = TRUE;
  1178.                     return;
  1179.                 }
  1180.                 data->context = context;
  1181.                 data->state = state;
  1182.                 data->tag = PA_CloneMDLTag(tag);
  1183.                 if (data->tag == NULL) {
  1184.                     top_state->out_of_memory = TRUE;
  1185.             XP_FREE(data);
  1186.                     return;
  1187.                 }
  1188.                 data->url = url;
  1189.                 data->archiveSrc = archiveSrc;
  1190.                 data->id = id;
  1191.                 if (codebase == NULL) {
  1192.                     StrAllocCopy(codebase, top_state->base_url);
  1193.                 }
  1194.                 data->codebase = codebase;
  1195.                 data->buffer = NULL;
  1196.                 data->bufferSize = 0;
  1197.                 data->version = top_state->version;
  1198.  
  1199.         /*
  1200.          * Only SCRIPT ARCHIVE= ID= without SRC= is an inline signed
  1201.          * script -- if there is a SRC= attribute, archiveSrc will be
  1202.          * non-null.
  1203.          */
  1204.                 data->inlineSigned = (JSBool)
  1205.             (url != NULL && archiveSrc == NULL && id != NULL);
  1206.  
  1207.                 /* Reset version accumulator */
  1208.                 top_state->version = JSVERSION_UNKNOWN;
  1209.  
  1210.                 XP_ASSERT (tag->type == P_SCRIPT || tag->type == P_STYLE || 
  1211.                tag->type == P_LINK);
  1212.  
  1213.             /* 
  1214.          * Out-of-line included (by src=) or inline signed script.
  1215.          * Save continuatation data on top_state.  If it's signed,
  1216.          * we'll verify the signature once we see </script> and
  1217.          * have the inline script to verify.
  1218.          */
  1219.         top_state->scriptData = data;
  1220.  
  1221.             } 
  1222.         else {
  1223.                 XP_FREE(url);
  1224.         XP_FREEIF(id);
  1225.         XP_FREEIF(archiveSrc);
  1226.             }
  1227.         }
  1228.     } 
  1229.     else {
  1230.  
  1231.     /*
  1232.      * We are in the </script> tag now...
  1233.      */
  1234.  
  1235.         size_t line_buf_len;
  1236.         intn script_type;
  1237.         char *scope_to=NULL;
  1238.         char *untransformed = NULL;
  1239.  
  1240.         script_type = top_state->in_script;
  1241.         top_state->in_script = SCRIPT_TYPE_NOT;
  1242.  
  1243.     /* guard against superfluous end tags */
  1244.     if (script_type == SCRIPT_TYPE_NOT)
  1245.         goto end_tag_out;
  1246.  
  1247.     /* convert from CSS to JavaScript here */
  1248.         if (tag->type != P_LINK && script_type == SCRIPT_TYPE_CSS) {
  1249.             char *new_buffer;
  1250.             int32 new_buffer_length;
  1251.  
  1252.             CSS_ConvertToJS((char *)state->line_buf, 
  1253.                             state->line_buf_len,
  1254.                             &new_buffer,
  1255.                             &new_buffer_length);
  1256.  
  1257.             if (!new_buffer) {
  1258.                 /* css translator error, unblock layout and return */
  1259.                 state->text_divert = P_UNKNOWN;
  1260.                 state->line_buf_len = 0; /* clear script text */
  1261.                 goto end_tag_out;
  1262.             }
  1263.  
  1264.             untransformed = (char *) state->line_buf;
  1265.             state->line_buf = (PA_Block) new_buffer;
  1266.             state->line_buf_len = new_buffer_length;
  1267.             state->line_buf_size = new_buffer_length;
  1268.  
  1269.             if (state->line_buf_len)
  1270.                 state->line_buf_len--; /* hack: subtract one to remove final \n */
  1271.  
  1272.             script_type = SCRIPT_TYPE_JSSS;
  1273.         }
  1274.  
  1275.         if (tag->type == P_STYLE) {
  1276.             /* mocha scoped to document == jsss */
  1277.             scope_to = "document";
  1278.         }
  1279.  
  1280.         /*
  1281.          * Reset these before potentially recursing indirectly through
  1282.          * the document.write() built-in function, which writes to the
  1283.          * very same doc_data->parser_stream that this <SCRIPT> tag
  1284.          * came in on.
  1285.          */
  1286.         state->text_divert = P_UNKNOWN;
  1287.         line_buf_len = state->line_buf_len;
  1288.         state->line_buf_len = 0;
  1289.  
  1290.         if (script_type != SCRIPT_TYPE_UNKNOWN && 
  1291.         script_type != SCRIPT_TYPE_NOT) {
  1292.             /*
  1293.              * If mocha is disabled or can't be done in this context we
  1294.              *   are going to just ignore the buffer contents
  1295.              */
  1296.             if (!LM_CanDoJS(context)) {
  1297.                 top_state->in_script = SCRIPT_TYPE_UNKNOWN;
  1298.                 goto end_tag_out;
  1299.             }
  1300.  
  1301.             if ((doc_data != NULL) &&
  1302.                 (state->in_relayout == FALSE) &&
  1303.                 SCRIPT_EXEC_OK(top_state, state, tag->type, P_SCRIPT)) {
  1304.  
  1305.                 /*
  1306.                  * First off, make sure layout is blocking on us
  1307.                  */
  1308.                 if (lo_create_script_blockage(context, state, 
  1309.                     tag->type == P_SCRIPT ? LO_SCRIPT : LO_UNKNOWN)) 
  1310.                 {
  1311.                     ScriptData *data;
  1312.  
  1313.                     /*
  1314.                      * Extreme hackery.  Hideous and shameful.  See the comment
  1315.                         * in lo_BlockScriptTag before similar is_end/overflow code
  1316.                         * and commence vomiting.
  1317.                      */
  1318.                     lo_BlockScriptTag(context, state, NULL);
  1319.  
  1320.             if (tag->is_end == (PRPackedBool)1) {
  1321.               PA_PushOverflow(doc_data);
  1322.               doc_data->overflow_depth ++;
  1323.             }
  1324.  
  1325.             /*
  1326.              * Set the document.write tag insertion point.
  1327.              */
  1328.              top_state->input_write_point[top_state->input_write_level] = &top_state->tags;
  1329.  
  1330.             data = top_state->scriptData;
  1331.                     top_state->scriptData = NULL;
  1332.                     if (data && data->url) {
  1333.             /*
  1334.              * Three cases:
  1335.              * 1.  SCRIPT SRC=: url non-null
  1336.              * 2.  SCRIPT ARCHIVE= SRC=: url, archiveSrc non-null
  1337.              * 3.  SCRIPT ARCHIVE= ID=: url, id non-null
  1338.              * In the last case, we copy the inline script into
  1339.              * data's buffer and let lo_script_archive_exit_fn do
  1340.              * the eval.  We use an inlineSigned flag to avoid a
  1341.              * bunch of (url != NULL && archiveSrc == NULL && id
  1342.              * != NULL) tests.
  1343.              */
  1344.             if (data->inlineSigned) {
  1345.                             StrAllocCopy(data->buffer, (char *) state->line_buf);
  1346.                             data->bufferSize = line_buf_len;
  1347.             }
  1348.             lo_GetScriptFromURL(data, script_type);
  1349.                     }
  1350.             else {
  1351.                         JSPrincipals *principals = NULL;
  1352.             ETEvalStuff * stuff;
  1353.             
  1354.                         if (data) {
  1355.                 principals = LM_NewJSPrincipals(NULL, data->id, 
  1356.                                 data->codebase);
  1357.                             if (untransformed &&
  1358.                 !LM_SetUntransformedSource(principals, 
  1359.                                                            untransformed,
  1360.                                                            (char *) state->line_buf))
  1361.                             {
  1362.                                 top_state->out_of_memory = TRUE;
  1363.                             }
  1364.                             lo_DestroyScriptData(data);
  1365.             }
  1366.  
  1367.                         /* 
  1368.                          * send the buffer off to be evaluated 
  1369.              */
  1370. #ifdef DEBUG_ScriptPlugin
  1371.                          if (script_type == SCRIPT_TYPE_PLUGIN)
  1372.                         {
  1373.                             XP_ASSERT(mimebuf == NULL);
  1374.                             npl_ScriptPlugin(context, state, tag, line_buf_len,top_state->mimetype);
  1375.                             lo_unblock_script_tag(context, TRUE);
  1376.                         }
  1377.                         else
  1378. #endif /* DEBUG_ScriptPlugin */
  1379.  
  1380.  
  1381.             stuff = (ETEvalStuff *) XP_NEW_ZAP(ETEvalStuff);
  1382.             if (!stuff)
  1383.                 goto end_tag_out;
  1384.  
  1385.             stuff->len = line_buf_len;
  1386.             stuff->line_no = top_state->script_lineno;
  1387.             if (scope_to)
  1388.                 stuff->scope_to = XP_STRDUP(scope_to);
  1389.             else
  1390.                 stuff->scope_to = NULL;
  1391.             stuff->want_result = JS_FALSE;
  1392.             stuff->data = context;
  1393.             stuff->version = top_state->version;
  1394.             stuff->principals = principals;
  1395.  
  1396.                         ET_EvaluateScript(context, 
  1397.                                           (char *) state->line_buf,
  1398.                       stuff,
  1399.                                           lo_ScriptEvalExitFn);
  1400.                     }
  1401.  
  1402.                     /* Reset version accumulator */
  1403.                     top_state->version = JSVERSION_UNKNOWN;
  1404.                 }
  1405.             }
  1406.         }
  1407.       end_tag_out:
  1408.     /*
  1409.      * If we got a </SCRIPT> and still have scriptData set here, it must
  1410.      *   be left over from an error case above, so we free it.
  1411.      */
  1412.     if (top_state->scriptData) {
  1413.         XP_ASSERT(!top_state->layout_blocking_element);
  1414.             lo_DestroyScriptData(top_state->scriptData);
  1415.         top_state->scriptData = NULL;
  1416.     }
  1417.         XP_FREEIF(untransformed);
  1418.     }
  1419. }
  1420.  
  1421. static char script_reblock_tag[]   = "<" PT_NSCP_REBLOCK ">";
  1422.  
  1423. /*
  1424.  * Create a tag that will reblock us
  1425.  */
  1426. void
  1427. LO_CreateReblockTag(MWContext * context, LO_Element * current_script)
  1428. {
  1429.     lo_TopState *top_state;
  1430.     pa_DocData *doc_data;
  1431.     PA_Tag * tag/*, ** tag_ptr*/;
  1432.  
  1433.     top_state = lo_FetchTopState(XP_DOCID(context));
  1434.     doc_data = (pa_DocData *)top_state->doc_data;
  1435.  
  1436.     tag = pa_CreateMDLTag(doc_data,
  1437.                           script_reblock_tag,
  1438.                           sizeof script_reblock_tag - 1);
  1439.  
  1440.     if (tag == NULL)
  1441.         return;
  1442.  
  1443.     tag->lo_data = current_script;
  1444.     
  1445.     /*
  1446.      * Kludge in the write level for sanity check in lo_LayoutTag.
  1447.      */
  1448.     tag->newline_count = (uint16)top_state->input_write_level;
  1449.  
  1450.     /*
  1451.      * Add the reblock tag to the tags list but don't advance the write_point
  1452.      *   in case we just wrote a nested script that also writes: the inner
  1453.      *   script must insert before the outer reblock tag, but after all the
  1454.      *   earlier tags.
  1455.      */
  1456. /*    tag_ptr = top_state->input_write_point; */
  1457.     lo_BlockTag(context, NULL, tag);
  1458. /*    top_state->input_write_point = tag_ptr; */
  1459. }
  1460.