]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/mime.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / mime.c
index 236ae11dc2d52cc2c3fe51926cd6b5a9b1c2486f..6edaa4a663742905f00545f284492f0637985834 100644 (file)
@@ -1,34 +1,37 @@
 /*
- * "$Id: mime.c 4613 2005-08-30 12:41:48Z mike $"
+ * "$Id: mime.c 6649 2007-07-11 21:46:42Z mike $"
  *
  *   MIME database file routines for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *   Copyright 2007 by Apple Inc.
+ *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
  *
  * Contents:
  *
- *   mimeDelete()   - Delete (free) a MIME database.
- *   mimeMerge()    - Merge a MIME database from disk with the current one.
- *   mimeNew()      - Create a new, empty MIME database.
- *   load_types()   - Load a xyz.types file...
- *   delete_rules() - Free all memory for the given rule tree.
- *   load_convs()   - Load a xyz.convs file...
+ *   mimeDelete()       - Delete (free) a MIME database.
+ *   mimeDeleteFilter() - Delete a filter from the MIME database.
+ *   mimeDeleteType()   - Delete a type from the MIME database.
+ *   mimeFirstFilter()  - Get the first filter in the MIME database.
+ *   mimeFirstType()    - Get the first type in the MIME database.
+ *   mimeLoad()         - Create a new MIME database from disk.
+ *   mimeMerge()        - Merge a MIME database from disk with the current one.
+ *   mimeNew()          - Create a new, empty MIME database.
+ *   mimeNextFilter()   - Get the next filter in the MIME database.
+ *   mimeNextType()     - Get the next type in the MIME database.
+ *   mimeNumFilters()   - Get the number of filters in a MIME database.
+ *   mimeNumTypes()     - Get the number of types in a MIME database.
+ *   add_fcache()       - Add a filter to the filter cache.
+ *   compare_fcache()   - Compare two filter cache entries.
+ *   delete_fcache()    - Free all memory used by the filter cache.
+ *   delete_rules()     - Free all memory for the given rule tree.
+ *   load_convs()       - Load a xyz.convs file...
+ *   load_types()       - Load a xyz.types file...
  */
 
 /*
 #include <stdlib.h>
 #include <ctype.h>
 
+#include <cups/debug.h>
+#include <cups/dir.h>
 #include <cups/string.h>
 #include "mime.h"
 
-#ifdef WIN32
-#  include <windows.h>
-#else
-#  include <dirent.h>
-#endif /* WIN32 */
+
+/*
+ * 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 void    load_types(mime_t *mime, const char *filename);
-static void    load_convs(mime_t *mime, const char *filename,
-                          const char *filterpath);
+static const char *add_fcache(cups_array_t *filtercache, const char *name,
+                             const char *filterpath);
+static int     compare_fcache(_mime_fcache_t *a, _mime_fcache_t *b);
+static void    delete_fcache(cups_array_t *filtercache);
 static void    delete_rules(mime_magic_t *rules);
+static void    load_convs(mime_t *mime, const char *filename,
+                          const char *filterpath,
+                          cups_array_t *filtercache);
+static void    load_types(mime_t *mime, const char *filename);
 
 
 /*
@@ -64,135 +79,142 @@ static void       delete_rules(mime_magic_t *rules);
  */
 
 void
-mimeDelete(mime_t *mime)       /* I - MIME database */
+mimeDelete(mime_t *mime)               /* I - MIME database */
 {
-  int  i;                      /* Looping var */
+  mime_type_t  *type;                  /* Current type */
+  mime_filter_t        *filter;                /* Current filter */
 
 
-  if (mime == NULL)
+  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 (i = 0; i < mime->num_types; i ++)
-  {
-    delete_rules(mime->types[i]->rules);
-    free(mime->types[i]->type);
-    free(mime->types[i]);
-  }
+  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.
   */
 
-  free(mime->types);
-  free(mime->filters);
+  cupsArrayDelete(mime->types);
+  cupsArrayDelete(mime->filters);
+  cupsArrayDelete(mime->srcs);
   free(mime);
 }
 
 
 /*
- * 'mimeMerge()' - Merge a MIME database from disk with the current one.
+ * 'mimeDeleteFilter()' - Delete a filter from the MIME database.
  */
 
