]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/testmime.c
c1f2b6029be6c40642b57e1fdd98602000e20b87
[thirdparty/cups.git] / scheduler / testmime.c
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 * 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/".
12 */
13
14 /*
15 * Include necessary headers...
16 */
17
18 #include <cups/string-private.h>
19 #include <cups/dir.h>
20 #include <cups/debug-private.h>
21 #include <cups/ppd-private.h>
22 #include "mime.h"
23
24
25 /*
26 * Local functions...
27 */
28
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);
32 static void print_rules(mime_magic_t *rules);
33 static void type_dir(mime_t *mime, const char *dirname);
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 {
44 int i; /* Looping vars */
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 */
49 int cost; /* Cost of filters */
50 mime_t *mime; /* MIME database */
51 mime_type_t *src, /* Source type */
52 *dst; /* Destination type */
53 struct stat srcinfo; /* Source information */
54 ppd_file_t *ppd; /* PPD file */
55 cups_array_t *filters; /* Filters for the file */
56 mime_filter_t *filter; /* Current filter */
57
58
59 mime = NULL;
60 src = NULL;
61 dst = NULL;
62 ppd = NULL;
63 filter_path = "../filter:" CUPS_SERVERBIN "/filter";
64
65 srcinfo.st_size = 0;
66
67 for (i = 1; i < argc; i ++)
68 if (!strcmp(argv[i], "-d"))
69 {
70 i ++;
71
72 if (i < argc)
73 {
74 mime = mimeLoad(argv[i], filter_path);
75
76 if (ppd)
77 add_ppd_filters(mime, ppd);
78 }
79 }
80 else if (!strcmp(argv[i], "-f"))
81 {
82 i ++;
83
84 if (i < argc)
85 filter_path = argv[i];
86 }
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 }
99 else if (!src)
100 {
101 if (!mime)
102 mime = mimeLoad("../conf", filter_path);
103
104 if (ppd)
105 add_ppd_filters(mime, ppd);
106
107 src = mimeFileType(mime, argv[i], NULL, &compression);
108 stat(argv[i], &srcinfo);
109
110 if (src)
111 printf("%s: %s/%s%s\n", argv[i], src->super, src->type,
112 compression ? " (gzipped)" : "");
113 else if ((src = mimeType(mime, "application", "octet-stream")) != NULL)
114 printf("%s: application/octet-stream\n", argv[i]);
115 else
116 {
117 printf("%s: unknown\n", argv[i]);
118 if (mime)
119 mimeDelete(mime);
120 return (1);
121 }
122 }
123 else
124 {
125 sscanf(argv[i], "%15[^/]/%255s", super, type);
126 dst = mimeType(mime, super, type);
127
128 filters = mimeFilter2(mime, src, (size_t)srcinfo.st_size, dst, &cost);
129
130 if (!filters)
131 {
132 printf("No filters to convert from %s/%s to %s.\n", src->super,
133 src->type, argv[i]);
134 }
135 else
136 {
137 int first = 1; /* First filter shown? */
138
139 printf("Filter cost = %d\n", cost);
140
141 for (filter = (mime_filter_t *)cupsArrayFirst(filters);
142 filter;
143 filter = (mime_filter_t *)cupsArrayNext(filters))
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 }
156
157 putchar('\n');
158
159 cupsArrayDelete(filters);
160 }
161 }
162
163 if (!mime)
164 {
165 mime = mimeLoad("../conf", filter_path);
166 if (ppd)
167 add_ppd_filters(mime, ppd);
168 }
169
170 if (!src)
171 {
172 puts("MIME database types:");
173 for (src = mimeFirstType(mime); src; src = mimeNextType(mime))
174 {
175 printf("\t%s/%s (%d):\n", src->super, src->type, src->priority);
176 print_rules(src->rules);
177 puts("");
178 }
179
180 puts("");
181
182 puts("MIME database filters:");
183 for (filter = mimeFirstFilter(mime); filter; filter = mimeNextFilter(mime))
184 printf("\t%s/%s to %s/%s: %s (%d)\n",
185 filter->src->super, filter->src->type,
186 filter->dst->super, filter->dst->type,
187 filter->filter, filter->cost);
188
189 type_dir(mime, "../doc");
190 }
191
192 return (0);
193 }
194
195
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
257 maxsize = (size_t)strtoll(program + 8, &ptr, 10);
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))
279 if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) ||
280 !_cups_strcasecmp(temptype->super, super)) &&
281 (type[0] == '*' || !_cups_strcasecmp(temptype->type, type)))
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));
295 mimeAddFilter(mime, desttype, filtertype, 0, "-");
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
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 /*
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 {
472 if (dent->filename[0] == '.')
473 continue;
474
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
490 filters = mimeFilter(mime, filetype, pstype, &cost);
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 }