2 * MIME database file routines for CUPS.
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
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 * missing or damaged, see the license at "http://www.cups.org/".
15 * Include necessary headers...
18 #include <cups/string-private.h>
19 #include <cups/debug-private.h>
21 #include "mime-private.h"
28 typedef struct _mime_fcache_s /**** Filter cache structure ****/
30 char *name, /* Filter name */
31 *path; /* Full path to filter if available */
39 static const char *mime_add_fcache(cups_array_t *filtercache, const char *name,
40 const char *filterpath);
41 static int mime_compare_fcache(_mime_fcache_t *a, _mime_fcache_t *b);
42 static void mime_delete_fcache(cups_array_t *filtercache);
43 static void mime_delete_rules(mime_magic_t *rules);
44 static void mime_load_convs(mime_t *mime, const char *filename,
45 const char *filterpath,
46 cups_array_t *filtercache);
47 static void mime_load_types(mime_t *mime, const char *filename);
51 * 'mimeDelete()' - Delete (free) a MIME database.
55 mimeDelete(mime_t *mime) /* I - MIME database */
57 mime_type_t *type; /* Current type */
58 mime_filter_t *filter; /* Current filter */
61 DEBUG_printf(("mimeDelete(mime=%p)", mime));
67 * Loop through filters and free them...
70 for (filter = (mime_filter_t *)cupsArrayFirst(mime->filters);
72 filter = (mime_filter_t *)cupsArrayNext(mime->filters))
73 mimeDeleteFilter(mime, filter);
76 * Loop through the file types and delete any rules...
79 for (type = (mime_type_t *)cupsArrayFirst(mime->types);
81 type = (mime_type_t *)cupsArrayNext(mime->types))
82 mimeDeleteType(mime, type);
85 * Free the types and filters arrays, and then the MIME database structure.
88 cupsArrayDelete(mime->types);
89 cupsArrayDelete(mime->filters);
90 cupsArrayDelete(mime->srcs);
96 * 'mimeDeleteFilter()' - Delete a filter from the MIME database.
100 mimeDeleteFilter(mime_t *mime, /* I - MIME database */
101 mime_filter_t *filter) /* I - Filter */
103 DEBUG_printf(("mimeDeleteFilter(mime=%p, filter=%p(%s/%s->%s/%s, cost=%d, "
104 "maxsize=" CUPS_LLFMT "))", mime, filter,
105 filter ? filter->src->super : "???",
106 filter ? filter->src->type : "???",
107 filter ? filter->dst->super : "???",
108 filter ? filter->dst->super : "???",
109 filter ? filter->cost : -1,
110 filter ? CUPS_LLCAST filter->maxsize : CUPS_LLCAST -1));
112 if (!mime || !filter)
116 if (!cupsArrayFind(mime->filters, filter))
117 DEBUG_puts("1mimeDeleteFilter: Filter not in MIME database.");
120 cupsArrayRemove(mime->filters, filter);
124 * Deleting a filter invalidates the source lookup cache used by
130 DEBUG_puts("1mimeDeleteFilter: Deleting source lookup cache.");
131 cupsArrayDelete(mime->srcs);
138 * 'mimeDeleteType()' - Delete a type from the MIME database.
142 mimeDeleteType(mime_t *mime, /* I - MIME database */
143 mime_type_t *mt) /* I - Type */
145 DEBUG_printf(("mimeDeleteType(mime=%p, mt=%p(%s/%s))", mime, mt,
146 mt ? mt->super : "???", mt ? mt->type : "???"));
152 if (!cupsArrayFind(mime->types, mt))
153 DEBUG_puts("1mimeDeleteFilter: Type not in MIME database.");
156 cupsArrayRemove(mime->types, mt);
158 mime_delete_rules(mt->rules);
164 * '_mimeError()' - Show an error message.
168 _mimeError(mime_t *mime, /* I - MIME database */
169 const char *message, /* I - Printf-style message string */
170 ...) /* I - Additional arguments as needed */
172 va_list ap; /* Argument pointer */
173 char buffer[8192]; /* Message buffer */
178 va_start(ap, message);
179 vsnprintf(buffer, sizeof(buffer), message, ap);
182 (*mime->error_cb)(mime->error_ctx, buffer);
188 * 'mimeFirstFilter()' - Get the first filter in the MIME database.
191 mime_filter_t * /* O - Filter or NULL */
192 mimeFirstFilter(mime_t *mime) /* I - MIME database */
194 DEBUG_printf(("6mimeFirstFilter(mime=%p)", mime));
198 DEBUG_puts("7mimeFirstFilter: Returning NULL.");
203 mime_filter_t *first = (mime_filter_t *)cupsArrayFirst(mime->filters);
206 DEBUG_printf(("7mimeFirstFilter: Returning %p.", first));
213 * 'mimeFirstType()' - Get the first type in the MIME database.
216 mime_type_t * /* O - Type or NULL */
217 mimeFirstType(mime_t *mime) /* I - MIME database */
219 DEBUG_printf(("6mimeFirstType(mime=%p)", mime));
223 DEBUG_puts("7mimeFirstType: Returning NULL.");
228 mime_type_t *first = (mime_type_t *)cupsArrayFirst(mime->types);
231 DEBUG_printf(("7mimeFirstType: Returning %p.", first));
238 * 'mimeLoad()' - Create a new MIME database from disk.
240 * This function uses @link mimeLoadFilters@ and @link mimeLoadTypes@ to
241 * create a MIME database from a single directory.
244 mime_t * /* O - New MIME database */
245 mimeLoad(const char *pathname, /* I - Directory to load */
246 const char *filterpath) /* I - Directory to load */
248 mime_t *mime; /* New MIME database */
250 DEBUG_printf(("mimeLoad(pathname=\"%s\", filterpath=\"%s\")", pathname,
253 mime = mimeLoadFilters(mimeLoadTypes(NULL, pathname), pathname, filterpath);
254 DEBUG_printf(("1mimeLoad: Returning %p.", mime));
261 * 'mimeLoadFilters()' - Load filter definitions from disk.
263 * This function loads all of the .convs files from the specified directory.
264 * Use @link mimeLoadTypes@ to load all types before you load the filters.
267 mime_t * /* O - MIME database */
268 mimeLoadFilters(mime_t *mime, /* I - MIME database */
269 const char *pathname, /* I - Directory to load from */
270 const char *filterpath) /* I - Default filter program directory */
272 cups_dir_t *dir; /* Directory */
273 cups_dentry_t *dent; /* Directory entry */
274 char filename[1024]; /* Full filename of .convs file */
275 cups_array_t *filtercache; /* Filter cache */
278 DEBUG_printf(("mimeLoadFilters(mime=%p, pathname=\"%s\", filterpath=\"%s\")",
279 mime, pathname, filterpath));
282 * Range check input...
285 if (!mime || !pathname || !filterpath)
287 DEBUG_puts("1mimeLoadFilters: Bad arguments.");
292 * Then open the directory specified by pathname...
295 if ((dir = cupsDirOpen(pathname)) == NULL)
297 DEBUG_printf(("1mimeLoadFilters: Unable to open \"%s\": %s", pathname,
299 _mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno));
304 * Read all the .convs files...
307 filtercache = cupsArrayNew((cups_array_func_t)mime_compare_fcache, NULL);
309 while ((dent = cupsDirRead(dir)) != NULL)
311 if (strlen(dent->filename) > 6 &&
312 !strcmp(dent->filename + strlen(dent->filename) - 6, ".convs"))
315 * Load a mime.convs file...
318 snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
319 DEBUG_printf(("1mimeLoadFilters: Loading \"%s\".", filename));
320 mime_load_convs(mime, filename, filterpath, filtercache);
324 mime_delete_fcache(filtercache);
333 * 'mimeLoadTypes()' - Load type definitions from disk.
335 * This function loads all of the .types files from the specified directory.
336 * Use @link mimeLoadFilters@ to load all filters after you load the types.
339 mime_t * /* O - MIME database */
340 mimeLoadTypes(mime_t *mime, /* I - MIME database or @code NULL@ to create a new one */
341 const char *pathname) /* I - Directory to load from */
343 cups_dir_t *dir; /* Directory */
344 cups_dentry_t *dent; /* Directory entry */
345 char filename[1024]; /* Full filename of .types file */
348 DEBUG_printf(("mimeLoadTypes(mime=%p, pathname=\"%s\")", mime, pathname));
351 * First open the directory specified by pathname...
354 if ((dir = cupsDirOpen(pathname)) == NULL)
356 DEBUG_printf(("1mimeLoadTypes: Unable to open \"%s\": %s", pathname,
358 DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime));
359 _mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno));
364 * If "mime" is NULL, make a new, empty database...
373 DEBUG_puts("1mimeLoadTypes: Returning NULL.");
378 * Read all the .types files...
381 while ((dent = cupsDirRead(dir)) != NULL)
383 if (strlen(dent->filename) > 6 &&
384 !strcmp(dent->filename + strlen(dent->filename) - 6, ".types"))
387 * Load a mime.types file...
390 snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
391 DEBUG_printf(("1mimeLoadTypes: Loading \"%s\".", filename));
392 mime_load_types(mime, filename);
398 DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime));
405 * 'mimeNew()' - Create a new, empty MIME database.
408 mime_t * /* O - MIME database */
411 return ((mime_t *)calloc(1, sizeof(mime_t)));
416 * 'mimeNextFilter()' - Get the next filter in the MIME database.
419 mime_filter_t * /* O - Filter or NULL */
420 mimeNextFilter(mime_t *mime) /* I - MIME database */
422 DEBUG_printf(("6mimeNextFilter(mime=%p)", mime));
426 DEBUG_puts("7mimeNextFilter: Returning NULL.");
431 mime_filter_t *next = (mime_filter_t *)cupsArrayNext(mime->filters);
434 DEBUG_printf(("7mimeNextFilter: Returning %p.", next));
441 * 'mimeNextType()' - Get the next type in the MIME database.
444 mime_type_t * /* O - Type or NULL */
445 mimeNextType(mime_t *mime) /* I - MIME database */
447 DEBUG_printf(("6mimeNextType(mime=%p)", mime));
451 DEBUG_puts("7mimeNextType: Returning NULL.");
456 mime_type_t *next = (mime_type_t *)cupsArrayNext(mime->types);
459 DEBUG_printf(("7mimeNextType: Returning %p.", next));
466 * 'mimeNumFilters()' - Get the number of filters in a MIME database.
470 mimeNumFilters(mime_t *mime) /* I - MIME database */
472 DEBUG_printf(("mimeNumFilters(mime=%p)", mime));
476 DEBUG_puts("1mimeNumFilters: Returning 0.");
481 DEBUG_printf(("1mimeNumFilters: Returning %d.",
482 cupsArrayCount(mime->filters)));
483 return (cupsArrayCount(mime->filters));
489 * 'mimeNumTypes()' - Get the number of types in a MIME database.
493 mimeNumTypes(mime_t *mime) /* I - MIME database */
495 DEBUG_printf(("mimeNumTypes(mime=%p)", mime));
499 DEBUG_puts("1mimeNumTypes: Returning 0.");
504 DEBUG_printf(("1mimeNumTypes: Returning %d.",
505 cupsArrayCount(mime->types)));
506 return (cupsArrayCount(mime->types));
512 * 'mimeSetErrorCallback()' - Set the callback for error messages.
516 mimeSetErrorCallback(
517 mime_t *mime, /* I - MIME database */
518 mime_error_cb_t cb, /* I - Callback function */
519 void *ctx) /* I - Context pointer for callback */
524 mime->error_ctx = ctx;
530 * 'mime_add_fcache()' - Add a filter to the filter cache.
533 static const char * /* O - Full path to filter or NULL */
535 cups_array_t *filtercache, /* I - Filter cache */
536 const char *name, /* I - Filter name */
537 const char *filterpath) /* I - Filter path */
539 _mime_fcache_t key, /* Search key */
540 *temp; /* New filter cache */
541 char path[1024]; /* Full path to filter */
544 DEBUG_printf(("2mime_add_fcache(filtercache=%p, name=\"%s\", "
545 "filterpath=\"%s\")", filtercache, name, filterpath));
547 key.name = (char *)name;
548 if ((temp = (_mime_fcache_t *)cupsArrayFind(filtercache, &key)) != NULL)
550 DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path));
554 if ((temp = calloc(1, sizeof(_mime_fcache_t))) == NULL)
556 DEBUG_puts("3mime_add_fcache: Returning NULL.");
560 temp->name = strdup(name);
562 if (cupsFileFind(name, filterpath, 1, path, sizeof(path)))
563 temp->path = strdup(path);
565 cupsArrayAdd(filtercache, temp);
567 DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path));
573 * 'mime_compare_fcache()' - Compare two filter cache entries.
576 static int /* O - Result of comparison */
577 mime_compare_fcache(_mime_fcache_t *a, /* I - First entry */
578 _mime_fcache_t *b) /* I - Second entry */
580 return (strcmp(a->name, b->name));
585 * 'mime_delete_fcache()' - Free all memory used by the filter cache.
590 cups_array_t *filtercache) /* I - Filter cache */
592 _mime_fcache_t *current; /* Current cache entry */
595 DEBUG_printf(("2mime_delete_fcache(filtercache=%p)", filtercache));
597 for (current = (_mime_fcache_t *)cupsArrayFirst(filtercache);
599 current = (_mime_fcache_t *)cupsArrayNext(filtercache))
609 cupsArrayDelete(filtercache);
614 * 'mime_delete_rules()' - Free all memory for the given rule tree.
618 mime_delete_rules(mime_magic_t *rules) /* I - Rules to free */
620 mime_magic_t *next; /* Next rule to free */
623 DEBUG_printf(("2mime_delete_rules(rules=%p)", rules));
626 * Free the rules list, descending recursively to free any child rules.
629 while (rules != NULL)
633 if (rules->child != NULL)
634 mime_delete_rules(rules->child);
636 if (rules->op == MIME_MAGIC_REGEX)
637 regfree(&(rules->value.rev));
646 * 'mime_load_convs()' - Load a xyz.convs file.
651 mime_t *mime, /* I - MIME database */
652 const char *filename, /* I - Convs file to load */
653 const char *filterpath, /* I - Path for filters */
654 cups_array_t *filtercache) /* I - Filter program cache */
656 cups_file_t *fp; /* Convs file */
657 char line[1024], /* Input line from file */
658 *lineptr, /* Current position in line */
659 super[MIME_MAX_SUPER], /* Super-type name */
660 type[MIME_MAX_TYPE], /* Type name */
661 *temp, /* Temporary pointer */
662 *filter; /* Filter program */
663 mime_type_t *temptype, /* MIME type looping var */
664 *dsttype; /* Destination MIME type */
665 int cost; /* Cost of filter */
668 DEBUG_printf(("2mime_load_convs(mime=%p, filename=\"%s\", filterpath=\"%s\", "
669 "filtercache=%p)", mime, filename, filterpath, filtercache));
672 * First try to open the file...
675 if ((fp = cupsFileOpen(filename, "r")) == NULL)
677 DEBUG_printf(("3mime_load_convs: Unable to open \"%s\": %s", filename,
679 _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno));
684 * Then read each line from the file, skipping any comments in the file...
687 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
690 * Skip blank lines and lines starting with a #...
693 if (!line[0] || line[0] == '#')
697 * Strip trailing whitespace...
700 for (lineptr = line + strlen(line) - 1;
701 lineptr >= line && isspace(*lineptr & 255);
706 * Extract the destination super-type and type names from the middle of
711 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
714 while (*lineptr == ' ' || *lineptr == '\t')
719 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
720 (temp - super + 1) < MIME_MAX_SUPER)
721 *temp++ = (char)tolower(*lineptr++ & 255);
731 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
732 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
733 *temp++ = (char)tolower(*lineptr++ & 255);
737 if (*lineptr == '\0' || *lineptr == '\n')
740 if ((dsttype = mimeType(mime, super, type)) == NULL)
742 DEBUG_printf(("3mime_load_convs: Destination type %s/%s not found.",
748 * Then get the cost and filter program...
751 while (*lineptr == ' ' || *lineptr == '\t')
754 if (*lineptr < '0' || *lineptr > '9')
757 cost = atoi(lineptr);
759 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
761 while (*lineptr == ' ' || *lineptr == '\t')
764 if (*lineptr == '\0' || *lineptr == '\n')
769 if (strcmp(filter, "-"))
772 * Verify that the filter exists and is executable...
775 if (!mime_add_fcache(filtercache, filter, filterpath))
777 DEBUG_printf(("mime_load_convs: Filter %s not found in %s.", filter,
779 _mimeError(mime, "Filter \"%s\" not found.", filter);
785 * Finally, get the source super-type and type names from the beginning of
786 * the line. We do it here so we can support wildcards...
792 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
793 (temp - super + 1) < MIME_MAX_SUPER)
794 *temp++ = (char)tolower(*lineptr++ & 255);
804 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
805 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
806 *temp++ = (char)tolower(*lineptr++ & 255);
810 if (!strcmp(super, "*") && !strcmp(type, "*"))
813 * Force * / * to be "application/octet-stream"...
816 strlcpy(super, "application", sizeof(super));
817 strlcpy(type, "octet-stream", sizeof(type));
821 * Add the filter to the MIME database, supporting wildcards as needed...
824 for (temptype = (mime_type_t *)cupsArrayFirst(mime->types);
826 temptype = (mime_type_t *)cupsArrayNext(mime->types))
827 if ((super[0] == '*' || !strcmp(temptype->super, super)) &&
828 (type[0] == '*' || !strcmp(temptype->type, type)))
829 mimeAddFilter(mime, temptype, dsttype, cost, filter);
837 * 'mime_load_types()' - Load a xyz.types file.
841 mime_load_types(mime_t *mime, /* I - MIME database */
842 const char *filename) /* I - Types file to load */
844 cups_file_t *fp; /* Types file */
845 size_t linelen; /* Length of line */
846 char line[32768], /* Input line from file */
847 *lineptr, /* Current position in line */
848 super[MIME_MAX_SUPER], /* Super-type name */
849 type[MIME_MAX_TYPE], /* Type name */
850 *temp; /* Temporary pointer */
851 mime_type_t *typeptr; /* New MIME type */
854 DEBUG_printf(("2mime_load_types(mime=%p, filename=\"%s\")", mime, filename));
857 * First try to open the file...
860 if ((fp = cupsFileOpen(filename, "r")) == NULL)
862 DEBUG_printf(("3mime_load_types: Unable to open \"%s\": %s", filename,
864 _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno));
869 * Then read each line from the file, skipping any comments in the file...
872 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
875 * Skip blank lines and lines starting with a #...
878 if (!line[0] || line[0] == '#')
882 * While the last character in the line is a backslash, continue on to the
883 * next line (and the next, etc.)
886 linelen = strlen(line);
888 while (line[linelen - 1] == '\\')
892 if (cupsFileGets(fp, line + linelen, sizeof(line) - linelen) == NULL)
893 line[linelen] = '\0';
895 linelen += strlen(line + linelen);
899 * Extract the super-type and type names from the beginning of the line.
905 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
906 (temp - super + 1) < MIME_MAX_SUPER)
907 *temp++ = (char)tolower(*lineptr++ & 255);
917 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
918 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
919 *temp++ = (char)tolower(*lineptr++ & 255);
924 * Add the type and rules to the MIME database...
927 typeptr = mimeAddType(mime, super, type);
928 mimeAddTypeRule(typeptr, lineptr);