-mime_t *                       /* O - Updated MIME database */
-mimeMerge(mime_t     *mime,    /* I - MIME database to add to */
-          const char *pathname,        /* I - Directory to load */
-          const char *filterpath)/* I - Directory to load */
+void
+mimeDeleteFilter(mime_t        *mime,  /* I - MIME database */
+                mime_filter_t *filter) /* I - Filter */
 {
-#ifdef WIN32
-  HANDLE       dir;            /* Directory handle */
-  WIN32_FIND_DATA dent;                /* Directory entry */
-  char         filename[1024], /* Full filename of types/converts file */
-               *pathsep;       /* Last character in path */
+  if (!mime || !filter)
+    return;
 
+  cupsArrayRemove(mime->filters, filter);
+  free(filter);
 
  /*
-  * First open the directory specified by pathname...  Return NULL if nothing
-  * was read or if the pathname is NULL...
+  * Deleting a filter invalidates the source lookup cache used by
+  * mimeFilter()...
   */
 
-  if (pathname == NULL)
-    return (NULL);
-
-  strlcpy(filename, pathname, sizeof(filename));
-
-  pathsep = filename + strlen(filename);
-  if ((pathsep - filename + 9) > sizeof(filename))
-    return (NULL);
-
-  if (pathsep == filename ||
-      (pathsep[-1] != '/' && pathsep[-1] != '\\'))
+  if (mime->srcs)
   {
-    strcpy(pathsep, "/");
-    pathsep ++;
+    cupsArrayDelete(mime->srcs);
+    mime->srcs = NULL;
   }
+}
 
-  strcpy(pathsep, "*.types");
-  
-  if ((dir = FindFirstFile(filename, &dent)) == 0)
-    return (NULL);
 
- /*
 * If "mime" is NULL, make a new, blank database...
 */
+/*
* 'mimeDeleteType()' - Delete a type from the MIME database.
+ */
 
-  if (mime == NULL)
-    if ((mime = mimeNew()) == NULL)
-      return (NULL);
+void
+mimeDeleteType(mime_t      *mime,      /* I - MIME database */
+              mime_type_t *mt)         /* I - Type */
+{
+  if (!mime || !mt)
+    return;
 
- /*
-  * Read all the .types files...
-  */
+  cupsArrayRemove(mime->types, mt);
 
-  do
-  {
-   /*
-    * Load a mime.types file...
-    */
+  delete_rules(mt->rules);
+  free(mt);
+}
 
-    if ((pathsep - filename + strlen(dent.cFileName)) >= sizeof(filename))
-      continue;
 
-    strcpy(pathsep, dent.cFileName);
-    load_types(mime, filename);
-  }
-  while (FindNextFile(dir, &dent));
+/*
+ * 'mimeFirstFilter()' - Get the first filter in the MIME database.
+ */
 
-  FindClose(dir);
+mime_filter_t *                                /* O - Filter or NULL */
+mimeFirstFilter(mime_t *mime)          /* I - MIME database */
+{
+  if (!mime)
+    return (NULL);
+  else
+    return ((mime_filter_t *)cupsArrayFirst(mime->filters));
+}
 
- /*
-  * Read all the .convs files...
-  */
 
-  strcpy(pathsep, "*.convs");
-  
-  if ((dir = FindFirstFile(filename, &dent)) == 0)
-    return (mime);
+/*
+ * 'mimeFirstType()' - Get the first type in the MIME database.
+ */
 
-  do
-  {
-   /*
-    * Load a mime.convs file...
-    */
+mime_type_t *                          /* O - Type or NULL */
+mimeFirstType(mime_t *mime)            /* I - MIME database */
+{
+  if (!mime)
+    return (NULL);
+  else
+    return ((mime_type_t *)cupsArrayFirst(mime->types));
+}
 
-    if ((pathsep - filename + strlen(dent.cFileName)) >= sizeof(filename))
-      continue;
 
-    strcpy(pathsep, dent.cFileName);
-    load_convs(mime, filename);
-  }
-  while (FindNextFile(dir, &dent));
+/*
+ * 'mimeLoad()' - Create a new MIME database from disk.
+ */
 
-  FindClose(dir);
+mime_t *                               /* O - New MIME database */
+mimeLoad(const char *pathname,         /* I - Directory to load */
+         const char *filterpath)       /* I - Directory to load */
+{
+  return (mimeMerge(NULL, pathname, filterpath));
+}
 
