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