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 * 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/".
15 * Include necessary headers...
18 #include <cups/string-private.h>
19 #include <cups/debug-private.h>
27 typedef struct _mime_typelist_s
/**** List of source types ****/
29 struct _mime_typelist_s
*next
; /* Next source type */
30 mime_type_t
*src
; /* Source type */
38 static int mime_compare_filters(mime_filter_t
*, mime_filter_t
*);
39 static int mime_compare_srcs(mime_filter_t
*, mime_filter_t
*);
40 static cups_array_t
*mime_find_filters(mime_t
*mime
, mime_type_t
*src
,
41 size_t srcsize
, mime_type_t
*dst
,
42 int *cost
, _mime_typelist_t
*visited
);
46 * 'mimeAddFilter()' - Add a filter to the current MIME database.
49 mime_filter_t
* /* O - New filter */
50 mimeAddFilter(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 */
56 mime_filter_t
*temp
; /* New filter */
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
: "???",
66 * Range-check the input...
69 if (!mime
|| !src
|| !dst
|| !filter
)
71 DEBUG_puts("1mimeAddFilter: Returning NULL.");
76 * See if we already have an existing filter for the given source and
80 if ((temp
= mimeFilterLookup(mime
, src
, dst
)) != NULL
)
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...
87 if (temp
->cost
> cost
)
89 DEBUG_printf(("1mimeAddFilter: Replacing filter \"%s\", cost %d.",
90 temp
->filter
, temp
->cost
));
92 strlcpy(temp
->filter
, filter
, sizeof(temp
->filter
));
98 * Nope, add a new one...
102 mime
->filters
= cupsArrayNew((cups_array_func_t
)mime_compare_filters
, NULL
);
107 if ((temp
= calloc(1, sizeof(mime_filter_t
))) == NULL
)
111 * Copy the information over and sort if necessary...
117 strlcpy(temp
->filter
, filter
, sizeof(temp
->filter
));
119 DEBUG_puts("1mimeAddFilter: Adding new filter.");
120 cupsArrayAdd(mime
->filters
, temp
);
121 cupsArrayAdd(mime
->srcs
, temp
);
125 * Return the new/updated filter...
128 DEBUG_printf(("1mimeAddFilter: Returning %p.", temp
));
135 * 'mimeFilter()' - Find the fastest way to convert from one type to another.
138 cups_array_t
* /* O - Array of filters to run */
139 mimeFilter(mime_t
*mime
, /* I - MIME database */
140 mime_type_t
*src
, /* I - Source file type */
141 mime_type_t
*dst
, /* I - Destination file type */
142 int *cost
) /* O - Cost of filters */
144 DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
145 "cost=%p(%d))", mime
,
146 src
, src
? src
->super
: "???", src
? src
->type
: "???",
147 dst
, dst
? dst
->super
: "???", dst
? dst
->type
: "???",
148 cost
, cost
? *cost
: 0));
150 return (mimeFilter2(mime
, src
, 0, dst
, cost
));
155 * 'mimeFilter2()' - Find the fastest way to convert from one type to another,
156 * including file size.
159 cups_array_t
* /* O - Array of filters to run */
160 mimeFilter2(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 */
166 cups_array_t
*filters
; /* Array of filters to run */
170 * Range-check the input...
173 DEBUG_printf(("mimeFilter2(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT
174 ", dst=%p(%s/%s), cost=%p(%d))", mime
,
175 src
, src
? src
->super
: "???", src
? src
->type
: "???",
177 dst
, dst
? dst
->super
: "???", dst
? dst
->type
: "???",
178 cost
, cost
? *cost
: 0));
183 if (!mime
|| !src
|| !dst
)
187 * (Re)build the source lookup array as needed...
192 mime_filter_t
*current
; /* Current filter */
194 mime
->srcs
= cupsArrayNew((cups_array_func_t
)mime_compare_srcs
, NULL
);
196 for (current
= mimeFirstFilter(mime
);
198 current
= mimeNextFilter(mime
))
199 cupsArrayAdd(mime
->srcs
, current
);
203 * Find the filters...
206 filters
= mime_find_filters(mime
, src
, srcsize
, dst
, cost
, NULL
);
208 DEBUG_printf(("1mimeFilter2: Returning %d filter(s), cost %d:",
209 cupsArrayCount(filters
), cost
? *cost
: -1));
212 mime_filter_t
*filter
; /* Current filter */
214 for (filter
= (mime_filter_t
*)cupsArrayFirst(filters
);
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
));
228 * 'mimeFilterLookup()' - Lookup a filter.
231 mime_filter_t
* /* O - Filter for src->dst */
232 mimeFilterLookup(mime_t
*mime
, /* I - MIME database */
233 mime_type_t
*src
, /* I - Source type */
234 mime_type_t
*dst
) /* I - Destination type */
236 mime_filter_t key
, /* Key record for filter search */
237 *filter
; /* Matching filter */
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
: "???"));
247 filter
= (mime_filter_t
*)cupsArrayFind(mime
->filters
, &key
);
248 DEBUG_printf(("3mimeFilterLookup: Returning %p(%s).", filter
,
249 filter
? filter
->filter
: "???"));
255 * 'mime_compare_filters()' - Compare two filters.
258 static int /* O - Comparison result */
259 mime_compare_filters(mime_filter_t
*f0
, /* I - First filter */
260 mime_filter_t
*f1
) /* I - Second filter */
262 int i
; /* Result of comparison */
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
);
275 * 'mime_compare_srcs()' - Compare two filter source types.
278 static int /* O - Comparison result */
279 mime_compare_srcs(mime_filter_t
*f0
, /* I - First filter */
280 mime_filter_t
*f1
) /* I - Second filter */
282 int i
; /* Result of comparison */
285 if ((i
= strcmp(f0
->src
->super
, f1
->src
->super
)) == 0)
286 i
= strcmp(f0
->src
->type
, f1
->src
->type
);
293 * 'mime_find_filters()' - Find the filters to convert from one type to another.
296 static cups_array_t
* /* O - Array of filters to run */
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 */
305 int tempcost
, /* Temporary cost */
306 mincost
; /* Current minimum */
307 cups_array_t
*temp
, /* Temporary filter */
308 *mintemp
; /* Current minimum */
309 mime_filter_t
*current
, /* Current filter */
310 srckey
; /* Source type key */
311 _mime_typelist_t listnode
, /* New list node */
312 *listptr
; /* Pointer in list */
315 DEBUG_printf(("2mime_find_filters(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT
316 ", dst=%p(%s/%s), cost=%p, list=%p)", mime
, src
, src
->super
,
317 src
->type
, CUPS_LLCAST srcsize
, dst
, dst
->super
, dst
->type
,
321 * See if there is a filter that can convert the files directly...
324 if ((current
= mimeFilterLookup(mime
, src
, dst
)) != NULL
&&
325 (current
->maxsize
== 0 || srcsize
<= current
->maxsize
))
328 * Got a direct filter!
331 DEBUG_puts("3mime_find_filters: Direct filter found.");
333 if ((mintemp
= cupsArrayNew(NULL
, NULL
)) == NULL
)
335 DEBUG_puts("3mime_find_filters: Returning NULL (out of memory).");
339 cupsArrayAdd(mintemp
, current
);
341 mincost
= current
->cost
;
345 DEBUG_printf(("3mime_find_filters: Returning 1 filter, cost %d:",
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
));
357 * No direct filter...
365 * Initialize this node in the type list...
368 listnode
.next
= list
;
371 * OK, now look for filters from the source type to any other type...
376 for (current
= (mime_filter_t
*)cupsArrayFind(mime
->srcs
, &srckey
);
377 current
&& current
->src
== src
;
378 current
= (mime_filter_t
*)cupsArrayNext(mime
->srcs
))
381 * See if we have already tried the destination type as a source
382 * type (this avoids extra filter looping...)
385 mime_type_t
*current_dst
; /* Current destination type */
387 if (current
->maxsize
> 0 && srcsize
> current
->maxsize
)
390 for (listptr
= list
, current_dst
= current
->dst
;
392 listptr
= listptr
->next
)
393 if (current_dst
== listptr
->src
)
400 * See if we have any filters that can convert from the destination type
401 * of this filter to the final type...
404 listnode
.src
= current
->src
;
406 cupsArraySave(mime
->srcs
);
407 temp
= mime_find_filters(mime
, current
->dst
, srcsize
, dst
, &tempcost
,
409 cupsArrayRestore(mime
->srcs
);
416 DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:",
417 cupsArrayCount(temp
), tempcost
));
420 for (current
= (mime_filter_t
*)cupsArrayFirst(temp
);
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
));
433 * Found a match; see if this one is less costly than the last (if
437 tempcost
+= current
->cost
;
439 if (tempcost
< mincost
)
441 cupsArrayDelete(mintemp
);
444 * Hey, we got a match! Add the current filter to the beginning of the
450 cupsArrayInsert(mintemp
, current
);
453 cupsArrayDelete(temp
);
459 * Hey, we got a match!
462 DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:",
463 cupsArrayCount(mintemp
), mincost
));
466 for (current
= (mime_filter_t
*)cupsArrayFirst(mintemp
);
468 current
= (mime_filter_t
*)cupsArrayNext(mintemp
))
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
));
481 DEBUG_puts("3mime_find_filters: Returning NULL (no matches).");