| /* |
| * MIME database file routines for CUPS. |
| * |
| * Copyright 2007-2014 by Apple Inc. |
| * Copyright 1997-2006 by Easy Software Products, all rights reserved. |
| * |
| * Licensed under Apache License v2.0. See the file "LICENSE" for more information. |
| */ |
| |
| /* |
| * Include necessary headers... |
| */ |
| |
| #include <cups/string-private.h> |
| #include <cups/dir.h> |
| #include "mime-private.h" |
| |
| |
| /* |
| * Debug macros that used to be private API... |
| */ |
| |
| #define DEBUG_puts(x) |
| #define DEBUG_printf(...) |
| |
| |
| /* |
| * Local types... |
| */ |
| |
| typedef struct _mime_fcache_s /**** Filter cache structure ****/ |
| { |
| char *name, /* Filter name */ |
| *path; /* Full path to filter if available */ |
| } _mime_fcache_t; |
| |
| |
| /* |
| * Local functions... |
| */ |
| |
| static const char *mime_add_fcache(cups_array_t *filtercache, const char *name, |
| const char *filterpath); |
| static int mime_compare_fcache(_mime_fcache_t *a, _mime_fcache_t *b); |
| static void mime_delete_fcache(cups_array_t *filtercache); |
| static void mime_delete_rules(mime_magic_t *rules); |
| static void mime_load_convs(mime_t *mime, const char *filename, |
| const char *filterpath, |
| cups_array_t *filtercache); |
| static void mime_load_types(mime_t *mime, const char *filename); |
| |
| |
| /* |
| * 'mimeDelete()' - Delete (free) a MIME database. |
| */ |
| |
| void |
| mimeDelete(mime_t *mime) /* I - MIME database */ |
| { |
| mime_type_t *type; /* Current type */ |
| mime_filter_t *filter; /* Current filter */ |
| |
| |
| DEBUG_printf(("mimeDelete(mime=%p)", mime)); |
| |
| if (!mime) |
| return; |
| |
| /* |
| * Loop through filters and free them... |
| */ |
| |
| for (filter = (mime_filter_t *)cupsArrayFirst(mime->filters); |
| filter; |
| filter = (mime_filter_t *)cupsArrayNext(mime->filters)) |
| mimeDeleteFilter(mime, filter); |
| |
| /* |
| * Loop through the file types and delete any rules... |
| */ |
| |
| for (type = (mime_type_t *)cupsArrayFirst(mime->types); |
| type; |
| type = (mime_type_t *)cupsArrayNext(mime->types)) |
| mimeDeleteType(mime, type); |
| |
| /* |
| * Free the types and filters arrays, and then the MIME database structure. |
| */ |
| |
| cupsArrayDelete(mime->types); |
| cupsArrayDelete(mime->filters); |
| cupsArrayDelete(mime->srcs); |
| free(mime); |
| } |
| |
| |
| /* |
| * 'mimeDeleteFilter()' - Delete a filter from the MIME database. |
| */ |
| |
| void |
| mimeDeleteFilter(mime_t *mime, /* I - MIME database */ |
| mime_filter_t *filter) /* I - Filter */ |
| { |
| DEBUG_printf(("mimeDeleteFilter(mime=%p, filter=%p(%s/%s->%s/%s, cost=%d, " |
| "maxsize=" CUPS_LLFMT "))", mime, filter, |
| filter ? filter->src->super : "???", |
| filter ? filter->src->type : "???", |
| filter ? filter->dst->super : "???", |
| filter ? filter->dst->super : "???", |
| filter ? filter->cost : -1, |
| filter ? CUPS_LLCAST filter->maxsize : CUPS_LLCAST -1)); |
| |
| if (!mime || !filter) |
| return; |
| |
| #ifdef DEBUG |
| if (!cupsArrayFind(mime->filters, filter)) |
| DEBUG_puts("1mimeDeleteFilter: Filter not in MIME database."); |
| #endif /* DEBUG */ |
| |
| cupsArrayRemove(mime->filters, filter); |
| free(filter); |
| |
| /* |
| * Deleting a filter invalidates the source lookup cache used by |
| * mimeFilter()... |
| */ |
| |
| if (mime->srcs) |
| { |
| DEBUG_puts("1mimeDeleteFilter: Deleting source lookup cache."); |
| cupsArrayDelete(mime->srcs); |
| mime->srcs = NULL; |
| } |
| } |
| |
| |
| /* |
| * 'mimeDeleteType()' - Delete a type from the MIME database. |
| */ |
| |
| void |
| mimeDeleteType(mime_t *mime, /* I - MIME database */ |
| mime_type_t *mt) /* I - Type */ |
| { |
| DEBUG_printf(("mimeDeleteType(mime=%p, mt=%p(%s/%s))", mime, mt, |
| mt ? mt->super : "???", mt ? mt->type : "???")); |
| |
| if (!mime || !mt) |
| return; |
| |
| #ifdef DEBUG |
| if (!cupsArrayFind(mime->types, mt)) |
| DEBUG_puts("1mimeDeleteFilter: Type not in MIME database."); |
| #endif /* DEBUG */ |
| |
| cupsArrayRemove(mime->types, mt); |
| |
| mime_delete_rules(mt->rules); |
| free(mt); |
| } |
| |
| |
| /* |
| * '_mimeError()' - Show an error message. |
| */ |
| |
| void |
| _mimeError(mime_t *mime, /* I - MIME database */ |
| const char *message, /* I - Printf-style message string */ |
| ...) /* I - Additional arguments as needed */ |
| { |
| va_list ap; /* Argument pointer */ |
| char buffer[8192]; /* Message buffer */ |
| |
| |
| if (mime->error_cb) |
| { |
| va_start(ap, message); |
| vsnprintf(buffer, sizeof(buffer), message, ap); |
| va_end(ap); |
| |
| (*mime->error_cb)(mime->error_ctx, buffer); |
| } |
| } |
| |
| |
| /* |
| * 'mimeFirstFilter()' - Get the first filter in the MIME database. |
| */ |
| |
| mime_filter_t * /* O - Filter or NULL */ |
| mimeFirstFilter(mime_t *mime) /* I - MIME database */ |
| { |
| DEBUG_printf(("6mimeFirstFilter(mime=%p)", mime)); |
| |
| if (!mime) |
| { |
| DEBUG_puts("7mimeFirstFilter: Returning NULL."); |
| return (NULL); |
| } |
| else |
| { |
| mime_filter_t *first = (mime_filter_t *)cupsArrayFirst(mime->filters); |
| /* First filter */ |
| |
| DEBUG_printf(("7mimeFirstFilter: Returning %p.", first)); |
| return (first); |
| } |
| } |
| |
| |
| /* |
| * 'mimeFirstType()' - Get the first type in the MIME database. |
| */ |
| |
| mime_type_t * /* O - Type or NULL */ |
| mimeFirstType(mime_t *mime) /* I - MIME database */ |
| { |
| DEBUG_printf(("6mimeFirstType(mime=%p)", mime)); |
| |
| if (!mime) |
| { |
| DEBUG_puts("7mimeFirstType: Returning NULL."); |
| return (NULL); |
| } |
| else |
| { |
| mime_type_t *first = (mime_type_t *)cupsArrayFirst(mime->types); |
| /* First type */ |
| |
| DEBUG_printf(("7mimeFirstType: Returning %p.", first)); |
| return (first); |
| } |
| } |
| |
| |
| /* |
| * 'mimeLoad()' - Create a new MIME database from disk. |
| * |
| * This function uses @link mimeLoadFilters@ and @link mimeLoadTypes@ to |
| * create a MIME database from a single directory. |
| */ |
| |
| mime_t * /* O - New MIME database */ |
| mimeLoad(const char *pathname, /* I - Directory to load */ |
| const char *filterpath) /* I - Directory to load */ |
| { |
| mime_t *mime; /* New MIME database */ |
| |
| DEBUG_printf(("mimeLoad(pathname=\"%s\", filterpath=\"%s\")", pathname, |
| filterpath)); |
| |
| mime = mimeLoadFilters(mimeLoadTypes(NULL, pathname), pathname, filterpath); |
| DEBUG_printf(("1mimeLoad: Returning %p.", mime)); |
| |
| return (mime); |
| } |
| |
| |
| /* |
| * 'mimeLoadFilters()' - Load filter definitions from disk. |
| * |
| * This function loads all of the .convs files from the specified directory. |
| * Use @link mimeLoadTypes@ to load all types before you load the filters. |
| */ |
| |
| mime_t * /* O - MIME database */ |
| mimeLoadFilters(mime_t *mime, /* I - MIME database */ |
| const char *pathname, /* I - Directory to load from */ |
| const char *filterpath) /* I - Default filter program directory */ |
| { |
| cups_dir_t *dir; /* Directory */ |
| cups_dentry_t *dent; /* Directory entry */ |
| char filename[1024]; /* Full filename of .convs file */ |
| cups_array_t *filtercache; /* Filter cache */ |
| |
| |
| DEBUG_printf(("mimeLoadFilters(mime=%p, pathname=\"%s\", filterpath=\"%s\")", |
| mime, pathname, filterpath)); |
| |
| /* |
| * Range check input... |
| */ |
| |
| if (!mime || !pathname || !filterpath) |
| { |
| DEBUG_puts("1mimeLoadFilters: Bad arguments."); |
| return (mime); |
| } |
| |
| /* |
| * Then open the directory specified by pathname... |
| */ |
| |
| if ((dir = cupsDirOpen(pathname)) == NULL) |
| { |
| DEBUG_printf(("1mimeLoadFilters: Unable to open \"%s\": %s", pathname, |
| strerror(errno))); |
| _mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno)); |
| return (mime); |
| } |
| |
| /* |
| * Read all the .convs files... |
| */ |
| |
| filtercache = cupsArrayNew((cups_array_func_t)mime_compare_fcache, NULL); |
| |
| while ((dent = cupsDirRead(dir)) != NULL) |
| { |
| if (strlen(dent->filename) > 6 && |
| !strcmp(dent->filename + strlen(dent->filename) - 6, ".convs")) |
| { |
| /* |
| * Load a mime.convs file... |
| */ |
| |
| snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename); |
| DEBUG_printf(("1mimeLoadFilters: Loading \"%s\".", filename)); |
| mime_load_convs(mime, filename, filterpath, filtercache); |
| } |
| } |
| |
| mime_delete_fcache(filtercache); |
| |
| cupsDirClose(dir); |
| |
| return (mime); |
| } |
| |
| |
| /* |
| * 'mimeLoadTypes()' - Load type definitions from disk. |
| * |
| * This function loads all of the .types files from the specified directory. |
| * Use @link mimeLoadFilters@ to load all filters after you load the types. |
| */ |
| |
| mime_t * /* O - MIME database */ |
| mimeLoadTypes(mime_t *mime, /* I - MIME database or @code NULL@ to create a new one */ |
| const char *pathname) /* I - Directory to load from */ |
| { |
| cups_dir_t *dir; /* Directory */ |
| cups_dentry_t *dent; /* Directory entry */ |
| char filename[1024]; /* Full filename of .types file */ |
| |
| |
| DEBUG_printf(("mimeLoadTypes(mime=%p, pathname=\"%s\")", mime, pathname)); |
| |
| /* |
| * First open the directory specified by pathname... |
| */ |
| |
| if ((dir = cupsDirOpen(pathname)) == NULL) |
| { |
| DEBUG_printf(("1mimeLoadTypes: Unable to open \"%s\": %s", pathname, |
| strerror(errno))); |
| DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime)); |
| _mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno)); |
| return (mime); |
| } |
| |
| /* |
| * If "mime" is NULL, make a new, empty database... |
| */ |
| |
| if (!mime) |
| mime = mimeNew(); |
| |
| if (!mime) |
| { |
| cupsDirClose(dir); |
| DEBUG_puts("1mimeLoadTypes: Returning NULL."); |
| return (NULL); |
| } |
| |
| /* |
| * Read all the .types files... |
| */ |
| |
| while ((dent = cupsDirRead(dir)) != NULL) |
| { |
| if (strlen(dent->filename) > 6 && |
| !strcmp(dent->filename + strlen(dent->filename) - 6, ".types")) |
| { |
| /* |
| * Load a mime.types file... |
| */ |
| |
| snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename); |
| DEBUG_printf(("1mimeLoadTypes: Loading \"%s\".", filename)); |
| mime_load_types(mime, filename); |
| } |
| } |
| |
| cupsDirClose(dir); |
| |
| DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime)); |
| |
| return (mime); |
| } |
| |
| |
| /* |
| * 'mimeNew()' - Create a new, empty MIME database. |
| */ |
| |
| mime_t * /* O - MIME database */ |
| mimeNew(void) |
| { |
| return ((mime_t *)calloc(1, sizeof(mime_t))); |
| } |
| |
| |
| /* |
| * 'mimeNextFilter()' - Get the next filter in the MIME database. |
| */ |
| |
| mime_filter_t * /* O - Filter or NULL */ |
| mimeNextFilter(mime_t *mime) /* I - MIME database */ |
| { |
| DEBUG_printf(("6mimeNextFilter(mime=%p)", mime)); |
| |
| if (!mime) |
| { |
| DEBUG_puts("7mimeNextFilter: Returning NULL."); |
| return (NULL); |
| } |
| else |
| { |
| mime_filter_t *next = (mime_filter_t *)cupsArrayNext(mime->filters); |
| /* Next filter */ |
| |
| DEBUG_printf(("7mimeNextFilter: Returning %p.", next)); |
| return (next); |
| } |
| } |
| |
| |
| /* |
| * 'mimeNextType()' - Get the next type in the MIME database. |
| */ |
| |
| mime_type_t * /* O - Type or NULL */ |
| mimeNextType(mime_t *mime) /* I - MIME database */ |
| { |
| DEBUG_printf(("6mimeNextType(mime=%p)", mime)); |
| |
| if (!mime) |
| { |
| DEBUG_puts("7mimeNextType: Returning NULL."); |
| return (NULL); |
| } |
| else |
| { |
| mime_type_t *next = (mime_type_t *)cupsArrayNext(mime->types); |
| /* Next type */ |
| |
| DEBUG_printf(("7mimeNextType: Returning %p.", next)); |
| return (next); |
| } |
| } |
| |
| |
| /* |
| * 'mimeNumFilters()' - Get the number of filters in a MIME database. |
| */ |
| |
| int |
| mimeNumFilters(mime_t *mime) /* I - MIME database */ |
| { |
| DEBUG_printf(("mimeNumFilters(mime=%p)", mime)); |
| |
| if (!mime) |
| { |
| DEBUG_puts("1mimeNumFilters: Returning 0."); |
| return (0); |
| } |
| else |
| { |
| DEBUG_printf(("1mimeNumFilters: Returning %d.", |
| cupsArrayCount(mime->filters))); |
| return (cupsArrayCount(mime->filters)); |
| } |
| } |
| |
| |
| /* |
| * 'mimeNumTypes()' - Get the number of types in a MIME database. |
| */ |
| |
| int |
| mimeNumTypes(mime_t *mime) /* I - MIME database */ |
| { |
| DEBUG_printf(("mimeNumTypes(mime=%p)", mime)); |
| |
| if (!mime) |
| { |
| DEBUG_puts("1mimeNumTypes: Returning 0."); |
| return (0); |
| } |
| else |
| { |
| DEBUG_printf(("1mimeNumTypes: Returning %d.", |
| cupsArrayCount(mime->types))); |
| return (cupsArrayCount(mime->types)); |
| } |
| } |
| |
| |
| /* |
| * 'mimeSetErrorCallback()' - Set the callback for error messages. |
| */ |
| |
| void |
| mimeSetErrorCallback( |
| mime_t *mime, /* I - MIME database */ |
| mime_error_cb_t cb, /* I - Callback function */ |
| void *ctx) /* I - Context pointer for callback */ |
| { |
| if (mime) |
| { |
| mime->error_cb = cb; |
| mime->error_ctx = ctx; |
| } |
| } |
| |
| |
| /* |
| * 'mime_add_fcache()' - Add a filter to the filter cache. |
| */ |
| |
| static const char * /* O - Full path to filter or NULL */ |
| mime_add_fcache( |
| cups_array_t *filtercache, /* I - Filter cache */ |
| const char *name, /* I - Filter name */ |
| const char *filterpath) /* I - Filter path */ |
| { |
| _mime_fcache_t key, /* Search key */ |
| *temp; /* New filter cache */ |
| char path[1024]; /* Full path to filter */ |
| |
| |
| DEBUG_printf(("2mime_add_fcache(filtercache=%p, name=\"%s\", " |
| "filterpath=\"%s\")", filtercache, name, filterpath)); |
| |
| key.name = (char *)name; |
| if ((temp = (_mime_fcache_t *)cupsArrayFind(filtercache, &key)) != NULL) |
| { |
| DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path)); |
| return (temp->path); |
| } |
| |
| if ((temp = calloc(1, sizeof(_mime_fcache_t))) == NULL) |
| { |
| DEBUG_puts("3mime_add_fcache: Returning NULL."); |
| return (NULL); |
| } |
| |
| temp->name = strdup(name); |
| |
| if (cupsFileFind(name, filterpath, 1, path, sizeof(path))) |
| temp->path = strdup(path); |
| |
| cupsArrayAdd(filtercache, temp); |
| |
| DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path)); |
| return (temp->path); |
| } |
| |
| |
| /* |
| * 'mime_compare_fcache()' - Compare two filter cache entries. |
| */ |
| |
| static int /* O - Result of comparison */ |
| mime_compare_fcache(_mime_fcache_t *a, /* I - First entry */ |
| _mime_fcache_t *b) /* I - Second entry */ |
| { |
| return (strcmp(a->name, b->name)); |
| } |
| |
| |
| /* |
| * 'mime_delete_fcache()' - Free all memory used by the filter cache. |
| */ |
| |
| static void |
| mime_delete_fcache( |
| cups_array_t *filtercache) /* I - Filter cache */ |
| { |
| _mime_fcache_t *current; /* Current cache entry */ |
| |
| |
| DEBUG_printf(("2mime_delete_fcache(filtercache=%p)", filtercache)); |
| |
| for (current = (_mime_fcache_t *)cupsArrayFirst(filtercache); |
| current; |
| current = (_mime_fcache_t *)cupsArrayNext(filtercache)) |
| { |
| free(current->name); |
| |
| if (current->path) |
| free(current->path); |
| |
| free(current); |
| } |
| |
| cupsArrayDelete(filtercache); |
| } |
| |
| |
| /* |
| * 'mime_delete_rules()' - Free all memory for the given rule tree. |
| */ |
| |
| static void |
| mime_delete_rules(mime_magic_t *rules) /* I - Rules to free */ |
| { |
| mime_magic_t *next; /* Next rule to free */ |
| |
| |
| DEBUG_printf(("2mime_delete_rules(rules=%p)", rules)); |
| |
| /* |
| * Free the rules list, descending recursively to free any child rules. |
| */ |
| |
| while (rules != NULL) |
| { |
| next = rules->next; |
| |
| if (rules->child != NULL) |
| mime_delete_rules(rules->child); |
| |
| if (rules->op == MIME_MAGIC_REGEX) |
| regfree(&(rules->value.rev)); |
| |
| free(rules); |
| rules = next; |
| } |
| } |
| |
| |
| /* |
| * 'mime_load_convs()' - Load a xyz.convs file. |
| */ |
| |
| static void |
| mime_load_convs( |
| mime_t *mime, /* I - MIME database */ |
| const char *filename, /* I - Convs file to load */ |
| const char *filterpath, /* I - Path for filters */ |
| cups_array_t *filtercache) /* I - Filter program cache */ |
| { |
| cups_file_t *fp; /* Convs file */ |
| char line[1024], /* Input line from file */ |
| *lineptr, /* Current position in line */ |
| super[MIME_MAX_SUPER], /* Super-type name */ |
| type[MIME_MAX_TYPE], /* Type name */ |
| *temp, /* Temporary pointer */ |
| *filter; /* Filter program */ |
| mime_type_t *temptype, /* MIME type looping var */ |
| *dsttype; /* Destination MIME type */ |
| int cost; /* Cost of filter */ |
| |
| |
| DEBUG_printf(("2mime_load_convs(mime=%p, filename=\"%s\", filterpath=\"%s\", " |
| "filtercache=%p)", mime, filename, filterpath, filtercache)); |
| |
| /* |
| * First try to open the file... |
| */ |
| |
| if ((fp = cupsFileOpen(filename, "r")) == NULL) |
| { |
| DEBUG_printf(("3mime_load_convs: Unable to open \"%s\": %s", filename, |
| strerror(errno))); |
| _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno)); |
| return; |
| } |
| |
| /* |
| * Then read each line from the file, skipping any comments in the file... |
| */ |
| |
| while (cupsFileGets(fp, line, sizeof(line)) != NULL) |
| { |
| /* |
| * Skip blank lines and lines starting with a #... |
| */ |
| |
| if (!line[0] || line[0] == '#') |
| continue; |
| |
| /* |
| * Strip trailing whitespace... |
| */ |
| |
| for (lineptr = line + strlen(line) - 1; |
| lineptr >= line && isspace(*lineptr & 255); |
| lineptr --) |
| *lineptr = '\0'; |
| |
| /* |
| * Extract the destination super-type and type names from the middle of |
| * the line. |
| */ |
| |
| lineptr = line; |
| while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0') |
| lineptr ++; |
| |
| while (*lineptr == ' ' || *lineptr == '\t') |
| lineptr ++; |
| |
| temp = super; |
| |
| while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && |
| (temp - super + 1) < MIME_MAX_SUPER) |
| *temp++ = (char)tolower(*lineptr++ & 255); |
| |
| *temp = '\0'; |
| |
| if (*lineptr != '/') |
| continue; |
| |
| lineptr ++; |
| temp = type; |
| |
| while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && |
| *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) |
| *temp++ = (char)tolower(*lineptr++ & 255); |
| |
| *temp = '\0'; |
| |
| if (*lineptr == '\0' || *lineptr == '\n') |
| continue; |
| |
| if ((dsttype = mimeType(mime, super, type)) == NULL) |
| { |
| DEBUG_printf(("3mime_load_convs: Destination type %s/%s not found.", |
| super, type)); |
| continue; |
| } |
| |
| /* |
| * Then get the cost and filter program... |
| */ |
| |
| while (*lineptr == ' ' || *lineptr == '\t') |
| lineptr ++; |
| |
| if (*lineptr < '0' || *lineptr > '9') |
| continue; |
| |
| cost = atoi(lineptr); |
| |
| while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0') |
| lineptr ++; |
| while (*lineptr == ' ' || *lineptr == '\t') |
| lineptr ++; |
| |
| if (*lineptr == '\0' || *lineptr == '\n') |
| continue; |
| |
| filter = lineptr; |
| |
| if (strcmp(filter, "-")) |
| { |
| /* |
| * Verify that the filter exists and is executable... |
| */ |
| |
| if (!mime_add_fcache(filtercache, filter, filterpath)) |
| { |
| DEBUG_printf(("mime_load_convs: Filter %s not found in %s.", filter, |
| filterpath)); |
| _mimeError(mime, "Filter \"%s\" not found.", filter); |
| continue; |
| } |
| } |
| |
| /* |
| * Finally, get the source super-type and type names from the beginning of |
| * the line. We do it here so we can support wildcards... |
| */ |
| |
| lineptr = line; |
| temp = super; |
| |
| while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && |
| (temp - super + 1) < MIME_MAX_SUPER) |
| *temp++ = (char)tolower(*lineptr++ & 255); |
| |
| *temp = '\0'; |
| |
| if (*lineptr != '/') |
| continue; |
| |
| lineptr ++; |
| temp = type; |
| |
| while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && |
| *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) |
| *temp++ = (char)tolower(*lineptr++ & 255); |
| |
| *temp = '\0'; |
| |
| if (!strcmp(super, "*") && !strcmp(type, "*")) |
| { |
| /* |
| * Force * / * to be "application/octet-stream"... |
| */ |
| |
| strlcpy(super, "application", sizeof(super)); |
| strlcpy(type, "octet-stream", sizeof(type)); |
| } |
| |
| /* |
| * Add the filter to the MIME database, supporting wildcards as needed... |
| */ |
| |
| for (temptype = (mime_type_t *)cupsArrayFirst(mime->types); |
| temptype; |
| temptype = (mime_type_t *)cupsArrayNext(mime->types)) |
| if ((super[0] == '*' || !strcmp(temptype->super, super)) && |
| (type[0] == '*' || !strcmp(temptype->type, type))) |
| mimeAddFilter(mime, temptype, dsttype, cost, filter); |
| } |
| |
| cupsFileClose(fp); |
| } |
| |
| |
| /* |
| * 'mime_load_types()' - Load a xyz.types file. |
| */ |
| |
| static void |
| mime_load_types(mime_t *mime, /* I - MIME database */ |
| const char *filename) /* I - Types file to load */ |
| { |
| cups_file_t *fp; /* Types file */ |
| size_t linelen; /* Length of line */ |
| char line[32768], /* Input line from file */ |
| *lineptr, /* Current position in line */ |
| super[MIME_MAX_SUPER], /* Super-type name */ |
| type[MIME_MAX_TYPE], /* Type name */ |
| *temp; /* Temporary pointer */ |
| mime_type_t *typeptr; /* New MIME type */ |
| |
| |
| DEBUG_printf(("2mime_load_types(mime=%p, filename=\"%s\")", mime, filename)); |
| |
| /* |
| * First try to open the file... |
| */ |
| |
| if ((fp = cupsFileOpen(filename, "r")) == NULL) |
| { |
| DEBUG_printf(("3mime_load_types: Unable to open \"%s\": %s", filename, |
| strerror(errno))); |
| _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno)); |
| return; |
| } |
| |
| /* |
| * Then read each line from the file, skipping any comments in the file... |
| */ |
| |
| while (cupsFileGets(fp, line, sizeof(line)) != NULL) |
| { |
| /* |
| * Skip blank lines and lines starting with a #... |
| */ |
| |
| if (!line[0] || line[0] == '#') |
| continue; |
| |
| /* |
| * While the last character in the line is a backslash, continue on to the |
| * next line (and the next, etc.) |
| */ |
| |
| linelen = strlen(line); |
| |
| while (line[linelen - 1] == '\\') |
| { |
| linelen --; |
| |
| if (cupsFileGets(fp, line + linelen, sizeof(line) - linelen) == NULL) |
| line[linelen] = '\0'; |
| else |
| linelen += strlen(line + linelen); |
| } |
| |
| /* |
| * Extract the super-type and type names from the beginning of the line. |
| */ |
| |
| lineptr = line; |
| temp = super; |
| |
| while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && |
| (temp - super + 1) < MIME_MAX_SUPER) |
| *temp++ = (char)tolower(*lineptr++ & 255); |
| |
| *temp = '\0'; |
| |
| if (*lineptr != '/') |
| continue; |
| |
| lineptr ++; |
| temp = type; |
| |
| while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && |
| *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) |
| *temp++ = (char)tolower(*lineptr++ & 255); |
| |
| *temp = '\0'; |
| |
| /* |
| * Add the type and rules to the MIME database... |
| */ |
| |
| typeptr = mimeAddType(mime, super, type); |
| mimeAddTypeRule(typeptr, lineptr); |
| } |
| |
| cupsFileClose(fp); |
| } |