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