]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
2 | * "$Id: filter.c 4833 2005-11-12 21:46:52Z mike $" | |
3 | * | |
4 | * File type conversion routines for the Common UNIX Printing System (CUPS). | |
5 | * | |
6 | * Copyright 1997-2005 by Easy Software Products, all rights reserved. | |
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 | * | |
26 | * mimeAddFilter() - Add a filter to the current MIME database. | |
27 | * mimeFilter() - Find the fastest way to convert from one type to another. | |
28 | * compare() - Compare two filter types... | |
29 | * lookup() - Lookup a filter... | |
30 | */ | |
31 | ||
32 | /* | |
33 | * Include necessary headers... | |
34 | */ | |
35 | ||
36 | #include <stdio.h> | |
37 | #include <stdlib.h> | |
38 | #include <ctype.h> | |
39 | ||
40 | #include <cups/debug.h> | |
41 | #include <cups/string.h> | |
42 | #include "mime.h" | |
43 | ||
44 | ||
45 | /* | |
46 | * Local functions... | |
47 | */ | |
48 | ||
49 | static int compare(mime_filter_t *, mime_filter_t *); | |
50 | static mime_filter_t *lookup(mime_t *, mime_type_t *, mime_type_t *); | |
51 | ||
52 | ||
53 | /* | |
54 | * 'mimeAddFilter()' - Add a filter to the current MIME database. | |
55 | */ | |
56 | ||
57 | mime_filter_t * /* O - New filter */ | |
58 | mimeAddFilter(mime_t *mime, /* I - MIME database */ | |
59 | mime_type_t *src, /* I - Source type */ | |
60 | mime_type_t *dst, /* I - Destination type */ | |
61 | int cost, /* I - Relative time/resource cost */ | |
62 | const char *filter) /* I - Filter program to run */ | |
63 | { | |
64 | mime_filter_t *temp; /* New filter */ | |
65 | ||
66 | ||
67 | /* | |
68 | * Range-check the input... | |
69 | */ | |
70 | ||
71 | if (mime == NULL || src == NULL || dst == NULL || filter == NULL) | |
72 | return (NULL); | |
73 | ||
74 | if (strlen(filter) > (MIME_MAX_FILTER - 1)) | |
75 | return (NULL); | |
76 | ||
77 | /* | |
78 | * See if we already have an existing filter for the given source and | |
79 | * destination... | |
80 | */ | |
81 | ||
82 | if ((temp = lookup(mime, src, dst)) != NULL) | |
83 | { | |
84 | /* | |
85 | * Yup, does the existing filter have a higher cost? If so, copy the | |
86 | * filter and cost to the existing filter entry and return it... | |
87 | */ | |
88 | ||
89 | if (temp->cost > cost) | |
90 | { | |
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 | ||
101 | if (mime->num_filters == 0) | |
102 | temp = malloc(sizeof(mime_filter_t)); | |
103 | else | |
104 | temp = realloc(mime->filters, sizeof(mime_filter_t) * (mime->num_filters + 1)); | |
105 | ||
106 | if (temp == NULL) | |
107 | return (NULL); | |
108 | ||
109 | mime->filters = temp; | |
110 | temp += mime->num_filters; | |
111 | mime->num_filters ++; | |
112 | ||
113 | /* | |
114 | * Copy the information over and sort if necessary... | |
115 | */ | |
116 | ||
117 | temp->src = src; | |
118 | temp->dst = dst; | |
119 | temp->cost = cost; | |
120 | strlcpy(temp->filter, filter, sizeof(temp->filter)); | |
121 | ||
122 | if (mime->num_filters > 1) | |
123 | qsort(mime->filters, mime->num_filters, sizeof(mime_filter_t), | |
124 | (int (*)(const void *, const void *))compare); | |
125 | } | |
126 | ||
127 | /* | |
128 | * Return the new/updated filter... | |
129 | */ | |
130 | ||
131 | return (temp); | |
132 | } | |
133 | ||
134 | ||
135 | /* | |
136 | * 'mimeFilter()' - Find the fastest way to convert from one type to another. | |
137 | */ | |
138 | ||
139 | mime_filter_t * /* O - Array of filters to run */ | |
140 | mimeFilter(mime_t *mime, /* I - MIME database */ | |
141 | mime_type_t *src, /* I - Source file type */ | |
142 | mime_type_t *dst, /* I - Destination file type */ | |
143 | int *num_filters, /* O - Number of filters to run */ | |
144 | int max_depth) /* I - Maximum depth of search */ | |
145 | { | |
146 | int i, j, /* Looping vars */ | |
147 | num_temp, /* Number of temporary filters */ | |
148 | num_mintemp, /* Number of filters in the minimum */ | |
149 | cost, /* Current cost */ | |
150 | mincost; /* Current minimum */ | |
151 | mime_filter_t *temp, /* Temporary filter */ | |
152 | *mintemp, /* Current minimum */ | |
153 | *current; /* Current filter */ | |
154 | ||
155 | ||
156 | /* | |
157 | * Range-check the input... | |
158 | */ | |
159 | ||
160 | DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), num_filters=%p(%d))\n", | |
161 | mime, src, src ? src->super : "?", src ? src->type : "?", | |
162 | dst, dst ? dst->super : "?", dst ? dst->type : "?", | |
163 | num_filters, num_filters ? *num_filters : 0)); | |
164 | ||
165 | if (mime == NULL || src == NULL || dst == NULL || num_filters == NULL || | |
166 | max_depth <= 0) | |
167 | return (NULL); | |
168 | ||
169 | *num_filters = 0; | |
170 | ||
171 | /* | |
172 | * See if there is a filter that can convert the files directly... | |
173 | */ | |
174 | ||
175 | if ((temp = lookup(mime, src, dst)) != NULL) | |
176 | { | |
177 | /* | |
178 | * Got a direct filter! | |
179 | */ | |
180 | ||
181 | if ((mintemp = (mime_filter_t *)malloc(sizeof(mime_filter_t))) == NULL) | |
182 | return (NULL); | |
183 | ||
184 | memcpy(mintemp, temp, sizeof(mime_filter_t)); | |
185 | num_mintemp = 1; | |
186 | mincost = mintemp->cost; | |
187 | ||
188 | DEBUG_puts(" Found direct filter:"); | |
189 | DEBUG_printf((" %s (cost=%d)\n", mintemp->filter, mincost)); | |
190 | } | |
191 | else | |
192 | { | |
193 | /* | |
194 | * No direct filter... | |
195 | */ | |
196 | ||
197 | mincost = 9999999; | |
198 | mintemp = NULL; | |
199 | num_mintemp = 0; | |
200 | } | |
201 | ||
202 | /* | |
203 | * OK, now look for filters from the source type to any other type... | |
204 | */ | |
205 | ||
206 | for (i = mime->num_filters, current = mime->filters; | |
207 | i > 0; | |
208 | i --, current ++) | |
209 | if (current->src == src) | |
210 | { | |
211 | /* | |
212 | * See if we have any filters that can convert from the destination type | |
213 | * of this filter to the final type... | |
214 | */ | |
215 | ||
216 | if ((temp = mimeFilter(mime, current->dst, dst, &num_temp, | |
217 | max_depth - 1)) == NULL) | |
218 | continue; | |
219 | ||
220 | /* | |
221 | * Found a match; see if this one is less costly than the last (if | |
222 | * any...) | |
223 | */ | |
224 | ||
225 | for (j = 0, cost = current->cost; j < num_temp; j ++) | |
226 | cost += temp[j].cost; | |
227 | ||
228 | if (cost < mincost) | |
229 | { | |
230 | if (mintemp != NULL) | |
231 | free(mintemp); | |
232 | ||
233 | /* | |
234 | * Hey, we got a match! Add the current filter to the beginning of the | |
235 | * filter list... | |
236 | */ | |
237 | ||
238 | mintemp = (mime_filter_t *)realloc(temp, sizeof(mime_filter_t) * | |
239 | (num_temp + 1)); | |
240 | ||
241 | if (mintemp == NULL) | |
242 | { | |
243 | *num_filters = 0; | |
244 | return (NULL); | |
245 | } | |
246 | ||
247 | memmove(mintemp + 1, mintemp, num_temp * sizeof(mime_filter_t)); | |
248 | memcpy(mintemp, current, sizeof(mime_filter_t)); | |
249 | ||
250 | num_mintemp = num_temp + 1; | |
251 | mincost = cost; | |
252 | } | |
253 | else | |
254 | free(temp); | |
255 | } | |
256 | ||
257 | if (mintemp != NULL) | |
258 | { | |
259 | /* | |
260 | * Hey, we got a match! | |
261 | */ | |
262 | ||
263 | *num_filters = num_mintemp; | |
264 | ||
265 | #ifdef DEBUG | |
266 | printf(" Returning %d filters:\n", *num_filters); | |
267 | for (i = 0; i < num_mintemp; i ++) | |
268 | printf(" %s\n", mintemp[i].filter); | |
269 | #endif /* DEBUG */ | |
270 | ||
271 | return (mintemp); | |
272 | } | |
273 | ||
274 | DEBUG_puts(" Returning zippo..."); | |
275 | ||
276 | return (NULL); | |
277 | } | |
278 | ||
279 | ||
280 | /* | |
281 | * 'compare()' - Compare two filter types... | |
282 | */ | |
283 | ||
284 | static int /* O - Comparison result */ | |
285 | compare(mime_filter_t *f0, /* I - First filter */ | |
286 | mime_filter_t *f1) /* I - Second filter */ | |
287 | { | |
288 | int i; /* Result of comparison */ | |
289 | ||
290 | ||
291 | if ((i = strcmp(f0->src->super, f1->src->super)) == 0) | |
292 | if ((i = strcmp(f0->src->type, f1->src->type)) == 0) | |
293 | if ((i = strcmp(f0->dst->super, f1->dst->super)) == 0) | |
294 | i = strcmp(f0->dst->type, f1->dst->type); | |
295 | ||
296 | return (i); | |
297 | } | |
298 | ||
299 | ||
300 | /* | |
301 | * 'lookup()' - Lookup a filter... | |
302 | */ | |
303 | ||
304 | static mime_filter_t * /* O - Filter for src->dst */ | |
305 | lookup(mime_t *mime, /* I - MIME database */ | |
306 | mime_type_t *src, /* I - Source type */ | |
307 | mime_type_t *dst) /* I - Destination type */ | |
308 | { | |
309 | mime_filter_t key; /* Key record for filter search */ | |
310 | ||
311 | ||
312 | if (mime->num_filters == 0) | |
313 | return (NULL); | |
314 | ||
315 | key.src = src; | |
316 | key.dst = dst; | |
317 | ||
318 | return ((mime_filter_t *)bsearch(&key, mime->filters, mime->num_filters, | |
319 | sizeof(mime_filter_t), | |
320 | (int (*)(const void *, const void *))compare)); | |
321 | } | |
322 | ||
323 | ||
324 | /* | |
325 | * End of "$Id: filter.c 4833 2005-11-12 21:46:52Z mike $". | |
326 | */ |