-  return (mime);
-#else
-  DIR          *dir;           /* Directory */
-  struct dirent        *dent;          /* Directory entry */
-  char         filename[1024]; /* Full filename of types/converts file */
+
+/*
+ * 'mimeMerge()' - Merge a MIME database from disk with the current one.
+ */
+
+mime_t *                               /* O - Updated MIME database */
+mimeMerge(mime_t     *mime,            /* I - MIME database to add to */
+          const char *pathname,                /* I - Directory to load */
+          const char *filterpath)      /* I - Directory to load */
+{
+  cups_dir_t   *dir;                   /* Directory */
+  cups_dentry_t        *dent;                  /* Directory entry */
+  char         filename[1024];         /* Full filename of types/converts file */
+  cups_array_t *filtercache;           /* Filter cache */
 
 
  /*
@@ -200,62 +222,66 @@ mimeMerge(mime_t     *mime,       /* I - MIME database to add to */
   * was read or if the pathname is NULL...
   */
 
-  if (pathname == NULL)
+  if (!pathname)
     return (NULL);
 
-  if ((dir = opendir(pathname)) == NULL)
+  if ((dir = cupsDirOpen(pathname)) == NULL)
     return (NULL);
 
  /*
   * If "mime" is NULL, make a new, blank database...
   */
 
-  if (mime == NULL)
-    if ((mime = mimeNew()) == NULL)
-      return (NULL);
+  if (!mime)
+    mime = mimeNew();
+  if (!mime)
+    return (NULL);
 
  /*
   * Read all the .types files...
   */
 
-  while ((dent = readdir(dir)) != NULL)
+  while ((dent = cupsDirRead(dir)) != NULL)
   {
-    if (strlen(dent->d_name) > 6 &&
-        strcmp(dent->d_name + strlen(dent->d_name) - 6, ".types") == 0)
+    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->d_name);
+      snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
       load_types(mime, filename);
     }
   }
 
-  rewinddir(dir);
+  cupsDirRewind(dir);
 
  /*
   * Read all the .convs files...
   */
 
-  while ((dent = readdir(dir)) != NULL)
+  filtercache = cupsArrayNew((cups_array_func_t)compare_fcache, NULL);
+
+  while ((dent = cupsDirRead(dir)) != NULL)
   {
-    if (strlen(dent->d_name) > 6 &&
-        strcmp(dent->d_name + strlen(dent->d_name) - 6, ".convs") == 0)
+    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->d_name);
-      load_convs(mime, filename, filterpath);
+      snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
+      load_convs(mime, filename, filterpath, filtercache);
     }
   }
 
-  closedir(dir);
+  delete_fcache(filtercache);
+
+  cupsDirClose(dir);
 
   return (mime);
-#endif /* WIN32 */
 }
 
 
