]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/filter.c
Remove svn:keywords since they cause svn_load_dirs.pl to complain about every file.
[thirdparty/cups.git] / scheduler / filter.c
index dbf19a0de2e18e26ef4af2a3fda6973fe928020c..38826e81f5be18d553a46efe72bd9ce45444986b 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$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 *);
 
 
@@ -68,10 +85,7 @@ mimeAddFilter(mime_t      *mime,     /* I - MIME database */
   * 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);
 
  /*
@@ -98,17 +112,14 @@ mimeAddFilter(mime_t      *mime,   /* I - MIME database */
     * 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...
@@ -119,9 +130,7 @@ mimeAddFilter(mime_t      *mime,    /* I - MIME database */
     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);
   }
 
  /*
@@ -136,57 +145,141 @@ mimeAddFilter(mime_t      *mime, /* I - MIME database */
  * '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
   {
@@ -194,80 +287,101 @@ mimeFilter(mime_t      *mime,            /* I - MIME database */
     * 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);
   }
 
@@ -277,50 +391,25 @@ mimeFilter(mime_t      *mime,             /* I - MIME database */
 }
 
 
-/*
- * '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 $".
  */