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>
19 * Debug macros that used to be private API...
23 #define DEBUG_printf(...)
30 typedef struct _mime_typelist_s
/**** List of source types ****/
32 struct _mime_typelist_s
*next
; /* Next source type */
33 mime_type_t
*src
; /* Source type */
41 static int mime_compare_filters(mime_filter_t
*, mime_filter_t
*);
42 static int mime_compare_srcs(mime_filter_t
*, mime_filter_t
*);
43 static cups_array_t
*mime_find_filters(mime_t
*mime
, mime_type_t
*src
,
44 size_t srcsize
, mime_type_t
*dst
,
45 int *cost
, _mime_typelist_t
*visited
);
49 * 'mimeAddFilter()' - Add a filter to the current MIME database.
52 mime_filter_t
* /* O - New filter */
53 mimeAddFilter(mime_t
*mime
, /* I - MIME database */
54 mime_type_t
*src
, /* I - Source type */
55 mime_type_t
*dst
, /* I - Destination type */
56 int cost
, /* I - Relative time/resource cost */
57 const char *filter
) /* I - Filter program to run */
59 mime_filter_t
*temp
; /* New filter */
62 DEBUG_printf(("mimeAddFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), cost=%d, "
63 "filter=\"%s\")", mime
,
64 src
, src
? src
->super
: "???", src
? src
->type
: "???",
65 dst
, dst
? dst
->super
: "???", dst
? dst
->type
: "???",
69 * Range-check the input...
72 if (!mime
|| !src
|| !dst
|| !filter
)
74 DEBUG_puts("1mimeAddFilter: Returning NULL.");
79 * See if we already have an existing filter for the given source and
83 if ((temp
= mimeFilterLookup(mime
, src
, dst
)) != NULL
)
86 * Yup, does the existing filter have a higher cost? If so, copy the
87 * filter and cost to the existing filter entry and return it...
90 if (temp
->cost
> cost
)
92 DEBUG_printf(("1mimeAddFilter: Replacing filter \"%s\", cost %d.",
93 temp
->filter
, temp
->cost
));
95 strlcpy(temp
->filter
, filter
, sizeof(temp
->filter
));
101 * Nope, add a new one...
105 mime
->filters
= cupsArrayNew((cups_array_func_t
)mime_compare_filters
, NULL
);
110 if ((temp
= calloc(1, sizeof(mime_filter_t
))) == NULL
)
114 * Copy the information over and sort if necessary...
120 strlcpy(temp
->filter
, filter
, sizeof(temp
->filter
));
122 DEBUG_puts("1mimeAddFilter: Adding new filter.");
123 cupsArrayAdd(mime
->filters
, temp
);
124 cupsArrayAdd(mime
->srcs
, temp
);
128 * Return the new/updated filter...
131 DEBUG_printf(("1mimeAddFilter: Returning %p.", temp
));
138 * 'mimeFilter()' - Find the fastest way to convert from one type to another.
141 cups_array_t
* /* O - Array of filters to run */
142 mimeFilter(mime_t
*mime
, /* I - MIME database */
143 mime_type_t
*src
, /* I - Source file type */
144 mime_type_t
*dst
, /* I - Destination file type */
145 int *cost
) /* O - Cost of filters */
147 DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
148 "cost=%p(%d))", mime
,
149 src
, src
? src
->super
: "???", src
? src
->type
: "???",
150 dst
, dst
? dst
->super
: "???", dst
? dst
->type
: "???",
151 cost
, cost
? *cost
: 0));
153 return (mimeFilter2(mime
, src
, 0, dst
, cost
));
158 * 'mimeFilter2()' - Find the fastest way to convert from one type to another,
159 * including file size.
162 cups_array_t
* /* O - Array of filters to run */
163 mimeFilter2(mime_t
*mime
, /* I - MIME database */
164 mime_type_t
*src
, /* I - Source file type */
165 size_t srcsize
, /* I - Size of source file */
166 mime_type_t
*dst
, /* I - Destination file type */
167 int *cost
) /* O - Cost of filters */
169 cups_array_t
*filters
; /* Array of filters to run */
173 * Range-check the input...
176 DEBUG_printf(("mimeFilter2(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT
177 ", dst=%p(%s/%s), cost=%p(%d))", mime
,
178 src
, src
? src
->super
: "???", src
? src
->type
: "???",
180 dst
, dst
? dst
->super
: "???", dst
? dst
->type
: "???",
181 cost
, cost
? *cost
: 0));
186 if (!mime
|| !src
|| !dst
)
190 * (Re)build the source lookup array as needed...
195 mime_filter_t
*current
; /* Current filter */
197 mime
->srcs
= cupsArrayNew((cups_array_func_t
)mime_compare_srcs
, NULL
);
199 for (current
= mimeFirstFilter(mime
);
201 current
= mimeNextFilter(mime
))
202 cupsArrayAdd(mime
->srcs
, current
);
206 * Find the filters...
209 filters
= mime_find_filters(mime
, src
, srcsize
, dst
, cost
, NULL
);
211 DEBUG_printf(("1mimeFilter2: Returning %d filter(s), cost %d:",
212 cupsArrayCount(filters
), cost
? *cost
: -1));
215 mime_filter_t
*filter
; /* Current filter */
217 for (filter
= (mime_filter_t
*)cupsArrayFirst(filters
);
219 filter
= (mime_filter_t
*)cupsArrayNext(filters
))
220 DEBUG_printf(("1mimeFilter2: %s/%s %s/%s %d %s", filter
->src
->super
,
221 filter
->src
->type
, filter
->dst
->super
, filter
->dst
->type
,
222 filter
->cost
, filter
->filter
));
231 * 'mimeFilterLookup()' - Lookup a filter.
234 mime_filter_t
* /* O - Filter for src->dst */
235 mimeFilterLookup(mime_t
*mime
, /* I - MIME database */
236 mime_type_t
*src
, /* I - Source type */
237 mime_type_t
*dst
) /* I - Destination type */
239 mime_filter_t key
, /* Key record for filter search */
240 *filter
; /* Matching filter */
243 DEBUG_printf(("2mimeFilterLookup(mime=%p, src=%p(%s/%s), dst=%p(%s/%s))", mime
,
244 src
, src
? src
->super
: "???", src
? src
->type
: "???",
245 dst
, dst
? dst
->super
: "???", dst
? dst
->type
: "???"));
250 filter
= (mime_filter_t
*)cupsArrayFind(mime
->filters
, &key
);
251 DEBUG_printf(("3mimeFilterLookup: Returning %p(%s).", filter
,
252 filter
? filter
->filter
: "???"));
258 * 'mime_compare_filters()' - Compare two filters.
261 static int /* O - Comparison result */
262 mime_compare_filters(mime_filter_t
*f0
, /* I - First filter */
263 mime_filter_t
*f1
) /* I - Second filter */
265 int i
; /* Result of comparison */
268 if ((i
= strcmp(f0
->src
->super
, f1
->src
->super
)) == 0)
269 if ((i
= strcmp(f0
->src
->type
, f1
->src
->type
)) == 0)
270 if ((i
= strcmp(f0
->dst
->super
, f1
->dst
->super
)) == 0)
271 i
= strcmp(f0
->dst
->type
, f1
->dst
->type
);
278 * 'mime_compare_srcs()' - Compare two filter source types.
281 static int /* O - Comparison result */
282 mime_compare_srcs(mime_filter_t
*f0
, /* I - First filter */
283 mime_filter_t
*f1
) /* I - Second filter */
285 int i
; /* Result of comparison */
288 if ((i
= strcmp(f0
->src
->super
, f1
->src
->super
)) == 0)
289 i
= strcmp(f0
->src
->type
, f1
->src
->type
);
296 * 'mime_find_filters()' - Find the filters to convert from one type to another.
299 static cups_array_t
* /* O - Array of filters to run */
301 mime_t
*mime
, /* I - MIME database */
302 mime_type_t
*src
, /* I - Source file type */
303 size_t srcsize
, /* I - Size of source file */
304 mime_type_t
*dst
, /* I - Destination file type */
305 int *cost
, /* O - Cost of filters */
306 _mime_typelist_t
*list
) /* I - Source types we've used */
308 int tempcost
, /* Temporary cost */
309 mincost
; /* Current minimum */
310 cups_array_t
*temp
, /* Temporary filter */
311 *mintemp
; /* Current minimum */
312 mime_filter_t
*current
, /* Current filter */
313 srckey
; /* Source type key */
314 _mime_typelist_t listnode
, /* New list node */
315 *listptr
; /* Pointer in list */
318 DEBUG_printf(("2mime_find_filters(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT
319 ", dst=%p(%s/%s), cost=%p, list=%p)", mime
, src
, src
->super
,
320 src
->type
, CUPS_LLCAST srcsize
, dst
, dst
->super
, dst
->type
,
324 * See if there is a filter that can convert the files directly...
327 if ((current
= mimeFilterLookup(mime
, src
, dst
)) != NULL
&&
328 (current
->maxsize
== 0 || srcsize
<= current
->maxsize
))
331 * Got a direct filter!
334 DEBUG_puts("3mime_find_filters: Direct filter found.");
336 if ((mintemp
= cupsArrayNew(NULL
, NULL
)) == NULL
)
338 DEBUG_puts("3mime_find_filters: Returning NULL (out of memory).");
342 cupsArrayAdd(mintemp
, current
);
344 mincost
= current
->cost
;
348 DEBUG_printf(("3mime_find_filters: Returning 1 filter, cost %d:",
350 DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s",
351 current
->src
->super
, current
->src
->type
,
352 current
->dst
->super
, current
->dst
->type
,
353 current
->cost
, current
->filter
));
360 * No direct filter...
368 * Initialize this node in the type list...
371 listnode
.next
= list
;
374 * OK, now look for filters from the source type to any other type...
379 for (current
= (mime_filter_t
*)cupsArrayFind(mime
->srcs
, &srckey
);
380 current
&& current
->src
== src
;
381 current
= (mime_filter_t
*)cupsArrayNext(mime
->srcs
))
384 * See if we have already tried the destination type as a source
385 * type (this avoids extra filter looping...)
388 mime_type_t
*current_dst
; /* Current destination type */
390 if (current
->maxsize
> 0 && srcsize
> current
->maxsize
)
393 for (listptr
= list
, current_dst
= current
->dst
;
395 listptr
= listptr
->next
)
396 if (current_dst
== listptr
->src
)
403 * See if we have any filters that can convert from the destination type
404 * of this filter to the final type...
407 listnode
.src
= current
->src
;
409 cupsArraySave(mime
->srcs
);
410 temp
= mime_find_filters(mime
, current
->dst
, srcsize
, dst
, &tempcost
,
412 cupsArrayRestore(mime
->srcs
);
419 DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:",
420 cupsArrayCount(temp
), tempcost
));
423 for (current
= (mime_filter_t
*)cupsArrayFirst(temp
);
425 current
= (mime_filter_t
*)cupsArrayNext(temp
))
426 DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s",
427 current
->src
->super
, current
->src
->type
,
428 current
->dst
->super
, current
->dst
->type
,
429 current
->cost
, current
->filter
));
436 * Found a match; see if this one is less costly than the last (if
440 tempcost
+= current
->cost
;
442 if (tempcost
< mincost
)
444 cupsArrayDelete(mintemp
);
447 * Hey, we got a match! Add the current filter to the beginning of the
453 cupsArrayInsert(mintemp
, current
);
456 cupsArrayDelete(temp
);
462 * Hey, we got a match!
465 DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:",
466 cupsArrayCount(mintemp
), mincost
));
469 for (current
= (mime_filter_t
*)cupsArrayFirst(mintemp
);
471 current
= (mime_filter_t
*)cupsArrayNext(mintemp
))
472 DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s",
473 current
->src
->super
, current
->src
->type
,
474 current
->dst
->super
, current
->dst
->type
,
475 current
->cost
, current
->filter
));
484 DEBUG_puts("3mime_find_filters: Returning NULL (no matches).");