@@ -263,7 +289,7 @@ mimeMerge(mime_t     *mime, /* I - MIME database to add to */
  * 'mimeNew()' - Create a new, empty MIME database.
  */
 
-mime_t *                       /* O - MIME database */
+mime_t *                               /* O - MIME database */
 mimeNew(void)
 {
   return ((mime_t *)calloc(1, sizeof(mime_t)));
@@ -271,94 +297,155 @@ mimeNew(void)
 
 
 /*
- * 'load_types()' - Load a xyz.types file...
+ * 'mimeNextFilter()' - Get the next filter in the MIME database.
  */
 
-static void
-load_types(mime_t     *mime,           /* I - MIME database */
-           const char *filename)       /* I - Types file to load */
+mime_filter_t *                                /* O - Filter or NULL */
+mimeNextFilter(mime_t *mime)           /* I - MIME database */
 {
-  cups_file_t  *fp;                    /* Types file */
-  int          linelen;                /* Length of line */
-  char         line[65536],            /* 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 */
+  if (!mime)
+    return (NULL);
+  else
+    return ((mime_filter_t *)cupsArrayNext(mime->filters));
+}
 
 
- /*
 * First try to open the file...
 */
+/*
* 'mimeNextType()' - Get the next type in the MIME database.
+ */
 
-  if ((fp = cupsFileOpen(filename, "r")) == NULL)
-    return;
+mime_type_t *                          /* O - Type or NULL */
+mimeNextType(mime_t *mime)             /* I - MIME database */
+{
+  if (!mime)
+    return (NULL);
+  else
+    return ((mime_type_t *)cupsArrayNext(mime->types));
+}
 
- /*
-  * 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 #...
-    */
+/*
+ * 'mimeNumFilters()' - Get the number of filters in a MIME database.
+ */
 
-    if (!line[0] || line[0] == '#')
-      continue;
+int
+mimeNumFilters(mime_t *mime)           /* I - MIME database */
+{
+  if (!mime)
+    return (0);
+  else
+    return (cupsArrayCount(mime->filters));
+}
 
-   /*
-    * While the last character in the line is a backslash, continue on to the
-    * next line (and the next, etc.)
-    */
 
-    linelen = strlen(line);
+/*
+ * 'mimeNumTypes()' - Get the number of types in a MIME database.
+ */
 
-    while (line[linelen - 1] == '\\')
-    {
-      linelen --;
+int
+mimeNumTypes(mime_t *mime)             /* I - MIME database */
+{
+  if (!mime)
+    return (0);
+  else
+    return (cupsArrayCount(mime->types));
+}
 
-      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.
   */
+/*
* 'add_fcache()' - Add a filter to the filter cache.
+ */
 
-    lineptr = line;
-    temp    = super;
+static const char *                    /* O - Full path to filter or NULL */
+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 */
 
-    while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
-           (temp - super + 1) < MIME_MAX_SUPER)
-      *temp++ = tolower(*lineptr++ & 255);
 
-    *temp = '\0';
+  key.name = (char *)name;
+  if ((temp = (_mime_fcache_t *)cupsArrayFind(filtercache, &key)) != NULL)
+    return (temp->path);
 
-    if (*lineptr != '/')
-      continue;
+  if ((temp = calloc(1, sizeof(_mime_fcache_t))) == NULL)
+    return (NULL);
 
-    lineptr ++;
-    temp = type;
+  temp->name = strdup(name);
 
-    while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
-           *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
-      *temp++ = tolower(*lineptr++ & 255);
+  if (cupsFileFind(name, filterpath, 1, path, sizeof(path)))
+    temp->path = strdup(path);
 
-    *temp = '\0';
+  cupsArrayAdd(filtercache, temp);
 
-   /*
-    * Add the type and rules to the MIME database...
-    */
+  return (temp->path);
+}
 
-    typeptr = mimeAddType(mime, super, type);
-    mimeAddTypeRule(typeptr, lineptr);
+
+/*
+ * 'compare_fcache()' - Compare two filter cache entries.
+ */
+
+static int                             /* O - Result of comparison */
+compare_fcache(_mime_fcache_t *a,      /* I - First entry */
+               _mime_fcache_t *b)      /* I - Second entry */
+{
+  return (strcmp(a->name, b->name));
+}
+
+
+/*
+ * 'delete_fcache()' - Free all memory used by the filter cache.
+ */
+
+static void
+delete_fcache(cups_array_t *filtercache)/* I - Filter cache */
+{
+  _mime_fcache_t       *current;       /* Current cache entry */
+
+
+  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);
   }
 
-  cupsFileClose(fp);
+  cupsArrayDelete(filtercache);
+}
+
+
+/*
+ * 'delete_rules()' - Free all memory for the given rule tree.
+ */
+
+static void
+delete_rules(mime_magic_t *rules)      /* I - Rules to free */
+{
+  mime_magic_t *next;                  /* Next rule to free */
+
+
+ /*
+  * Free the rules list, descending recursively to free any child rules.
+  */
+
+  while (rules != NULL)
+  {
+    next = rules->next;
+
+    if (rules->child != NULL)
+      delete_rules(rules->child);
+
+    free(rules);
+    rules = next;
+  }
 }
 
 
