зеркало из https://github.com/mozilla/gecko-dev.git
583 строки
16 KiB
C
583 строки
16 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
/* Please leave outside of ifdef for windows precompiled headers */
|
|
#include "xp.h"
|
|
#include "plstr.h"
|
|
#include "prmem.h"
|
|
#include "netutils.h"
|
|
#include "mkselect.h"
|
|
#include "mktcp.h"
|
|
#include "mkgeturl.h"
|
|
|
|
#ifdef MOZILLA_CLIENT
|
|
|
|
/* take an HTML stream. Escape all the HTML and
|
|
* use <FONT color=> to color the different syntactical parts
|
|
* of the HTML stream
|
|
*/
|
|
#include "xpgetstr.h"
|
|
#include "intl_csi.h"
|
|
#define VIEW_SOURCE_TARGET_WINDOW_NAME "%ViewSourceWindow"
|
|
|
|
typedef enum StatesEnum {
|
|
IN_CONTENT,
|
|
IN_SCRIPT,
|
|
ABOUT_TO_BEGIN_TAG,
|
|
IN_BEGIN_TAG,
|
|
IN_TAG,
|
|
BEGIN_ATTRIBUTE_VALUE,
|
|
IN_QUOTED_ATTRIBUTE_VALUE,
|
|
IN_BROKEN_QUOTED_ATTRIBUTE_VALUE,
|
|
IN_UNQUOTED_ATTRIBUTE_VALUE,
|
|
IN_COMMENT,
|
|
IN_AMPERSAND_THINGY
|
|
} StatesEnum;
|
|
|
|
#define MAXTAGLEN 15
|
|
|
|
typedef struct _DataObject {
|
|
NET_StreamClass * next_stream;
|
|
StatesEnum state;
|
|
char tag[MAXTAGLEN+1];
|
|
uint tag_index;
|
|
PRBool in_broken_html;
|
|
} DataObject;
|
|
|
|
#define BEGIN_TAG_MARKUP "<B>"
|
|
#define END_TAG_MARKUP "</B>"
|
|
#define BEGIN_TAG_NAME_MARKUP "<FONT SIZE=+0 COLOR=\"#551A8B\">"
|
|
#define END_TAG_NAME_MARKUP "</FONT>"
|
|
#define BEGIN_ATTRIBUTE_VALUE_MARKUP "</B><FONT SIZE=+0 COLOR=\"003E98\">"
|
|
#define END_ATTRIBUTE_VALUE_MARKUP "</FONT><B>"
|
|
#define BEGIN_BROKEN_ATTRIBUTE_MARKUP "<FONT COLOR=#0000FF><BLINK>"
|
|
#define END_BROKEN_ATTRIBUTE_MARKUP "</BLINK></FONT>"
|
|
#define BEGIN_COMMENT_MARKUP "<I>"
|
|
#define END_COMMENT_MARKUP "</I>"
|
|
#define BEGIN_AMPERSAND_THINGY_MARKUP "<FONT SIZE=+0 COLOR=\"#2F4F2F\">"
|
|
#define END_AMPERSAND_THINGY_MARKUP "</FONT>"
|
|
|
|
extern int MK_CVCOLOR_SOURCE_OF;
|
|
|
|
PRIVATE char *net_BeginColorHTMLTag (DataObject *obj)
|
|
{
|
|
char *new_markup = 0;
|
|
|
|
StrAllocCat(new_markup, BEGIN_TAG_MARKUP);
|
|
StrAllocCat(new_markup, "<");
|
|
StrAllocCat(new_markup, BEGIN_TAG_NAME_MARKUP);
|
|
obj->state = ABOUT_TO_BEGIN_TAG;
|
|
return new_markup;
|
|
}
|
|
|
|
PRIVATE char *net_EndColorHTMLTag (DataObject *obj)
|
|
{
|
|
char *new_markup = 0;
|
|
|
|
if(obj->in_broken_html)
|
|
{
|
|
StrAllocCopy(new_markup, END_BROKEN_ATTRIBUTE_MARKUP);
|
|
obj->in_broken_html = PR_FALSE;
|
|
}
|
|
StrAllocCat(new_markup, ">");
|
|
StrAllocCat(new_markup, END_TAG_MARKUP);
|
|
return new_markup;
|
|
}
|
|
|
|
PRIVATE int net_ColorHTMLWrite (NET_StreamClass *stream, CONST char *s, int32 l)
|
|
{
|
|
int32 i;
|
|
int32 last_output_point;
|
|
char *new_markup=0;
|
|
char *tmp_markup=0;
|
|
char tiny_buf[4];
|
|
CONST char *cp;
|
|
int status;
|
|
DataObject *obj=stream->data_object;
|
|
|
|
last_output_point = 0;
|
|
|
|
for(i = 0, cp = s; i < l; i++, cp++)
|
|
{
|
|
switch(obj->state)
|
|
{
|
|
case IN_CONTENT:
|
|
/* do nothing until you find a '<' "<!--" or '&' */
|
|
if(*cp == '<')
|
|
{
|
|
/* XXX we can miss a comment spanning a block boundary */
|
|
if(i+4 <= l && !PL_strncmp(cp, "<!--", 4))
|
|
{
|
|
StrAllocCopy(new_markup, BEGIN_COMMENT_MARKUP);
|
|
StrAllocCat(new_markup, "<");
|
|
obj->state = IN_COMMENT;
|
|
}
|
|
else
|
|
{
|
|
new_markup = net_BeginColorHTMLTag(obj);
|
|
}
|
|
}
|
|
else if(*cp == '&')
|
|
{
|
|
StrAllocCopy(new_markup, BEGIN_AMPERSAND_THINGY_MARKUP);
|
|
StrAllocCat(new_markup, "&");
|
|
obj->state = IN_AMPERSAND_THINGY;
|
|
}
|
|
break;
|
|
case IN_SCRIPT:
|
|
/* do nothing until you find '</SCRIPT>' */
|
|
if(*cp == '<')
|
|
{
|
|
/* XXX we can miss a </SCRIPT> spanning a block boundary */
|
|
if(i+8 <= l && !PL_strncasecmp(cp, "</SCRIPT", 8))
|
|
{
|
|
new_markup = net_BeginColorHTMLTag(obj);
|
|
}
|
|
}
|
|
break;
|
|
case ABOUT_TO_BEGIN_TAG:
|
|
/* we have seen the first '<'
|
|
* once we see a non-whitespace character
|
|
* we will be in the tag identifier
|
|
*/
|
|
if(*cp == '>')
|
|
{
|
|
StrAllocCopy(new_markup, END_TAG_NAME_MARKUP);
|
|
tmp_markup = net_EndColorHTMLTag(obj);
|
|
StrAllocCat(new_markup, tmp_markup);
|
|
PR_FREEIF(tmp_markup);
|
|
tmp_markup = NULL;
|
|
}
|
|
else if(!NET_IS_SPACE(*cp))
|
|
{
|
|
obj->state = IN_BEGIN_TAG;
|
|
obj->tag_index = 0;
|
|
obj->tag[obj->tag_index++] = *cp;
|
|
if(*cp == '<')
|
|
StrAllocCopy(new_markup, "<");
|
|
|
|
}
|
|
break;
|
|
case IN_BEGIN_TAG:
|
|
/* go to the IN_TAG state when we see
|
|
* the first whitespace
|
|
*/
|
|
if(NET_IS_SPACE(*cp))
|
|
{
|
|
StrAllocCopy(new_markup, END_TAG_NAME_MARKUP);
|
|
sprintf(tiny_buf, "%c", *cp);
|
|
StrAllocCat(new_markup, tiny_buf);
|
|
obj->state = IN_TAG;
|
|
obj->tag[obj->tag_index] = '\0';
|
|
}
|
|
else if(*cp == '>')
|
|
{
|
|
StrAllocCopy(new_markup, END_TAG_NAME_MARKUP);
|
|
tmp_markup = net_EndColorHTMLTag(obj);
|
|
StrAllocCat(new_markup, tmp_markup);
|
|
PR_FREEIF(tmp_markup);
|
|
tmp_markup = NULL;
|
|
}
|
|
else if(*cp == '<')
|
|
{
|
|
/* protect ourselves from markup */
|
|
if(!obj->in_broken_html)
|
|
{
|
|
obj->in_broken_html = PR_TRUE;
|
|
StrAllocCopy(new_markup, BEGIN_BROKEN_ATTRIBUTE_MARKUP);
|
|
StrAllocCat(new_markup, "<");
|
|
}
|
|
else
|
|
{
|
|
StrAllocCopy(new_markup, "<");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (obj->tag_index < MAXTAGLEN)
|
|
obj->tag[obj->tag_index++] = *cp;
|
|
}
|
|
break;
|
|
case IN_TAG:
|
|
/* do nothing until you find a opening '=' or end '>' */
|
|
if(*cp == '=')
|
|
{
|
|
StrAllocCopy(new_markup, "=");
|
|
StrAllocCat(new_markup, BEGIN_ATTRIBUTE_VALUE_MARKUP);
|
|
obj->state = BEGIN_ATTRIBUTE_VALUE;
|
|
}
|
|
else if(*cp == '>')
|
|
{
|
|
new_markup = net_EndColorHTMLTag(obj);
|
|
}
|
|
else if(*cp == '<')
|
|
{
|
|
/* protect ourselves from markup */
|
|
StrAllocCopy(new_markup, "<");
|
|
}
|
|
break;
|
|
case BEGIN_ATTRIBUTE_VALUE:
|
|
/* when we reach the first non-whitespace
|
|
* we will enter the UNQUOTED or the QUOTED
|
|
* ATTRIBUTE state
|
|
*/
|
|
if(!NET_IS_SPACE(*cp))
|
|
{
|
|
if(*cp == '"')
|
|
{
|
|
obj->state = IN_QUOTED_ATTRIBUTE_VALUE;
|
|
/* no need to jump to the quoted attr handler
|
|
* since this char can't be a dangerous char
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
obj->state = IN_UNQUOTED_ATTRIBUTE_VALUE;
|
|
/* need to jump to the unquoted attr handler
|
|
* since this char can be a dangerous character
|
|
*/
|
|
goto unquoted_attribute_jump_point;
|
|
}
|
|
}
|
|
else if(*cp == '>')
|
|
{
|
|
StrAllocCopy(new_markup, END_ATTRIBUTE_VALUE_MARKUP);
|
|
tmp_markup = net_EndColorHTMLTag(obj);
|
|
StrAllocCat(new_markup, tmp_markup);
|
|
PR_FREEIF(tmp_markup);
|
|
tmp_markup = NULL;
|
|
}
|
|
else if(*cp == '<')
|
|
{
|
|
/* protect ourselves from markup */
|
|
StrAllocCopy(new_markup, "<");
|
|
}
|
|
break;
|
|
case IN_UNQUOTED_ATTRIBUTE_VALUE:
|
|
unquoted_attribute_jump_point:
|
|
/* do nothing until you find a whitespace */
|
|
if(NET_IS_SPACE(*cp))
|
|
{
|
|
StrAllocCopy(new_markup, END_ATTRIBUTE_VALUE_MARKUP);
|
|
sprintf(tiny_buf, "%c", *cp);
|
|
StrAllocCat(new_markup, tiny_buf);
|
|
obj->state = IN_TAG;
|
|
}
|
|
else if(*cp == '>')
|
|
{
|
|
StrAllocCopy(new_markup, END_ATTRIBUTE_VALUE_MARKUP);
|
|
tmp_markup = net_EndColorHTMLTag(obj);
|
|
StrAllocCat(new_markup, tmp_markup);
|
|
PR_FREEIF(tmp_markup);
|
|
tmp_markup = NULL;
|
|
}
|
|
else if(*cp == '<')
|
|
{
|
|
/* protect ourselves from markup */
|
|
StrAllocCopy(new_markup, "<");
|
|
}
|
|
else if(*cp == '&')
|
|
{
|
|
/* protect ourselves from markup */
|
|
StrAllocCopy(new_markup, "&");
|
|
}
|
|
break;
|
|
case IN_QUOTED_ATTRIBUTE_VALUE:
|
|
/* do nothing until you find a closing '"' */
|
|
if(*cp == '\"')
|
|
{
|
|
if(obj->in_broken_html)
|
|
{
|
|
StrAllocCopy(new_markup, END_BROKEN_ATTRIBUTE_MARKUP);
|
|
obj->in_broken_html = PR_FALSE;
|
|
}
|
|
StrAllocCat(new_markup, "\"");
|
|
StrAllocCat(new_markup, END_ATTRIBUTE_VALUE_MARKUP);
|
|
obj->state = IN_TAG;
|
|
}
|
|
else if(*cp == '<')
|
|
{
|
|
/* protect ourselves from markup */
|
|
StrAllocCopy(new_markup, "<");
|
|
}
|
|
else if(*cp == '&')
|
|
{
|
|
/* protect ourselves from markup */
|
|
StrAllocCopy(new_markup, "&");
|
|
}
|
|
else if(*cp == '>')
|
|
{
|
|
/* probably a broken attribute value */
|
|
if(!obj->in_broken_html)
|
|
{
|
|
obj->in_broken_html = PR_TRUE;
|
|
StrAllocCopy(new_markup, BEGIN_BROKEN_ATTRIBUTE_MARKUP);
|
|
StrAllocCat(new_markup, ">");
|
|
}
|
|
}
|
|
break;
|
|
case IN_COMMENT:
|
|
/* do nothing until you find a closing '-->' */
|
|
if(!PL_strncmp(cp, "-->", 3))
|
|
{
|
|
StrAllocCopy(new_markup, ">");
|
|
cp += 2;
|
|
i += 2;
|
|
StrAllocCat(new_markup, END_COMMENT_MARKUP);
|
|
obj->state = IN_CONTENT;
|
|
}
|
|
else if(*cp == '<')
|
|
{
|
|
/* protect ourselves from markup */
|
|
StrAllocCopy(new_markup, "<");
|
|
}
|
|
break;
|
|
case IN_AMPERSAND_THINGY:
|
|
/* do nothing until you find a ';' or space */
|
|
if(*cp == ';' || NET_IS_SPACE(*cp))
|
|
{
|
|
sprintf(tiny_buf, "%c", *cp);
|
|
StrAllocCopy(new_markup, tiny_buf);
|
|
StrAllocCat(new_markup, END_AMPERSAND_THINGY_MARKUP);
|
|
obj->state = IN_CONTENT;
|
|
}
|
|
else if(*cp == '<')
|
|
{
|
|
/* protect ourselves from markup */
|
|
StrAllocCopy(new_markup, "<");
|
|
}
|
|
break;
|
|
default:
|
|
PR_ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
if(new_markup)
|
|
{
|
|
/* push all the way up to but not including *cp */
|
|
status = (*obj->next_stream->put_block)
|
|
(obj->next_stream,
|
|
&s[last_output_point],
|
|
i-last_output_point);
|
|
last_output_point = i+1;
|
|
|
|
if(status < 0)
|
|
{
|
|
PR_Free(new_markup);
|
|
return(status);
|
|
}
|
|
|
|
/* add new markup */
|
|
status = (*obj->next_stream->put_block)
|
|
(obj->next_stream,
|
|
new_markup, PL_strlen(new_markup));
|
|
if(status < 0)
|
|
{
|
|
PR_Free(new_markup);
|
|
return(status);
|
|
}
|
|
|
|
PR_FREEIF(new_markup);
|
|
new_markup = NULL;
|
|
}
|
|
}
|
|
|
|
if(last_output_point < l)
|
|
return((*obj->next_stream->put_block)(obj->next_stream,
|
|
&s[last_output_point],
|
|
(l-last_output_point)));
|
|
else
|
|
return(0);
|
|
}
|
|
|
|
/* is the stream ready for writeing?
|
|
*/
|
|
PRIVATE unsigned int net_ColorHTMLWriteReady (NET_StreamClass * stream)
|
|
{
|
|
DataObject *obj=stream->data_object;
|
|
return((*obj->next_stream->is_write_ready)(obj->next_stream));
|
|
}
|
|
|
|
|
|
PRIVATE void net_ColorHTMLComplete (NET_StreamClass *stream)
|
|
{
|
|
DataObject *obj=stream->data_object;
|
|
(*obj->next_stream->complete)(obj->next_stream);
|
|
}
|
|
|
|
PRIVATE void net_ColorHTMLAbort (NET_StreamClass *stream, int status)
|
|
{
|
|
DataObject *obj=stream->data_object;
|
|
(*obj->next_stream->abort)(obj->next_stream, status);
|
|
}
|
|
|
|
PUBLIC NET_StreamClass *
|
|
net_ColorHTMLStream (int format_out,
|
|
void *data_obj,
|
|
URL_Struct *URL_s,
|
|
MWContext *window_id)
|
|
{
|
|
DataObject* obj;
|
|
char *new_markup=0;
|
|
char *new_url=0;
|
|
char *old_url;
|
|
int status, type;
|
|
NET_StreamClass *next_stream, *new_stream;
|
|
PRBool is_html_stream = PR_FALSE;
|
|
INTL_CharSetInfo csi = LO_GetDocumentCharacterSetInfo(window_id);
|
|
INTL_CharSetInfo next_csi;
|
|
|
|
TRACEMSG(("Setting up ColorHTML stream. Have URL: %s\n", URL_s->address));
|
|
|
|
/* treat the stream as html if the closure data says
|
|
* it's HTML and it is also not a mail or news message
|
|
*/
|
|
type = NET_URL_Type(URL_s->address);
|
|
if(data_obj
|
|
&& !PL_strcmp((char *)data_obj, TEXT_HTML)
|
|
&& type != MAILBOX_TYPE_URL
|
|
&& type != IMAP_TYPE_URL
|
|
&& type != NEWS_TYPE_URL)
|
|
is_html_stream = PR_TRUE;
|
|
|
|
/* use a new named window */
|
|
StrAllocCopy(URL_s->window_target, VIEW_SOURCE_TARGET_WINDOW_NAME);
|
|
|
|
/* add the url address to the name so that there can be
|
|
* one view source window per url
|
|
*/
|
|
StrAllocCat(URL_s->window_target, URL_s->address);
|
|
|
|
/* zero position_tag to prevent hash lossage */
|
|
URL_s->position_tag = 0;
|
|
|
|
/* alloc a new chrome struct and stick it in the URL
|
|
* so that we can turn off the relavent stuff
|
|
*/
|
|
URL_s->window_chrome = PR_NEW(Chrome);
|
|
if(URL_s->window_chrome)
|
|
{
|
|
/* zero everything to turn off all chrome */
|
|
memset(URL_s->window_chrome, 0, sizeof(Chrome));
|
|
URL_s->window_chrome->type = MWContextDialog;
|
|
URL_s->window_chrome->show_scrollbar = PR_TRUE;
|
|
URL_s->window_chrome->allow_resize = PR_TRUE;
|
|
URL_s->window_chrome->allow_close = PR_TRUE;
|
|
}
|
|
|
|
/* call the HTML parser */
|
|
StrAllocCopy(URL_s->content_type, INTERNAL_PARSER);
|
|
|
|
/* use the view-source: url instead */
|
|
StrAllocCopy(new_url, VIEW_SOURCE_URL_PREFIX);
|
|
StrAllocCat(new_url, URL_s->address);
|
|
old_url = URL_s->address;
|
|
URL_s->address = new_url;
|
|
|
|
format_out = FO_PRESENT;
|
|
|
|
/* open next stream */
|
|
next_stream = NET_StreamBuilder(format_out, URL_s, window_id);
|
|
|
|
if(!next_stream)
|
|
{
|
|
PR_Free(old_url);
|
|
return(NULL);
|
|
}
|
|
next_csi = LO_GetDocumentCharacterSetInfo(next_stream->window_id);
|
|
|
|
/* jliu: for international's reason,
|
|
set the value ASAP, so the following stream can share it */
|
|
INTL_SetCSIWinCSID(next_csi, INTL_GetCSIWinCSID(csi));
|
|
INTL_SetCSIDocCSID(next_csi, INTL_GetCSIDocCSID(csi));
|
|
|
|
|
|
#define DEF_PICS_LABEL "<META http-equiv=PICS-Label content='(PICS-1.0 \"http://home.netscape.com/default_rating\" l gen true r (s 0))'>"
|
|
|
|
/* add a PICS label */
|
|
StrAllocCopy(new_markup, DEF_PICS_LABEL);
|
|
StrAllocCat(new_markup, "<TITLE>");
|
|
StrAllocCat(new_markup, XP_GetString(MK_CVCOLOR_SOURCE_OF));
|
|
StrAllocCat(new_markup, old_url);
|
|
StrAllocCat(new_markup, "</TITLE><BODY BGCOLOR=#C0C0C0>");
|
|
|
|
|
|
if(!is_html_stream)
|
|
StrAllocCat(new_markup, "<PLAINTEXT>");
|
|
else
|
|
StrAllocCat(new_markup, "<PRE>");
|
|
|
|
PR_Free(old_url);
|
|
|
|
status = (*next_stream->put_block)(next_stream,
|
|
new_markup,
|
|
PL_strlen(new_markup));
|
|
PR_Free(new_markup);
|
|
|
|
if(status < 0)
|
|
{
|
|
(*next_stream->abort)(next_stream, status);
|
|
PR_Free(next_stream);
|
|
return(NULL);
|
|
}
|
|
|
|
if(!is_html_stream)
|
|
return(next_stream);
|
|
|
|
/* else; continue on and build up this stream module
|
|
* and attach the next stream to it
|
|
*/
|
|
|
|
new_stream = PR_NEW(NET_StreamClass);
|
|
if(new_stream == NULL)
|
|
{
|
|
(*next_stream->abort)(next_stream, status);
|
|
PR_Free(next_stream);
|
|
return(NULL);
|
|
}
|
|
|
|
obj = PR_NEW(DataObject);
|
|
|
|
if (obj == NULL)
|
|
{
|
|
(*next_stream->abort)(next_stream, status);
|
|
PR_Free(next_stream);
|
|
PR_Free(new_stream);
|
|
return(NULL);
|
|
}
|
|
|
|
memset(obj, 0, sizeof(DataObject));
|
|
|
|
obj->state = IN_CONTENT;
|
|
|
|
obj->next_stream = next_stream;
|
|
|
|
new_stream->name = "HTML Colorer";
|
|
new_stream->complete = (MKStreamCompleteFunc) net_ColorHTMLComplete;
|
|
new_stream->abort = (MKStreamAbortFunc) net_ColorHTMLAbort;
|
|
new_stream->put_block = (MKStreamWriteFunc) net_ColorHTMLWrite;
|
|
new_stream->is_write_ready = (MKStreamWriteReadyFunc)
|
|
net_ColorHTMLWriteReady;
|
|
new_stream->data_object = (void *) obj; /* document info object */
|
|
new_stream->window_id = window_id;
|
|
|
|
TRACEMSG(("Returning stream from HTMLColorConverter\n"));
|
|
|
|
return new_stream;
|
|
}
|
|
#endif /* MOZILLA_CLIENT */
|