]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
7e86f2f6 | 2 | * MIME test program for CUPS. |
ef416fc2 | 3 | * |
7e86f2f6 MS |
4 | * Copyright 2007-2014 by Apple Inc. |
5 | * Copyright 1997-2006 by Easy Software Products, all rights reserved. | |
ef416fc2 | 6 | * |
e3101897 | 7 | * Licensed under Apache License v2.0. See the file "LICENSE" for more information. |
ef416fc2 | 8 | */ |
9 | ||
10 | /* | |
11 | * Include necessary headers... | |
12 | */ | |
13 | ||
71e16022 | 14 | #include <cups/string-private.h> |
4400e98d | 15 | #include <cups/dir.h> |
22c9029b MS |
16 | #include <cups/debug-private.h> |
17 | #include <cups/ppd-private.h> | |
71e16022 | 18 | #include "mime.h" |
ef416fc2 | 19 | |
20 | ||
21 | /* | |
22 | * Local functions... | |
23 | */ | |
24 | ||
22c9029b MS |
25 | static void add_ppd_filter(mime_t *mime, mime_type_t *filtertype, |
26 | const char *filter); | |
27 | static void add_ppd_filters(mime_t *mime, ppd_file_t *ppd); | |
4400e98d | 28 | static void print_rules(mime_magic_t *rules); |
29 | static void type_dir(mime_t *mime, const char *dirname); | |
ef416fc2 | 30 | |
31 | ||
32 | /* | |
33 | * 'main()' - Main entry for the test program. | |
34 | */ | |
35 | ||
36 | int /* O - Exit status */ | |
37 | main(int argc, /* I - Number of command-line args */ | |
38 | char *argv[]) /* I - Command-line arguments */ | |
39 | { | |
fa73b229 | 40 | int i; /* Looping vars */ |
ef416fc2 | 41 | const char *filter_path; /* Filter path */ |
42 | char super[MIME_MAX_SUPER], /* Super-type name */ | |
43 | type[MIME_MAX_TYPE]; /* Type name */ | |
44 | int compression; /* Compression of file */ | |
fa73b229 | 45 | int cost; /* Cost of filters */ |
ef416fc2 | 46 | mime_t *mime; /* MIME database */ |
47 | mime_type_t *src, /* Source type */ | |
fa73b229 | 48 | *dst; /* Destination type */ |
22c9029b MS |
49 | struct stat srcinfo; /* Source information */ |
50 | ppd_file_t *ppd; /* PPD file */ | |
fa73b229 | 51 | cups_array_t *filters; /* Filters for the file */ |
52 | mime_filter_t *filter; /* Current filter */ | |
ef416fc2 | 53 | |
54 | ||
55 | mime = NULL; | |
56 | src = NULL; | |
57 | dst = NULL; | |
22c9029b MS |
58 | ppd = NULL; |
59 | filter_path = "../filter:" CUPS_SERVERBIN "/filter"; | |
60 | ||
61 | srcinfo.st_size = 0; | |
ef416fc2 | 62 | |
63 | for (i = 1; i < argc; i ++) | |
fa73b229 | 64 | if (!strcmp(argv[i], "-d")) |
ef416fc2 | 65 | { |
66 | i ++; | |
67 | ||
68 | if (i < argc) | |
22c9029b | 69 | { |
ef416fc2 | 70 | mime = mimeLoad(argv[i], filter_path); |
22c9029b MS |
71 | |
72 | if (ppd) | |
73 | add_ppd_filters(mime, ppd); | |
74 | } | |
ef416fc2 | 75 | } |
fa73b229 | 76 | else if (!strcmp(argv[i], "-f")) |
ef416fc2 | 77 | { |
78 | i ++; | |
79 | ||
80 | if (i < argc) | |
81 | filter_path = argv[i]; | |
82 | } | |
22c9029b MS |
83 | else if (!strcmp(argv[i], "-p")) |
84 | { | |
85 | i ++; | |
86 | ||
87 | if (i < argc) | |
88 | { | |
89 | ppd = ppdOpenFile(argv[i]); | |
90 | ||
91 | if (mime) | |
92 | add_ppd_filters(mime, ppd); | |
93 | } | |
94 | } | |
fa73b229 | 95 | else if (!src) |
ef416fc2 | 96 | { |
97 | if (!mime) | |
98 | mime = mimeLoad("../conf", filter_path); | |
99 | ||
22c9029b MS |
100 | if (ppd) |
101 | add_ppd_filters(mime, ppd); | |
102 | ||
4400e98d | 103 | src = mimeFileType(mime, argv[i], NULL, &compression); |
22c9029b | 104 | stat(argv[i], &srcinfo); |
ef416fc2 | 105 | |
fa73b229 | 106 | if (src) |
ef416fc2 | 107 | printf("%s: %s/%s%s\n", argv[i], src->super, src->type, |
108 | compression ? " (gzipped)" : ""); | |
f301802f | 109 | else if ((src = mimeType(mime, "application", "octet-stream")) != NULL) |
110 | printf("%s: application/octet-stream\n", argv[i]); | |
ef416fc2 | 111 | else |
112 | { | |
113 | printf("%s: unknown\n", argv[i]); | |
114 | if (mime) | |
115 | mimeDelete(mime); | |
116 | return (1); | |
117 | } | |
118 | } | |
119 | else | |
120 | { | |
c5b24bfa | 121 | sscanf(argv[i], "%15[^/]/%255s", super, type); |
ef416fc2 | 122 | dst = mimeType(mime, super, type); |
123 | ||
7e86f2f6 | 124 | filters = mimeFilter2(mime, src, (size_t)srcinfo.st_size, dst, &cost); |
ef416fc2 | 125 | |
fa73b229 | 126 | if (!filters) |
ef416fc2 | 127 | { |
128 | printf("No filters to convert from %s/%s to %s.\n", src->super, | |
129 | src->type, argv[i]); | |
130 | } | |
131 | else | |
132 | { | |
22c9029b | 133 | int first = 1; /* First filter shown? */ |
ef416fc2 | 134 | |
22c9029b | 135 | printf("Filter cost = %d\n", cost); |
fa73b229 | 136 | |
22c9029b | 137 | for (filter = (mime_filter_t *)cupsArrayFirst(filters); |
fa73b229 | 138 | filter; |
139 | filter = (mime_filter_t *)cupsArrayNext(filters)) | |
22c9029b MS |
140 | { |
141 | if (!strcmp(filter->filter, "-")) | |
142 | continue; | |
143 | ||
144 | if (first) | |
145 | { | |
146 | first = 0; | |
147 | fputs(filter->filter, stdout); | |
148 | } | |
149 | else | |
150 | printf(" | %s", filter->filter); | |
151 | } | |
fa73b229 | 152 | |
153 | putchar('\n'); | |
154 | ||
155 | cupsArrayDelete(filters); | |
ef416fc2 | 156 | } |
157 | } | |
158 | ||
159 | if (!mime) | |
22c9029b | 160 | { |
ef416fc2 | 161 | mime = mimeLoad("../conf", filter_path); |
22c9029b MS |
162 | if (ppd) |
163 | add_ppd_filters(mime, ppd); | |
164 | } | |
ef416fc2 | 165 | |
fa73b229 | 166 | if (!src) |
ef416fc2 | 167 | { |
168 | puts("MIME database types:"); | |
fa73b229 | 169 | for (src = mimeFirstType(mime); src; src = mimeNextType(mime)) |
ef416fc2 | 170 | { |
c168a833 | 171 | printf("\t%s/%s (%d):\n", src->super, src->type, src->priority); |
fa73b229 | 172 | print_rules(src->rules); |
ef416fc2 | 173 | puts(""); |
174 | } | |
175 | ||
176 | puts(""); | |
177 | ||
178 | puts("MIME database filters:"); | |
fa73b229 | 179 | for (filter = mimeFirstFilter(mime); filter; filter = mimeNextFilter(mime)) |
ef416fc2 | 180 | printf("\t%s/%s to %s/%s: %s (%d)\n", |
fa73b229 | 181 | filter->src->super, filter->src->type, |
182 | filter->dst->super, filter->dst->type, | |
183 | filter->filter, filter->cost); | |
4400e98d | 184 | |
f301802f | 185 | type_dir(mime, "../doc"); |
ef416fc2 | 186 | } |
187 | ||
188 | return (0); | |
189 | } | |
190 | ||
191 | ||
22c9029b MS |
192 | /* |
193 | * 'add_printer_filter()' - Add a printer filter from a PPD. | |
194 | */ | |
195 | ||
196 | static void | |
197 | add_ppd_filter(mime_t *mime, /* I - MIME database */ | |
198 | mime_type_t *filtertype, /* I - Filter or prefilter MIME type */ | |
199 | const char *filter) /* I - Filter to add */ | |
200 | { | |
201 | char super[MIME_MAX_SUPER], /* Super-type for filter */ | |
202 | type[MIME_MAX_TYPE], /* Type for filter */ | |
203 | dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */ | |
204 | dtype[MIME_MAX_TYPE], /* Destination type for filter */ | |
205 | dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2], | |
206 | /* Destination super/type */ | |
207 | program[1024]; /* Program/filter name */ | |
208 | int cost; /* Cost of filter */ | |
209 | size_t maxsize = 0; /* Maximum supported file size */ | |
210 | mime_type_t *temptype, /* MIME type looping var */ | |
211 | *desttype; /* Destination MIME type */ | |
212 | mime_filter_t *filterptr; /* MIME filter */ | |
213 | ||
214 | ||
22c9029b MS |
215 | /* |
216 | * Parse the filter string; it should be in one of the following formats: | |
217 | * | |
218 | * source/type cost program | |
219 | * source/type cost maxsize(nnnn) program | |
220 | * source/type dest/type cost program | |
221 | * source/type dest/type cost maxsize(nnnn) program | |
222 | */ | |
223 | ||
224 | if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", | |
225 | super, type, dsuper, dtype, &cost, program) == 6) | |
226 | { | |
227 | snprintf(dest, sizeof(dest), "test/%s/%s", dsuper, dtype); | |
228 | ||
229 | if ((desttype = mimeType(mime, "printer", dest)) == NULL) | |
230 | desttype = mimeAddType(mime, "printer", dest); | |
231 | } | |
232 | else | |
233 | { | |
234 | if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost, | |
235 | program) == 4) | |
236 | { | |
237 | desttype = filtertype; | |
238 | } | |
239 | else | |
240 | { | |
241 | printf("testmime: Invalid filter string \"%s\".\n", filter); | |
242 | return; | |
243 | } | |
244 | } | |
245 | ||
246 | if (!strncmp(program, "maxsize(", 8)) | |
247 | { | |
248 | char *ptr; /* Pointer into maxsize(nnnn) program */ | |
249 | ||
7e86f2f6 | 250 | maxsize = (size_t)strtoll(program + 8, &ptr, 10); |
22c9029b MS |
251 | |
252 | if (*ptr != ')') | |
253 | { | |
254 | printf("testmime: Invalid filter string \"%s\".\n", filter); | |
255 | return; | |
256 | } | |
257 | ||
258 | ptr ++; | |
259 | while (_cups_isspace(*ptr)) | |
260 | ptr ++; | |
261 | ||
262 | _cups_strcpy(program, ptr); | |
263 | } | |
264 | ||
265 | /* | |
266 | * Add the filter to the MIME database, supporting wildcards as needed... | |
267 | */ | |
268 | ||
269 | for (temptype = mimeFirstType(mime); | |
270 | temptype; | |
271 | temptype = mimeNextType(mime)) | |
88f9aafc MS |
272 | if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) || |
273 | !_cups_strcasecmp(temptype->super, super)) && | |
274 | (type[0] == '*' || !_cups_strcasecmp(temptype->type, type))) | |
22c9029b MS |
275 | { |
276 | if (desttype != filtertype) | |
277 | { | |
22c9029b MS |
278 | filterptr = mimeAddFilter(mime, temptype, desttype, cost, program); |
279 | ||
280 | if (!mimeFilterLookup(mime, desttype, filtertype)) | |
771bd8cb | 281 | mimeAddFilter(mime, desttype, filtertype, 0, "-"); |
22c9029b MS |
282 | } |
283 | else | |
22c9029b | 284 | filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program); |
22c9029b MS |
285 | |
286 | if (filterptr) | |
287 | filterptr->maxsize = maxsize; | |
288 | } | |
289 | } | |
290 | ||
291 | ||
292 | /* | |
293 | * 'add_ppd_filters()' - Add all filters from a PPD. | |
294 | */ | |
295 | ||
296 | static void | |
297 | add_ppd_filters(mime_t *mime, /* I - MIME database */ | |
298 | ppd_file_t *ppd) /* I - PPD file */ | |
299 | { | |
300 | _ppd_cache_t *pc; /* Cache data for PPD */ | |
301 | const char *value; /* Filter definition value */ | |
302 | mime_type_t *filter, /* Filter type */ | |
303 | *prefilter; /* Pre-filter type */ | |
304 | ||
305 | ||
306 | pc = _ppdCacheCreateWithPPD(ppd); | |
307 | if (!pc) | |
308 | return; | |
309 | ||
310 | filter = mimeAddType(mime, "printer", "test"); | |
311 | ||
312 | if (pc->filters) | |
313 | { | |
314 | for (value = (const char *)cupsArrayFirst(pc->filters); | |
315 | value; | |
316 | value = (const char *)cupsArrayNext(pc->filters)) | |
317 | add_ppd_filter(mime, filter, value); | |
318 | } | |
319 | else | |
320 | { | |
321 | add_ppd_filter(mime, filter, "application/vnd.cups-raw 0 -"); | |
322 | add_ppd_filter(mime, filter, "application/vnd.cups-postscript 0 -"); | |
323 | } | |
324 | ||
325 | if (pc->prefilters) | |
326 | { | |
327 | prefilter = mimeAddType(mime, "prefilter", "test"); | |
328 | ||
329 | for (value = (const char *)cupsArrayFirst(pc->prefilters); | |
330 | value; | |
331 | value = (const char *)cupsArrayNext(pc->prefilters)) | |
332 | add_ppd_filter(mime, prefilter, value); | |
333 | } | |
334 | } | |
335 | ||
336 | ||
ef416fc2 | 337 | /* |
338 | * 'print_rules()' - Print the rules for a file type... | |
339 | */ | |
340 | ||
341 | static void | |
342 | print_rules(mime_magic_t *rules) /* I - Rules to print */ | |
343 | { | |
344 | int i; /* Looping var */ | |
345 | static char indent[255] = "\t"; /* Indentation for rules */ | |
346 | ||
347 | ||
348 | if (rules == NULL) | |
349 | return; | |
350 | ||
351 | while (rules != NULL) | |
352 | { | |
353 | printf("%s[%p] ", indent, rules); | |
354 | ||
355 | if (rules->invert) | |
356 | printf("NOT "); | |
357 | ||
358 | switch (rules->op) | |
359 | { | |
360 | case MIME_MAGIC_MATCH : | |
361 | printf("match(%s)", rules->value.matchv); | |
362 | break; | |
363 | case MIME_MAGIC_LOCALE : | |
364 | printf("locale(%s)", rules->value.localev); | |
365 | break; | |
366 | case MIME_MAGIC_ASCII : | |
367 | printf("ascii(%d,%d)", rules->offset, rules->length); | |
368 | break; | |
369 | case MIME_MAGIC_PRINTABLE : | |
370 | printf("printable(%d,%d)", rules->offset, rules->length); | |
371 | break; | |
372 | case MIME_MAGIC_STRING : | |
373 | printf("string(%d,", rules->offset); | |
374 | for (i = 0; i < rules->length; i ++) | |
375 | if (rules->value.stringv[i] < ' ' || | |
376 | rules->value.stringv[i] > 126) | |
377 | printf("<%02X>", rules->value.stringv[i]); | |
378 | else | |
379 | putchar(rules->value.stringv[i]); | |
380 | putchar(')'); | |
381 | break; | |
382 | case MIME_MAGIC_CHAR : | |
383 | printf("char(%d,%d)", rules->offset, rules->value.charv); | |
384 | break; | |
385 | case MIME_MAGIC_SHORT : | |
386 | printf("short(%d,%d)", rules->offset, rules->value.shortv); | |
387 | break; | |
388 | case MIME_MAGIC_INT : | |
389 | printf("int(%d,%d)", rules->offset, rules->value.intv); | |
390 | break; | |
391 | case MIME_MAGIC_CONTAINS : | |
392 | printf("contains(%d,%d,", rules->offset, rules->region); | |
393 | for (i = 0; i < rules->length; i ++) | |
394 | if (rules->value.stringv[i] < ' ' || | |
395 | rules->value.stringv[i] > 126) | |
396 | printf("<%02X>", rules->value.stringv[i]); | |
397 | else | |
398 | putchar(rules->value.stringv[i]); | |
399 | putchar(')'); | |
400 | break; | |
401 | default : | |
402 | break; | |
403 | } | |
404 | ||
405 | if (rules->child != NULL) | |
406 | { | |
407 | if (rules->op == MIME_MAGIC_OR) | |
408 | puts("OR ("); | |
409 | else | |
410 | puts("AND ("); | |
411 | ||
412 | strcat(indent, "\t"); | |
413 | print_rules(rules->child); | |
414 | indent[strlen(indent) - 1] = '\0'; | |
415 | printf("%s)\n", indent); | |
416 | } | |
417 | else | |
418 | putchar('\n'); | |
419 | ||
420 | rules = rules->next; | |
421 | } | |
422 | } | |
423 | ||
424 | ||
425 | /* | |
4400e98d | 426 | * 'type_dir()' - Show the MIME types for a given directory. |
427 | */ | |
428 | ||
429 | static void | |
430 | type_dir(mime_t *mime, /* I - MIME database */ | |
431 | const char *dirname) /* I - Directory */ | |
432 | { | |
433 | cups_dir_t *dir; /* Directory */ | |
434 | cups_dentry_t *dent; /* Directory entry */ | |
435 | char filename[1024]; /* File to type */ | |
436 | mime_type_t *filetype; /* File type */ | |
437 | int compression; /* Compressed file? */ | |
438 | mime_type_t *pstype; /* application/vnd.cups-postscript */ | |
439 | cups_array_t *filters; /* Filters to pstype */ | |
440 | mime_filter_t *filter; /* Current filter */ | |
441 | int cost; /* Filter cost */ | |
442 | ||
443 | ||
444 | dir = cupsDirOpen(dirname); | |
445 | if (!dir) | |
446 | return; | |
447 | ||
448 | pstype = mimeType(mime, "application", "vnd.cups-postscript"); | |
449 | ||
450 | while ((dent = cupsDirRead(dir)) != NULL) | |
451 | { | |
f301802f | 452 | if (dent->filename[0] == '.') |
453 | continue; | |
454 | ||
4400e98d | 455 | snprintf(filename, sizeof(filename), "%s/%s", dirname, dent->filename); |
456 | ||
457 | if (S_ISDIR(dent->fileinfo.st_mode)) | |
458 | type_dir(mime, filename); | |
459 | ||
460 | if (!S_ISREG(dent->fileinfo.st_mode)) | |
461 | continue; | |
462 | ||
463 | filetype = mimeFileType(mime, filename, NULL, &compression); | |
464 | ||
465 | if (filetype) | |
466 | { | |
467 | printf("%s: %s/%s%s\n", filename, filetype->super, filetype->type, | |
468 | compression ? " (compressed)" : ""); | |
469 | ||
bd7854cb | 470 | filters = mimeFilter(mime, filetype, pstype, &cost); |
4400e98d | 471 | |
472 | if (!filters) | |
473 | puts(" No filters to convert application/vnd.cups-postscript."); | |
474 | else | |
475 | { | |
476 | printf(" Filter cost = %d\n", cost); | |
477 | ||
478 | filter = (mime_filter_t *)cupsArrayFirst(filters); | |
479 | printf(" %s", filter->filter); | |
480 | ||
481 | for (filter = (mime_filter_t *)cupsArrayNext(filters); | |
482 | filter; | |
483 | filter = (mime_filter_t *)cupsArrayNext(filters)) | |
484 | printf(" | %s", filter->filter); | |
485 | ||
486 | putchar('\n'); | |
487 | ||
488 | cupsArrayDelete(filters); | |
489 | } | |
490 | } | |
491 | else | |
492 | printf("%s: unknown%s\n", filename, compression ? " (compressed)" : ""); | |
493 | } | |
494 | ||
495 | cupsDirClose(dir); | |
496 | } |