/*
- * "$Id: filter.c 4833 2005-11-12 21:46:52Z mike $"
+ * "$Id: filter.c 181 2006-06-22 20:01:18Z jlovell $"
*
* File type conversion routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ * 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
*
* Contents:
*
- * mimeAddFilter() - Add a filter to the current MIME database.
- * mimeFilter() - Find the fastest way to convert from one type to another.
- * compare() - Compare two filter types...
- * lookup() - Lookup a filter...
+ * mimeAddFilter() - Add a filter to the current MIME database.
+ * mimeFilter() - Find the fastest way to convert from one type to
+ * another.
+ * compare_filters() - Compare two filters...
+ * find_filters() - Find the filters to convert from one type to another.
+ * lookup() - Lookup a filter...
*/
/*
#include "mime.h"
+/*
+ * Local types...
+ */
+
+typedef struct _mime_typelist_s /**** List of source types ****/
+{
+ struct _mime_typelist_s *next; /* Next source type */
+ mime_type_t *src; /* Source type */
+} _mime_typelist_t;
+
+
/*
* Local functions...
*/
-static int compare(mime_filter_t *, mime_filter_t *);
+static int compare_filters(mime_filter_t *, mime_filter_t *);
+static int compare_srcs(mime_filter_t *, mime_filter_t *);
+static cups_array_t *find_filters(mime_t *mime, mime_type_t *src,
+ mime_type_t *dst, int *cost,
+ _mime_typelist_t *visited);
static mime_filter_t *lookup(mime_t *, mime_type_t *, mime_type_t *);
* Range-check the input...
*/
- if (mime == NULL || src == NULL || dst == NULL || filter == NULL)
- return (NULL);
-
- if (strlen(filter) > (MIME_MAX_FILTER - 1))
+ if (!mime || !src || !dst || !filter)
return (NULL);
/*
* Nope, add a new one...
*/
- if (mime->num_filters == 0)
- temp = malloc(sizeof(mime_filter_t));
- else
- temp = realloc(mime->filters, sizeof(mime_filter_t) * (mime->num_filters + 1));
+ if (!mime->filters)
+ mime->filters = cupsArrayNew((cups_array_func_t)compare_filters, NULL);
- if (temp == NULL)
+ if (!mime->filters)
return (NULL);
- mime->filters = temp;
- temp += mime->num_filters;
- mime->num_filters ++;
+ if ((temp = calloc(1, sizeof(mime_filter_t))) == NULL)
+ return (NULL);
/*
* Copy the information over and sort if necessary...
temp->cost = cost;
strlcpy(temp->filter, filter, sizeof(temp->filter));
- if (mime->num_filters > 1)
- qsort(mime->filters, mime->num_filters, sizeof(mime_filter_t),
- (int (*)(const void *, const void *))compare);
+ cupsArrayAdd(mime->filters, temp);
}
/*
* 'mimeFilter()' - Find the fastest way to convert from one type to another.
*/
-mime_filter_t * /* O - Array of filters to run */
+cups_array_t * /* O - Array of filters to run */
mimeFilter(mime_t *mime, /* I - MIME database */
mime_type_t *src, /* I - Source file type */
mime_type_t *dst, /* I - Destination file type */
- int *num_filters, /* O - Number of filters to run */
- int max_depth) /* I - Maximum depth of search */
+ int *cost) /* O - Cost of filters */
{
- int i, j, /* Looping vars */
- num_temp, /* Number of temporary filters */
- num_mintemp, /* Number of filters in the minimum */
- cost, /* Current cost */
- mincost; /* Current minimum */
- mime_filter_t *temp, /* Temporary filter */
- *mintemp, /* Current minimum */
- *current; /* Current filter */
-
-
/*
* Range-check the input...
*/
- DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), num_filters=%p(%d))\n",
+ DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
+ "cost=%p(%d))\n",
mime, src, src ? src->super : "?", src ? src->type : "?",
dst, dst ? dst->super : "?", dst ? dst->type : "?",
- num_filters, num_filters ? *num_filters : 0));
+ cost, cost ? *cost : 0));
+
+
+ if (cost)
+ *cost = 0;
- if (mime == NULL || src == NULL || dst == NULL || num_filters == NULL ||
- max_depth <= 0)
+ if (!mime || !src || !dst)
return (NULL);
- *num_filters = 0;
+ /*
+ * (Re)build the source lookup array as needed...
+ */
+
+ if (!mime->srcs)
+ {
+ mime_filter_t *current; /* Current filter */
+
+
+ mime->srcs = cupsArrayNew((cups_array_func_t)compare_srcs, NULL);
+
+ for (current = mimeFirstFilter(mime);
+ current;
+ current = mimeNextFilter(mime))
+ cupsArrayAdd(mime->srcs, current);
+ }
+
+ /*
+ * Find the filters...
+ */
+
+ return (find_filters(mime, src, dst, cost, NULL));
+}
+
+
+/*
+ * 'compare_filters()' - Compare two filters...
+ */
+
+static int /* O - Comparison result */
+compare_filters(mime_filter_t *f0, /* I - First filter */
+ mime_filter_t *f1) /* I - Second filter */
+{
+ int i; /* Result of comparison */
+
+
+ if ((i = strcmp(f0->src->super, f1->src->super)) == 0)
+ if ((i = strcmp(f0->src->type, f1->src->type)) == 0)
+ if ((i = strcmp(f0->dst->super, f1->dst->super)) == 0)
+ i = strcmp(f0->dst->type, f1->dst->type);
+
+ return (i);
+}
+
+
+/*
+ * 'compare_srcs()' - Compare two srcs...
+ */
+
+static int /* O - Comparison result */
+compare_srcs(mime_filter_t *f0, /* I - First filter */
+ mime_filter_t *f1) /* I - Second filter */
+{
+ int i; /* Result of comparison */
+
+
+ if ((i = strcmp(f0->src->super, f1->src->super)) == 0)
+ i = strcmp(f0->src->type, f1->src->type);
+
+ return (i);
+}
+
+
+/*
+ * 'find_filters()' - Find the filters to convert from one type to another.
+ */
+
+static cups_array_t * /* O - Array of filters to run */
+find_filters(mime_t *mime, /* I - MIME database */
+ mime_type_t *src, /* I - Source file type */
+ mime_type_t *dst, /* I - Destination file type */
+ int *cost, /* O - Cost of filters */
+ _mime_typelist_t *list) /* I - Source types we've used */
+{
+ int tempcost, /* Temporary cost */
+ mincost; /* Current minimum */
+ cups_array_t *temp, /* Temporary filter */
+ *mintemp; /* Current minimum */
+ mime_filter_t *current, /* Current filter */
+ srckey; /* Source type key */
+ _mime_typelist_t listnode, /* New list node */
+ *listptr; /* Pointer in list */
+
+
+ DEBUG_printf(("find_filters(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
+ "cost=%p, list=%p)\n", mime, src, src->super, src->type,
+ dst, dst->super, dst->type, cost, list));
/*
* See if there is a filter that can convert the files directly...
*/
- if ((temp = lookup(mime, src, dst)) != NULL)
+ if ((current = lookup(mime, src, dst)) != NULL)
{
/*
* Got a direct filter!
*/
- if ((mintemp = (mime_filter_t *)malloc(sizeof(mime_filter_t))) == NULL)
+ DEBUG_puts("Direct filter found!");
+
+ if ((mintemp = cupsArrayNew(NULL, NULL)) == NULL)
return (NULL);
- memcpy(mintemp, temp, sizeof(mime_filter_t));
- num_mintemp = 1;
- mincost = mintemp->cost;
+ cupsArrayAdd(mintemp, current);
+
+ mincost = current->cost;
+
+ if (!cost)
+ return (mintemp);
DEBUG_puts(" Found direct filter:");
- DEBUG_printf((" %s (cost=%d)\n", mintemp->filter, mincost));
+ DEBUG_printf((" %s (cost=%d)\n", current->filter, mincost));
}
else
{
* No direct filter...
*/
- mincost = 9999999;
- mintemp = NULL;
- num_mintemp = 0;
+ mintemp = NULL;
+ mincost = 9999999;
}
+ /*
+ * Initialize this node in the type list...
+ */
+
+ listnode.next = list;
+
/*
* OK, now look for filters from the source type to any other type...
*/
- for (i = mime->num_filters, current = mime->filters;
- i > 0;
- i --, current ++)
- if (current->src == src)
- {
- /*
- * See if we have any filters that can convert from the destination type
- * of this filter to the final type...
- */
+ srckey.src = src;
- if ((temp = mimeFilter(mime, current->dst, dst, &num_temp,
- max_depth - 1)) == NULL)
- continue;
+ for (current = (mime_filter_t *)cupsArrayFind(mime->srcs, &srckey);
+ current && current->src == src;
+ current = (mime_filter_t *)cupsArrayNext(mime->srcs))
+ {
+ /*
+ * See if we have already tried the destination type as a source
+ * type (this avoids extra filter looping...)
+ */
- /*
- * Found a match; see if this one is less costly than the last (if
- * any...)
- */
+ mime_type_t *current_dst; /* Current destination type */
+
+
+ for (listptr = list, current_dst = current->dst;
+ listptr;
+ listptr = listptr->next)
+ if (current_dst == listptr->src)
+ break;
+
+ if (listptr)
+ continue;
+
+ /*
+ * See if we have any filters that can convert from the destination type
+ * of this filter to the final type...
+ */
- for (j = 0, cost = current->cost; j < num_temp; j ++)
- cost += temp[j].cost;
+ listnode.src = current->src;
- if (cost < mincost)
- {
- if (mintemp != NULL)
- free(mintemp);
+ cupsArraySave(mime->srcs);
+ temp = find_filters(mime, current->dst, dst, &tempcost, &listnode);
+ cupsArrayRestore(mime->srcs);
- /*
- * Hey, we got a match! Add the current filter to the beginning of the
- * filter list...
- */
+ if (!temp)
+ continue;
- mintemp = (mime_filter_t *)realloc(temp, sizeof(mime_filter_t) *
- (num_temp + 1));
+ if (!cost)
+ return (temp);
- if (mintemp == NULL)
- {
- *num_filters = 0;
- return (NULL);
- }
+ /*
+ * Found a match; see if this one is less costly than the last (if
+ * any...)
+ */
- memmove(mintemp + 1, mintemp, num_temp * sizeof(mime_filter_t));
- memcpy(mintemp, current, sizeof(mime_filter_t));
+ tempcost += current->cost;
+
+ if (tempcost < mincost)
+ {
+ cupsArrayDelete(mintemp);
+
+ /*
+ * Hey, we got a match! Add the current filter to the beginning of the
+ * filter list...
+ */
- num_mintemp = num_temp + 1;
- mincost = cost;
- }
- else
- free(temp);
+ mintemp = temp;
+ mincost = tempcost;
+ cupsArrayInsert(mintemp, current);
}
+ else
+ cupsArrayDelete(temp);
+ }
- if (mintemp != NULL)
+ if (mintemp)
{
/*
* Hey, we got a match!
*/
- *num_filters = num_mintemp;
-
#ifdef DEBUG
- printf(" Returning %d filters:\n", *num_filters);
- for (i = 0; i < num_mintemp; i ++)
- printf(" %s\n", mintemp[i].filter);
+ printf(" Returning %d filters:\n", cupsArrayCount(mintemp));
+ for (current = (mime_filter_t *)cupsArrayFirst(mintemp);
+ current;
+ current = (mime_filter_t *)cupsArrayNext(mintemp))
+ printf(" %s\n", current->filter);
#endif /* DEBUG */
+ if (cost)
+ *cost = mincost;
+
return (mintemp);
}
}
-/*
- * 'compare()' - Compare two filter types...
- */
-
-static int /* O - Comparison result */
-compare(mime_filter_t *f0, /* I - First filter */
- mime_filter_t *f1) /* I - Second filter */
-{
- int i; /* Result of comparison */
-
-
- if ((i = strcmp(f0->src->super, f1->src->super)) == 0)
- if ((i = strcmp(f0->src->type, f1->src->type)) == 0)
- if ((i = strcmp(f0->dst->super, f1->dst->super)) == 0)
- i = strcmp(f0->dst->type, f1->dst->type);
-
- return (i);
-}
-
-
/*
* 'lookup()' - Lookup a filter...
*/
-static mime_filter_t * /* O - Filter for src->dst */
-lookup(mime_t *mime, /* I - MIME database */
- mime_type_t *src, /* I - Source type */
- mime_type_t *dst) /* I - Destination type */
+static mime_filter_t * /* O - Filter for src->dst */
+lookup(mime_t *mime, /* I - MIME database */
+ mime_type_t *src, /* I - Source type */
+ mime_type_t *dst) /* I - Destination type */
{
- mime_filter_t key; /* Key record for filter search */
-
+ mime_filter_t key; /* Key record for filter search */
- if (mime->num_filters == 0)
- return (NULL);
key.src = src;
key.dst = dst;
- return ((mime_filter_t *)bsearch(&key, mime->filters, mime->num_filters,
- sizeof(mime_filter_t),
- (int (*)(const void *, const void *))compare));
+ return ((mime_filter_t *)cupsArrayFind(mime->filters, &key));
}
/*
- * End of "$Id: filter.c 4833 2005-11-12 21:46:52Z mike $".
+ * End of "$Id: filter.c 181 2006-06-22 20:01:18Z jlovell $".
*/