mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
1263 lines
28 KiB
C
1263 lines
28 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.
|
|
*/
|
|
/*
|
|
* determine the format of a file
|
|
*
|
|
* Started with Rob's code and
|
|
* then hacked up by Lou.
|
|
*/
|
|
|
|
#include "mkutils.h"
|
|
#include "mkformat.h"
|
|
|
|
static char *net_default_types [] = {
|
|
# include "mktypes.h"
|
|
0 };
|
|
|
|
|
|
/* func proto
|
|
*/
|
|
PRIVATE int cinfo_parse_mcc_line(char *line, Bool is_external,
|
|
Bool is_local, char **src_string);
|
|
PRIVATE int net_cinfo_merge(char *fn, Bool is_local);
|
|
|
|
/* ----------------------------- Static data ------------------------------ */
|
|
|
|
/* The master database of content info (linked list) */
|
|
PRIVATE XP_List * NET_ciMasterList=0;
|
|
|
|
/*
|
|
* cinfo.c: Content Information for a file, i.e. its type, etc.
|
|
*
|
|
* See cinfo.h for full details.
|
|
*
|
|
* Rob McCool
|
|
*/
|
|
|
|
/* init types loads standard types so that a config file
|
|
* is not required and can also read
|
|
* a mime types file if filename is passed in non empty and
|
|
* non null
|
|
*
|
|
* on each call to NET_InitFileFormatTypes the extension list
|
|
* will be completely free'd and rebuilt.
|
|
*
|
|
* if you pass in NULL filename pointers they will not be
|
|
* attempted to be read
|
|
*/
|
|
PUBLIC int
|
|
NET_InitFileFormatTypes(char * personal_file, char *global_file)
|
|
{
|
|
/* init the data structures
|
|
*/
|
|
int i = 0;
|
|
|
|
#ifdef XP_UNIX
|
|
NET_CleanupFileFormat(NULL);
|
|
#else /* !XP_UNIX */
|
|
NET_CleanupFileFormat();
|
|
#endif /* !XP_UNIX */
|
|
NET_ciMasterList = XP_ListNew();
|
|
|
|
TRACEMSG((" Setting up File Format code"));
|
|
|
|
while (net_default_types [i])
|
|
{
|
|
char buf [256];
|
|
char *src_string = 0;
|
|
XP_STRCPY (buf, net_default_types [i]);
|
|
StrAllocCopy(src_string, buf);
|
|
cinfo_parse_mcc_line (buf, FALSE, FALSE, &src_string); /* destroys buf */
|
|
i++;
|
|
if (src_string) XP_FREE(src_string);
|
|
|
|
}
|
|
|
|
/* read the external mime types file and return */
|
|
if(global_file)
|
|
{
|
|
net_cinfo_merge(global_file, FALSE);
|
|
}
|
|
if(personal_file)
|
|
{
|
|
net_cinfo_merge(personal_file, TRUE);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* -------------------------- Module structures --------------------------- */
|
|
|
|
|
|
|
|
static NET_cinfo default_cinfo_type = {
|
|
#ifdef MCC_PROXY
|
|
MAGNUS_INTERNAL_UNKNOWN,
|
|
#else
|
|
UNKNOWN_CONTENT_TYPE,
|
|
#endif
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
TRUE,
|
|
0
|
|
};
|
|
|
|
#ifdef NOT_USED
|
|
static NET_cinfo default_cinfo_enc = {
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
0
|
|
};
|
|
#endif /* NOT_USED */
|
|
|
|
/* ------------------------------ _cinfo_free ------------------------------ */
|
|
|
|
|
|
PRIVATE void
|
|
_cinfo_free(NET_cinfo *ci)
|
|
{
|
|
|
|
FREEIF(ci->type);
|
|
FREEIF(ci->encoding);
|
|
FREEIF(ci->language);
|
|
FREEIF(ci->desc);
|
|
FREEIF(ci->icon);
|
|
FREEIF(ci->alt_text);
|
|
}
|
|
|
|
|
|
/* ---------------------------- NET_cdataCreate ---------------------------- */
|
|
|
|
|
|
PUBLIC NET_cdataStruct *
|
|
NET_cdataCreate(void)
|
|
{
|
|
NET_cdataStruct *cd = XP_NEW(NET_cdataStruct);
|
|
|
|
if(!cd)
|
|
return(NULL);
|
|
|
|
memset(cd, 0, sizeof(NET_cdataStruct));
|
|
|
|
return cd;
|
|
}
|
|
|
|
|
|
/* ----------------------------- NET_cdataFree ---------------------------- */
|
|
|
|
|
|
PUBLIC void
|
|
NET_cdataFree(NET_cdataStruct *cd)
|
|
{
|
|
register int x;
|
|
|
|
if(cd->exts)
|
|
{
|
|
for(x = 0; x < cd->num_exts; x++)
|
|
XP_FREE(cd->exts[x]);
|
|
XP_FREE(cd->exts);
|
|
}
|
|
if ( cd->src_string )
|
|
XP_FREE(cd->src_string);
|
|
|
|
_cinfo_free(&cd->ci);
|
|
|
|
XP_FREE(cd);
|
|
cd = 0;
|
|
}
|
|
|
|
/* ---------------------------- NET_cdataAdd ------------------------------- */
|
|
|
|
PUBLIC void
|
|
NET_cdataAdd(NET_cdataStruct *cd)
|
|
{
|
|
XP_ListAddObject(NET_ciMasterList, cd);
|
|
}
|
|
|
|
/* ---------------------------- NET_cdataRemove ---------------------------- */
|
|
|
|
PUBLIC void
|
|
NET_cdataRemove(NET_cdataStruct *cd)
|
|
{
|
|
XP_ListRemoveObject(NET_ciMasterList, cd);
|
|
|
|
NET_cdataFree(cd);
|
|
}
|
|
|
|
PUBLIC NET_cdataStruct*
|
|
NET_cdataExist(NET_cdataStruct *old_cd )
|
|
{
|
|
NET_cdataStruct *found_cd = NULL;
|
|
NET_cdataStruct *cd = NULL;
|
|
XP_List *infoList;
|
|
|
|
infoList = cinfo_MasterListPointer();
|
|
|
|
if ( !infoList )
|
|
return found_cd;
|
|
|
|
while ((cd= (NET_cdataStruct *)XP_ListNextObject(infoList)) != NULL)
|
|
{
|
|
if ( old_cd->ci.type &&
|
|
cd->ci.type &&
|
|
!strcasecomp(old_cd->ci.type, cd->ci.type))
|
|
{
|
|
/* found matching type */
|
|
found_cd = cd;
|
|
break;
|
|
}
|
|
else if ( !old_cd->ci.type &&
|
|
old_cd->ci.encoding &&
|
|
cd->ci.encoding &&
|
|
!strcasecomp(old_cd->ci.encoding, cd->ci.encoding))
|
|
{
|
|
/* found matching encoding */
|
|
found_cd = cd;
|
|
break;
|
|
}
|
|
}
|
|
return found_cd;
|
|
}
|
|
|
|
#if 0
|
|
PRIVATE
|
|
Bool
|
|
net_cdata_exist_ext( char *ext, NET_cdataStruct *cd )
|
|
{
|
|
Bool not_found = FALSE;
|
|
int n;
|
|
|
|
if (!cd->exts) return not_found;
|
|
|
|
for ( n = 0; n < cd->num_exts; n++ )
|
|
{
|
|
if (!strcasecomp(cd->exts[n], ext) )
|
|
{
|
|
not_found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return not_found;
|
|
}
|
|
#endif
|
|
|
|
/* ---------------------------- net_cdata_new_ext ----------------------------- */
|
|
|
|
|
|
PRIVATE
|
|
void
|
|
net_cdata_new_ext(char *ext, NET_cdataStruct *cd)
|
|
{
|
|
int n = cd->num_exts;
|
|
|
|
cd->exts = (char **) (n ? XP_REALLOC(cd->exts, (n+1)*sizeof(char *))
|
|
: XP_ALLOC(sizeof(char *)));
|
|
|
|
if(!cd->exts)
|
|
return;
|
|
|
|
cd->exts[n] = 0;
|
|
StrAllocCopy(cd->exts[n], ext);
|
|
cd->num_exts = ++n;
|
|
}
|
|
|
|
|
|
/* ----------------------------- cinfo_merge ------------------------------ */
|
|
|
|
|
|
int _cinfo_parse_mimetypes(XP_File fp, char *t, Bool is_local);
|
|
int _cinfo_parse_mcc(XP_File fp, char *t, Bool is_local);
|
|
|
|
PRIVATE int
|
|
net_cinfo_merge(char *fn, Bool is_local)
|
|
{
|
|
XP_File fp;
|
|
char t[CINFO_MAX_LEN];
|
|
int ret;
|
|
|
|
TRACEMSG(("\n\nnet_cinfo_merge: called with %s\n\n\n", fn));
|
|
if(!(fp = XP_FileOpen(fn ? fn : "mime.types", xpMimeTypes, XP_FILE_READ))) {
|
|
TRACEMSG(("cinfo.c: File open failed"));
|
|
return -1;
|
|
}
|
|
|
|
TRACEMSG(("Reading mime.types file"));
|
|
|
|
if(!(XP_FileReadLine(t, CINFO_MAX_LEN, fp))) {
|
|
TRACEMSG(("cinfo.c: Mime types file is empty"));
|
|
return -1;
|
|
|
|
} else if(!strncmp(t, MCC_MT_MAGIC, MCC_MT_MAGIC_LEN) ||
|
|
!strncmp(t, NCC_MT_MAGIC, NCC_MT_MAGIC_LEN)) {
|
|
/* Look for magic number */
|
|
TRACEMSG(("Loading MCC mime types file"));
|
|
ret = _cinfo_parse_mcc(fp, t, is_local);
|
|
|
|
} else {
|
|
TRACEMSG(("Loading old NCSA mime types file"));
|
|
ret = _cinfo_parse_mimetypes(fp, t, is_local);
|
|
}
|
|
|
|
XP_FileClose(fp);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static NET_cinfo *
|
|
net_cinfo_find_type_or_encoding (char *uri, XP_Bool type_p)
|
|
{
|
|
char *start = uri;
|
|
char *end, *c;
|
|
NET_cinfo *result = &default_cinfo_type;
|
|
XP_Bool saw_encoding = FALSE;
|
|
|
|
c = XP_STRRCHR (uri, '/');
|
|
if (c) start = c;
|
|
|
|
end = start + XP_STRLEN (start);
|
|
c = XP_STRRCHR (start, '?');
|
|
if (c) end = c;
|
|
c = XP_STRRCHR (start, '#');
|
|
if (c && c < end) end = c;
|
|
|
|
AGAIN:
|
|
for (c = end - 1; c >= uri; c--)
|
|
if (*c == '/' || *c == '.')
|
|
break;
|
|
|
|
if (c >= uri && *c == '.')
|
|
{
|
|
int32 i;
|
|
XP_List *list_ptr = NET_ciMasterList;
|
|
NET_cdataStruct *cdata;
|
|
uint32 ext_len;
|
|
start = c + 1;
|
|
ext_len = end - start;
|
|
while ((cdata = (NET_cdataStruct *) XP_ListNextObject (list_ptr)) != NULL)
|
|
for (i = cdata->num_exts - 1; i >= 0; i--)
|
|
if (XP_STRLEN (cdata->exts[i]) == ext_len &&
|
|
!strncasecomp (start, cdata->exts [i], ext_len))
|
|
{
|
|
if (type_p && cdata->ci.type)
|
|
{
|
|
/* We are looking for a type, and this extension represents
|
|
one. Since this is the last one in the path (since we
|
|
start from the end and go backwards) we're done now.
|
|
*/
|
|
return &cdata->ci;
|
|
}
|
|
else if (type_p && cdata->ci.encoding)
|
|
{
|
|
/* We are looking for a type, and this extension represents
|
|
an encoding. Skip over it and look for the next
|
|
extension earlier in the file name (as that may turn out
|
|
to be a type which we should take instead.)
|
|
|
|
But, if this is the second encoding we've seen, then the
|
|
final content-type is irrelevant, because we have no
|
|
mechanism for decoding multiple encodings. So, while
|
|
"foo.gif.gz" gets type gif, encoding gz, "foo.tar.gz.uu"
|
|
gets type unknown, encoding uu. This is especially
|
|
important for the types that we put on outgoing MIME
|
|
attachments.
|
|
*/
|
|
if (saw_encoding)
|
|
return &default_cinfo_type;
|
|
saw_encoding = TRUE;
|
|
end = start - 1;
|
|
goto AGAIN;
|
|
}
|
|
else if (cdata->ci.type)
|
|
{
|
|
XP_ASSERT (!type_p);
|
|
/* We are looking for an encoding, and this extension
|
|
represents a content-type. That means that there are
|
|
no encodings after the type in this file name, and
|
|
therefore it has no encoding (an encoding which occurs
|
|
before a type doesn't count: "foo.uu.gif" should be of
|
|
type gif with no encoding, not encoding uu. Also,
|
|
"foo.uu.unknown" should be of an unknown type with no
|
|
encoding; and "foo.uu.gif.Z" should be type gif,
|
|
encoding compress.)
|
|
*/
|
|
return &default_cinfo_type;
|
|
}
|
|
else if (cdata->ci.encoding)
|
|
{
|
|
XP_ASSERT (!type_p);
|
|
/* We are looking for an encoding, and this extension
|
|
represents one. It is the last one in the file name,
|
|
so now we're done. ("foo.gz.uu" gets encoding "uu"
|
|
instead of "gz".)
|
|
*/
|
|
return &cdata->ci;
|
|
}
|
|
/* Else, this cdata is junk, or something... Skip it. */
|
|
}
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
|
|
PUBLIC NET_cinfo *
|
|
NET_cinfo_find_type (char *uri)
|
|
{
|
|
return net_cinfo_find_type_or_encoding (uri, TRUE);
|
|
}
|
|
|
|
PUBLIC NET_cinfo *
|
|
NET_cinfo_find_enc (char *uri)
|
|
{
|
|
return net_cinfo_find_type_or_encoding (uri, FALSE);
|
|
}
|
|
|
|
|
|
#if defined(DEBUG) && defined(XP_UNIX)
|
|
void
|
|
print_mime_types()
|
|
{
|
|
int32 i;
|
|
XP_List *list_ptr = NET_ciMasterList;
|
|
NET_cdataStruct *cdata;
|
|
|
|
fprintf(stderr, "\n---------\n");
|
|
|
|
while ((cdata = (NET_cdataStruct *) XP_ListNextObject (list_ptr)))
|
|
{
|
|
fprintf (stderr, "%s%s%s (%s; %s):",
|
|
(cdata->ci.type ? cdata->ci.type : ""),
|
|
(cdata->ci.type && *cdata->ci.type &&
|
|
cdata->ci.encoding && *cdata->ci.encoding
|
|
? "+" : ""),
|
|
(cdata->ci.encoding ? cdata->ci.encoding : ""),
|
|
(cdata->ci.desc ? cdata->ci.desc : "no desc"),
|
|
(cdata->ci.icon ? cdata->ci.icon : "no icon"));
|
|
|
|
for (i = cdata->num_exts - 1; i >= 0; i--)
|
|
fprintf (stderr, " %s", cdata->exts[i]);
|
|
fprintf (stderr, "\n");
|
|
}
|
|
}
|
|
#endif /* DEBUG && XP_UNIX */
|
|
|
|
|
|
/* return a cdataStruct from a mime_type
|
|
*/
|
|
PRIVATE NET_cdataStruct *
|
|
NET_cinfo_find_cdata_by_type(char *mime_type)
|
|
{
|
|
NET_cdataStruct *cdata;
|
|
XP_List * list_ptr;
|
|
|
|
if(!mime_type)
|
|
return(NULL);
|
|
|
|
list_ptr = NET_ciMasterList;
|
|
while((cdata = (NET_cdataStruct *) XP_ListNextObject(list_ptr)) != NULL)
|
|
{
|
|
if(cdata->ci.type && !strcasecomp(mime_type, cdata->ci.type))
|
|
return(cdata);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/* return a cinfo from a mime_type
|
|
*/
|
|
PUBLIC NET_cinfo *
|
|
NET_cinfo_find_info_by_type(char *mime_type)
|
|
{
|
|
NET_cdataStruct *cdata = NET_cinfo_find_cdata_by_type(mime_type);
|
|
|
|
if(cdata)
|
|
return(&cdata->ci);
|
|
else
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/* --------------------------- cinfo_find_ext ------------------------------ */
|
|
|
|
/* returns an extension (without the ".") for
|
|
* a given mime type.
|
|
*
|
|
* If no match is found NULL is returned.
|
|
*
|
|
* Do not free the returned char *
|
|
*/
|
|
PUBLIC char *
|
|
NET_cinfo_find_ext(char *mime_type)
|
|
{
|
|
NET_cdataStruct *cdata = NET_cinfo_find_cdata_by_type(mime_type);
|
|
|
|
if(cdata)
|
|
return(cdata->exts[0]);
|
|
else
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/* ----------------------------- File parsers ----------------------------- */
|
|
|
|
|
|
#if 0
|
|
static void
|
|
net_build_string(char** curr_str, char *new_str)
|
|
{
|
|
int len;
|
|
|
|
if ( new_str && *new_str )
|
|
{
|
|
if (!*curr_str )
|
|
{
|
|
len = strlen(new_str);
|
|
*curr_str = (char *)XP_ALLOC((len+1)*sizeof(char));
|
|
sprintf(*curr_str, "%s", new_str);
|
|
}
|
|
else
|
|
{
|
|
len = strlen(new_str) + strlen(*curr_str);
|
|
*curr_str = (char *)XP_ALLOC((len+1)*sizeof(char));
|
|
sprintf(*curr_str, "%s%s", *curr_str, new_str);
|
|
}
|
|
}
|
|
}
|
|
#endif /* 0 */
|
|
|
|
/* Parse old NCSA mime.types files */
|
|
|
|
int
|
|
_cinfo_parse_mimetypes(XP_File fp, char *t, Bool is_local)
|
|
{
|
|
char *ext, *end;
|
|
NET_cdataStruct *cd;
|
|
char *src_string = 0;
|
|
|
|
/* t is already filled. */
|
|
while(1) {
|
|
|
|
if ( src_string )
|
|
{
|
|
src_string = XP_AppendStr(src_string, t);
|
|
}
|
|
else
|
|
{
|
|
StrAllocCopy(src_string, t);
|
|
}
|
|
|
|
while((*t) && (XP_IS_SPACE(*t)))
|
|
++t;
|
|
|
|
if(*t && (*t != '#')) {
|
|
ext = t;
|
|
while((*ext) && (!XP_IS_SPACE(*ext))) ++ext;
|
|
if((*ext))
|
|
*ext++ = '\0';
|
|
|
|
cd = NULL;
|
|
|
|
while((*ext)) {
|
|
while((*ext) && (XP_IS_SPACE(*ext))) ++ext;
|
|
|
|
if((*ext)) {
|
|
if(!cd) {
|
|
cd = NET_cdataCreate();
|
|
if(!cd)
|
|
return(-1);
|
|
}
|
|
|
|
cd->is_local = is_local;
|
|
cd->is_external = FALSE; /* don't count these as external types */
|
|
|
|
cd->is_modified = FALSE; /* default is not modified in any way */
|
|
end = ext+1;
|
|
while((*end) && (!XP_IS_SPACE(*end))) ++end;
|
|
if(*end)
|
|
*end++ = '\0';
|
|
net_cdata_new_ext(ext, cd);
|
|
ext = end;
|
|
}
|
|
}
|
|
if(cd) {
|
|
NET_cdataStruct *old_cd = NULL;
|
|
FREEIF(cd->ci.type);
|
|
cd->ci.type = 0;
|
|
StrAllocCopy(cd->ci.type, t);
|
|
FREEIF(cd->src_string);
|
|
StrAllocCopy(cd->src_string, src_string);
|
|
|
|
if ( (old_cd = NET_cdataExist(cd)) != NULL)
|
|
/* Found an old one, remove it first */
|
|
{
|
|
/* Extra hack: if the old one defined an icon, or a desc,
|
|
and the new one does not, carry those over. */
|
|
char *icon = (old_cd->ci.icon && !cd->ci.icon
|
|
? XP_STRDUP(old_cd->ci.icon)
|
|
: 0);
|
|
char *desc = (old_cd->ci.desc && !cd->ci.desc
|
|
? XP_STRDUP(old_cd->ci.desc)
|
|
: 0);
|
|
|
|
NET_cdataRemove(old_cd);
|
|
old_cd = 0;
|
|
|
|
if (icon) cd->ci.icon = icon;
|
|
if (desc) cd->ci.desc = desc;
|
|
}
|
|
/* Not an existing type, we add a new one */
|
|
NET_cdataAdd(cd);
|
|
XP_FREE(src_string);
|
|
src_string = 0;
|
|
}
|
|
}
|
|
if(!(XP_FileReadLine(t, CINFO_MAX_LEN, fp)))
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
PUBLIC int
|
|
cinfo_parse_mcc_line(char *line, Bool is_external, Bool is_local,
|
|
char **src_string)
|
|
{
|
|
int ln = 1;
|
|
char *t, *u, *v, *name, *value, c;
|
|
NET_cdataStruct *cd;
|
|
|
|
if(line && *line)
|
|
{
|
|
cd = NULL;
|
|
|
|
t = line;
|
|
|
|
if((*t) && (*t != '#')) {
|
|
while(1) {
|
|
|
|
while(*t && XP_IS_SPACE(*t)) ++t;
|
|
if(!(*t))
|
|
break;
|
|
name = t;
|
|
|
|
while(*t && (*t != '=')) ++t;
|
|
if(!(*t)) {
|
|
TRACEMSG(("line %d: name without =", ln));
|
|
if(cd)
|
|
NET_cdataFree(cd);
|
|
return (-1);
|
|
}
|
|
for(u = t - 1; XP_IS_SPACE(*u); --u)
|
|
;
|
|
*(u+1) = '\0'; /* terminate name */
|
|
++t;
|
|
while(*t && (*t != '\"') && (XP_IS_SPACE(*t))) ++t;
|
|
if(!(*t)) {
|
|
TRACEMSG(("line %d: empty value", ln));
|
|
if(cd)
|
|
NET_cdataFree(cd);
|
|
return (-1);
|
|
}
|
|
if(*t == '\"') {
|
|
value = ++t;
|
|
while(*t && (*t != '\"')) ++t;
|
|
if(!(*t)) {
|
|
TRACEMSG(("line %d: missing closing quotes", ln));
|
|
if(cd)
|
|
NET_cdataFree(cd);
|
|
return (-1);
|
|
}
|
|
}
|
|
else {
|
|
value = t;
|
|
while(*t && (!XP_IS_SPACE(*t))) ++t;
|
|
/* null t is okay */
|
|
}
|
|
if(*t) *t++ = '\0';
|
|
if(!cd) {
|
|
cd = NET_cdataCreate();
|
|
if(!cd)
|
|
return(0);
|
|
|
|
cd->is_external = is_external;
|
|
cd->is_modified = FALSE; /* default is "not modified yet!*/
|
|
cd->is_local = is_local;
|
|
FREEIF(cd->src_string);
|
|
cd->src_string = *src_string;
|
|
*src_string = 0;
|
|
}
|
|
|
|
if(!strcasecomp(name, "type")) {
|
|
FREEIF(cd->ci.type);
|
|
cd->ci.type = 0;
|
|
StrAllocCopy(cd->ci.type, value);
|
|
|
|
} else if(!strcasecomp(name, "enc")) {
|
|
FREEIF(cd->ci.encoding);
|
|
cd->ci.encoding = 0;
|
|
StrAllocCopy(cd->ci.encoding, value);
|
|
|
|
} else if(!strcasecomp(name, "lang")) {
|
|
FREEIF(cd->ci.language);
|
|
cd->ci.language = 0;
|
|
StrAllocCopy(cd->ci.language, value);
|
|
|
|
} else if(!strcasecomp(name, "desc")) {
|
|
FREEIF(cd->ci.desc);
|
|
cd->ci.desc = 0;
|
|
StrAllocCopy(cd->ci.desc, value);
|
|
|
|
} else if(!strcasecomp(name, "alt")) {
|
|
FREEIF(cd->ci.alt_text);
|
|
cd->ci.alt_text = 0;
|
|
StrAllocCopy(cd->ci.alt_text, value);
|
|
|
|
} else if(!strcasecomp(name, "icon")) {
|
|
FREEIF(cd->ci.icon);
|
|
cd->ci.icon = 0;
|
|
StrAllocCopy(cd->ci.icon, value);
|
|
|
|
} else if(!strcasecomp(name, "exts")) {
|
|
u = value;
|
|
while(1) {
|
|
v = u;
|
|
while(*u && (*u != ',')) ++u;
|
|
c = *u;
|
|
*u = '\0';
|
|
net_cdata_new_ext(v, cd);
|
|
if(c)
|
|
++u;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Some people like to be clever and use mime.types entries
|
|
like "type=application/x-tar enc=x-gzip exts=tgz",
|
|
but unfortunately, that doesn't even come close to working,
|
|
and will override (delete) the existing tar entry, causing
|
|
disaster of various forms.
|
|
|
|
So, if this line defines *both* "type" and "enc", just throw
|
|
it away.
|
|
*/
|
|
if (cd &&
|
|
cd->ci.type && *cd->ci.type &&
|
|
cd->ci.encoding && *cd->ci.encoding)
|
|
{
|
|
NET_cdataFree(cd);
|
|
cd = 0;
|
|
}
|
|
|
|
if(cd)
|
|
{
|
|
NET_cdataStruct *old_cd = NULL;
|
|
|
|
if ((old_cd = NET_cdataExist(cd)) != NULL)
|
|
/* Found an old one, remove it first */
|
|
{
|
|
/* Extra hack: if the old one defined an icon, or a desc,
|
|
and the new one does not, carry those over. */
|
|
char *icon = (old_cd->ci.icon && !cd->ci.icon
|
|
? XP_STRDUP(old_cd->ci.icon)
|
|
: 0);
|
|
char *desc = (old_cd->ci.desc && !cd->ci.desc
|
|
? XP_STRDUP(old_cd->ci.desc)
|
|
: 0);
|
|
|
|
NET_cdataRemove(old_cd);
|
|
old_cd = 0;
|
|
|
|
if (icon) cd->ci.icon = icon;
|
|
if (desc) cd->ci.desc = desc;
|
|
}
|
|
NET_cdataAdd(cd);
|
|
}
|
|
}
|
|
|
|
ln++;
|
|
}
|
|
return 0; /* #### what should return value be? */
|
|
}
|
|
|
|
|
|
/* Parse sexy new MCC mime types files */
|
|
int
|
|
_cinfo_parse_mcc(XP_File fp, char *line, Bool is_local)
|
|
{
|
|
char *end;
|
|
char *src_string = 0;
|
|
|
|
TRACEMSG(("mime.types file is MCC type"));
|
|
|
|
/* t is already filled. */
|
|
|
|
if ( !src_string )
|
|
StrAllocCopy(src_string, line);
|
|
else
|
|
{
|
|
src_string = XP_AppendStr(src_string, line);
|
|
}
|
|
while(1) {
|
|
cinfo_parse_mcc_line(line, TRUE, is_local, &src_string);
|
|
|
|
if(!(XP_FileReadLine(line, CINFO_MAX_LEN, fp)))
|
|
break;
|
|
|
|
if ( !src_string )
|
|
StrAllocCopy(src_string, line);
|
|
else
|
|
{
|
|
src_string = XP_AppendStr(src_string, line);
|
|
}
|
|
/* assemble extended lines
|
|
*/
|
|
end = &line[XP_STRLEN(line)-1];
|
|
while (end > line && (*end == CR || *end == LF))
|
|
end--;
|
|
while(*end == '\\')
|
|
{
|
|
*end = ' ';
|
|
end++;
|
|
|
|
if(!(XP_FileReadLine(end, CINFO_MAX_LEN-(end-line), fp)))
|
|
break;
|
|
|
|
if ( !src_string )
|
|
StrAllocCopy(src_string, end);
|
|
else
|
|
src_string = XP_AppendStr(src_string, end);
|
|
|
|
|
|
end = &end[XP_STRLEN(end)-1];
|
|
while (end > line && (*end == CR || *end == LF))
|
|
end--;
|
|
|
|
if((end-line)+2 >= CINFO_MAX_LEN)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* return the master cdata List pointer
|
|
*/
|
|
PUBLIC XP_List *
|
|
cinfo_MasterListPointer()
|
|
{
|
|
return(NET_ciMasterList);
|
|
}
|
|
|
|
/* fills in cdata structure
|
|
*
|
|
* if cdata for a given type do not exist, create a new one
|
|
*/
|
|
PUBLIC void
|
|
NET_cdataCommit(char * mimeType, char * cdataString)
|
|
{
|
|
XP_List * extensionList;
|
|
NET_cdataStruct * matchInfo = NULL;
|
|
int listSize;
|
|
int i;
|
|
|
|
extensionList = cinfo_MasterListPointer();
|
|
if (!extensionList)
|
|
{
|
|
NET_ciMasterList = XP_ListNew();
|
|
extensionList = cinfo_MasterListPointer(); /* Lou help me out here,
|
|
create the list and
|
|
matchInfo */
|
|
}
|
|
if (!extensionList)
|
|
return;
|
|
|
|
listSize = XP_ListCount(extensionList);
|
|
for (i = 1; i<=listSize; i++)
|
|
{
|
|
NET_cdataStruct * cinfo =
|
|
(NET_cdataStruct *)XP_ListGetObjectNum(extensionList, i);
|
|
if (cinfo &&
|
|
cinfo->ci.type &&
|
|
(strcasecomp(mimeType, cinfo->ci.type) == 0))
|
|
{
|
|
int j;
|
|
matchInfo = cinfo;
|
|
for ( j= 0; j< matchInfo->num_exts; j++) /* Free 'em all */
|
|
XP_FREE((char*)matchInfo->exts[j]);
|
|
XP_FREE(matchInfo->exts);
|
|
matchInfo->exts = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (matchInfo == NULL)
|
|
{
|
|
matchInfo = NET_cdataCreate();
|
|
if (matchInfo == NULL)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
FREEIF(matchInfo->ci.type);
|
|
matchInfo->ci.type = 0;
|
|
StrAllocCopy(matchInfo->ci.type, mimeType);
|
|
}
|
|
NET_cdataAdd(matchInfo);
|
|
|
|
}
|
|
/* Found the right type */
|
|
{
|
|
char newExtension[30]; /* extension limit is 30 chars */
|
|
char * citer;
|
|
int newExIndex = 0;
|
|
XP_BZERO(newExtension, sizeof(newExtension));
|
|
citer = cdataString;
|
|
newExtension[0] = 0;
|
|
matchInfo->num_exts = 0;
|
|
matchInfo->exts = (char**)XP_ALLOC(10);
|
|
memset(newExtension, 0, 30);
|
|
if (matchInfo->exts == NULL)
|
|
return;
|
|
while (*citer != 0) /* Parse the string. Skip all non-c*/
|
|
{
|
|
if (isalnum(*citer) && (newExIndex < 29)) /* XP_IS_ALPHA(*citer) */
|
|
newExtension[newExIndex++] = *citer;
|
|
else if (XP_STRLEN(newExtension) > 0)
|
|
{
|
|
char * newString = NULL;
|
|
newExtension[newExIndex] = 0;
|
|
StrAllocCopy(newString, newExtension);
|
|
matchInfo->num_exts++;
|
|
matchInfo->exts =
|
|
(char**)XP_REALLOC(matchInfo->exts,
|
|
matchInfo->num_exts * sizeof(void*));
|
|
matchInfo->exts[matchInfo->num_exts-1] = newString;
|
|
newExIndex = 0;
|
|
newExtension[0] = 0;
|
|
}
|
|
citer++;
|
|
}
|
|
/* commit the last extension, if there was one */
|
|
if (XP_STRLEN(newExtension) > 0)
|
|
{
|
|
char * newString = NULL;
|
|
newExtension[newExIndex] = 0;
|
|
StrAllocCopy(newString, newExtension);
|
|
matchInfo->num_exts++;
|
|
matchInfo->exts =
|
|
(char**)XP_REALLOC(matchInfo->exts,
|
|
matchInfo->num_exts * sizeof(void*));
|
|
matchInfo->exts[matchInfo->num_exts-1] = newString;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
PUBLIC XP_Bool
|
|
NET_IsOldMimeTypes (XP_List *masterList)
|
|
{
|
|
NET_cdataStruct *cd;
|
|
|
|
while((cd = XP_ListNextObject(masterList)) != NULL)
|
|
{
|
|
if ( cd->is_local && !cd->is_external )
|
|
{ /* This means that this is a old mime types */
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef XP_UNIX
|
|
static void
|
|
net_Real_CleanupFileFormat(char *filename, Bool file_not_open)
|
|
{
|
|
NET_cdataStruct * cdata;
|
|
XP_File fp = 0;
|
|
int len = 0;
|
|
XP_Bool failed = FALSE;
|
|
char buffer[512];
|
|
int i;
|
|
|
|
if(!NET_ciMasterList)
|
|
return;
|
|
|
|
/* Need to remove from the end so that the next time
|
|
around, the file will be loaded up into a list in
|
|
the consistent way */
|
|
while(!failed && ((cdata = (NET_cdataStruct *)XP_ListRemoveEndObject(NET_ciMasterList)) != NULL))
|
|
{
|
|
|
|
if(file_not_open &&
|
|
(cdata->is_external|| cdata->is_modified))
|
|
{
|
|
/* open file
|
|
* if it doesn't open we won't try again
|
|
*/
|
|
fp = XP_FileOpen(filename? filename : "mime.types",
|
|
xpMimeTypes, XP_FILE_WRITE);
|
|
TRACEMSG(("Writing mime types file..."));
|
|
file_not_open = FALSE;
|
|
|
|
if(fp)
|
|
{
|
|
PR_snprintf(buffer, sizeof(buffer), "#\
|
|
--Netscape Communications Corporation MIME Information\n#\
|
|
Do not delete the above line. It is used to identify the file type.\n#\n");
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Save out the modfied entries as well */
|
|
/* cdata might be modified in FE */
|
|
|
|
if((cdata->is_external||cdata->is_modified) && fp)
|
|
{
|
|
if(!failed && cdata->ci.type)
|
|
{
|
|
PR_snprintf(buffer, sizeof(buffer), "type=%.500s ",
|
|
cdata->ci.type);
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
}
|
|
|
|
if(!failed && cdata->ci.encoding)
|
|
{
|
|
PR_snprintf(buffer, sizeof(buffer), "enc=%.500s ",
|
|
cdata->ci.encoding);
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
}
|
|
|
|
if(!failed && (cdata->num_exts > 0))
|
|
{
|
|
PR_snprintf(buffer, sizeof(buffer), "exts=%.500s",
|
|
cdata->exts[0]);
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
|
|
for(i=1; !failed, i<cdata->num_exts; i++)
|
|
{
|
|
PR_snprintf(buffer, sizeof(buffer), ",%.500s",
|
|
cdata->exts[i]);
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
}
|
|
|
|
PR_snprintf(buffer, sizeof(buffer), " ");
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
}
|
|
|
|
if(!failed && cdata->ci.icon)
|
|
{
|
|
PR_snprintf(buffer, sizeof(buffer), "icon=\"%.500s\" ",
|
|
cdata->ci.icon);
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
}
|
|
|
|
if(!failed && cdata->ci.desc)
|
|
{
|
|
PR_snprintf(buffer, sizeof(buffer), "desc=\"%.500s\" ",
|
|
cdata->ci.desc);
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
}
|
|
|
|
if(!failed && cdata->ci.alt_text)
|
|
{
|
|
PR_snprintf(buffer, sizeof(buffer), "alt=\"%.500s\" ",
|
|
cdata->ci.alt_text);
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
}
|
|
|
|
PR_snprintf(buffer, sizeof(buffer), "%c", LF);
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
}
|
|
|
|
/* free the data
|
|
*/
|
|
NET_cdataFree(cdata);
|
|
}
|
|
|
|
XP_ListDestroy(NET_ciMasterList);
|
|
NET_ciMasterList = 0;
|
|
|
|
if(!file_not_open && fp)
|
|
XP_FileClose(fp);
|
|
/* This function should really return a return code, and handle any errors */
|
|
|
|
}
|
|
#endif /* XP_UNIX */
|
|
|
|
#ifdef XP_UNIX
|
|
PUBLIC void
|
|
NET_CleanupFileFormat(char *filename)
|
|
{
|
|
NET_cdataStruct *cdata;
|
|
XP_File fp = 0;
|
|
int len = 0;
|
|
XP_Bool failed = FALSE;
|
|
Bool file_open = FALSE;
|
|
XP_List *modifiedList = NULL;
|
|
char buffer[512];
|
|
Bool first = TRUE;
|
|
|
|
if ( !NET_ciMasterList ) return;
|
|
|
|
if ( filename )
|
|
{
|
|
fp = XP_FileOpen(filename, xpMimeTypes, XP_FILE_WRITE);
|
|
/* Need to remove from the end so that the next time
|
|
around, the file will be loaded up into a list in
|
|
the consistent way */
|
|
|
|
if ( fp )
|
|
{
|
|
file_open = TRUE;
|
|
modifiedList = XP_ListNew();
|
|
while((cdata = (NET_cdataStruct *) XP_ListRemoveEndObject(NET_ciMasterList)))
|
|
{
|
|
if ( cdata->is_local )
|
|
{
|
|
if ( first && !NET_IsOldMimeTypes(NET_ciMasterList) )
|
|
{
|
|
first = FALSE;
|
|
if (cdata->src_string && *cdata->src_string &&
|
|
strncmp(cdata->src_string, MCC_MT_MAGIC,
|
|
MCC_MT_MAGIC_LEN) &&
|
|
strncmp(cdata->src_string, NCC_MT_MAGIC,
|
|
NCC_MT_MAGIC_LEN))
|
|
{
|
|
/* Write out standard new mime type header info */
|
|
PR_snprintf(buffer, sizeof(buffer),
|
|
"#\
|
|
--Netscape Communications Corporation MIME Information\n#\
|
|
Do not delete the above line. It is used to identify the file type.\n#\n");
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
}
|
|
}
|
|
if (!failed && cdata->src_string && *cdata->src_string )
|
|
{
|
|
len = XP_FileWrite(cdata->src_string,
|
|
strlen(cdata->src_string), fp);
|
|
|
|
if (cdata->src_string[strlen(cdata->src_string)-1] != '\n')
|
|
len = XP_FileWrite("\n", strlen("\n"), fp);
|
|
}
|
|
NET_cdataFree(cdata);
|
|
|
|
}
|
|
else if ( cdata->is_modified )
|
|
XP_ListAddObject(modifiedList, cdata);
|
|
else
|
|
NET_cdataFree(cdata);
|
|
|
|
}
|
|
|
|
while (!failed && (cdata = (NET_cdataStruct *) XP_ListRemoveEndObject(modifiedList)))
|
|
{
|
|
|
|
if ( first && !NET_IsOldMimeTypes(NET_ciMasterList) )
|
|
{
|
|
first = FALSE;
|
|
if (cdata->src_string && *cdata->src_string &&
|
|
strncmp(cdata->src_string, MCC_MT_MAGIC,
|
|
MCC_MT_MAGIC_LEN) &&
|
|
strncmp(cdata->src_string, NCC_MT_MAGIC,
|
|
NCC_MT_MAGIC_LEN))
|
|
{
|
|
/* Write out standard new mime type header info */
|
|
PR_snprintf(buffer, sizeof(buffer),
|
|
"#\
|
|
--Netscape Communications Corporation MIME Information\n#\
|
|
Do not delete the above line. It is used to identify the file type.\n#\n");
|
|
len = XP_FileWrite(buffer, strlen(buffer), fp);
|
|
if (len != (int) strlen(buffer))
|
|
failed = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
if (!failed && cdata->src_string && *cdata->src_string )
|
|
{
|
|
len = XP_FileWrite(cdata->src_string,
|
|
strlen(cdata->src_string), fp);
|
|
if (len != (int) strlen(cdata->src_string))
|
|
failed = TRUE;
|
|
if ( cdata->src_string[strlen(cdata->src_string)-1] != '\n')
|
|
{
|
|
len = XP_FileWrite("\n", strlen("\n"), fp);
|
|
if (len != (int) strlen("\n"))
|
|
failed = TRUE;
|
|
}
|
|
}
|
|
|
|
NET_cdataFree(cdata);
|
|
}
|
|
XP_FileClose(fp);
|
|
}
|
|
}
|
|
else /* Clean up each node before deleting the root node */
|
|
{
|
|
while((cdata = (NET_cdataStruct *) XP_ListRemoveEndObject(NET_ciMasterList)))
|
|
NET_cdataFree(cdata);
|
|
}
|
|
XP_ListDestroy(NET_ciMasterList);
|
|
NET_ciMasterList = 0;
|
|
/* This function should really return an error code and deal with any errors when they happen */
|
|
}
|
|
|
|
#else /* !XP_UNIX */
|
|
|
|
PUBLIC void
|
|
NET_CleanupFileFormat()
|
|
{
|
|
Bool file_not_open=TRUE;
|
|
net_Real_CleanupFileFormat(NULL, file_not_open);
|
|
}
|
|
|
|
#endif /* !XP_UNIX */
|