]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
b423cd4c | 2 | * "$Id: filter.c 5196 2006-02-27 21:23:00Z mike $" |
ef416fc2 | 3 | * |
4 | * File type conversion routines for the Common UNIX Printing System (CUPS). | |
5 | * | |
fa73b229 | 6 | * Copyright 1997-2006 by Easy Software Products, all rights reserved. |
ef416fc2 | 7 | * |
8 | * These coded instructions, statements, and computer programs are the | |
9 | * property of Easy Software Products and are protected by Federal | |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE.txt" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
14 | * | |
15 | * Attn: CUPS Licensing Information | |
16 | * Easy Software Products | |
17 | * 44141 Airport View Drive, Suite 204 | |
18 | * Hollywood, Maryland 20636 USA | |
19 | * | |
20 | * Voice: (301) 373-9600 | |
21 | * EMail: cups-info@cups.org | |
22 | * WWW: http://www.cups.org | |
23 | * | |
24 | * Contents: | |
25 | * | |
fa73b229 | 26 | * mimeAddFilter() - Add a filter to the current MIME database. |
bd7854cb | 27 | * mimeFilter() - Find the fastest way to convert from one type to |
28 | * another. | |
fa73b229 | 29 | * compare_filters() - Compare two filters... |
bd7854cb | 30 | * find_filters() - Find the filters to convert from one type to another. |
fa73b229 | 31 | * lookup() - Lookup a filter... |
ef416fc2 | 32 | */ |
33 | ||
34 | /* | |
35 | * Include necessary headers... | |
36 | */ | |
37 | ||
38 | #include <stdio.h> | |
39 | #include <stdlib.h> | |
40 | #include <ctype.h> | |
41 | ||
42 | #include <cups/debug.h> | |
43 | #include <cups/string.h> | |
44 | #include "mime.h" | |
45 | ||
46 | ||
bd7854cb | 47 | /* |
48 | * Local types... | |
49 | */ | |
50 | ||
51 | typedef struct _mime_typelist_s /**** List of source types ****/ | |
52 | { | |
53 | struct _mime_typelist_s *next; /* Next source type */ | |
54 | mime_type_t *src; /* Source type */ | |
55 | } _mime_typelist_t; | |
56 | ||
57 | ||
ef416fc2 | 58 | /* |
59 | * Local functions... | |
60 | */ | |
61 | ||
fa73b229 | 62 | static int compare_filters(mime_filter_t *, mime_filter_t *); |
bd7854cb | 63 | static cups_array_t *find_filters(mime_t *mime, mime_type_t *src, |
64 | mime_type_t *dst, int *cost, | |
65 | _mime_typelist_t *visited); | |
ef416fc2 | 66 | static mime_filter_t *lookup(mime_t *, mime_type_t *, mime_type_t *); |
67 | ||
68 | ||
69 | /* | |
70 | * 'mimeAddFilter()' - Add a filter to the current MIME database. | |
71 | */ | |
72 | ||
73 | mime_filter_t * /* O - New filter */ | |
74 | mimeAddFilter(mime_t *mime, /* I - MIME database */ | |
75 | mime_type_t *src, /* I - Source type */ | |
76 | mime_type_t *dst, /* I - Destination type */ | |
77 | int cost, /* I - Relative time/resource cost */ | |
78 | const char *filter) /* I - Filter program to run */ | |
79 | { | |
80 | mime_filter_t *temp; /* New filter */ | |
81 | ||
82 | ||
83 | /* | |
84 | * Range-check the input... | |
85 | */ | |
86 | ||
fa73b229 | 87 | if (!mime || !src || !dst || !filter) |
ef416fc2 | 88 | return (NULL); |
89 | ||
90 | /* | |
91 | * See if we already have an existing filter for the given source and | |
92 | * destination... | |
93 | */ | |
94 | ||
95 | if ((temp = lookup(mime, src, dst)) != NULL) | |
96 | { | |
97 | /* | |
98 | * Yup, does the existing filter have a higher cost? If so, copy the | |
99 | * filter and cost to the existing filter entry and return it... | |
100 | */ | |
101 | ||
102 | if (temp->cost > cost) | |
103 | { | |
104 | temp->cost = cost; | |
105 | strlcpy(temp->filter, filter, sizeof(temp->filter)); | |
106 | } | |
107 | } | |
108 | else | |
109 | { | |
110 | /* | |
111 | * Nope, add a new one... | |
112 | */ | |
113 | ||
fa73b229 | 114 | if (!mime->filters) |
115 | mime->filters = cupsArrayNew((cups_array_func_t)compare_filters, NULL); | |
ef416fc2 | 116 | |
fa73b229 | 117 | if (!mime->filters) |
ef416fc2 | 118 | return (NULL); |
119 | ||
fa73b229 | 120 | if ((temp = calloc(1, sizeof(mime_filter_t))) == NULL) |
121 | return (NULL); | |
ef416fc2 | 122 | |
123 | /* | |
124 | * Copy the information over and sort if necessary... | |
125 | */ | |
126 | ||
127 | temp->src = src; | |
128 | temp->dst = dst; | |
129 | temp->cost = cost; | |
130 | strlcpy(temp->filter, filter, sizeof(temp->filter)); | |
131 | ||
fa73b229 | 132 | cupsArrayAdd(mime->filters, temp); |
ef416fc2 | 133 | } |
134 | ||
135 | /* | |
136 | * Return the new/updated filter... | |
137 | */ | |
138 | ||
139 | return (temp); | |
140 | } | |
141 | ||
142 | ||
143 | /* | |
144 | * 'mimeFilter()' - Find the fastest way to convert from one type to another. | |
145 | */ | |
146 | ||
fa73b229 | 147 | cups_array_t * /* O - Array of filters to run */ |
ef416fc2 | 148 | mimeFilter(mime_t *mime, /* I - MIME database */ |
149 | mime_type_t *src, /* I - Source file type */ | |
150 | mime_type_t *dst, /* I - Destination file type */ | |
bd7854cb | 151 | int *cost) /* O - Cost of filters */ |
ef416fc2 | 152 | { |
ef416fc2 | 153 | /* |
154 | * Range-check the input... | |
155 | */ | |
156 | ||
fa73b229 | 157 | DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), " |
bd7854cb | 158 | "cost=%p(%d))\n", |
ef416fc2 | 159 | mime, src, src ? src->super : "?", src ? src->type : "?", |
160 | dst, dst ? dst->super : "?", dst ? dst->type : "?", | |
bd7854cb | 161 | cost, cost ? *cost : 0)); |
162 | ||
ef416fc2 | 163 | |
fa73b229 | 164 | if (cost) |
165 | *cost = 0; | |
ef416fc2 | 166 | |
bd7854cb | 167 | if (!mime || !src || !dst) |
fa73b229 | 168 | return (NULL); |
ef416fc2 | 169 | |
bd7854cb | 170 | /* |
171 | * Find the filters... | |
172 | */ | |
173 | ||
174 | return (find_filters(mime, src, dst, cost, NULL)); | |
175 | } | |
176 | ||
177 | ||
178 | /* | |
179 | * 'compare_filters()' - Compare two filters... | |
180 | */ | |
181 | ||
182 | static int /* O - Comparison result */ | |
183 | compare_filters(mime_filter_t *f0, /* I - First filter */ | |
184 | mime_filter_t *f1) /* I - Second filter */ | |
185 | { | |
186 | int i; /* Result of comparison */ | |
187 | ||
188 | ||
189 | if ((i = strcmp(f0->src->super, f1->src->super)) == 0) | |
190 | if ((i = strcmp(f0->src->type, f1->src->type)) == 0) | |
191 | if ((i = strcmp(f0->dst->super, f1->dst->super)) == 0) | |
192 | i = strcmp(f0->dst->type, f1->dst->type); | |
193 | ||
194 | return (i); | |
195 | } | |
196 | ||
197 | ||
198 | /* | |
199 | * 'find_filters()' - Find the filters to convert from one type to another. | |
200 | */ | |
201 | ||
b423cd4c | 202 | static cups_array_t * /* O - Array of filters to run */ |
bd7854cb | 203 | find_filters(mime_t *mime, /* I - MIME database */ |
204 | mime_type_t *src, /* I - Source file type */ | |
205 | mime_type_t *dst, /* I - Destination file type */ | |
206 | int *cost, /* O - Cost of filters */ | |
207 | _mime_typelist_t *list) /* I - Source types we've used */ | |
208 | { | |
209 | int tempcost, /* Temporary cost */ | |
210 | mincost; /* Current minimum */ | |
211 | cups_array_t *temp, /* Temporary filter */ | |
212 | *mintemp; /* Current minimum */ | |
213 | mime_filter_t *current; /* Current filter */ | |
214 | _mime_typelist_t listnode, /* New list node */ | |
215 | *listptr; /* Pointer in list */ | |
216 | ||
217 | ||
218 | DEBUG_printf(("find_filters(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), " | |
219 | "cost=%p, list=%p)\n", mime, src, src->super, src->type, | |
220 | dst, dst->super, dst->type, cost, list)); | |
221 | ||
ef416fc2 | 222 | /* |
223 | * See if there is a filter that can convert the files directly... | |
224 | */ | |
225 | ||
fa73b229 | 226 | if ((current = lookup(mime, src, dst)) != NULL) |
ef416fc2 | 227 | { |
228 | /* | |
229 | * Got a direct filter! | |
230 | */ | |
231 | ||
bd7854cb | 232 | DEBUG_puts("Direct filter found!"); |
233 | ||
fa73b229 | 234 | if ((mintemp = cupsArrayNew(NULL, NULL)) == NULL) |
ef416fc2 | 235 | return (NULL); |
236 | ||
fa73b229 | 237 | cupsArrayAdd(mintemp, current); |
238 | ||
239 | mincost = current->cost; | |
ef416fc2 | 240 | |
241 | DEBUG_puts(" Found direct filter:"); | |
bd7854cb | 242 | DEBUG_printf((" %s (cost=%d)\n", current->filter, mincost)); |
ef416fc2 | 243 | } |
244 | else | |
245 | { | |
246 | /* | |
247 | * No direct filter... | |
248 | */ | |
249 | ||
fa73b229 | 250 | mintemp = NULL; |
251 | mincost = 9999999; | |
ef416fc2 | 252 | } |
253 | ||
bd7854cb | 254 | /* |
255 | * Initialize this node in the type list... | |
256 | */ | |
257 | ||
258 | listnode.next = list; | |
259 | ||
ef416fc2 | 260 | /* |
261 | * OK, now look for filters from the source type to any other type... | |
262 | */ | |
263 | ||
fa73b229 | 264 | for (current = (mime_filter_t *)cupsArrayFirst(mime->filters); |
265 | current; | |
266 | current = (mime_filter_t *)cupsArrayNext(mime->filters)) | |
ef416fc2 | 267 | if (current->src == src) |
268 | { | |
bd7854cb | 269 | /* |
270 | * See if we have already tried the destination type as a source | |
271 | * type (this avoids extra filter looping...) | |
272 | */ | |
273 | ||
274 | for (listptr = list; listptr; listptr = listptr->next) | |
275 | if (current->dst == listptr->src) | |
276 | break; | |
277 | ||
278 | if (listptr) | |
279 | continue; | |
280 | ||
ef416fc2 | 281 | /* |
282 | * See if we have any filters that can convert from the destination type | |
283 | * of this filter to the final type... | |
284 | */ | |
285 | ||
bd7854cb | 286 | listnode.src = current->src; |
287 | ||
fa73b229 | 288 | cupsArraySave(mime->filters); |
bd7854cb | 289 | temp = find_filters(mime, current->dst, dst, &tempcost, &listnode); |
fa73b229 | 290 | cupsArrayRestore(mime->filters); |
291 | ||
292 | if (!temp) | |
ef416fc2 | 293 | continue; |
294 | ||
295 | /* | |
296 | * Found a match; see if this one is less costly than the last (if | |
297 | * any...) | |
298 | */ | |
299 | ||
fa73b229 | 300 | if (tempcost < mincost) |
ef416fc2 | 301 | { |
fa73b229 | 302 | cupsArrayDelete(mintemp); |
ef416fc2 | 303 | |
304 | /* | |
305 | * Hey, we got a match! Add the current filter to the beginning of the | |
306 | * filter list... | |
307 | */ | |
308 | ||
fa73b229 | 309 | mintemp = temp; |
310 | mincost = tempcost + current->cost; | |
311 | cupsArrayInsert(mintemp, current); | |
ef416fc2 | 312 | } |
313 | else | |
fa73b229 | 314 | cupsArrayDelete(temp); |
ef416fc2 | 315 | } |
316 | ||
fa73b229 | 317 | if (mintemp) |
ef416fc2 | 318 | { |
319 | /* | |
320 | * Hey, we got a match! | |
321 | */ | |
322 | ||
ef416fc2 | 323 | #ifdef DEBUG |
fa73b229 | 324 | printf(" Returning %d filters:\n", cupsArrayCount(mintemp)); |
325 | for (current = (mime_filter_t *)cupsArrayFirst(mintemp); | |
326 | current; | |
327 | current = (mime_filter_t *)cupsArrayNext(mintemp)) | |
328 | printf(" %s\n", current->filter); | |
ef416fc2 | 329 | #endif /* DEBUG */ |
330 | ||
bd7854cb | 331 | if (cost) |
332 | *cost = mincost; | |
fa73b229 | 333 | |
ef416fc2 | 334 | return (mintemp); |
335 | } | |
336 | ||
337 | DEBUG_puts(" Returning zippo..."); | |
338 | ||
339 | return (NULL); | |
340 | } | |
341 | ||
342 | ||
ef416fc2 | 343 | /* |
344 | * 'lookup()' - Lookup a filter... | |
345 | */ | |
346 | ||
fa73b229 | 347 | static mime_filter_t * /* O - Filter for src->dst */ |
348 | lookup(mime_t *mime, /* I - MIME database */ | |
349 | mime_type_t *src, /* I - Source type */ | |
350 | mime_type_t *dst) /* I - Destination type */ | |
ef416fc2 | 351 | { |
fa73b229 | 352 | mime_filter_t key; /* Key record for filter search */ |
ef416fc2 | 353 | |
354 | ||
ef416fc2 | 355 | key.src = src; |
356 | key.dst = dst; | |
357 | ||
fa73b229 | 358 | return ((mime_filter_t *)cupsArrayFind(mime->filters, &key)); |
ef416fc2 | 359 | } |
360 | ||
361 | ||
362 | /* | |
b423cd4c | 363 | * End of "$Id: filter.c 5196 2006-02-27 21:23:00Z mike $". |
ef416fc2 | 364 | */ |