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