@@ -367,11 +454,11 @@ load_types(mime_t     *mime,              /* I - MIME database */
  */
 
 static void
-load_convs(mime_t     *mime,           /* I - MIME database */
-           const char *filename,       /* I - Convs file to load */
-           const char *filterpath)     /* I - Directory to load */
+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 */
 {
-  int          i;                      /* Looping var */
   cups_file_t  *fp;                    /* Convs file */
   char         line[1024],             /* Input line from file */
                *lineptr,               /* Current position in line */
@@ -379,10 +466,9 @@ load_convs(mime_t     *mime,               /* I - MIME database */
                type[MIME_MAX_TYPE],    /* Type name */
                *temp,                  /* Temporary pointer */
                *filter;                /* Filter program */
-  mime_type_t  **temptype,             /* MIME type looping var */
+  mime_type_t  *temptype,              /* MIME type looping var */
                *dsttype;               /* Destination MIME type */
   int          cost;                   /* Cost of filter */
-  char         filterprog[1024];       /* Full path of filter... */
 
 
  /*
@@ -392,6 +478,8 @@ load_convs(mime_t     *mime,                /* I - MIME database */
   if ((fp = cupsFileOpen(filename, "r")) == NULL)
     return;
 
+  DEBUG_printf(("\"%s\":\n", filename));
+
  /*
   * Then read each line from the file, skipping any comments in the file...
   */
@@ -402,6 +490,8 @@ load_convs(mime_t     *mime,                /* I - MIME database */
     * Skip blank lines and lines starting with a #...
     */
 
+    DEBUG_puts(line);
+
     if (!line[0] || line[0] == '#')
       continue;
 
@@ -450,7 +540,10 @@ load_convs(mime_t     *mime,               /* I - MIME database */
       continue;
 
     if ((dsttype = mimeType(mime, super, type)) == NULL)
+    {
+      DEBUG_printf(("    Destination type %s/%s not found!\n", super, type));
       continue;
+    }
 
    /*
     * Then get the cost and filter program...
@@ -474,22 +567,18 @@ load_convs(mime_t     *mime,              /* I - MIME database */
 
     filter = lineptr;
 
-#ifndef WIN32
-    if (strcmp(filter, "-") != 0)
+    if (strcmp(filter, "-"))
     {
      /*
       * Verify that the filter exists and is executable...
       */
 
-      if (filter[0] == '/')
-       strlcpy(filterprog, filter, sizeof(filterprog));
-      else
-       snprintf(filterprog, sizeof(filterprog), "%s/%s", filterpath, filter);
-
-      if (access(filterprog, X_OK))
-       continue;
+      if (!add_fcache(filtercache, filter, filterpath))
+      {
+        DEBUG_printf(("    Filter %s not found in %s!\n", filter, filterpath)); 
+        continue;
+      }
     }
-#endif /* !WIN32 */
 
    /*
     * Finally, get the source super-type and type names from the beginning of
@@ -517,7 +606,7 @@ load_convs(mime_t     *mime,                /* I - MIME database */
 
     *temp = '\0';
 
-    if (strcmp(super, "*") == 0 && strcmp(type, "*") == 0)
+    if (!strcmp(super, "*") && !strcmp(type, "*"))
     {
      /*
       * Force * / * to be "application/octet-stream"...
@@ -531,10 +620,12 @@ load_convs(mime_t     *mime,              /* I - MIME database */
     * Add the filter to the MIME database, supporting wildcards as needed...
     */
 
-    for (temptype = mime->types, i = 0; i < mime->num_types; i ++, temptype ++)
-      if ((super[0] == '*' || strcmp((*temptype)->super, super) == 0) &&
-          (type[0] == '*' || strcmp((*temptype)->type, type) == 0))
-       mimeAddFilter(mime, *temptype, dsttype, cost, filter);
+    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);
@@ -542,32 +633,101 @@ load_convs(mime_t     *mime,             /* I - MIME database */
 
 
 /*
- * 'delete_rules()' - Free all memory for the given rule tree.
+ * 'load_types()' - Load a xyz.types file...
  */
 
 static void
-delete_rules(mime_magic_t *rules)      /* I - Rules to free */
+load_types(mime_t     *mime,           /* I - MIME database */
+           const char *filename)       /* I - Types file to load */
 {
-  mime_magic_t *next;                  /* Next rule to free */
+  cups_file_t  *fp;                    /* Types file */
+  int          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 */
 
 
  /*
-  * Free the rules list, descending recursively to free any child rules.
+  * First try to open the file...
   */
 
-  while (rules != NULL)
+  if ((fp = cupsFileOpen(filename, "r")) == NULL)
+    return;
+
+  DEBUG_printf(("\"%s\":\n", filename));
+
+ /*
+  * Then read each line from the file, skipping any comments in the file...
+  */
+
+  while (cupsFileGets(fp, line, sizeof(line)) != NULL)
   {
-    next = rules->next;
+   /*
+    * Skip blank lines and lines starting with a #...
+    */
 
-    if (rules->child != NULL)
-      delete_rules(rules->child);
+    DEBUG_puts(line);
 
-    free(rules);
-    rules = next;
+    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++ = 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++ = tolower(*lineptr++ & 255);
+
+    *temp = '\0';
+
+   /*
+    * Add the type and rules to the MIME database...
+    */
+
+    typeptr = mimeAddType(mime, super, type);
+    mimeAddTypeRule(typeptr, lineptr);
   }
+
+  cupsFileClose(fp);
 }
 
 
 /*
- * End of "$Id: mime.c 4613 2005-08-30 12:41:48Z mike $".
+ * End of "$Id: mime.c 6649 2007-07-11 21:46:42Z mike $".
  */