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