Bump to cups 2.3.3
[platform/upstream/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  * 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 */
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
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
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
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
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 }