]>
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 | ||
215 | DEBUG_printf(("add_ppd_filter(mime=%p, filtertype=%p(%s/%s), filter=\"%s\")", | |
216 | mime, filtertype, filtertype->super, filtertype->type, filter)); | |
217 | ||
218 | /* | |
219 | * Parse the filter string; it should be in one of the following formats: | |
220 | * | |
221 | * source/type cost program | |
222 | * source/type cost maxsize(nnnn) program | |
223 | * source/type dest/type cost program | |
224 | * source/type dest/type cost maxsize(nnnn) program | |
225 | */ | |
226 | ||
227 | if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", | |
228 | super, type, dsuper, dtype, &cost, program) == 6) | |
229 | { | |
230 | snprintf(dest, sizeof(dest), "test/%s/%s", dsuper, dtype); | |
231 | ||
232 | if ((desttype = mimeType(mime, "printer", dest)) == NULL) | |
233 | desttype = mimeAddType(mime, "printer", dest); | |
234 | } | |
235 | else | |
236 | { | |
237 | if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost, | |
238 | program) == 4) | |
239 | { | |
240 | desttype = filtertype; | |
241 | } | |
242 | else | |
243 | { | |
244 | printf("testmime: Invalid filter string \"%s\".\n", filter); | |
245 | return; | |
246 | } | |
247 | } | |
248 | ||
249 | if (!strncmp(program, "maxsize(", 8)) | |
250 | { | |
251 | char *ptr; /* Pointer into maxsize(nnnn) program */ | |
252 | ||
7e86f2f6 | 253 | maxsize = (size_t)strtoll(program + 8, &ptr, 10); |
22c9029b MS |
254 | |
255 | if (*ptr != ')') | |
256 | { | |
257 | printf("testmime: Invalid filter string \"%s\".\n", filter); | |
258 | return; | |
259 | } | |
260 | ||
261 | ptr ++; | |
262 | while (_cups_isspace(*ptr)) | |
263 | ptr ++; | |
264 | ||
265 | _cups_strcpy(program, ptr); | |
266 | } | |
267 | ||
268 | /* | |
269 | * Add the filter to the MIME database, supporting wildcards as needed... | |
270 | */ | |
271 | ||
272 | for (temptype = mimeFirstType(mime); | |
273 | temptype; | |
274 | temptype = mimeNextType(mime)) | |
88f9aafc MS |
275 | if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) || |
276 | !_cups_strcasecmp(temptype->super, super)) && | |
277 | (type[0] == '*' || !_cups_strcasecmp(temptype->type, type))) | |
22c9029b MS |
278 | { |
279 | if (desttype != filtertype) | |
280 | { | |
281 | DEBUG_printf(("add_ppd_filter: Adding filter %s/%s %s/%s %d %s", | |
282 | temptype->super, temptype->type, desttype->super, | |
283 | desttype->type, cost, program)); | |
284 | filterptr = mimeAddFilter(mime, temptype, desttype, cost, program); | |
285 | ||
286 | if (!mimeFilterLookup(mime, desttype, filtertype)) | |
287 | { | |
288 | DEBUG_printf(("add_printer_filter: Adding filter %s/%s %s/%s 0 -", | |
289 | desttype->super, desttype->type, filtertype->super, | |
290 | filtertype->type)); | |
771bd8cb | 291 | mimeAddFilter(mime, desttype, filtertype, 0, "-"); |
22c9029b MS |
292 | } |
293 | } | |
294 | else | |
295 | { | |
296 | DEBUG_printf(("add_printer_filter: Adding filter %s/%s %s/%s %d %s", | |
297 | temptype->super, temptype->type, filtertype->super, | |
298 | filtertype->type, cost, program)); | |
299 | filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program); | |
300 | } | |
301 | ||
302 | if (filterptr) | |
303 | filterptr->maxsize = maxsize; | |
304 | } | |
305 | } | |
306 | ||
307 | ||
308 | /* | |
309 | * 'add_ppd_filters()' - Add all filters from a PPD. | |
310 | */ | |
311 | ||
312 | static void | |
313 | add_ppd_filters(mime_t *mime, /* I - MIME database */ | |
314 | ppd_file_t *ppd) /* I - PPD file */ | |
315 | { | |
316 | _ppd_cache_t *pc; /* Cache data for PPD */ | |
317 | const char *value; /* Filter definition value */ | |
318 | mime_type_t *filter, /* Filter type */ | |
319 | *prefilter; /* Pre-filter type */ | |
320 | ||
321 | ||
322 | pc = _ppdCacheCreateWithPPD(ppd); | |
323 | if (!pc) | |
324 | return; | |
325 | ||
326 | filter = mimeAddType(mime, "printer", "test"); | |
327 | ||
328 | if (pc->filters) | |
329 | { | |
330 | for (value = (const char *)cupsArrayFirst(pc->filters); | |
331 | value; | |
332 | value = (const char *)cupsArrayNext(pc->filters)) | |
333 | add_ppd_filter(mime, filter, value); | |
334 | } | |
335 | else | |
336 | { | |
337 | add_ppd_filter(mime, filter, "application/vnd.cups-raw 0 -"); | |
338 | add_ppd_filter(mime, filter, "application/vnd.cups-postscript 0 -"); | |
339 | } | |
340 | ||
341 | if (pc->prefilters) | |
342 | { | |
343 | prefilter = mimeAddType(mime, "prefilter", "test"); | |
344 | ||
345 | for (value = (const char *)cupsArrayFirst(pc->prefilters); | |
346 | value; | |
347 | value = (const char *)cupsArrayNext(pc->prefilters)) | |
348 | add_ppd_filter(mime, prefilter, value); | |
349 | } | |
350 | } | |
351 | ||
352 | ||
ef416fc2 | 353 | /* |
354 | * 'print_rules()' - Print the rules for a file type... | |
355 | */ | |
356 | ||
357 | static void | |
358 | print_rules(mime_magic_t *rules) /* I - Rules to print */ | |
359 | { | |
360 | int i; /* Looping var */ | |
361 | static char indent[255] = "\t"; /* Indentation for rules */ | |
362 | ||
363 | ||
364 | if (rules == NULL) | |
365 | return; | |
366 | ||
367 | while (rules != NULL) | |
368 | { | |
369 | printf("%s[%p] ", indent, rules); | |
370 | ||
371 | if (rules->invert) | |
372 | printf("NOT "); | |
373 | ||
374 | switch (rules->op) | |
375 | { | |
376 | case MIME_MAGIC_MATCH : | |
377 | printf("match(%s)", rules->value.matchv); | |
378 | break; | |
379 | case MIME_MAGIC_LOCALE : | |
380 | printf("locale(%s)", rules->value.localev); | |
381 | break; | |
382 | case MIME_MAGIC_ASCII : | |
383 | printf("ascii(%d,%d)", rules->offset, rules->length); | |
384 | break; | |
385 | case MIME_MAGIC_PRINTABLE : | |
386 | printf("printable(%d,%d)", rules->offset, rules->length); | |
387 | break; | |
388 | case MIME_MAGIC_STRING : | |
389 | printf("string(%d,", rules->offset); | |
390 | for (i = 0; i < rules->length; i ++) | |
391 | if (rules->value.stringv[i] < ' ' || | |
392 | rules->value.stringv[i] > 126) | |
393 | printf("<%02X>", rules->value.stringv[i]); | |
394 | else | |
395 | putchar(rules->value.stringv[i]); | |
396 | putchar(')'); | |
397 | break; | |
398 | case MIME_MAGIC_CHAR : | |
399 | printf("char(%d,%d)", rules->offset, rules->value.charv); | |
400 | break; | |
401 | case MIME_MAGIC_SHORT : | |
402 | printf("short(%d,%d)", rules->offset, rules->value.shortv); | |
403 | break; | |
404 | case MIME_MAGIC_INT : | |
405 | printf("int(%d,%d)", rules->offset, rules->value.intv); | |
406 | break; | |
407 | case MIME_MAGIC_CONTAINS : | |
408 | printf("contains(%d,%d,", rules->offset, rules->region); | |
409 | for (i = 0; i < rules->length; i ++) | |
410 | if (rules->value.stringv[i] < ' ' || | |
411 | rules->value.stringv[i] > 126) | |
412 | printf("<%02X>", rules->value.stringv[i]); | |
413 | else | |
414 | putchar(rules->value.stringv[i]); | |
415 | putchar(')'); | |
416 | break; | |
417 | default : | |
418 | break; | |
419 | } | |
420 | ||
421 | if (rules->child != NULL) | |
422 | { | |
423 | if (rules->op == MIME_MAGIC_OR) | |
424 | puts("OR ("); | |
425 | else | |
426 | puts("AND ("); | |
427 | ||
428 | strcat(indent, "\t"); | |
429 | print_rules(rules->child); | |
430 | indent[strlen(indent) - 1] = '\0'; | |
431 | printf("%s)\n", indent); | |
432 | } | |
433 | else | |
434 | putchar('\n'); | |
435 | ||
436 | rules = rules->next; | |
437 | } | |
438 | } | |
439 | ||
440 | ||
441 | /* | |
4400e98d | 442 | * 'type_dir()' - Show the MIME types for a given directory. |
443 | */ | |
444 | ||
445 | static void | |
446 | type_dir(mime_t *mime, /* I - MIME database */ | |
447 | const char *dirname) /* I - Directory */ | |
448 | { | |
449 | cups_dir_t *dir; /* Directory */ | |
450 | cups_dentry_t *dent; /* Directory entry */ | |
451 | char filename[1024]; /* File to type */ | |
452 | mime_type_t *filetype; /* File type */ | |
453 | int compression; /* Compressed file? */ | |
454 | mime_type_t *pstype; /* application/vnd.cups-postscript */ | |
455 | cups_array_t *filters; /* Filters to pstype */ | |
456 | mime_filter_t *filter; /* Current filter */ | |
457 | int cost; /* Filter cost */ | |
458 | ||
459 | ||
460 | dir = cupsDirOpen(dirname); | |
461 | if (!dir) | |
462 | return; | |
463 | ||
464 | pstype = mimeType(mime, "application", "vnd.cups-postscript"); | |
465 | ||
466 | while ((dent = cupsDirRead(dir)) != NULL) | |
467 | { | |
f301802f | 468 | if (dent->filename[0] == '.') |
469 | continue; | |
470 | ||
4400e98d | 471 | snprintf(filename, sizeof(filename), "%s/%s", dirname, dent->filename); |
472 | ||
473 | if (S_ISDIR(dent->fileinfo.st_mode)) | |
474 | type_dir(mime, filename); | |
475 | ||
476 | if (!S_ISREG(dent->fileinfo.st_mode)) | |
477 | continue; | |
478 | ||
479 | filetype = mimeFileType(mime, filename, NULL, &compression); | |
480 | ||
481 | if (filetype) | |
482 | { | |
483 | printf("%s: %s/%s%s\n", filename, filetype->super, filetype->type, | |
484 | compression ? " (compressed)" : ""); | |
485 | ||
bd7854cb | 486 | filters = mimeFilter(mime, filetype, pstype, &cost); |
4400e98d | 487 | |
488 | if (!filters) | |
489 | puts(" No filters to convert application/vnd.cups-postscript."); | |
490 | else | |
491 | { | |
492 | printf(" Filter cost = %d\n", cost); | |
493 | ||
494 | filter = (mime_filter_t *)cupsArrayFirst(filters); | |
495 | printf(" %s", filter->filter); | |
496 | ||
497 | for (filter = (mime_filter_t *)cupsArrayNext(filters); | |
498 | filter; | |
499 | filter = (mime_filter_t *)cupsArrayNext(filters)) | |
500 | printf(" | %s", filter->filter); | |
501 | ||
502 | putchar('\n'); | |
503 | ||
504 | cupsArrayDelete(filters); | |
505 | } | |
506 | } | |
507 | else | |
508 | printf("%s: unknown%s\n", filename, compression ? " (compressed)" : ""); | |
509 | } | |
510 | ||
511 | cupsDirClose(dir); | |
512 | } |