1 /*
2 * MIME test program for CUPS.
3 *
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
8 */
9
10 /*
11 * Include necessary headers...
12 */
13
14 #include <cups/string-private.h>
15 #include <cups/dir.h>
16 #include <cups/debug-private.h>
17 #include <cups/ppd-private.h>
18 #include "mime.h"
19
20
21 /*
22 * Local functions...
23 */
24
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);
28 static void print_rules(mime_magic_t *rules);
29 static void type_dir(mime_t *mime, const char *dirname);
30
31
32 /*
33 * 'main()' - Main entry for the test program.
34 */
35
36 int /* O - Exit status */
main(int argc,char * argv[])37 main(int argc, /* I - Number of command-line args */
38 char *argv[]) /* I - Command-line arguments */
39 {
40 int i; /* Looping vars */
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 */
45 int cost; /* Cost of filters */
46 mime_t *mime; /* MIME database */
47 mime_type_t *src, /* Source type */
48 *dst; /* Destination type */
49 struct stat srcinfo; /* Source information */
50 ppd_file_t *ppd; /* PPD file */
51 cups_array_t *filters; /* Filters for the file */
52 mime_filter_t *filter; /* Current filter */
53
54
55 mime = NULL;
56 src = NULL;
57 dst = NULL;
58 ppd = NULL;
59 filter_path = "../filter:" CUPS_SERVERBIN "/filter";
60
61 srcinfo.st_size = 0;
62
63 for (i = 1; i < argc; i ++)
64 if (!strcmp(argv[i], "-d"))
65 {
66 i ++;
67
68 if (i < argc)
69 {
70 mime = mimeLoad(argv[i], filter_path);
71
72 if (ppd)
73 add_ppd_filters(mime, ppd);
74 }
75 }
76 else if (!strcmp(argv[i], "-f"))
77 {
78 i ++;
79
80 if (i < argc)
81 filter_path = argv[i];
82 }
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 }
95 else if (!src)
96 {
97 if (!mime)
98 mime = mimeLoad("../conf", filter_path);
99
100 if (ppd)
101 add_ppd_filters(mime, ppd);
102
103 src = mimeFileType(mime, argv[i], NULL, &compression);
104 stat(argv[i], &srcinfo);
105
106 if (src)
107 printf("%s: %s/%s%s\n", argv[i], src->super, src->type,
108 compression ? " (gzipped)" : "");
109 else if ((src = mimeType(mime, "application", "octet-stream")) != NULL)
110 printf("%s: application/octet-stream\n", argv[i]);
111 else
112 {
113 printf("%s: unknown\n", argv[i]);
114 if (mime)
115 mimeDelete(mime);
116 return (1);
117 }
118 }
119 else
120 {
121 sscanf(argv[i], "%15[^/]/%255s", super, type);
122 dst = mimeType(mime, super, type);
123
124 filters = mimeFilter2(mime, src, (size_t)srcinfo.st_size, dst, &cost);
125
126 if (!filters)
127 {
128 printf("No filters to convert from %s/%s to %s.\n", src->super,
129 src->type, argv[i]);
130 }
131 else
132 {
133 int first = 1; /* First filter shown? */
134
135 printf("Filter cost = %d\n", cost);
136
137 for (filter = (mime_filter_t *)cupsArrayFirst(filters);
138 filter;
139 filter = (mime_filter_t *)cupsArrayNext(filters))
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 }
152
153 putchar('\n');
154
155 cupsArrayDelete(filters);
156 }
157 }
158
159 if (!mime)
160 {
161 mime = mimeLoad("../conf", filter_path);
162 if (ppd)
163 add_ppd_filters(mime, ppd);
164 }
165
166 if (!src)
167 {
168 puts("MIME database types:");
169 for (src = mimeFirstType(mime); src; src = mimeNextType(mime))
170 {
171 printf("\t%s/%s (%d):\n", src->super, src->type, src->priority);
172 print_rules(src->rules);
173 puts("");
174 }
175
176 puts("");
177
178 puts("MIME database filters:");
179 for (filter = mimeFirstFilter(mime); filter; filter = mimeNextFilter(mime))
180 printf("\t%s/%s to %s/%s: %s (%d)\n",
181 filter->src->super, filter->src->type,
182 filter->dst->super, filter->dst->type,
183 filter->filter, filter->cost);
184
185 type_dir(mime, "../doc");
186 }
187
188 return (0);
189 }
190
191
192 /*
193 * 'add_printer_filter()' - Add a printer filter from a PPD.
194 */
195
196 static void
add_ppd_filter(mime_t * mime,mime_type_t * filtertype,const char * filter)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 /*
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
250 maxsize = (size_t)strtoll(program + 8, &ptr, 10);
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))
272 if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) ||
273 !_cups_strcasecmp(temptype->super, super)) &&
274 (type[0] == '*' || !_cups_strcasecmp(temptype->type, type)))
275 {
276 if (desttype != filtertype)
277 {
278 filterptr = mimeAddFilter(mime, temptype, desttype, cost, program);
279
280 if (!mimeFilterLookup(mime, desttype, filtertype))
281 mimeAddFilter(mime, desttype, filtertype, 0, "-");
282 }
283 else
284 filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program);
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
add_ppd_filters(mime_t * mime,ppd_file_t * ppd)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
337 /*
338 * 'print_rules()' - Print the rules for a file type...
339 */
340
341 static void
print_rules(mime_magic_t * rules)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 /*
426 * 'type_dir()' - Show the MIME types for a given directory.
427 */
428
429 static void
type_dir(mime_t * mime,const char * dirname)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 {
452 if (dent->filename[0] == '.')
453 continue;
454
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
470 filters = mimeFilter(mime, filetype, pstype, &cost);
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 }
497