2 * "$Id: filter.c 7694 2008-06-26 00:23:20Z mike $"
4 * File type conversion routines for CUPS.
6 * Copyright 2007-2010 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * mimeAddFilter() - Add a filter to the current MIME database.
18 * mimeFilter() - Find the fastest way to convert from one type to
20 * mimeFilterLookup() - Lookup a filter...
21 * compare_filters() - Compare two filters...
22 * find_filters() - Find the filters to convert from one type to another.
26 * Include necessary headers...
29 #include <cups/string-private.h>
30 #include <cups/debug-private.h>
38 typedef struct _mime_typelist_s
/**** List of source types ****/
40 struct _mime_typelist_s
*next
; /* Next source type */
41 mime_type_t
*src
; /* Source type */
49 static int compare_filters(mime_filter_t
*, mime_filter_t
*);
50 static int compare_srcs(mime_filter_t
*, mime_filter_t
*);
51 static cups_array_t
*find_filters(mime_t
*mime
, mime_type_t
*src
,
52 mime_type_t
*dst
, int *cost
,
53 _mime_typelist_t
*visited
);
57 * 'mimeAddFilter()' - Add a filter to the current MIME database.
60 mime_filter_t
* /* O - New filter */
61 mimeAddFilter(mime_t
*mime
, /* I - MIME database */
62 mime_type_t
*src
, /* I - Source type */
63 mime_type_t
*dst
, /* I - Destination type */
64 int cost
, /* I - Relative time/resource cost */
65 const char *filter
) /* I - Filter program to run */
67 mime_filter_t
*temp
; /* New filter */
71 * Range-check the input...
74 if (!mime
|| !src
|| !dst
|| !filter
)
78 * See if we already have an existing filter for the given source and
82 if ((temp
= mimeFilterLookup(mime
, src
, dst
)) != NULL
)
85 * Yup, does the existing filter have a higher cost? If so, copy the
86 * filter and cost to the existing filter entry and return it...
89 if (temp
->cost
> cost
)
92 strlcpy(temp
->filter
, filter
, sizeof(temp
->filter
));
98 * Nope, add a new one...
102 mime
->filters
= cupsArrayNew((cups_array_func_t
)compare_filters
, NULL
);
107 if ((temp
= calloc(1, sizeof(mime_filter_t
))) == NULL
)
111 * Copy the information over and sort if necessary...
117 strlcpy(temp
->filter
, filter
, sizeof(temp
->filter
));
119 cupsArrayAdd(mime
->filters
, temp
);
123 * Return the new/updated filter...
131 * 'mimeFilter()' - Find the fastest way to convert from one type to another.
134 cups_array_t
* /* O - Array of filters to run */
135 mimeFilter(mime_t
*mime
, /* I - MIME database */
136 mime_type_t
*src
, /* I - Source file type */
137 mime_type_t
*dst
, /* I - Destination file type */
138 int *cost
) /* O - Cost of filters */
141 * Range-check the input...
144 DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
146 mime
, src
, src
? src
->super
: "?", src
? src
->type
: "?",
147 dst
, dst
? dst
->super
: "?", dst
? dst
->type
: "?",
148 cost
, cost
? *cost
: 0));
154 if (!mime
|| !src
|| !dst
)
158 * (Re)build the source lookup array as needed...
163 mime_filter_t
*current
; /* Current filter */
166 mime
->srcs
= cupsArrayNew((cups_array_func_t
)compare_srcs
, NULL
);
168 for (current
= mimeFirstFilter(mime
);
170 current
= mimeNextFilter(mime
))
171 cupsArrayAdd(mime
->srcs
, current
);
175 * Find the filters...
178 return (find_filters(mime
, src
, dst
, cost
, NULL
));
183 * 'mimeFilterLookup()' - Lookup a filter...
186 mime_filter_t
* /* O - Filter for src->dst */
187 mimeFilterLookup(mime_t
*mime
, /* I - MIME database */
188 mime_type_t
*src
, /* I - Source type */
189 mime_type_t
*dst
) /* I - Destination type */
191 mime_filter_t key
; /* Key record for filter search */
197 return ((mime_filter_t
*)cupsArrayFind(mime
->filters
, &key
));
202 * 'compare_filters()' - Compare two filters...
205 static int /* O - Comparison result */
206 compare_filters(mime_filter_t
*f0
, /* I - First filter */
207 mime_filter_t
*f1
) /* I - Second filter */
209 int i
; /* Result of comparison */
212 if ((i
= strcmp(f0
->src
->super
, f1
->src
->super
)) == 0)
213 if ((i
= strcmp(f0
->src
->type
, f1
->src
->type
)) == 0)
214 if ((i
= strcmp(f0
->dst
->super
, f1
->dst
->super
)) == 0)
215 i
= strcmp(f0
->dst
->type
, f1
->dst
->type
);
222 * 'compare_srcs()' - Compare two srcs...
225 static int /* O - Comparison result */
226 compare_srcs(mime_filter_t
*f0
, /* I - First filter */
227 mime_filter_t
*f1
) /* I - Second filter */
229 int i
; /* Result of comparison */
232 if ((i
= strcmp(f0
->src
->super
, f1
->src
->super
)) == 0)
233 i
= strcmp(f0
->src
->type
, f1
->src
->type
);
240 * 'find_filters()' - Find the filters to convert from one type to another.
243 static cups_array_t
* /* O - Array of filters to run */
244 find_filters(mime_t
*mime
, /* I - MIME database */
245 mime_type_t
*src
, /* I - Source file type */
246 mime_type_t
*dst
, /* I - Destination file type */
247 int *cost
, /* O - Cost of filters */
248 _mime_typelist_t
*list
) /* I - Source types we've used */
250 int tempcost
, /* Temporary cost */
251 mincost
; /* Current minimum */
252 cups_array_t
*temp
, /* Temporary filter */
253 *mintemp
; /* Current minimum */
254 mime_filter_t
*current
, /* Current filter */
255 srckey
; /* Source type key */
256 _mime_typelist_t listnode
, /* New list node */
257 *listptr
; /* Pointer in list */
260 DEBUG_printf(("find_filters(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
261 "cost=%p, list=%p)\n", mime
, src
, src
->super
, src
->type
,
262 dst
, dst
->super
, dst
->type
, cost
, list
));
265 * See if there is a filter that can convert the files directly...
268 if ((current
= mimeFilterLookup(mime
, src
, dst
)) != NULL
)
271 * Got a direct filter!
274 DEBUG_puts("find_filters: Direct filter found!");
276 if ((mintemp
= cupsArrayNew(NULL
, NULL
)) == NULL
)
279 cupsArrayAdd(mintemp
, current
);
281 mincost
= current
->cost
;
286 DEBUG_puts("find_filters: Found direct filter:");
287 DEBUG_printf(("find_filters: %s (cost=%d)\n", current
->filter
, mincost
));
292 * No direct filter...
300 * Initialize this node in the type list...
303 listnode
.next
= list
;
306 * OK, now look for filters from the source type to any other type...
311 for (current
= (mime_filter_t
*)cupsArrayFind(mime
->srcs
, &srckey
);
312 current
&& current
->src
== src
;
313 current
= (mime_filter_t
*)cupsArrayNext(mime
->srcs
))
316 * See if we have already tried the destination type as a source
317 * type (this avoids extra filter looping...)
320 mime_type_t
*current_dst
; /* Current destination type */
323 for (listptr
= list
, current_dst
= current
->dst
;
325 listptr
= listptr
->next
)
326 if (current_dst
== listptr
->src
)
333 * See if we have any filters that can convert from the destination type
334 * of this filter to the final type...
337 listnode
.src
= current
->src
;
339 cupsArraySave(mime
->srcs
);
340 temp
= find_filters(mime
, current
->dst
, dst
, &tempcost
, &listnode
);
341 cupsArrayRestore(mime
->srcs
);
350 * Found a match; see if this one is less costly than the last (if
354 tempcost
+= current
->cost
;
356 if (tempcost
< mincost
)
358 cupsArrayDelete(mintemp
);
361 * Hey, we got a match! Add the current filter to the beginning of the
367 cupsArrayInsert(mintemp
, current
);
370 cupsArrayDelete(temp
);
376 * Hey, we got a match!
380 DEBUG_printf(("find_filters: Returning %d filters:\n",
381 cupsArrayCount(mintemp
)));
383 for (current
= (mime_filter_t
*)cupsArrayFirst(mintemp
);
385 current
= (mime_filter_t
*)cupsArrayNext(mintemp
))
386 DEBUG_printf(("find_filters: %s\n", current
->filter
));
395 DEBUG_puts("find_filters: Returning zippo...");
402 * End of "$Id: filter.c 7694 2008-06-26 00:23:20Z mike $".