]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/filter.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / filter.c
1 /*
2 * "$Id: filter.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * File type conversion routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
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/".
14 *
15 * Contents:
16 *
17 * mimeAddFilter() - Add a filter to the current MIME database.
18 * mimeFilter() - Find the fastest way to convert from one type to
19 * another.
20 * mimeFilterLookup() - Lookup a filter...
21 * compare_filters() - Compare two filters...
22 * find_filters() - Find the filters to convert from one type to another.
23 */
24
25 /*
26 * Include necessary headers...
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32
33 #include <cups/debug.h>
34 #include <cups/string.h>
35 #include "mime.h"
36
37
38 /*
39 * Local types...
40 */
41
42 typedef struct _mime_typelist_s /**** List of source types ****/
43 {
44 struct _mime_typelist_s *next; /* Next source type */
45 mime_type_t *src; /* Source type */
46 } _mime_typelist_t;
47
48
49 /*
50 * Local functions...
51 */
52
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);
58
59
60 /*
61 * 'mimeAddFilter()' - Add a filter to the current MIME database.
62 */
63
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 */
70 {
71 mime_filter_t *temp; /* New filter */
72
73
74 /*
75 * Range-check the input...
76 */
77
78 if (!mime || !src || !dst || !filter)
79 return (NULL);
80
81 /*
82 * See if we already have an existing filter for the given source and
83 * destination...
84 */
85
86 if ((temp = mimeFilterLookup(mime, src, dst)) != NULL)
87 {
88 /*
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...
91 */
92
93 if (temp->cost > cost)
94 {
95 temp->cost = cost;
96 strlcpy(temp->filter, filter, sizeof(temp->filter));
97 }
98 }
99 else
100 {
101 /*
102 * Nope, add a new one...
103 */
104
105 if (!mime->filters)
106 mime->filters = cupsArrayNew((cups_array_func_t)compare_filters, NULL);
107
108 if (!mime->filters)
109 return (NULL);
110
111 if ((temp = calloc(1, sizeof(mime_filter_t))) == NULL)
112 return (NULL);
113
114 /*
115 * Copy the information over and sort if necessary...
116 */
117
118 temp->src = src;
119 temp->dst = dst;
120 temp->cost = cost;
121 strlcpy(temp->filter, filter, sizeof(temp->filter));
122
123 cupsArrayAdd(mime->filters, temp);
124 }
125
126 /*
127 * Return the new/updated filter...
128 */
129
130 return (temp);
131 }
132
133
134 /*
135 * 'mimeFilter()' - Find the fastest way to convert from one type to another.
136 */
137
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 */
143 {
144 /*
145 * Range-check the input...
146 */
147
148 DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
149 "cost=%p(%d))\n",
150 mime, src, src ? src->super : "?", src ? src->type : "?",
151 dst, dst ? dst->super : "?", dst ? dst->type : "?",
152 cost, cost ? *cost : 0));
153
154
155 if (cost)
156 *cost = 0;
157
158 if (!mime || !src || !dst)
159 return (NULL);
160
161 /*
162 * (Re)build the source lookup array as needed...
163 */
164
165 if (!mime->srcs)
166 {
167 mime_filter_t *current; /* Current filter */
168
169
170 mime->srcs = cupsArrayNew((cups_array_func_t)compare_srcs, NULL);
171
172 for (current = mimeFirstFilter(mime);
173 current;
174 current = mimeNextFilter(mime))
175 cupsArrayAdd(mime->srcs, current);
176 }
177
178 /*
179 * Find the filters...
180 */
181
182 return (find_filters(mime, src, dst, cost, NULL));
183 }
184
185
186 /*
187 * 'mimeFilterLookup()' - Lookup a filter...
188 */
189
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 */
194 {
195 mime_filter_t key; /* Key record for filter search */
196
197
198 key.src = src;
199 key.dst = dst;
200
201 return ((mime_filter_t *)cupsArrayFind(mime->filters, &key));
202 }
203
204
205 /*
206 * 'compare_filters()' - Compare two filters...
207 */
208
209 static int /* O - Comparison result */
210 compare_filters(mime_filter_t *f0, /* I - First filter */
211 mime_filter_t *f1) /* I - Second filter */
212 {
213 int i; /* Result of comparison */
214
215
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);
220
221 return (i);
222 }
223
224
225 /*
226 * 'compare_srcs()' - Compare two srcs...
227 */
228
229 static int /* O - Comparison result */
230 compare_srcs(mime_filter_t *f0, /* I - First filter */
231 mime_filter_t *f1) /* I - Second filter */
232 {
233 int i; /* Result of comparison */
234
235
236 if ((i = strcmp(f0->src->super, f1->src->super)) == 0)
237 i = strcmp(f0->src->type, f1->src->type);
238
239 return (i);
240 }
241
242
243 /*
244 * 'find_filters()' - Find the filters to convert from one type to another.
245 */
246
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 */
253 {
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 */
262
263
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));
267
268 /*
269 * See if there is a filter that can convert the files directly...
270 */
271
272 if ((current = mimeFilterLookup(mime, src, dst)) != NULL)
273 {
274 /*
275 * Got a direct filter!
276 */
277
278 DEBUG_puts("Direct filter found!");
279
280 if ((mintemp = cupsArrayNew(NULL, NULL)) == NULL)
281 return (NULL);
282
283 cupsArrayAdd(mintemp, current);
284
285 mincost = current->cost;
286
287 if (!cost)
288 return (mintemp);
289
290 DEBUG_puts(" Found direct filter:");
291 DEBUG_printf((" %s (cost=%d)\n", current->filter, mincost));
292 }
293 else
294 {
295 /*
296 * No direct filter...
297 */
298
299 mintemp = NULL;
300 mincost = 9999999;
301 }
302
303 /*
304 * Initialize this node in the type list...
305 */
306
307 listnode.next = list;
308
309 /*
310 * OK, now look for filters from the source type to any other type...
311 */
312
313 srckey.src = src;
314
315 for (current = (mime_filter_t *)cupsArrayFind(mime->srcs, &srckey);
316 current && current->src == src;
317 current = (mime_filter_t *)cupsArrayNext(mime->srcs))
318 {
319 /*
320 * See if we have already tried the destination type as a source
321 * type (this avoids extra filter looping...)
322 */
323
324 mime_type_t *current_dst; /* Current destination type */
325
326
327 for (listptr = list, current_dst = current->dst;
328 listptr;
329 listptr = listptr->next)
330 if (current_dst == listptr->src)
331 break;
332
333 if (listptr)
334 continue;
335
336 /*
337 * See if we have any filters that can convert from the destination type
338 * of this filter to the final type...
339 */
340
341 listnode.src = current->src;
342
343 cupsArraySave(mime->srcs);
344 temp = find_filters(mime, current->dst, dst, &tempcost, &listnode);
345 cupsArrayRestore(mime->srcs);
346
347 if (!temp)
348 continue;
349
350 if (!cost)
351 return (temp);
352
353 /*
354 * Found a match; see if this one is less costly than the last (if
355 * any...)
356 */
357
358 tempcost += current->cost;
359
360 if (tempcost < mincost)
361 {
362 cupsArrayDelete(mintemp);
363
364 /*
365 * Hey, we got a match! Add the current filter to the beginning of the
366 * filter list...
367 */
368
369 mintemp = temp;
370 mincost = tempcost;
371 cupsArrayInsert(mintemp, current);
372 }
373 else
374 cupsArrayDelete(temp);
375 }
376
377 if (mintemp)
378 {
379 /*
380 * Hey, we got a match!
381 */
382
383 #ifdef DEBUG
384 printf(" Returning %d filters:\n", cupsArrayCount(mintemp));
385 for (current = (mime_filter_t *)cupsArrayFirst(mintemp);
386 current;
387 current = (mime_filter_t *)cupsArrayNext(mintemp))
388 printf(" %s\n", current->filter);
389 #endif /* DEBUG */
390
391 if (cost)
392 *cost = mincost;
393
394 return (mintemp);
395 }
396
397 DEBUG_puts(" Returning zippo...");
398
399 return (NULL);
400 }
401
402
403 /*
404 * End of "$Id: filter.c 6649 2007-07-11 21:46:42Z mike $".
405 */