2 * "$Id: filter.c 6649 2007-07-11 21:46:42Z mike $"
4 * File type conversion routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 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...
33 #include <cups/debug.h>
34 #include <cups/string.h>
42 typedef struct _mime_typelist_s
/**** List of source types ****/
44 struct _mime_typelist_s
*next
; /* Next source type */
45 mime_type_t
*src
; /* Source type */
53 static int compare_filters(mime_filter_t
*, mime_filter_t
*);
54 static int compare_srcs(mime_filter_t
*, mime_filter_t
*);
55 static cups_array_t
*find_filters(mime_t
*mime
, mime_type_t
*src
,
56 mime_type_t
*dst
, int *cost
,
57 _mime_typelist_t
*visited
);
61 * 'mimeAddFilter()' - Add a filter to the current MIME database.
64 mime_filter_t
* /* O - New filter */
65 mimeAddFilter(mime_t
*mime
, /* I - MIME database */
66 mime_type_t
*src
, /* I - Source type */
67 mime_type_t
*dst
, /* I - Destination type */
68 int cost
, /* I - Relative time/resource cost */
69 const char *filter
) /* I - Filter program to run */
71 mime_filter_t
*temp
; /* New filter */
75 * Range-check the input...
78 if (!mime
|| !src
|| !dst
|| !filter
)
82 * See if we already have an existing filter for the given source and
86 if ((temp
= mimeFilterLookup(mime
, src
, dst
)) != NULL
)
89 * Yup, does the existing filter have a higher cost? If so, copy the
90 * filter and cost to the existing filter entry and return it...
93 if (temp
->cost
> cost
)
96 strlcpy(temp
->filter
, filter
, sizeof(temp
->filter
));
102 * Nope, add a new one...
106 mime
->filters
= cupsArrayNew((cups_array_func_t
)compare_filters
, NULL
);
111 if ((temp
= calloc(1, sizeof(mime_filter_t
))) == NULL
)
115 * Copy the information over and sort if necessary...
121 strlcpy(temp
->filter
, filter
, sizeof(temp
->filter
));
123 cupsArrayAdd(mime
->filters
, temp
);
127 * Return the new/updated filter...
135 * 'mimeFilter()' - Find the fastest way to convert from one type to another.
138 cups_array_t
* /* O - Array of filters to run */
139 mimeFilter(mime_t
*mime
, /* I - MIME database */
140 mime_type_t
*src
, /* I - Source file type */
141 mime_type_t
*dst
, /* I - Destination file type */
142 int *cost
) /* O - Cost of filters */
145 * Range-check the input...
148 DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
150 mime
, src
, src
? src
->super
: "?", src
? src
->type
: "?",
151 dst
, dst
? dst
->super
: "?", dst
? dst
->type
: "?",
152 cost
, cost
? *cost
: 0));
158 if (!mime
|| !src
|| !dst
)
162 * (Re)build the source lookup array as needed...
167 mime_filter_t
*current
; /* Current filter */
170 mime
->srcs
= cupsArrayNew((cups_array_func_t
)compare_srcs
, NULL
);
172 for (current
= mimeFirstFilter(mime
);
174 current
= mimeNextFilter(mime
))
175 cupsArrayAdd(mime
->srcs
, current
);
179 * Find the filters...
182 return (find_filters(mime
, src
, dst
, cost
, NULL
));
187 * 'mimeFilterLookup()' - Lookup a filter...
190 mime_filter_t
* /* O - Filter for src->dst */
191 mimeFilterLookup(mime_t
*mime
, /* I - MIME database */
192 mime_type_t
*src
, /* I - Source type */
193 mime_type_t
*dst
) /* I - Destination type */
195 mime_filter_t key
; /* Key record for filter search */
201 return ((mime_filter_t
*)cupsArrayFind(mime
->filters
, &key
));
206 * 'compare_filters()' - Compare two filters...
209 static int /* O - Comparison result */
210 compare_filters(mime_filter_t
*f0
, /* I - First filter */
211 mime_filter_t
*f1
) /* I - Second filter */
213 int i
; /* Result of comparison */
216 if ((i
= strcmp(f0
->src
->super
, f1
->src
->super
)) == 0)
217 if ((i
= strcmp(f0
->src
->type
, f1
->src
->type
)) == 0)
218 if ((i
= strcmp(f0
->dst
->super
, f1
->dst
->super
)) == 0)
219 i
= strcmp(f0
->dst
->type
, f1
->dst
->type
);
226 * 'compare_srcs()' - Compare two srcs...
229 static int /* O - Comparison result */
230 compare_srcs(mime_filter_t
*f0
, /* I - First filter */
231 mime_filter_t
*f1
) /* I - Second filter */
233 int i
; /* Result of comparison */
236 if ((i
= strcmp(f0
->src
->super
, f1
->src
->super
)) == 0)
237 i
= strcmp(f0
->src
->type
, f1
->src
->type
);
244 * 'find_filters()' - Find the filters to convert from one type to another.
247 static cups_array_t
* /* O - Array of filters to run */
248 find_filters(mime_t
*mime
, /* I - MIME database */
249 mime_type_t
*src
, /* I - Source file type */
250 mime_type_t
*dst
, /* I - Destination file type */
251 int *cost
, /* O - Cost of filters */
252 _mime_typelist_t
*list
) /* I - Source types we've used */
254 int tempcost
, /* Temporary cost */
255 mincost
; /* Current minimum */
256 cups_array_t
*temp
, /* Temporary filter */
257 *mintemp
; /* Current minimum */
258 mime_filter_t
*current
, /* Current filter */
259 srckey
; /* Source type key */
260 _mime_typelist_t listnode
, /* New list node */
261 *listptr
; /* Pointer in list */
264 DEBUG_printf(("find_filters(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
265 "cost=%p, list=%p)\n", mime
, src
, src
->super
, src
->type
,
266 dst
, dst
->super
, dst
->type
, cost
, list
));
269 * See if there is a filter that can convert the files directly...
272 if ((current
= mimeFilterLookup(mime
, src
, dst
)) != NULL
)
275 * Got a direct filter!
278 DEBUG_puts("find_filters: Direct filter found!");
280 if ((mintemp
= cupsArrayNew(NULL
, NULL
)) == NULL
)
283 cupsArrayAdd(mintemp
, current
);
285 mincost
= current
->cost
;
290 DEBUG_puts("find_filters: Found direct filter:");
291 DEBUG_printf(("find_filters: %s (cost=%d)\n", current
->filter
, mincost
));
296 * No direct filter...
304 * Initialize this node in the type list...
307 listnode
.next
= list
;
310 * OK, now look for filters from the source type to any other type...
315 for (current
= (mime_filter_t
*)cupsArrayFind(mime
->srcs
, &srckey
);
316 current
&& current
->src
== src
;
317 current
= (mime_filter_t
*)cupsArrayNext(mime
->srcs
))
320 * See if we have already tried the destination type as a source
321 * type (this avoids extra filter looping...)
324 mime_type_t
*current_dst
; /* Current destination type */
327 for (listptr
= list
, current_dst
= current
->dst
;
329 listptr
= listptr
->next
)
330 if (current_dst
== listptr
->src
)
337 * See if we have any filters that can convert from the destination type
338 * of this filter to the final type...
341 listnode
.src
= current
->src
;
343 cupsArraySave(mime
->srcs
);
344 temp
= find_filters(mime
, current
->dst
, dst
, &tempcost
, &listnode
);
345 cupsArrayRestore(mime
->srcs
);
354 * Found a match; see if this one is less costly than the last (if
358 tempcost
+= current
->cost
;
360 if (tempcost
< mincost
)
362 cupsArrayDelete(mintemp
);
365 * Hey, we got a match! Add the current filter to the beginning of the
371 cupsArrayInsert(mintemp
, current
);
374 cupsArrayDelete(temp
);
380 * Hey, we got a match!
384 DEBUG_printf(("find_filters: Returning %d filters:\n",
385 cupsArrayCount(mintemp
)));
387 for (current
= (mime_filter_t
*)cupsArrayFirst(mintemp
);
389 current
= (mime_filter_t
*)cupsArrayNext(mintemp
))
390 DEBUG_printf(("find_filters: %s\n", current
->filter
));
399 DEBUG_puts("find_filters: Returning zippo...");
406 * End of "$Id: filter.c 6649 2007-07-11 21:46:42Z mike $".