]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/filter.c
Changelog.
[thirdparty/cups.git] / scheduler / filter.c
CommitLineData
79df52e3 1/*
c9d3f842 2 * "$Id$"
79df52e3 3 *
017b5eae 4 * File type conversion routines for CUPS.
79df52e3 5 *
45cf1d00 6 * Copyright 2007-2011 by Apple Inc.
0ce83b5b 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
79df52e3 8 *
9 * These coded instructions, statements, and computer programs are the
4e8d321f 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/".
79df52e3 14 *
15 * Contents:
16 *
45cf1d00 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 * mimeFilter2() - Find the fastest way to convert from one type to
21 * another, including the file size.
22 * mimeFilterLookup() - Lookup a filter.
23 * mime_compare_filters() - Compare two filters.
24 * mime_compare_srcs() - Compare two filter source types.
25 * mime_find_filters() - Find the filters to convert from one type to
26 * another.
79df52e3 27 */
28
29/*
30 * Include necessary headers...
31 */
32
017b5eae 33#include <cups/string-private.h>
34#include <cups/debug-private.h>
0b74af7d 35#include "mime.h"
36
37
238ad980 38/*
39 * Local types...
40 */
41
42typedef 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
0b74af7d 49/*
50 * Local functions...
51 */
52
45cf1d00 53static int mime_compare_filters(mime_filter_t *, mime_filter_t *);
54static int mime_compare_srcs(mime_filter_t *, mime_filter_t *);
55static cups_array_t *mime_find_filters(mime_t *mime, mime_type_t *src,
1d4f9c69 56 size_t srcsize, mime_type_t *dst,
57 int *cost, _mime_typelist_t *visited);
0b74af7d 58
59
60/*
61 * 'mimeAddFilter()' - Add a filter to the current MIME database.
62 */
63
64mime_filter_t * /* O - New filter */
65mimeAddFilter(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 */
063e1ac7 69 const char *filter) /* I - Filter program to run */
0b74af7d 70{
71 mime_filter_t *temp; /* New filter */
72
73
45cf1d00 74 DEBUG_printf(("mimeAddFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), cost=%d, "
75 "filter=\"%s\")", mime,
76 src, src ? src->super : "???", src ? src->type : "???",
77 dst, dst ? dst->super : "???", dst ? dst->type : "???",
78 cost, filter));
79
0b74af7d 80 /*
81 * Range-check the input...
82 */
83
0557217b 84 if (!mime || !src || !dst || !filter)
45cf1d00 85 {
86 DEBUG_puts("1mimeAddFilter: Returning NULL.");
0b74af7d 87 return (NULL);
45cf1d00 88 }
0b74af7d 89
90 /*
91 * See if we already have an existing filter for the given source and
92 * destination...
93 */
94
0ce83b5b 95 if ((temp = mimeFilterLookup(mime, src, dst)) != NULL)
0b74af7d 96 {
97 /*
98 * Yup, does the existing filter have a higher cost? If so, copy the
99 * filter and cost to the existing filter entry and return it...
100 */
101
102 if (temp->cost > cost)
103 {
45cf1d00 104 DEBUG_printf(("1mimeAddFilter: Replacing filter \"%s\", cost %d.",
105 temp->filter, temp->cost));
0b74af7d 106 temp->cost = cost;
def978d5 107 strlcpy(temp->filter, filter, sizeof(temp->filter));
e8fda7b9 108 }
0b74af7d 109 }
110 else
111 {
112 /*
113 * Nope, add a new one...
114 */
115
0557217b 116 if (!mime->filters)
45cf1d00 117 mime->filters = cupsArrayNew((cups_array_func_t)mime_compare_filters, NULL);
0b74af7d 118
48b71928 119 if (!mime->filters)
0b74af7d 120 return (NULL);
121
0557217b 122 if ((temp = calloc(1, sizeof(mime_filter_t))) == NULL)
123 return (NULL);
0b74af7d 124
125 /*
126 * Copy the information over and sort if necessary...
127 */
128
129 temp->src = src;
130 temp->dst = dst;
131 temp->cost = cost;
def978d5 132 strlcpy(temp->filter, filter, sizeof(temp->filter));
0b74af7d 133
45cf1d00 134 DEBUG_puts("1mimeAddFilter: Adding new filter.");
0557217b 135 cupsArrayAdd(mime->filters, temp);
9ac66165 136 cupsArrayAdd(mime->srcs, temp);
e8fda7b9 137 }
0b74af7d 138
139 /*
140 * Return the new/updated filter...
141 */
142
45cf1d00 143 DEBUG_printf(("1mimeAddFilter: Returning %p.", temp));
144
0b74af7d 145 return (temp);
146}
147
148
149/*
150 * 'mimeFilter()' - Find the fastest way to convert from one type to another.
0b74af7d 151 */
152
0557217b 153cups_array_t * /* O - Array of filters to run */
0b74af7d 154mimeFilter(mime_t *mime, /* I - MIME database */
155 mime_type_t *src, /* I - Source file type */
156 mime_type_t *dst, /* I - Destination file type */
238ad980 157 int *cost) /* O - Cost of filters */
0b74af7d 158{
0557217b 159 DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
45cf1d00 160 "cost=%p(%d))", mime,
161 src, src ? src->super : "???", src ? src->type : "???",
162 dst, dst ? dst->super : "???", dst ? dst->type : "???",
238ad980 163 cost, cost ? *cost : 0));
164
1d4f9c69 165 return (mimeFilter2(mime, src, 0, dst, cost));
166}
167
168
169/*
170 * 'mimeFilter2()' - Find the fastest way to convert from one type to another,
171 * including file size.
172 */
173
174cups_array_t * /* O - Array of filters to run */
175mimeFilter2(mime_t *mime, /* I - MIME database */
176 mime_type_t *src, /* I - Source file type */
177 size_t srcsize, /* I - Size of source file */
178 mime_type_t *dst, /* I - Destination file type */
179 int *cost) /* O - Cost of filters */
180{
9ac66165 181 cups_array_t *filters; /* Array of filters to run */
182
183
1d4f9c69 184 /*
185 * Range-check the input...
186 */
187
188 DEBUG_printf(("mimeFilter2(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT
45cf1d00 189 ", dst=%p(%s/%s), cost=%p(%d))", mime,
190 src, src ? src->super : "???", src ? src->type : "???",
191 CUPS_LLCAST srcsize,
192 dst, dst ? dst->super : "???", dst ? dst->type : "???",
193 cost, cost ? *cost : 0));
c5488f2f 194
0557217b 195 if (cost)
196 *cost = 0;
0b74af7d 197
d318937f 198 if (!mime || !src || !dst)
0557217b 199 return (NULL);
0b74af7d 200
48b71928 201 /*
202 * (Re)build the source lookup array as needed...
203 */
204
205 if (!mime->srcs)
206 {
207 mime_filter_t *current; /* Current filter */
208
45cf1d00 209 mime->srcs = cupsArrayNew((cups_array_func_t)mime_compare_srcs, NULL);
48b71928 210
211 for (current = mimeFirstFilter(mime);
212 current;
213 current = mimeNextFilter(mime))
214 cupsArrayAdd(mime->srcs, current);
215 }
216
238ad980 217 /*
218 * Find the filters...
219 */
220
9ac66165 221 filters = mime_find_filters(mime, src, srcsize, dst, cost, NULL);
222
223 DEBUG_printf(("1mimeFilter2: Returning %d filter(s), cost %d:",
224 cupsArrayCount(filters), cost ? *cost : -1));
225#ifdef DEBUG
226 {
227 mime_filter_t *filter; /* Current filter */
228
229 for (filter = (mime_filter_t *)cupsArrayFirst(filters);
230 filter;
231 filter = (mime_filter_t *)cupsArrayNext(filters))
232 DEBUG_printf(("1mimeFilter2: %s/%s %s/%s %d %s", filter->src->super,
233 filter->src->type, filter->dst->super, filter->dst->type,
234 filter->cost, filter->filter));
235 }
236#endif /* DEBUG */
237
238 return (filters);
238ad980 239}
240
241
0ce83b5b 242/*
1d4f9c69 243 * 'mimeFilterLookup()' - Lookup a filter.
0ce83b5b 244 */
245
246mime_filter_t * /* O - Filter for src->dst */
247mimeFilterLookup(mime_t *mime, /* I - MIME database */
248 mime_type_t *src, /* I - Source type */
249 mime_type_t *dst) /* I - Destination type */
250{
45cf1d00 251 mime_filter_t key, /* Key record for filter search */
252 *filter; /* Matching filter */
253
0ce83b5b 254
9ac66165 255 DEBUG_printf(("2mimeFilterLookup(mime=%p, src=%p(%s/%s), dst=%p(%s/%s))", mime,
45cf1d00 256 src, src ? src->super : "???", src ? src->type : "???",
257 dst, dst ? dst->super : "???", dst ? dst->type : "???"));
0ce83b5b 258
259 key.src = src;
260 key.dst = dst;
261
45cf1d00 262 filter = (mime_filter_t *)cupsArrayFind(mime->filters, &key);
9ac66165 263 DEBUG_printf(("3mimeFilterLookup: Returning %p(%s).", filter,
45cf1d00 264 filter ? filter->filter : "???"));
265 return (filter);
0ce83b5b 266}
267
268
238ad980 269/*
45cf1d00 270 * 'mime_compare_filters()' - Compare two filters.
238ad980 271 */
272
273static int /* O - Comparison result */
45cf1d00 274mime_compare_filters(mime_filter_t *f0, /* I - First filter */
275 mime_filter_t *f1) /* I - Second filter */
238ad980 276{
277 int i; /* Result of comparison */
278
279
280 if ((i = strcmp(f0->src->super, f1->src->super)) == 0)
281 if ((i = strcmp(f0->src->type, f1->src->type)) == 0)
282 if ((i = strcmp(f0->dst->super, f1->dst->super)) == 0)
283 i = strcmp(f0->dst->type, f1->dst->type);
284
285 return (i);
286}
287
288
9acc1468 289/*
45cf1d00 290 * 'mime_compare_srcs()' - Compare two filter source types.
9acc1468 291 */
292
293static int /* O - Comparison result */
45cf1d00 294mime_compare_srcs(mime_filter_t *f0, /* I - First filter */
295 mime_filter_t *f1) /* I - Second filter */
9acc1468 296{
297 int i; /* Result of comparison */
298
299
300 if ((i = strcmp(f0->src->super, f1->src->super)) == 0)
301 i = strcmp(f0->src->type, f1->src->type);
302
303 return (i);
304}
305
306
238ad980 307/*
45cf1d00 308 * 'mime_find_filters()' - Find the filters to convert from one type to another.
238ad980 309 */
310
95c68078 311static cups_array_t * /* O - Array of filters to run */
45cf1d00 312mime_find_filters(
313 mime_t *mime, /* I - MIME database */
314 mime_type_t *src, /* I - Source file type */
315 size_t srcsize, /* I - Size of source file */
316 mime_type_t *dst, /* I - Destination file type */
317 int *cost, /* O - Cost of filters */
318 _mime_typelist_t *list) /* I - Source types we've used */
238ad980 319{
320 int tempcost, /* Temporary cost */
321 mincost; /* Current minimum */
322 cups_array_t *temp, /* Temporary filter */
323 *mintemp; /* Current minimum */
9acc1468 324 mime_filter_t *current, /* Current filter */
325 srckey; /* Source type key */
238ad980 326 _mime_typelist_t listnode, /* New list node */
327 *listptr; /* Pointer in list */
328
329
45cf1d00 330 DEBUG_printf(("2mime_find_filters(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT
1d4f9c69 331 ", dst=%p(%s/%s), cost=%p, list=%p)", mime, src, src->super,
332 src->type, CUPS_LLCAST srcsize, dst, dst->super, dst->type,
333 cost, list));
d318937f 334
0b74af7d 335 /*
336 * See if there is a filter that can convert the files directly...
337 */
338
1d4f9c69 339 if ((current = mimeFilterLookup(mime, src, dst)) != NULL &&
340 (current->maxsize == 0 || srcsize <= current->maxsize))
0b74af7d 341 {
342 /*
343 * Got a direct filter!
344 */
345
45cf1d00 346 DEBUG_puts("3mime_find_filters: Direct filter found.");
d318937f 347
0557217b 348 if ((mintemp = cupsArrayNew(NULL, NULL)) == NULL)
45cf1d00 349 {
350 DEBUG_puts("3mime_find_filters: Returning NULL (out of memory).");
0b74af7d 351 return (NULL);
45cf1d00 352 }
0b74af7d 353
0557217b 354 cupsArrayAdd(mintemp, current);
355
356 mincost = current->cost;
c5488f2f 357
9acc1468 358 if (!cost)
45cf1d00 359 {
360 DEBUG_printf(("3mime_find_filters: Returning 1 filter, cost %d:",
361 mincost));
9ac66165 362 DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s",
363 current->src->super, current->src->type,
364 current->dst->super, current->dst->type,
365 current->cost, current->filter));
9acc1468 366 return (mintemp);
45cf1d00 367 }
767ae392 368 }
369 else
370 {
371 /*
372 * No direct filter...
373 */
c5488f2f 374
0557217b 375 mintemp = NULL;
376 mincost = 9999999;
e8fda7b9 377 }
0b74af7d 378
238ad980 379 /*
380 * Initialize this node in the type list...
381 */
382
383 listnode.next = list;
384
0b74af7d 385 /*
386 * OK, now look for filters from the source type to any other type...
387 */
388
9acc1468 389 srckey.src = src;
238ad980 390
9acc1468 391 for (current = (mime_filter_t *)cupsArrayFind(mime->srcs, &srckey);
392 current && current->src == src;
393 current = (mime_filter_t *)cupsArrayNext(mime->srcs))
394 {
395 /*
396 * See if we have already tried the destination type as a source
397 * type (this avoids extra filter looping...)
398 */
238ad980 399
9acc1468 400 mime_type_t *current_dst; /* Current destination type */
238ad980 401
1d4f9c69 402 if (current->maxsize > 0 && srcsize > current->maxsize)
403 continue;
0b74af7d 404
9acc1468 405 for (listptr = list, current_dst = current->dst;
406 listptr;
407 listptr = listptr->next)
408 if (current_dst == listptr->src)
409 break;
410
411 if (listptr)
412 continue;
413
414 /*
415 * See if we have any filters that can convert from the destination type
416 * of this filter to the final type...
417 */
418
419 listnode.src = current->src;
420
421 cupsArraySave(mime->srcs);
45cf1d00 422 temp = mime_find_filters(mime, current->dst, srcsize, dst, &tempcost,
423 &listnode);
9acc1468 424 cupsArrayRestore(mime->srcs);
238ad980 425
9acc1468 426 if (!temp)
427 continue;
0557217b 428
9acc1468 429 if (!cost)
45cf1d00 430 {
431 DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:",
432 cupsArrayCount(temp), tempcost));
433
434#ifdef DEBUG
435 for (current = (mime_filter_t *)cupsArrayFirst(temp);
436 current;
437 current = (mime_filter_t *)cupsArrayNext(temp))
9ac66165 438 DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s",
439 current->src->super, current->src->type,
440 current->dst->super, current->dst->type,
441 current->cost, current->filter));
45cf1d00 442#endif /* DEBUG */
443
9acc1468 444 return (temp);
45cf1d00 445 }
9acc1468 446
447 /*
448 * Found a match; see if this one is less costly than the last (if
449 * any...)
450 */
451
5adebf48 452 tempcost += current->cost;
453
9acc1468 454 if (tempcost < mincost)
455 {
456 cupsArrayDelete(mintemp);
0b74af7d 457
458 /*
9acc1468 459 * Hey, we got a match! Add the current filter to the beginning of the
460 * filter list...
0b74af7d 461 */
462
9acc1468 463 mintemp = temp;
5adebf48 464 mincost = tempcost;
9acc1468 465 cupsArrayInsert(mintemp, current);
4ca01b29 466 }
9acc1468 467 else
468 cupsArrayDelete(temp);
469 }
0b74af7d 470
0557217b 471 if (mintemp)
4ca01b29 472 {
473 /*
7b3a0e77 474 * Hey, we got a match!
4ca01b29 475 */
0b74af7d 476
45cf1d00 477 DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:",
478 cupsArrayCount(mintemp), mincost));
7e8f437e 479
45cf1d00 480#ifdef DEBUG
0557217b 481 for (current = (mime_filter_t *)cupsArrayFirst(mintemp);
482 current;
483 current = (mime_filter_t *)cupsArrayNext(mintemp))
9ac66165 484 DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s",
485 current->src->super, current->src->type,
486 current->dst->super, current->dst->type,
487 current->cost, current->filter));
c5488f2f 488#endif /* DEBUG */
489
d318937f 490 if (cost)
491 *cost = mincost;
0557217b 492
7b3a0e77 493 return (mintemp);
4ca01b29 494 }
495
45cf1d00 496 DEBUG_puts("3mime_find_filters: Returning NULL (no matches).");
c5488f2f 497
0b74af7d 498 return (NULL);
499}
500
501
79df52e3 502/*
c9d3f842 503 * End of "$Id$".
79df52e3 504 */