/*
- * "$Id: mime.c 4613 2005-08-30 12:41:48Z mike $"
+ * "$Id: mime.c 6649 2007-07-11 21:46:42Z mike $"
*
* MIME database file routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* Contents:
*
- * mimeDelete() - Delete (free) a MIME database.
- * mimeMerge() - Merge a MIME database from disk with the current one.
- * mimeNew() - Create a new, empty MIME database.
- * load_types() - Load a xyz.types file...
- * delete_rules() - Free all memory for the given rule tree.
- * load_convs() - Load a xyz.convs file...
+ * mimeDelete() - Delete (free) a MIME database.
+ * mimeDeleteFilter() - Delete a filter from the MIME database.
+ * mimeDeleteType() - Delete a type from the MIME database.
+ * mimeFirstFilter() - Get the first filter in the MIME database.
+ * mimeFirstType() - Get the first type in the MIME database.
+ * mimeLoad() - Create a new MIME database from disk.
+ * mimeMerge() - Merge a MIME database from disk with the current one.
+ * mimeNew() - Create a new, empty MIME database.
+ * mimeNextFilter() - Get the next filter in the MIME database.
+ * mimeNextType() - Get the next type in the MIME database.
+ * mimeNumFilters() - Get the number of filters in a MIME database.
+ * mimeNumTypes() - Get the number of types in a MIME database.
+ * add_fcache() - Add a filter to the filter cache.
+ * compare_fcache() - Compare two filter cache entries.
+ * delete_fcache() - Free all memory used by the filter cache.
+ * delete_rules() - Free all memory for the given rule tree.
+ * load_convs() - Load a xyz.convs file...
+ * load_types() - Load a xyz.types file...
*/
/*
#include <stdlib.h>
#include <ctype.h>
+#include <cups/debug.h>
+#include <cups/dir.h>
#include <cups/string.h>
#include "mime.h"
-#ifdef WIN32
-# include <windows.h>
-#else
-# include <dirent.h>
-#endif /* WIN32 */
+
+/*
+ * Local types...
+ */
+
+typedef struct _mime_fcache_s /**** Filter cache structure ****/
+{
+ char *name, /* Filter name */
+ *path; /* Full path to filter if available */
+} _mime_fcache_t;
/*
* Local functions...
*/
-static void load_types(mime_t *mime, const char *filename);
-static void load_convs(mime_t *mime, const char *filename,
- const char *filterpath);
+static const char *add_fcache(cups_array_t *filtercache, const char *name,
+ const char *filterpath);
+static int compare_fcache(_mime_fcache_t *a, _mime_fcache_t *b);
+static void delete_fcache(cups_array_t *filtercache);
static void delete_rules(mime_magic_t *rules);
+static void load_convs(mime_t *mime, const char *filename,
+ const char *filterpath,
+ cups_array_t *filtercache);
+static void load_types(mime_t *mime, const char *filename);
/*
*/
void
-mimeDelete(mime_t *mime) /* I - MIME database */
+mimeDelete(mime_t *mime) /* I - MIME database */
{
- int i; /* Looping var */
+ mime_type_t *type; /* Current type */
+ mime_filter_t *filter; /* Current filter */
- if (mime == NULL)
+ if (!mime)
return;
+ /*
+ * Loop through filters and free them...
+ */
+
+ for (filter = (mime_filter_t *)cupsArrayFirst(mime->filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(mime->filters))
+ mimeDeleteFilter(mime, filter);
+
/*
* Loop through the file types and delete any rules...
*/
- for (i = 0; i < mime->num_types; i ++)
- {
- delete_rules(mime->types[i]->rules);
- free(mime->types[i]->type);
- free(mime->types[i]);
- }
+ for (type = (mime_type_t *)cupsArrayFirst(mime->types);
+ type;
+ type = (mime_type_t *)cupsArrayNext(mime->types))
+ mimeDeleteType(mime, type);
/*
* Free the types and filters arrays, and then the MIME database structure.
*/
- free(mime->types);
- free(mime->filters);
+ cupsArrayDelete(mime->types);
+ cupsArrayDelete(mime->filters);
+ cupsArrayDelete(mime->srcs);
free(mime);
}
/*
- * 'mimeMerge()' - Merge a MIME database from disk with the current one.
+ * 'mimeDeleteFilter()' - Delete a filter from the MIME database.
*/
-mime_t * /* O - Updated MIME database */
-mimeMerge(mime_t *mime, /* I - MIME database to add to */
- const char *pathname, /* I - Directory to load */
- const char *filterpath)/* I - Directory to load */
+void
+mimeDeleteFilter(mime_t *mime, /* I - MIME database */
+ mime_filter_t *filter) /* I - Filter */
{
-#ifdef WIN32
- HANDLE dir; /* Directory handle */
- WIN32_FIND_DATA dent; /* Directory entry */
- char filename[1024], /* Full filename of types/converts file */
- *pathsep; /* Last character in path */
+ if (!mime || !filter)
+ return;
+ cupsArrayRemove(mime->filters, filter);
+ free(filter);
/*
- * First open the directory specified by pathname... Return NULL if nothing
- * was read or if the pathname is NULL...
+ * Deleting a filter invalidates the source lookup cache used by
+ * mimeFilter()...
*/
- if (pathname == NULL)
- return (NULL);
-
- strlcpy(filename, pathname, sizeof(filename));
-
- pathsep = filename + strlen(filename);
- if ((pathsep - filename + 9) > sizeof(filename))
- return (NULL);
-
- if (pathsep == filename ||
- (pathsep[-1] != '/' && pathsep[-1] != '\\'))
+ if (mime->srcs)
{
- strcpy(pathsep, "/");
- pathsep ++;
+ cupsArrayDelete(mime->srcs);
+ mime->srcs = NULL;
}
+}
- strcpy(pathsep, "*.types");
-
- if ((dir = FindFirstFile(filename, &dent)) == 0)
- return (NULL);
- /*
- * If "mime" is NULL, make a new, blank database...
- */
+/*
+ * 'mimeDeleteType()' - Delete a type from the MIME database.
+ */
- if (mime == NULL)
- if ((mime = mimeNew()) == NULL)
- return (NULL);
+void
+mimeDeleteType(mime_t *mime, /* I - MIME database */
+ mime_type_t *mt) /* I - Type */
+{
+ if (!mime || !mt)
+ return;
- /*
- * Read all the .types files...
- */
+ cupsArrayRemove(mime->types, mt);
- do
- {
- /*
- * Load a mime.types file...
- */
+ delete_rules(mt->rules);
+ free(mt);
+}
- if ((pathsep - filename + strlen(dent.cFileName)) >= sizeof(filename))
- continue;
- strcpy(pathsep, dent.cFileName);
- load_types(mime, filename);
- }
- while (FindNextFile(dir, &dent));
+/*
+ * 'mimeFirstFilter()' - Get the first filter in the MIME database.
+ */
- FindClose(dir);
+mime_filter_t * /* O - Filter or NULL */
+mimeFirstFilter(mime_t *mime) /* I - MIME database */
+{
+ if (!mime)
+ return (NULL);
+ else
+ return ((mime_filter_t *)cupsArrayFirst(mime->filters));
+}
- /*
- * Read all the .convs files...
- */
- strcpy(pathsep, "*.convs");
-
- if ((dir = FindFirstFile(filename, &dent)) == 0)
- return (mime);
+/*
+ * 'mimeFirstType()' - Get the first type in the MIME database.
+ */
- do
- {
- /*
- * Load a mime.convs file...
- */
+mime_type_t * /* O - Type or NULL */
+mimeFirstType(mime_t *mime) /* I - MIME database */
+{
+ if (!mime)
+ return (NULL);
+ else
+ return ((mime_type_t *)cupsArrayFirst(mime->types));
+}
- if ((pathsep - filename + strlen(dent.cFileName)) >= sizeof(filename))
- continue;
- strcpy(pathsep, dent.cFileName);
- load_convs(mime, filename);
- }
- while (FindNextFile(dir, &dent));
+/*
+ * 'mimeLoad()' - Create a new MIME database from disk.
+ */
- FindClose(dir);
+mime_t * /* O - New MIME database */
+mimeLoad(const char *pathname, /* I - Directory to load */
+ const char *filterpath) /* I - Directory to load */
+{
+ return (mimeMerge(NULL, pathname, filterpath));
+}
- return (mime);
-#else
- DIR *dir; /* Directory */
- struct dirent *dent; /* Directory entry */
- char filename[1024]; /* Full filename of types/converts file */
+
+/*
+ * 'mimeMerge()' - Merge a MIME database from disk with the current one.
+ */
+
+mime_t * /* O - Updated MIME database */
+mimeMerge(mime_t *mime, /* I - MIME database to add to */
+ const char *pathname, /* I - Directory to load */
+ const char *filterpath) /* I - Directory to load */
+{
+ cups_dir_t *dir; /* Directory */
+ cups_dentry_t *dent; /* Directory entry */
+ char filename[1024]; /* Full filename of types/converts file */
+ cups_array_t *filtercache; /* Filter cache */
/*
* was read or if the pathname is NULL...
*/
- if (pathname == NULL)
+ if (!pathname)
return (NULL);
- if ((dir = opendir(pathname)) == NULL)
+ if ((dir = cupsDirOpen(pathname)) == NULL)
return (NULL);
/*
* If "mime" is NULL, make a new, blank database...
*/
- if (mime == NULL)
- if ((mime = mimeNew()) == NULL)
- return (NULL);
+ if (!mime)
+ mime = mimeNew();
+ if (!mime)
+ return (NULL);
/*
* Read all the .types files...
*/
- while ((dent = readdir(dir)) != NULL)
+ while ((dent = cupsDirRead(dir)) != NULL)
{
- if (strlen(dent->d_name) > 6 &&
- strcmp(dent->d_name + strlen(dent->d_name) - 6, ".types") == 0)
+ if (strlen(dent->filename) > 6 &&
+ !strcmp(dent->filename + strlen(dent->filename) - 6, ".types"))
{
/*
* Load a mime.types file...
*/
- snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->d_name);
+ snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
load_types(mime, filename);
}
}
- rewinddir(dir);
+ cupsDirRewind(dir);
/*
* Read all the .convs files...
*/
- while ((dent = readdir(dir)) != NULL)
+ filtercache = cupsArrayNew((cups_array_func_t)compare_fcache, NULL);
+
+ while ((dent = cupsDirRead(dir)) != NULL)
{
- if (strlen(dent->d_name) > 6 &&
- strcmp(dent->d_name + strlen(dent->d_name) - 6, ".convs") == 0)
+ if (strlen(dent->filename) > 6 &&
+ !strcmp(dent->filename + strlen(dent->filename) - 6, ".convs"))
{
/*
* Load a mime.convs file...
*/
- snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->d_name);
- load_convs(mime, filename, filterpath);
+ snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
+ load_convs(mime, filename, filterpath, filtercache);
}
}
- closedir(dir);
+ delete_fcache(filtercache);
+
+ cupsDirClose(dir);
return (mime);
-#endif /* WIN32 */
}
* 'mimeNew()' - Create a new, empty MIME database.
*/
-mime_t * /* O - MIME database */
+mime_t * /* O - MIME database */
mimeNew(void)
{
return ((mime_t *)calloc(1, sizeof(mime_t)));
/*
- * 'load_types()' - Load a xyz.types file...
+ * 'mimeNextFilter()' - Get the next filter in the MIME database.
*/
-static void
-load_types(mime_t *mime, /* I - MIME database */
- const char *filename) /* I - Types file to load */
+mime_filter_t * /* O - Filter or NULL */
+mimeNextFilter(mime_t *mime) /* I - MIME database */
{
- cups_file_t *fp; /* Types file */
- int linelen; /* Length of line */
- char line[65536], /* Input line from file */
- *lineptr, /* Current position in line */
- super[MIME_MAX_SUPER], /* Super-type name */
- type[MIME_MAX_TYPE], /* Type name */
- *temp; /* Temporary pointer */
- mime_type_t *typeptr; /* New MIME type */
+ if (!mime)
+ return (NULL);
+ else
+ return ((mime_filter_t *)cupsArrayNext(mime->filters));
+}
- /*
- * First try to open the file...
- */
+/*
+ * 'mimeNextType()' - Get the next type in the MIME database.
+ */
- if ((fp = cupsFileOpen(filename, "r")) == NULL)
- return;
+mime_type_t * /* O - Type or NULL */
+mimeNextType(mime_t *mime) /* I - MIME database */
+{
+ if (!mime)
+ return (NULL);
+ else
+ return ((mime_type_t *)cupsArrayNext(mime->types));
+}
- /*
- * Then read each line from the file, skipping any comments in the file...
- */
- while (cupsFileGets(fp, line, sizeof(line)) != NULL)
- {
- /*
- * Skip blank lines and lines starting with a #...
- */
+/*
+ * 'mimeNumFilters()' - Get the number of filters in a MIME database.
+ */
- if (!line[0] || line[0] == '#')
- continue;
+int
+mimeNumFilters(mime_t *mime) /* I - MIME database */
+{
+ if (!mime)
+ return (0);
+ else
+ return (cupsArrayCount(mime->filters));
+}
- /*
- * While the last character in the line is a backslash, continue on to the
- * next line (and the next, etc.)
- */
- linelen = strlen(line);
+/*
+ * 'mimeNumTypes()' - Get the number of types in a MIME database.
+ */
- while (line[linelen - 1] == '\\')
- {
- linelen --;
+int
+mimeNumTypes(mime_t *mime) /* I - MIME database */
+{
+ if (!mime)
+ return (0);
+ else
+ return (cupsArrayCount(mime->types));
+}
- if (cupsFileGets(fp, line + linelen, sizeof(line) - linelen) == NULL)
- line[linelen] = '\0';
- else
- linelen += strlen(line + linelen);
- }
- /*
- * Extract the super-type and type names from the beginning of the line.
- */
+/*
+ * 'add_fcache()' - Add a filter to the filter cache.
+ */
- lineptr = line;
- temp = super;
+static const char * /* O - Full path to filter or NULL */
+add_fcache(cups_array_t *filtercache, /* I - Filter cache */
+ const char *name, /* I - Filter name */
+ const char *filterpath) /* I - Filter path */
+{
+ _mime_fcache_t key, /* Search key */
+ *temp; /* New filter cache */
+ char path[1024]; /* Full path to filter */
- while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
- (temp - super + 1) < MIME_MAX_SUPER)
- *temp++ = tolower(*lineptr++ & 255);
- *temp = '\0';
+ key.name = (char *)name;
+ if ((temp = (_mime_fcache_t *)cupsArrayFind(filtercache, &key)) != NULL)
+ return (temp->path);
- if (*lineptr != '/')
- continue;
+ if ((temp = calloc(1, sizeof(_mime_fcache_t))) == NULL)
+ return (NULL);
- lineptr ++;
- temp = type;
+ temp->name = strdup(name);
- while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
- *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
- *temp++ = tolower(*lineptr++ & 255);
+ if (cupsFileFind(name, filterpath, 1, path, sizeof(path)))
+ temp->path = strdup(path);
- *temp = '\0';
+ cupsArrayAdd(filtercache, temp);
- /*
- * Add the type and rules to the MIME database...
- */
+ return (temp->path);
+}
- typeptr = mimeAddType(mime, super, type);
- mimeAddTypeRule(typeptr, lineptr);
+
+/*
+ * 'compare_fcache()' - Compare two filter cache entries.
+ */
+
+static int /* O - Result of comparison */
+compare_fcache(_mime_fcache_t *a, /* I - First entry */
+ _mime_fcache_t *b) /* I - Second entry */
+{
+ return (strcmp(a->name, b->name));
+}
+
+
+/*
+ * 'delete_fcache()' - Free all memory used by the filter cache.
+ */
+
+static void
+delete_fcache(cups_array_t *filtercache)/* I - Filter cache */
+{
+ _mime_fcache_t *current; /* Current cache entry */
+
+
+ for (current = (_mime_fcache_t *)cupsArrayFirst(filtercache);
+ current;
+ current = (_mime_fcache_t *)cupsArrayNext(filtercache))
+ {
+ free(current->name);
+
+ if (current->path)
+ free(current->path);
+
+ free(current);
}
- cupsFileClose(fp);
+ cupsArrayDelete(filtercache);
+}
+
+
+/*
+ * 'delete_rules()' - Free all memory for the given rule tree.
+ */
+
+static void
+delete_rules(mime_magic_t *rules) /* I - Rules to free */
+{
+ mime_magic_t *next; /* Next rule to free */
+
+
+ /*
+ * Free the rules list, descending recursively to free any child rules.
+ */
+
+ while (rules != NULL)
+ {
+ next = rules->next;
+
+ if (rules->child != NULL)
+ delete_rules(rules->child);
+
+ free(rules);
+ rules = next;
+ }
}
*/
static void
-load_convs(mime_t *mime, /* I - MIME database */
- const char *filename, /* I - Convs file to load */
- const char *filterpath) /* I - Directory to load */
+load_convs(mime_t *mime, /* I - MIME database */
+ const char *filename, /* I - Convs file to load */
+ const char *filterpath, /* I - Path for filters */
+ cups_array_t *filtercache) /* I - Filter program cache */
{
- int i; /* Looping var */
cups_file_t *fp; /* Convs file */
char line[1024], /* Input line from file */
*lineptr, /* Current position in line */
type[MIME_MAX_TYPE], /* Type name */
*temp, /* Temporary pointer */
*filter; /* Filter program */
- mime_type_t **temptype, /* MIME type looping var */
+ mime_type_t *temptype, /* MIME type looping var */
*dsttype; /* Destination MIME type */
int cost; /* Cost of filter */
- char filterprog[1024]; /* Full path of filter... */
/*
if ((fp = cupsFileOpen(filename, "r")) == NULL)
return;
+ DEBUG_printf(("\"%s\":\n", filename));
+
/*
* Then read each line from the file, skipping any comments in the file...
*/
* Skip blank lines and lines starting with a #...
*/
+ DEBUG_puts(line);
+
if (!line[0] || line[0] == '#')
continue;
continue;
if ((dsttype = mimeType(mime, super, type)) == NULL)
+ {
+ DEBUG_printf((" Destination type %s/%s not found!\n", super, type));
continue;
+ }
/*
* Then get the cost and filter program...
filter = lineptr;
-#ifndef WIN32
- if (strcmp(filter, "-") != 0)
+ if (strcmp(filter, "-"))
{
/*
* Verify that the filter exists and is executable...
*/
- if (filter[0] == '/')
- strlcpy(filterprog, filter, sizeof(filterprog));
- else
- snprintf(filterprog, sizeof(filterprog), "%s/%s", filterpath, filter);
-
- if (access(filterprog, X_OK))
- continue;
+ if (!add_fcache(filtercache, filter, filterpath))
+ {
+ DEBUG_printf((" Filter %s not found in %s!\n", filter, filterpath));
+ continue;
+ }
}
-#endif /* !WIN32 */
/*
* Finally, get the source super-type and type names from the beginning of
*temp = '\0';
- if (strcmp(super, "*") == 0 && strcmp(type, "*") == 0)
+ if (!strcmp(super, "*") && !strcmp(type, "*"))
{
/*
* Force * / * to be "application/octet-stream"...
* Add the filter to the MIME database, supporting wildcards as needed...
*/
- for (temptype = mime->types, i = 0; i < mime->num_types; i ++, temptype ++)
- if ((super[0] == '*' || strcmp((*temptype)->super, super) == 0) &&
- (type[0] == '*' || strcmp((*temptype)->type, type) == 0))
- mimeAddFilter(mime, *temptype, dsttype, cost, filter);
+ for (temptype = (mime_type_t *)cupsArrayFirst(mime->types);
+ temptype;
+ temptype = (mime_type_t *)cupsArrayNext(mime->types))
+ if ((super[0] == '*' || !strcmp(temptype->super, super)) &&
+ (type[0] == '*' || !strcmp(temptype->type, type)))
+ mimeAddFilter(mime, temptype, dsttype, cost, filter);
}
cupsFileClose(fp);
/*
- * 'delete_rules()' - Free all memory for the given rule tree.
+ * 'load_types()' - Load a xyz.types file...
*/
static void
-delete_rules(mime_magic_t *rules) /* I - Rules to free */
+load_types(mime_t *mime, /* I - MIME database */
+ const char *filename) /* I - Types file to load */
{
- mime_magic_t *next; /* Next rule to free */
+ cups_file_t *fp; /* Types file */
+ int linelen; /* Length of line */
+ char line[32768], /* Input line from file */
+ *lineptr, /* Current position in line */
+ super[MIME_MAX_SUPER], /* Super-type name */
+ type[MIME_MAX_TYPE], /* Type name */
+ *temp; /* Temporary pointer */
+ mime_type_t *typeptr; /* New MIME type */
/*
- * Free the rules list, descending recursively to free any child rules.
+ * First try to open the file...
*/
- while (rules != NULL)
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ return;
+
+ DEBUG_printf(("\"%s\":\n", filename));
+
+ /*
+ * Then read each line from the file, skipping any comments in the file...
+ */
+
+ while (cupsFileGets(fp, line, sizeof(line)) != NULL)
{
- next = rules->next;
+ /*
+ * Skip blank lines and lines starting with a #...
+ */
- if (rules->child != NULL)
- delete_rules(rules->child);
+ DEBUG_puts(line);
- free(rules);
- rules = next;
+ if (!line[0] || line[0] == '#')
+ continue;
+
+ /*
+ * While the last character in the line is a backslash, continue on to the
+ * next line (and the next, etc.)
+ */
+
+ linelen = strlen(line);
+
+ while (line[linelen - 1] == '\\')
+ {
+ linelen --;
+
+ if (cupsFileGets(fp, line + linelen, sizeof(line) - linelen) == NULL)
+ line[linelen] = '\0';
+ else
+ linelen += strlen(line + linelen);
+ }
+
+ /*
+ * Extract the super-type and type names from the beginning of the line.
+ */
+
+ lineptr = line;
+ temp = super;
+
+ while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
+ (temp - super + 1) < MIME_MAX_SUPER)
+ *temp++ = tolower(*lineptr++ & 255);
+
+ *temp = '\0';
+
+ if (*lineptr != '/')
+ continue;
+
+ lineptr ++;
+ temp = type;
+
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
+ *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
+ *temp++ = tolower(*lineptr++ & 255);
+
+ *temp = '\0';
+
+ /*
+ * Add the type and rules to the MIME database...
+ */
+
+ typeptr = mimeAddType(mime, super, type);
+ mimeAddTypeRule(typeptr, lineptr);
}
+
+ cupsFileClose(fp);
}
/*
- * End of "$Id: mime.c 4613 2005-08-30 12:41:48Z mike $".
+ * End of "$Id: mime.c 6649 2007-07-11 21:46:42Z mike $".
*/