mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
1245 lines
37 KiB
C
1245 lines
37 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.
|
|
*/
|
|
/*
|
|
* Do stream related stuff like push data down the
|
|
* stream and determine which converter to use to
|
|
* set up the stream.
|
|
* Additions/Changes by Judson Valeski 1998
|
|
*/
|
|
#include "mkutils.h"
|
|
#include "cstream.h"
|
|
#include "plstr.h"
|
|
#include "prmem.h"
|
|
#include "mkgeturl.h"
|
|
#include "netstream.h"
|
|
#include "strmutil.h"
|
|
#include "mktcp.h"
|
|
|
|
/* for XP_GetString() */
|
|
#include "xpgetstr.h"
|
|
extern int XP_ALERT_CANTFIND_CONVERTER;
|
|
|
|
|
|
#ifdef PROFILE
|
|
#pragma profile on
|
|
#endif
|
|
|
|
typedef struct _net_ConverterStruct {
|
|
XP_List * converter_stack; /* the ordered list of converters;
|
|
* elements are net_ConverterElement's
|
|
*/
|
|
char * format_in; /* the input (mime) type that the
|
|
* function accepts
|
|
*/
|
|
char * encoding_in; /* the input content-encoding that the
|
|
* function accepts, or 0 for `any'.
|
|
*/
|
|
FO_Present_Types format_out; /* the output type of the function */
|
|
Bool bAutomated; /* this flag currently only used by Window on the
|
|
client side. */
|
|
} net_ConverterStruct;
|
|
|
|
typedef struct _net_ConverterElement {
|
|
NET_Converter * converter; /* the converter function */
|
|
void * data_obj; /* a converter specific data object
|
|
* passed in at the
|
|
* time of registration
|
|
*/
|
|
} net_ConverterElement;
|
|
|
|
/* MWH - this is an ugly implement to get get around the following: I need to pass
|
|
a flag to NET_RegisterContentTypeConverter(), but I don't want to change the API.
|
|
If we changed this API please fixed this problem.
|
|
*/
|
|
|
|
static Bool autoFlag = 0;
|
|
|
|
#define MAX_FORMATS_OUT FO_ONLY_FROM_CACHE_AND_LOAD_HTML_HELP_MAP_FILE +1
|
|
|
|
static Bool needInit = TRUE; /* this is the flag to tell us that we need to initialize
|
|
net_converter_list, and net_decoder_list. */
|
|
|
|
PRIVATE XP_List * net_converter_list[MAX_FORMATS_OUT]; /* a list of converters */
|
|
PRIVATE XP_List * net_decoder_list[MAX_FORMATS_OUT]; /* a list of decoders */
|
|
|
|
#define NET_MIME_EXACT_MATCH 1
|
|
#define NET_MIME_PARTIAL_MATCH 2
|
|
#define NET_WILDCARD_MATCH 3
|
|
|
|
/* will compare two mime times and return
|
|
* NET_MIME_EXACT_MATCH if they match exactly
|
|
* or NET_MIME_PARTIAL_MATCH if they match due
|
|
* to a wildcard entry (image.*, or movie.*).
|
|
*
|
|
* if 'partial' equals '*' then
|
|
* NET_WILDCARD_MATCH is returned
|
|
*
|
|
* If there is no match then 0(zero) is returned
|
|
*/
|
|
PRIVATE int
|
|
net_compare_mime_types(char * absolute, char * partial)
|
|
{
|
|
char *star;
|
|
|
|
TRACEMSG(("StreamBuilder: Comparing %s and %s\n",absolute, partial));
|
|
|
|
if(!PL_strcasecmp(absolute, partial))
|
|
return(NET_MIME_EXACT_MATCH);
|
|
|
|
if(!PL_strcmp(partial, "*"))
|
|
return(NET_WILDCARD_MATCH);
|
|
|
|
if((star = PL_strchr(partial, '*')) == 0)
|
|
return(0); /* not a wildcard mime type */
|
|
|
|
/* compare just the part before the slash star
|
|
*
|
|
*/
|
|
if(!PL_strncasecmp(absolute, partial, (star-1)-partial))
|
|
return(NET_MIME_PARTIAL_MATCH);
|
|
|
|
return(0); /* no match */
|
|
}
|
|
|
|
PUBLIC XP_Bool
|
|
NET_HaveConverterForMimeType(char *content_type)
|
|
{
|
|
net_ConverterStruct * cs_ptr;
|
|
XP_List * ct_list_ptr = net_converter_list[FO_PRESENT];
|
|
|
|
while ((cs_ptr=(net_ConverterStruct *) XP_ListNextObject(ct_list_ptr))
|
|
!= 0)
|
|
{
|
|
if (FO_PRESENT == cs_ptr->format_out)
|
|
{
|
|
int compare_val = net_compare_mime_types (content_type, cs_ptr->format_in);
|
|
if (compare_val == NET_MIME_PARTIAL_MATCH || compare_val == NET_MIME_EXACT_MATCH)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Find a converter routine to create a stream and return the stream struct
|
|
*/
|
|
PUBLIC NET_StreamClass *
|
|
NET_StreamBuilder (FO_Present_Types format_out,
|
|
URL_Struct *URL_s,
|
|
MWContext *context)
|
|
{
|
|
net_ConverterStruct * cs_ptr;
|
|
XP_List * ct_list_ptr = net_converter_list[format_out];
|
|
|
|
|
|
|
|
XP_List * ce_list_ptr = net_decoder_list[format_out];
|
|
|
|
assert (URL_s->content_type);
|
|
|
|
TRACEMSG(("Entering StreamBuilder:\n\
|
|
F-in: %s\n\
|
|
F-out: %d\n\
|
|
Enc: %s\n",URL_s->content_type,format_out,
|
|
(URL_s->content_encoding ? URL_s->content_encoding : "None Specified")));
|
|
|
|
#if 0
|
|
/* First, determine whether there is a content-type converter for this
|
|
document; if there isn't one, then the only way to handle it is to
|
|
send it straight to disk, so try that.
|
|
*/
|
|
if (format_out != FO_SAVE_TO_DISK)
|
|
{
|
|
while ((cs_ptr=(net_ConverterStruct *) XP_ListNextObject(ct_list_ptr))
|
|
!= 0)
|
|
{
|
|
if (format_out == cs_ptr->format_out &&
|
|
net_compare_mime_types (URL_s->content_type,
|
|
cs_ptr->format_in))
|
|
break;
|
|
}
|
|
|
|
if (! cs_ptr) /* There is no content-type converter; save it. */
|
|
format_out = FO_SAVE_TO_DISK;
|
|
ct_list_ptr = net_converter_list; /* Reset for next traversal. */
|
|
}
|
|
#endif
|
|
|
|
|
|
/* if there are content encodings then
|
|
* execute decoders first
|
|
*/
|
|
/* go through list of converters and choose
|
|
* the first exact or partial match we
|
|
* find. The order of the list
|
|
* is guarenteed by the registration
|
|
* routines
|
|
*
|
|
* the format-out is compared as well.
|
|
*
|
|
* if there are transfer_encodings use them even before
|
|
* content_encodings
|
|
*/
|
|
if ((URL_s->transfer_encoding && *URL_s->transfer_encoding)
|
|
|| (URL_s->content_encoding && *URL_s->content_encoding))
|
|
{
|
|
char *encoding;
|
|
|
|
if(URL_s->transfer_encoding && *URL_s->transfer_encoding)
|
|
encoding = URL_s->transfer_encoding;
|
|
else
|
|
encoding = URL_s->content_encoding;
|
|
|
|
|
|
while ((cs_ptr=(net_ConverterStruct *) XP_ListNextObject(ce_list_ptr))
|
|
!= 0)
|
|
{
|
|
if (format_out == cs_ptr->format_out &&
|
|
net_compare_mime_types (URL_s->content_type,
|
|
cs_ptr->format_in) &&
|
|
net_compare_mime_types (encoding,
|
|
cs_ptr->encoding_in))
|
|
{
|
|
net_ConverterElement *elem = XP_ListPeekTopObject(cs_ptr->converter_stack);
|
|
PR_ASSERT(elem != (net_ConverterElement *)0);
|
|
return ((NET_StreamClass *)
|
|
((*elem->converter)
|
|
(format_out, elem->data_obj, URL_s, context)));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* now search for content-type converters
|
|
*/
|
|
/* go through list of converters and choose
|
|
* the first exact or partial match we
|
|
* find. The order of the list
|
|
* is guarenteed by the registration
|
|
* routines
|
|
*/
|
|
while((cs_ptr=(net_ConverterStruct *) XP_ListNextObject(ct_list_ptr)) != 0)
|
|
{
|
|
if(format_out == cs_ptr->format_out)
|
|
if(net_compare_mime_types(URL_s->content_type, cs_ptr->format_in))
|
|
{
|
|
net_ConverterElement *elem = XP_ListPeekTopObject(cs_ptr->converter_stack);
|
|
PR_ASSERT(elem != (net_ConverterElement *)0);
|
|
return( (NET_StreamClass *) (*elem->converter) (format_out,
|
|
elem->data_obj, URL_s, context));
|
|
}
|
|
}
|
|
|
|
TRACEMSG(("Alert! did not find a converter or decoder\n"));
|
|
FE_Alert(context, XP_GetString(XP_ALERT_CANTFIND_CONVERTER));
|
|
|
|
return(0); /* Uh-oh. didn't find a converter. VERY VERY BAD! */
|
|
}
|
|
|
|
/* prints out all presentation mime types during successive calls
|
|
* call with first equal true to reset to the beginning
|
|
* and with first equal false to print out the next
|
|
* converter in the list. Returns zero when all converters
|
|
* are printed out.
|
|
*/
|
|
MODULE_PRIVATE char *
|
|
XP_ListNextPresentationType(PRBool first)
|
|
{
|
|
static XP_List * converter_list_ptr;
|
|
net_ConverterStruct * converter;
|
|
|
|
/* reset list pointers
|
|
*/
|
|
if(first)
|
|
converter_list_ptr = net_converter_list[FO_PRESENT];
|
|
|
|
/* print out next converter if there are any more
|
|
*/
|
|
converter = (net_ConverterStruct *) XP_ListNextObject(converter_list_ptr);
|
|
|
|
if(converter && converter->format_out == FO_PRESENT)
|
|
return(converter->format_in);
|
|
|
|
/* else */
|
|
return(NULL);
|
|
}
|
|
|
|
/* prints out all encoding mime types during successive calls
|
|
* call with first equal true to reset to the beginning
|
|
* and with first equal false to print out the next
|
|
* converter in the list. Returns zero when all converters
|
|
* are printed out.
|
|
*/
|
|
MODULE_PRIVATE char *
|
|
XP_ListNextEncodingType(PRBool first)
|
|
{
|
|
static XP_List * decoder_list_ptr;
|
|
net_ConverterStruct * converter;
|
|
static int count;
|
|
static index = 0;
|
|
static int curArrayIndex = 0;
|
|
|
|
|
|
while ((index < count) && (curArrayIndex < MAX_FORMATS_OUT)) {
|
|
decoder_list_ptr = net_decoder_list[curArrayIndex];
|
|
count = XP_ListCount(decoder_list_ptr);
|
|
if (count > 0) {
|
|
index = 0;
|
|
break;
|
|
}
|
|
else count++;
|
|
}
|
|
#if 0
|
|
/* reset list pointers
|
|
*/
|
|
if(first)
|
|
{
|
|
decoder_list_ptr = net_decoder_list;
|
|
}
|
|
#endif
|
|
converter = (net_ConverterStruct *) XP_ListNextObject(decoder_list_ptr);
|
|
if(converter) {
|
|
index++;
|
|
return(converter->format_in);
|
|
}
|
|
|
|
/* else */
|
|
return(NULL);
|
|
}
|
|
|
|
PRIVATE void
|
|
net_RegisterGenericConverterOrDecoder(XP_List ** conv_list,
|
|
char * format_in,
|
|
char * encoding_in,
|
|
FO_Present_Types format_out,
|
|
void * data_obj,
|
|
NET_Converter * converter_func)
|
|
{
|
|
XP_List * list_ptr = *conv_list;
|
|
net_ConverterStruct * converter_struct_ptr;
|
|
net_ConverterStruct * new_converter_struct;
|
|
net_ConverterElement *elem;
|
|
int f_in_type;
|
|
XP_List *pList;
|
|
int i;
|
|
|
|
if (needInit) { /* MWH - this will only happen once. It is pretty ugly,
|
|
but I don't know how to get around it. */
|
|
needInit = FALSE;
|
|
|
|
for (i = 0; i <MAX_FORMATS_OUT;i++) {
|
|
net_converter_list[i] = net_decoder_list[i] = 0;
|
|
}
|
|
|
|
}
|
|
|
|
pList = list_ptr = conv_list[format_out];
|
|
/* check for an existing converter with the same format_in and format_out
|
|
* and add this to the list if found.
|
|
*
|
|
* if the list is NULL XP_ListNextObject will return 0
|
|
*/
|
|
while((converter_struct_ptr = (net_ConverterStruct *) XP_ListNextObject(list_ptr)) != 0){
|
|
if(format_out == converter_struct_ptr->format_out)
|
|
/* Rewritten to logic equivalent but should-be-faster version:*/
|
|
if (((!encoding_in && !converter_struct_ptr->encoding_in) ||
|
|
(encoding_in && converter_struct_ptr->encoding_in &&
|
|
!PL_strcmp (encoding_in,
|
|
converter_struct_ptr->encoding_in)))
|
|
&& !PL_strcasecmp(format_in, converter_struct_ptr->format_in)
|
|
#ifdef XP_WIN
|
|
&& (converter_struct_ptr->bAutomated == autoFlag)
|
|
#endif
|
|
)
|
|
{
|
|
/* Add a new converter element to the list */
|
|
net_ConverterElement *elem = PR_NEWZAP(net_ConverterElement);
|
|
if( elem == (net_ConverterElement *)0 ) return;
|
|
elem->converter = converter_func;
|
|
elem->data_obj = data_obj;
|
|
XP_ListAddObject(converter_struct_ptr->converter_stack, elem);
|
|
return;
|
|
}
|
|
}
|
|
/* find out the type of entry format_in is
|
|
*/
|
|
f_in_type = NET_MIME_EXACT_MATCH;
|
|
if(PL_strchr(format_in, '*'))
|
|
{
|
|
if(!PL_strcmp(format_in, "*"))
|
|
f_in_type = NET_WILDCARD_MATCH;
|
|
else
|
|
f_in_type = NET_MIME_PARTIAL_MATCH;
|
|
}
|
|
|
|
/* if existing converter not found/replaced
|
|
* add this converter to the list in
|
|
* its order of importance so that we can
|
|
* take the first exact or partial fit
|
|
*/
|
|
new_converter_struct = PR_NEW(net_ConverterStruct);
|
|
if(!new_converter_struct) {
|
|
return;
|
|
}
|
|
|
|
new_converter_struct->converter_stack = XP_ListNew();
|
|
if( new_converter_struct->converter_stack == (XP_List *)0 )
|
|
{
|
|
PR_Free(new_converter_struct);
|
|
return;
|
|
}
|
|
|
|
elem = PR_NEWZAP(net_ConverterElement);
|
|
if( elem == (net_ConverterElement *)0 )
|
|
{
|
|
XP_ListDestroy(new_converter_struct->converter_stack);
|
|
PR_Free(new_converter_struct);
|
|
return;
|
|
}
|
|
|
|
elem->converter = converter_func;
|
|
elem->data_obj = data_obj;
|
|
new_converter_struct->format_in = 0;
|
|
StrAllocCopy(new_converter_struct->format_in, format_in);
|
|
new_converter_struct->encoding_in = (encoding_in
|
|
? PL_strdup (encoding_in) : 0);
|
|
new_converter_struct->format_out = format_out;
|
|
XP_ListAddObject(new_converter_struct->converter_stack, elem);
|
|
new_converter_struct->bAutomated = autoFlag;
|
|
|
|
|
|
if(!pList) {
|
|
/* if(!*conv_list) */
|
|
/* create the list and add this object
|
|
* don't worry about order since there
|
|
* can't be any
|
|
*/
|
|
pList = XP_ListNew();
|
|
if(!pList)
|
|
return; /* big error */
|
|
conv_list[format_out] = pList;
|
|
XP_ListAddObject(pList, new_converter_struct);
|
|
return;
|
|
}
|
|
if(f_in_type == NET_MIME_EXACT_MATCH)
|
|
{
|
|
#if defined(XP_WIN) && defined (MOZILLA_CLIENT)
|
|
net_ConverterStruct *pRegistered;
|
|
XP_List *tempList = pList;
|
|
int count = XP_ListCount(tempList);
|
|
for (i = 0; i < count; i++) {
|
|
pRegistered = (net_ConverterStruct *) XP_ListNextObject(tempList);
|
|
|
|
if(new_converter_struct->bAutomated == TRUE) {
|
|
if(pRegistered->bAutomated == FALSE) {
|
|
XP_ListInsertObject (pList, pRegistered, new_converter_struct);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* if it is an exact match type
|
|
* then we can just add it to the beginning
|
|
* of the list
|
|
*/
|
|
if (!PL_strcasecmp(pRegistered->format_in, new_converter_struct->format_in)
|
|
&& ((!pRegistered->encoding_in && !new_converter_struct->format_in)
|
|
|| !PL_strcasecmp(pRegistered->encoding_in, new_converter_struct->encoding_in))) {
|
|
if(new_converter_struct->bAutomated == TRUE) {
|
|
PR_Free( new_converter_struct);
|
|
return;
|
|
}
|
|
|
|
// Overwrite
|
|
memcpy(pRegistered, new_converter_struct, sizeof(net_ConverterStruct));
|
|
PR_Free( new_converter_struct);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XP_ListInsertObject (pList, pRegistered, new_converter_struct);
|
|
#else
|
|
XP_ListAddObject(pList, new_converter_struct);
|
|
TRACEMSG(("Adding Converter to Beginning of list"));
|
|
#endif
|
|
}
|
|
else if(f_in_type == NET_MIME_PARTIAL_MATCH)
|
|
{
|
|
/* this is a partial wildcard of the form (image/(star))
|
|
* store it at the end of all the exact match pairs
|
|
*/
|
|
list_ptr = pList;
|
|
while((converter_struct_ptr = (net_ConverterStruct *) XP_ListNextObject(list_ptr)) != 0)
|
|
{
|
|
if(PL_strchr(converter_struct_ptr->format_in, '*'))
|
|
{
|
|
XP_ListInsertObject (pList,
|
|
converter_struct_ptr,
|
|
new_converter_struct);
|
|
return;
|
|
}
|
|
}
|
|
/* else no * objects in list */
|
|
XP_ListAddObjectToEnd(pList, new_converter_struct);
|
|
TRACEMSG(("Adding Converter to Middle of list"));
|
|
}
|
|
else
|
|
{
|
|
/* this is a very wild wildcard match of the form "*" only.
|
|
* It has the least precedence so store it at the end
|
|
* of the list. (There must always be at least one
|
|
* item in the list (see above))
|
|
*/
|
|
XP_ListAddObjectToEnd(pList, new_converter_struct);
|
|
TRACEMSG(("Adding Converter to end of list"));
|
|
}
|
|
}
|
|
|
|
struct net_encoding_converter
|
|
{
|
|
char *encoding_in;
|
|
void *data_obj;
|
|
NET_Converter * converter_func;
|
|
};
|
|
|
|
static struct net_encoding_converter *net_all_encoding_converters;
|
|
static int net_encoding_converter_size = 0;
|
|
static int net_encoding_converter_fp = 0;
|
|
|
|
PUBLIC void* NET_GETDataObject(XP_List* list, char* mineType, void** obj)
|
|
{
|
|
net_ConverterStruct* converter_struct_ptr;
|
|
|
|
*obj = (void*)0;
|
|
|
|
while((converter_struct_ptr = (net_ConverterStruct *)XP_ListNextObject(list)) != NULL) {
|
|
if(converter_struct_ptr->bAutomated) {
|
|
if(!PL_strcmp(converter_struct_ptr->format_in, mineType)) {
|
|
net_ConverterElement *elem = XP_ListPeekTopObject(converter_struct_ptr->converter_stack);
|
|
*obj = (void*)converter_struct_ptr;
|
|
return elem->data_obj;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (void*)0;
|
|
}
|
|
|
|
PUBLIC XP_List* NET_GetRegConverterList(FO_Present_Types iFormatOut)
|
|
{
|
|
return net_converter_list[iFormatOut];
|
|
|
|
}
|
|
/* register a routine to decode a stream
|
|
*/
|
|
|
|
PUBLIC void
|
|
NET_RegisterEncodingConverter(char *encoding_in,
|
|
void * data_obj,
|
|
NET_Converter * converter_func)
|
|
{
|
|
|
|
/* Don't register anything right now, but remember that we have a
|
|
decoder for this so that we can register it hither and yon at
|
|
a later date.
|
|
*/
|
|
if (net_encoding_converter_size <= net_encoding_converter_fp)
|
|
{
|
|
net_encoding_converter_size += 10;
|
|
if (net_all_encoding_converters)
|
|
net_all_encoding_converters = (struct net_encoding_converter *)
|
|
PR_Realloc (net_all_encoding_converters,
|
|
net_encoding_converter_size
|
|
* sizeof (*net_all_encoding_converters));
|
|
else
|
|
net_all_encoding_converters = (struct net_encoding_converter *)
|
|
PR_Calloc (net_encoding_converter_size,
|
|
sizeof (*net_all_encoding_converters));
|
|
}
|
|
|
|
{ /* Don't register the same decoder twice; having too many
|
|
decoders is multiplicatively expensive with respect to the number of
|
|
calls to net_RegisterGenericConverterOrDecoder() from the loop inside
|
|
NET_RegisterAllEncodingConverters(). */
|
|
int i;
|
|
for (i=0; i < net_encoding_converter_fp; i++)
|
|
if ((net_all_encoding_converters[i].data_obj == data_obj)
|
|
&& (net_all_encoding_converters[i].converter_func == converter_func)
|
|
&& (strcmp(net_all_encoding_converters[i].encoding_in,encoding_in)
|
|
== 0))
|
|
return;
|
|
}
|
|
|
|
net_all_encoding_converters [net_encoding_converter_fp].encoding_in
|
|
= PL_strdup (encoding_in);
|
|
net_all_encoding_converters [net_encoding_converter_fp].data_obj
|
|
= data_obj;
|
|
net_all_encoding_converters [net_encoding_converter_fp].converter_func
|
|
= converter_func;
|
|
net_encoding_converter_fp++;
|
|
|
|
}
|
|
|
|
|
|
#ifdef MOZILLA_CLIENT
|
|
|
|
void
|
|
NET_DumpDecoders()
|
|
{
|
|
#ifdef DEBUG
|
|
net_ConverterStruct * cs_ptr;
|
|
XP_List *list_ptr = net_decoder_list[FO_PRESENT];
|
|
|
|
while((cs_ptr = XP_ListNextObject(list_ptr)))
|
|
{
|
|
char *msg = PR_smprintf("in: %s out: %d\n",cs_ptr->encoding_in, cs_ptr->format_out);
|
|
|
|
TRACEMSG(("%s", msg));
|
|
FREE(msg);
|
|
}
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
/* register an encoding converter that is used for everything,
|
|
* no exeptions
|
|
* this is necessary for chunked encoding
|
|
*/
|
|
MODULE_PRIVATE void
|
|
NET_RegisterUniversalEncodingConverter(char *encoding_in,
|
|
void * data_obj,
|
|
NET_Converter * converter_func)
|
|
{
|
|
int i;
|
|
|
|
/* for each list in the net_decoder_list array */
|
|
for (i = 0; i < MAX_FORMATS_OUT; i++)
|
|
{
|
|
|
|
net_RegisterGenericConverterOrDecoder (net_decoder_list,
|
|
"*",
|
|
encoding_in,
|
|
i, /* format out */
|
|
data_obj,
|
|
converter_func);
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
NET_RegisterAllEncodingConverters (char *format_in,
|
|
FO_Present_Types format_out)
|
|
{
|
|
int i;
|
|
|
|
#ifdef XP_UNIX
|
|
/* On Unix at least, there should be *some* registered... */
|
|
assert (net_encoding_converter_fp > 0);
|
|
#endif
|
|
|
|
for (i = 0; i < net_encoding_converter_fp; i++)
|
|
{
|
|
char *encoding_in = net_all_encoding_converters [i].encoding_in;
|
|
void *data_obj = net_all_encoding_converters [i].data_obj;
|
|
NET_Converter *func = net_all_encoding_converters [i].converter_func;
|
|
|
|
net_RegisterGenericConverterOrDecoder (net_decoder_list,
|
|
format_in,
|
|
encoding_in,
|
|
format_out,
|
|
data_obj,
|
|
func);
|
|
|
|
net_RegisterGenericConverterOrDecoder (net_decoder_list,
|
|
format_in,
|
|
encoding_in,
|
|
format_out | FO_CACHE_ONLY,
|
|
data_obj,
|
|
func);
|
|
|
|
net_RegisterGenericConverterOrDecoder (net_decoder_list,
|
|
format_in,
|
|
encoding_in,
|
|
format_out | FO_ONLY_FROM_CACHE,
|
|
data_obj,
|
|
func);
|
|
}
|
|
}
|
|
|
|
#endif /* MOZILLA_CLIENT */
|
|
|
|
|
|
|
|
|
|
/* Register a routine to convert between format_in and format_out
|
|
*
|
|
*/
|
|
#if (defined(XP_WIN) || defined(XP_OS2)) && defined(MOZILLA_CLIENT)
|
|
/* Reroute XP handling of streams for windows.
|
|
* MWH -This routine should not be called recursively.
|
|
It rely on the static global variable to set the
|
|
* automatedflag. The reason for this is I don't to
|
|
change the API on NET_RegisterContentTypeConverter
|
|
because some other group still depend on this API.
|
|
* If we decided to change API, please fix this.
|
|
*/
|
|
PUBLIC void
|
|
NET_RegContentTypeConverter (char * format_in,
|
|
FO_Present_Types format_out,
|
|
void * data_obj,
|
|
NET_Converter * converter_func,
|
|
Bool bAutomated)
|
|
{
|
|
autoFlag = bAutomated;
|
|
NET_RegisterContentTypeConverter (format_in, format_out,
|
|
data_obj,
|
|
converter_func);
|
|
autoFlag = FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
PUBLIC void
|
|
NET_RegisterContentTypeConverter (char * format_in,
|
|
FO_Present_Types format_out,
|
|
void * data_obj,
|
|
NET_Converter * converter_func)
|
|
{
|
|
net_RegisterGenericConverterOrDecoder(net_converter_list,
|
|
format_in,
|
|
0,
|
|
format_out,
|
|
data_obj,
|
|
converter_func);
|
|
|
|
}
|
|
|
|
#ifdef MOZILLA_CLIENT
|
|
#ifdef XP_UNIX
|
|
|
|
#include "cvview.h"
|
|
#include "cvextcon.h"
|
|
|
|
/* register a mime type and a command to be executed
|
|
*
|
|
* if stream_block_size is zero then the data will be completely
|
|
* pooled and the external viewer called with the filename.
|
|
* if stream_block_size is greater than zero the viewer will be
|
|
* called with a popen and the stream_block_size will be used as
|
|
* the maximum size of each buffer to pass to the viewer
|
|
*/
|
|
MODULE_PRIVATE void
|
|
NET_RegisterExternalViewerCommand(char * format_in,
|
|
char * system_command,
|
|
unsigned int stream_block_size)
|
|
{
|
|
CV_ExtViewStruct * new_obj = PR_NEW(CV_ExtViewStruct);
|
|
|
|
if(!new_obj)
|
|
return;
|
|
|
|
memset(new_obj, 0, sizeof(CV_ExtViewStruct));
|
|
|
|
/* make a new copy of the command so it can be passed
|
|
* as the data object
|
|
*/
|
|
StrAllocCopy(new_obj->system_command, system_command);
|
|
new_obj->stream_block_size = stream_block_size;
|
|
|
|
/* register the routine
|
|
*/
|
|
NET_RegisterContentTypeConverter(format_in, FO_PRESENT, new_obj, NET_ExtViewerConverter);
|
|
|
|
/* Also register the content-encoding converters on this type.
|
|
Those get registered only on types we know how to display,
|
|
either internally or externally - and don't get registered
|
|
on types we know nothing about.
|
|
*/
|
|
NET_RegisterAllEncodingConverters (format_in, FO_PRESENT);
|
|
}
|
|
|
|
/* removes all external viewer commands
|
|
*/
|
|
PUBLIC void
|
|
NET_ClearExternalViewerConverters(void)
|
|
{
|
|
XP_List * list_ptr;
|
|
XP_List *temp_list;
|
|
net_ConverterStruct * converter_struct_ptr;
|
|
int i;
|
|
|
|
for (i = 0; i <MAX_FORMATS_OUT; i++) {
|
|
list_ptr = temp_list = net_converter_list[i];
|
|
while((converter_struct_ptr =
|
|
(net_ConverterStruct *) XP_ListNextObject(list_ptr)))
|
|
{
|
|
XP_List *new;
|
|
net_ConverterElement *elem;
|
|
|
|
new = XP_ListNew();
|
|
if( new == (XP_List *)0 ) return;
|
|
|
|
while( (elem = XP_ListRemoveTopObject(converter_struct_ptr->converter_stack)) != (net_ConverterElement *)0 )
|
|
{
|
|
if( elem->converter == NET_ExtViewerConverter )
|
|
{
|
|
PR_FREEIF(elem->data_obj);
|
|
PR_Free(elem);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
XP_ListAddObjectToEnd(new, elem);
|
|
}
|
|
}
|
|
|
|
XP_ListDestroy(converter_struct_ptr->converter_stack);
|
|
|
|
if( XP_ListCount(new) > 0 )
|
|
{
|
|
converter_struct_ptr->converter_stack = new;
|
|
}
|
|
else
|
|
{
|
|
XP_ListDestroy(new);
|
|
XP_ListRemoveObject(temp_list, converter_struct_ptr);
|
|
PR_Free(converter_struct_ptr->format_in);
|
|
PR_Free(converter_struct_ptr->encoding_in);
|
|
PR_Free(converter_struct_ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* removes all registered converters of any kind
|
|
*/
|
|
PUBLIC void
|
|
NET_ClearAllConverters(void)
|
|
{
|
|
net_ConverterStruct * aConverter;
|
|
net_ConverterElement * aConverterStackElement;
|
|
XP_List * theList;
|
|
int i;
|
|
|
|
/* for each list in the net_converter_list array */
|
|
for (i = 0; i < MAX_FORMATS_OUT; i++) {
|
|
theList = net_converter_list[i];
|
|
/* Traverse it, removing each converter, and freeing its data */
|
|
while( aConverter = (net_ConverterStruct *) XP_ListRemoveTopObject(theList) )
|
|
{
|
|
FREEIF(aConverter->format_in);
|
|
FREEIF(aConverter->encoding_in);
|
|
while( aConverterStackElement = XP_ListRemoveTopObject(aConverter->converter_stack) )
|
|
{
|
|
#ifdef XP_UNIX
|
|
if(aConverterStackElement->converter == NET_ExtViewerConverter)
|
|
PR_FREEIF(aConverterStackElement->data_obj);
|
|
#endif /* XP_UNIX */
|
|
PR_Free(aConverterStackElement);
|
|
}
|
|
XP_ListDestroy(aConverter->converter_stack);
|
|
FREE(aConverter);
|
|
}
|
|
XP_ListDestroy(theList);
|
|
net_converter_list[i] = NULL;
|
|
}
|
|
|
|
/* for each list in the net_decoder_list array */
|
|
for (i = 0; i < MAX_FORMATS_OUT; i++) {
|
|
theList = net_decoder_list[i];
|
|
/* Traverse it, removing each converter, and freeing its data */
|
|
while( aConverter = (net_ConverterStruct *) XP_ListRemoveTopObject(theList) )
|
|
{
|
|
FREEIF(aConverter->format_in);
|
|
FREEIF(aConverter->encoding_in);
|
|
while( aConverterStackElement = XP_ListRemoveTopObject(aConverter->converter_stack) )
|
|
{
|
|
#ifdef XP_UNIX
|
|
if(aConverterStackElement->converter == NET_ExtViewerConverter)
|
|
PR_FREEIF(aConverterStackElement->data_obj);
|
|
#endif /* XP_UNIX */
|
|
PR_Free(aConverterStackElement);
|
|
}
|
|
XP_ListDestroy(aConverter->converter_stack);
|
|
FREE(aConverter);
|
|
}
|
|
XP_ListDestroy(theList);
|
|
net_decoder_list[i] = NULL;
|
|
}
|
|
}
|
|
|
|
/* register an external program to act as a content-type
|
|
* converter
|
|
*/
|
|
MODULE_PRIVATE void
|
|
NET_RegisterExternalConverterCommand(char * format_in,
|
|
int format_out,
|
|
char * system_command,
|
|
char * new_format)
|
|
{
|
|
CV_ExtConverterStruct * new_obj = PR_NEW(CV_ExtConverterStruct);
|
|
|
|
if(!new_obj)
|
|
return;
|
|
|
|
memset(new_obj, 0, sizeof(CV_ExtConverterStruct));
|
|
|
|
/* make a new copy of the command so it can be passed
|
|
* as the data object
|
|
*/
|
|
StrAllocCopy(new_obj->command, system_command);
|
|
StrAllocCopy(new_obj->new_format, new_format);
|
|
new_obj->is_encoding_converter = FALSE;
|
|
|
|
/* register the routine
|
|
*/
|
|
NET_RegisterContentTypeConverter(format_in, format_out, new_obj, NET_ExtConverterConverter);
|
|
}
|
|
|
|
/* register an external program to act as a content-encoding
|
|
* converter
|
|
*/
|
|
PUBLIC void
|
|
NET_RegisterExternalDecoderCommand (char * format_in,
|
|
char * format_out,
|
|
char * system_command)
|
|
{
|
|
CV_ExtConverterStruct * new_obj = PR_NEW(CV_ExtConverterStruct);
|
|
|
|
if(!new_obj)
|
|
return;
|
|
|
|
memset(new_obj, 0, sizeof(CV_ExtConverterStruct));
|
|
|
|
/* make a new copy of the command so it can be passed
|
|
* as the data object
|
|
*/
|
|
StrAllocCopy(new_obj->command, system_command);
|
|
StrAllocCopy(new_obj->new_format, format_out);
|
|
new_obj->is_encoding_converter = TRUE;
|
|
|
|
/* register the routine
|
|
*/
|
|
NET_RegisterEncodingConverter (format_in, new_obj,
|
|
NET_ExtConverterConverter);
|
|
}
|
|
|
|
|
|
#endif /* XP_UNIX */
|
|
#endif /* MOZILLA_CLIENT */
|
|
|
|
/* NewMKStream
|
|
* Utility to create a new initialized NET_StreamClass object
|
|
*/
|
|
NET_StreamClass *
|
|
NET_NewStream (char *name,
|
|
MKStreamWriteFunc process,
|
|
MKStreamCompleteFunc complete,
|
|
MKStreamAbortFunc abort,
|
|
MKStreamWriteReadyFunc ready,
|
|
void *streamData,
|
|
MWContext *windowID)
|
|
{
|
|
NET_StreamClass *stream = PR_NEW (NET_StreamClass);
|
|
if (!stream)
|
|
return nil;
|
|
|
|
stream->name = name;
|
|
stream->window_id = windowID;
|
|
stream->data_object = streamData;
|
|
stream->put_block = process;
|
|
stream->complete = complete;
|
|
stream->abort = abort;
|
|
stream->is_write_ready = ready;
|
|
|
|
return stream;
|
|
}
|
|
|
|
PRIVATE XP_List *
|
|
net_GetConverterOrDecoderList(XP_List ** conv_list,
|
|
char * format_in,
|
|
char * encoding_in,
|
|
FO_Present_Types format_out)
|
|
{
|
|
XP_List * list_ptr = *conv_list;
|
|
net_ConverterStruct * converter_struct_ptr;
|
|
|
|
while((converter_struct_ptr = (net_ConverterStruct *) XP_ListNextObject(list_ptr)) != 0)
|
|
if(format_out == converter_struct_ptr->format_out)
|
|
if(!PL_strcasecmp(format_in, converter_struct_ptr->format_in)
|
|
&& ((!encoding_in && !converter_struct_ptr->encoding_in) ||
|
|
(encoding_in && converter_struct_ptr->encoding_in &&
|
|
!PL_strcmp (encoding_in,
|
|
converter_struct_ptr->encoding_in)))
|
|
)
|
|
{
|
|
return converter_struct_ptr->converter_stack;
|
|
}
|
|
|
|
return (XP_List *)0;
|
|
}
|
|
|
|
PUBLIC void
|
|
NET_DeregisterContentTypeConverter(char *format_in, FO_Present_Types format_out)
|
|
{
|
|
XP_List *l;
|
|
net_ConverterElement *elem;
|
|
|
|
l = net_GetConverterOrDecoderList(net_converter_list, format_in, 0, format_out);
|
|
if( l == (XP_List *)0 ) return;
|
|
|
|
elem = XP_ListRemoveTopObject(l);
|
|
# ifdef XP_UNIX
|
|
/* total kludge!! */
|
|
if( elem->converter == NET_ExtViewerConverter )
|
|
PR_FREEIF(elem->data_obj);
|
|
# endif
|
|
PR_Free(elem);
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
MODULE_PRIVATE void
|
|
NET_DisplayStreamInfoAsHTML(ActiveEntry *cur_entry)
|
|
{
|
|
char *buffer = (char*)PR_Malloc(2048);
|
|
NET_StreamClass * stream;
|
|
int i;
|
|
|
|
static char *fo_names[] = {
|
|
/* 0 */ "(unknown)",
|
|
/* 1 */ "Present",
|
|
/* 2 */ "Internal Image",
|
|
/* 3 */ "Out to Proxy Client",
|
|
/* 4 */ "View Source",
|
|
/* 5 */ "Save As",
|
|
/* 6 */ "Save as Text",
|
|
/* 7 */ "Save as Postscript",
|
|
/* 8 */ "Quote Message",
|
|
/* 9 */ "Mail To",
|
|
/* 10 */ "OLE Network",
|
|
/* 11 */ "Multipart Image",
|
|
/* 12 */ "Embed",
|
|
/* 13 */ "Print",
|
|
/* 14 */ "Plugin",
|
|
/* 15 */ "Append to Folder",
|
|
/* 16 */ "Do Java",
|
|
/* 17 */ "Byterange",
|
|
/* 18 */ "EDT Save Image",
|
|
/* 19 */ "Edit",
|
|
/* 20 */ "Load HTML Help Map File",
|
|
/* 21 */ "Save to News DB",
|
|
/* 22 */ "Open Draft",
|
|
};
|
|
|
|
if(!buffer)
|
|
{
|
|
cur_entry->status = MK_UNABLE_TO_CONVERT;
|
|
return;
|
|
}
|
|
|
|
StrAllocCopy(cur_entry->URL_s->content_type, TEXT_HTML);
|
|
|
|
cur_entry->format_out = CLEAR_CACHE_BIT(cur_entry->format_out);
|
|
stream = NET_StreamBuilder(cur_entry->format_out,
|
|
cur_entry->URL_s,
|
|
cur_entry->window_id);
|
|
|
|
if(!stream)
|
|
{
|
|
cur_entry->status = MK_UNABLE_TO_CONVERT;
|
|
FREE(buffer);
|
|
return;
|
|
}
|
|
|
|
|
|
/* define a macro to push a string up the stream
|
|
* and handle errors
|
|
*/
|
|
#define PUT_PART(part) \
|
|
cur_entry->status = (*stream->put_block)(stream, \
|
|
part ? part : "Unknown", \
|
|
part ? PL_strlen(part) : 7); \
|
|
if(cur_entry->status < 0) \
|
|
goto END;
|
|
|
|
sprintf(buffer,
|
|
"<html><head><title>Information about the Netscape streams configuration</title></head>\n"
|
|
"<body><h1>Information about the Netscape streams configuration</h1>\n"
|
|
);
|
|
|
|
PUT_PART(buffer);
|
|
|
|
sprintf(buffer, "<h2>Converter List</h2>\n<ul>");
|
|
PUT_PART(buffer);
|
|
|
|
for( i = 0; i < MAX_FORMATS_OUT; i++ )
|
|
{
|
|
int j = i & ~FO_CACHE_ONLY & ~FO_ONLY_FROM_CACHE;
|
|
XP_List *list_ptr = net_converter_list[i];
|
|
net_ConverterStruct *csp;
|
|
|
|
sprintf(buffer, "<li><ul><p>%s", j < sizeof(fo_names)/sizeof(fo_names[0]) ?
|
|
fo_names[j] : fo_names[0]);
|
|
PUT_PART(buffer);
|
|
|
|
if( i & FO_CACHE_ONLY )
|
|
{
|
|
sprintf(buffer, " | Cache Only");
|
|
PUT_PART(buffer);
|
|
}
|
|
|
|
if( i & FO_ONLY_FROM_CACHE )
|
|
{
|
|
sprintf(buffer, " | Only From Cache");
|
|
PUT_PART(buffer);
|
|
}
|
|
|
|
sprintf(buffer, " [%d]</p>", i);
|
|
PUT_PART(buffer);
|
|
|
|
while( (csp = (net_ConverterStruct *)XP_ListNextObject(list_ptr)) != (net_ConverterStruct *)0 )
|
|
{
|
|
XP_List *stack = csp->converter_stack;
|
|
int stack_count = XP_ListCount(stack);
|
|
net_ConverterElement *elem;
|
|
sprintf(buffer,
|
|
"<li>Format In: %s<br>\n"
|
|
"Encoding In: %s<br>\n"
|
|
"Present Type: %d<br>\n"
|
|
"%s<br><ol>%d Converter%s:\n",
|
|
(csp->format_in != (char *)0) ? csp->format_in : "(null)",
|
|
(csp->encoding_in != (char *)0) ? csp->encoding_in : "(null)",
|
|
csp->format_out,
|
|
csp->bAutomated ? "Automated" : "Not automated",
|
|
stack_count, (stack_count == 1) ? "" : "s");
|
|
PUT_PART(buffer);
|
|
|
|
while( (elem = (net_ConverterElement *)XP_ListNextObject(stack)) != (net_ConverterElement *)0 )
|
|
{
|
|
#if defined(__sun) && !defined(SVR4)
|
|
sprintf(buffer, "<li>Converter: %lu<br>Object: %lu<br>\n",
|
|
elem->converter, elem->data_obj);
|
|
#else
|
|
sprintf(buffer, "<li>Converter: %p<br>Object: %p<br>\n",
|
|
elem->converter, elem->data_obj);
|
|
#endif
|
|
PUT_PART(buffer);
|
|
}
|
|
|
|
sprintf(buffer, "<br></ol>\n");
|
|
PUT_PART(buffer);
|
|
}
|
|
|
|
sprintf(buffer, "</ul>\n");
|
|
PUT_PART(buffer);
|
|
}
|
|
|
|
sprintf(buffer, "</ul>\n");
|
|
PUT_PART(buffer);
|
|
|
|
sprintf(buffer, "<h2>Decoder List</h2>\n<ul>");
|
|
PUT_PART(buffer);
|
|
|
|
for( i = 0; i < MAX_FORMATS_OUT; i++ )
|
|
{
|
|
int j = i & ~FO_CACHE_ONLY & ~FO_ONLY_FROM_CACHE;
|
|
XP_List *list_ptr = net_decoder_list[i];
|
|
net_ConverterStruct *csp;
|
|
|
|
sprintf(buffer, "<li><ul><p>%s", j < sizeof(fo_names)/sizeof(fo_names[0]) ?
|
|
fo_names[j] : fo_names[0]);
|
|
PUT_PART(buffer);
|
|
|
|
if( i & FO_CACHE_ONLY )
|
|
{
|
|
sprintf(buffer, " | Cache Only");
|
|
PUT_PART(buffer);
|
|
}
|
|
|
|
if( i & FO_ONLY_FROM_CACHE )
|
|
{
|
|
sprintf(buffer, " | Only From Cache");
|
|
PUT_PART(buffer);
|
|
}
|
|
|
|
sprintf(buffer, " [%d]</p>", i);
|
|
PUT_PART(buffer);
|
|
|
|
while( (csp = (net_ConverterStruct *)XP_ListNextObject(list_ptr)) != (net_ConverterStruct *)0 )
|
|
{
|
|
XP_List *stack = csp->converter_stack;
|
|
int stack_count = XP_ListCount(stack);
|
|
net_ConverterElement *elem;
|
|
sprintf(buffer,
|
|
"<li>Format In: %s<br>\n"
|
|
"Encoding In: %s<br>\n"
|
|
"Present Type: %d<br>\n"
|
|
"%s<br><ol>%d Converter%s:\n",
|
|
(csp->format_in != (char *)0) ? csp->format_in : "(null)",
|
|
(csp->encoding_in != (char *)0) ? csp->encoding_in : "(null)",
|
|
csp->format_out,
|
|
csp->bAutomated ? "Automated" : "Not automated",
|
|
stack_count, (stack_count == 1) ? "" : "s");
|
|
PUT_PART(buffer);
|
|
|
|
while( (elem = (net_ConverterElement *)XP_ListNextObject(stack)) != (net_ConverterElement *)0 )
|
|
{
|
|
#if defined(__sun) && !defined(SVR4)
|
|
sprintf(buffer, "<li>Converter: %lu<br>Object: %lu<br>\n",
|
|
elem->converter, elem->data_obj);
|
|
#else
|
|
sprintf(buffer, "<li>Converter: %p<br>Object: %p<br>\n",
|
|
elem->converter, elem->data_obj);
|
|
#endif
|
|
PUT_PART(buffer);
|
|
}
|
|
|
|
sprintf(buffer, "<br></ol>\n");
|
|
PUT_PART(buffer);
|
|
}
|
|
|
|
sprintf(buffer, "</ul>\n");
|
|
PUT_PART(buffer);
|
|
}
|
|
|
|
sprintf(buffer, "</ul>\n");
|
|
PUT_PART(buffer);
|
|
|
|
END:
|
|
PR_Free(buffer);
|
|
if( cur_entry->status < 0 )
|
|
(*stream->abort)(stream, cur_entry->status);
|
|
else
|
|
(*stream->complete)(stream);
|
|
|
|
return;
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
#ifdef PROFILE
|
|
#pragma profile off
|
|
#endif
|
|
|