2 * File type conversion routines for CUPS.
4 * Copyright 2007-2011 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
11 * Include necessary headers...
14 #include <cups/string-private.h>
15 #include <cups/debug-private.h>
23 typedef struct _mime_typelist_s
/**** List of source types ****/
25 struct _mime_typelist_s
*next
; /* Next source type */
26 mime_type_t
*src
; /* Source type */
34 static int mime_compare_filters(mime_filter_t
*, mime_filter_t
*);
35 static int mime_compare_srcs(mime_filter_t
*, mime_filter_t
*);
36 static cups_array_t
*mime_find_filters(mime_t
*mime
, mime_type_t
*src
,
37 size_t srcsize
, mime_type_t
*dst
,
38 int *cost
, _mime_typelist_t
*visited
);
42 * 'mimeAddFilter()' - Add a filter to the current MIME database.
45 mime_filter_t
* /* O - New filter */
46 mimeAddFilter(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 */
52 mime_filter_t
*temp
; /* New filter */
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
: "???",
62 * Range-check the input...
65 if (!mime
|| !src
|| !dst
|| !filter
)
67 DEBUG_puts("1mimeAddFilter: Returning NULL.");
72 * See if we already have an existing filter for the given source and
76 if ((temp
= mimeFilterLookup(mime
, src
, dst
)) != NULL
)
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...
83 if (temp
->cost
> cost
)
85 DEBUG_printf(("1mimeAddFilter: Replacing filter \"%s\", cost %d.",
86 temp
->filter
, temp
->cost
));
88 strlcpy(temp
->filter
, filter
, sizeof(temp
->filter
));
94 * Nope, add a new one...
98 mime
->filters
= cupsArrayNew((cups_array_func_t
)mime_compare_filters
, NULL
);
103 if ((temp
= calloc(1, sizeof(mime_filter_t
))) == NULL
)
107 * Copy the information over and sort if necessary...
113 strlcpy(temp
->filter
, filter
, sizeof(temp
->filter
));
115 DEBUG_puts("1mimeAddFilter: Adding new filter.");
116 cupsArrayAdd(mime
->filters
, temp
);
117 cupsArrayAdd(mime
->srcs
, temp
);
121 * Return the new/updated filter...
124 DEBUG_printf(("1mimeAddFilter: Returning %p.", temp
));
131 * 'mimeFilter()' - Find the fastest way to convert from one type to another.
134 cups_array_t
* /* O - Array of filters to run */
135 mimeFilter(mime_t
*mime
, /* I - MIME database */
136 mime_type_t
*src
, /* I - Source file type */
137 mime_type_t
*dst
, /* I - Destination file type */
138 int *cost
) /* O - Cost of filters */
140 DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
141 "cost=%p(%d))", mime
,
142 src
, src
? src
->super
: "???", src
? src
->type
: "???",
143 dst
, dst
? dst
->super
: "???", dst
? dst
->type
: "???",
144 cost
, cost
? *cost
: 0));
146 return (mimeFilter2(mime
, src
, 0, dst
, cost
));
151 * 'mimeFilter2()' - Find the fastest way to convert from one type to another,
152 * including file size.
155 cups_array_t
* /* O - Array of filters to run */
156 mimeFilter2(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 */
162 cups_array_t
*filters
; /* Array of filters to run */
166 * Range-check the input...
169 DEBUG_printf(("mimeFilter2(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT
170 ", dst=%p(%s/%s), cost=%p(%d))", mime
,
171 src
, src
? src
->super
: "???", src
? src
->type
: "???",
173 dst
, dst
? dst
->super
: "???", dst
? dst
->type
: "???",
174 cost
, cost
? *cost
: 0));
179 if (!mime
|| !src
|| !dst
)
183 * (Re)build the source lookup array as needed...
188 mime_filter_t
*current
; /* Current filter */
190 mime
->srcs
= cupsArrayNew((cups_array_func_t
)mime_compare_srcs
, NULL
);
192 for (current
= mimeFirstFilter(mime
);
194 current
= mimeNextFilter(mime
))
195 cupsArrayAdd(mime
->srcs
, current
);
199 * Find the filters...
202 filters
= mime_find_filters(mime
, src
, srcsize
, dst
, cost
, NULL
);
204 DEBUG_printf(("1mimeFilter2: Returning %d filter(s), cost %d:",
205 cupsArrayCount(filters
), cost
? *cost
: -1));
208 mime_filter_t
*filter
; /* Current filter */
210 for (filter
= (mime_filter_t
*)cupsArrayFirst(filters
);
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
));
224 * 'mimeFilterLookup()' - Lookup a filter.
227 mime_filter_t
* /* O - Filter for src->dst */
228 mimeFilterLookup(mime_t
*mime
, /* I - MIME database */
229 mime_type_t
*src
, /* I - Source type */
230 mime_type_t
*dst
) /* I - Destination type */
232 mime_filter_t key
, /* Key record for filter search */
233 *filter
; /* Matching filter */
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
: "???"));
243 filter
= (mime_filter_t
*)cupsArrayFind(mime
->filters
, &key
);
244 DEBUG_printf(("3mimeFilterLookup: Returning %p(%s).", filter
,
245 filter
? filter
->filter
: "???"));
251 * 'mime_compare_filters()' - Compare two filters.
254 static int /* O - Comparison result */
255 mime_compare_filters(mime_filter_t
*f0
, /* I - First filter */
256 mime_filter_t
*f1
) /* I - Second filter */
258 int i
; /* Result of comparison */
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
);
271 * 'mime_compare_srcs()' - Compare two filter source types.
274 static int /* O - Comparison result */
275 mime_compare_srcs(mime_filter_t
*f0
, /* I - First filter */
276 mime_filter_t
*f1
) /* I - Second filter */
278 int i
; /* Result of comparison */
281 if ((i
= strcmp(f0
->src
->super
, f1
->src
->super
)) == 0)
282 i
= strcmp(f0
->src
->type
, f1
->src
->type
);
289 * 'mime_find_filters()' - Find the filters to convert from one type to another.
292 static cups_array_t
* /* O - Array of filters to run */
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 */
301 int tempcost
, /* Temporary cost */
302 mincost
; /* Current minimum */
303 cups_array_t
*temp
, /* Temporary filter */
304 *mintemp
; /* Current minimum */
305 mime_filter_t
*current
, /* Current filter */
306 srckey
; /* Source type key */
307 _mime_typelist_t listnode
, /* New list node */
308 *listptr
; /* Pointer in list */
311 DEBUG_printf(("2mime_find_filters(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT
312 ", dst=%p(%s/%s), cost=%p, list=%p)", mime
, src
, src
->super
,
313 src
->type
, CUPS_LLCAST srcsize
, dst
, dst
->super
, dst
->type
,
317 * See if there is a filter that can convert the files directly...
320 if ((current
= mimeFilterLookup(mime
, src
, dst
)) != NULL
&&
321 (current
->maxsize
== 0 || srcsize
<= current
->maxsize
))
324 * Got a direct filter!
327 DEBUG_puts("3mime_find_filters: Direct filter found.");
329 if ((mintemp
= cupsArrayNew(NULL
, NULL
)) == NULL
)
331 DEBUG_puts("3mime_find_filters: Returning NULL (out of memory).");
335 cupsArrayAdd(mintemp
, current
);
337 mincost
= current
->cost
;
341 DEBUG_printf(("3mime_find_filters: Returning 1 filter, cost %d:",
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
));
353 * No direct filter...
361 * Initialize this node in the type list...
364 listnode
.next
= list
;
367 * OK, now look for filters from the source type to any other type...
372 for (current
= (mime_filter_t
*)cupsArrayFind(mime
->srcs
, &srckey
);
373 current
&& current
->src
== src
;
374 current
= (mime_filter_t
*)cupsArrayNext(mime
->srcs
))
377 * See if we have already tried the destination type as a source
378 * type (this avoids extra filter looping...)
381 mime_type_t
*current_dst
; /* Current destination type */
383 if (current
->maxsize
> 0 && srcsize
> current
->maxsize
)
386 for (listptr
= list
, current_dst
= current
->dst
;
388 listptr
= listptr
->next
)
389 if (current_dst
== listptr
->src
)
396 * See if we have any filters that can convert from the destination type
397 * of this filter to the final type...
400 listnode
.src
= current
->src
;
402 cupsArraySave(mime
->srcs
);
403 temp
= mime_find_filters(mime
, current
->dst
, srcsize
, dst
, &tempcost
,
405 cupsArrayRestore(mime
->srcs
);
412 DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:",
413 cupsArrayCount(temp
), tempcost
));
416 for (current
= (mime_filter_t
*)cupsArrayFirst(temp
);
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
));
429 * Found a match; see if this one is less costly than the last (if
433 tempcost
+= current
->cost
;
435 if (tempcost
< mincost
)
437 cupsArrayDelete(mintemp
);
440 * Hey, we got a match! Add the current filter to the beginning of the
446 cupsArrayInsert(mintemp
, current
);
449 cupsArrayDelete(temp
);
455 * Hey, we got a match!
458 DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:",
459 cupsArrayCount(mintemp
), mincost
));
462 for (current
= (mime_filter_t
*)cupsArrayFirst(mintemp
);
464 current
= (mime_filter_t
*)cupsArrayNext(mintemp
))
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
));
477 DEBUG_puts("3mime_find_filters: Returning NULL (no matches).");