]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/type.c
Move debug printfs to internal usage only.
[thirdparty/cups.git] / scheduler / type.c
index 50d49d26a627b5dfb94f6d26937116b4b0fedef9..2cceeda58c8ed43dd6abc6c337aa0dc457aaf2e2 100644 (file)
@@ -1,49 +1,27 @@
 /*
- * "$Id: type.c 5052 2006-02-02 16:21:13Z mike $"
+ * MIME typing routines for CUPS.
  *
- *   MIME typing routines for the Common UNIX Printing System (CUPS).
+ * Copyright 2007-2016 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
- *   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
- *
- * Contents:
- *
- *   mimeAddType()      - Add a MIME type to a database.
- *   mimeAddTypeRule()  - Add a detection rule for a file type.
- *   mimeFileType()     - Determine the type of a file.
- *   mimeType()         - Lookup a file type.
- *   compare_types()    - Compare two MIME super/type names.
- *   checkrules()       - Check each rule in a list.
- *   patmatch()         - Pattern matching...
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
  */
 
 /*
  * Include necessary headers...
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
+#include <cups/string-private.h>
 #include <locale.h>
-
-#include <cups/string.h>
 #include "mime.h"
-#include <cups/debug.h>
+
+
+/*
+ * Debug macros that used to be private API...
+ */
+
+#define DEBUG_puts(x)
+#define DEBUG_printf(...)
 
 
 /*
@@ -63,10 +41,35 @@ typedef struct _mime_filebuf_s              /**** File buffer for MIME typing ****/
  * Local functions...
  */
 
-static int     compare_types(mime_type_t *t0, mime_type_t *t1);
-static int     checkrules(const char *filename, _mime_filebuf_t *fb,
-                          mime_magic_t *rules);
-static int     patmatch(const char *s, const char *pat);
+static int     mime_compare_types(mime_type_t *t0, mime_type_t *t1);
+static int     mime_check_rules(const char *filename, _mime_filebuf_t *fb,
+                                mime_magic_t *rules);
+static int     mime_patmatch(const char *s, const char *pat);
+
+
+/*
+ * Local globals...
+ */
+
+#ifdef MIME_DEBUG
+static const char * const debug_ops[] =
+               {                       /* Test names... */
+                 "NOP",                /* No operation */
+                 "AND",                /* Logical AND of all children */
+                 "OR",                 /* Logical OR of all children */
+                 "MATCH",              /* Filename match */
+                 "ASCII",              /* ASCII characters in range */
+                 "PRINTABLE",          /* Printable characters (32-255) */
+                 "STRING",             /* String matches */
+                 "CHAR",               /* Character/byte matches */
+                 "SHORT",              /* Short/16-bit word matches */
+                 "INT",                /* Integer/32-bit word matches */
+                 "LOCALE",             /* Current locale matches string */
+                 "CONTAINS",           /* File contains a string */
+                 "ISTRING",            /* Case-insensitive string matches */
+                 "REGEX"               /* Regular expression matches */
+               };
+#endif /* DEBUG */
 
 
 /*
@@ -79,41 +82,60 @@ mimeAddType(mime_t     *mime,               /* I - MIME database */
            const char *type)           /* I - Type name */
 {
   mime_type_t  *temp;                  /* New MIME type */
+  size_t       typelen;                /* Length of type name */
+
 
+  DEBUG_printf(("mimeAddType(mime=%p, super=\"%s\", type=\"%s\")", mime, super,
+                type));
 
  /*
   * Range check input...
   */
 
   if (!mime || !super || !type)
+  {
+    DEBUG_puts("1mimeAddType: Returning NULL (bad arguments).");
     return (NULL);
+  }
 
  /*
   * See if the type already exists; if so, return the existing type...
   */
 
   if ((temp = mimeType(mime, super, type)) != NULL)
+  {
+    DEBUG_printf(("1mimeAddType: Returning %p (existing).", temp));
     return (temp);
+  }
 
  /*
   * The type doesn't exist; add it...
   */
 
   if (!mime->types)
-    mime->types = cupsArrayNew((cups_array_func_t)compare_types, NULL);
+    mime->types = cupsArrayNew((cups_array_func_t)mime_compare_types, NULL);
 
   if (!mime->types)
+  {
+    DEBUG_puts("1mimeAddType: Returning NULL (no types).");
     return (NULL);
+  }
 
-  if ((temp = calloc(1, sizeof(mime_type_t) - MIME_MAX_TYPE +
-                        strlen(type) + 1)) == NULL)
+  typelen = strlen(type) + 1;
+
+  if ((temp = calloc(1, sizeof(mime_type_t) - MIME_MAX_TYPE + typelen)) == NULL)
+  {
+    DEBUG_puts("1mimeAddType: Returning NULL (out of memory).");
     return (NULL);
+  }
 
   strlcpy(temp->super, super, sizeof(temp->super));
-  strcpy(temp->type, type);            /* Safe: temp->type is allocated */
+  memcpy(temp->type, type, typelen);
+  temp->priority = 100;
 
   cupsArrayAdd(mime->types, temp);
 
+  DEBUG_printf(("1mimeAddType: Returning %p (new).", temp));
   return (temp);
 }
 
@@ -139,6 +161,9 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
                *current;               /* Current rule */
 
 
+  DEBUG_printf(("mimeAddTypeRule(mt=%p(%s/%s), rule=\"%s\")", mt,
+                mt ? mt->super : "???", mt ? mt->type : "???", rule));
+
  /*
   * Range check input...
   */
@@ -165,8 +190,6 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
   logic  = MIME_MAGIC_NOP;
   invert = 0;
 
-  DEBUG_printf(("%s/%s: %s\n", mt->super, mt->type, rule));
-
   while (*rule != '\0')
   {
     while (isspace(*rule & 255))
@@ -174,13 +197,13 @@ mimeAddTypeRule(mime_type_t *mt,  /* I - Type to add to */
 
     if (*rule == '(')
     {
-      DEBUG_puts("new parenthesis group");
+      DEBUG_puts("1mimeAddTypeRule: New parenthesis group");
       logic = MIME_MAGIC_NOP;
       rule ++;
     }
     else if (*rule == ')')
     {
-      DEBUG_puts("close paren...");
+      DEBUG_puts("1mimeAddTypeRule: Close paren...");
       if (current == NULL || current->parent == NULL)
         return (-1);
 
@@ -196,8 +219,7 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
     else if (*rule == '+' && current != NULL)
     {
       if (logic != MIME_MAGIC_AND &&
-          current != NULL && current->prev != NULL &&
-         current->prev->prev != NULL)
+          current != NULL && current->prev != NULL)
       {
        /*
         * OK, we have more than 1 rule in the current tree level...  Make a
@@ -216,11 +238,12 @@ mimeAddTypeRule(mime_type_t *mt,  /* I - Type to add to */
         current->prev   = NULL;
        current->parent = temp;
 
-        DEBUG_printf(("creating new AND group %p...\n", temp));
+        DEBUG_printf(("1mimeAddTypeRule: Creating new AND group %p.", temp));
       }
-      else
+      else if (current->parent)
       {
-        DEBUG_printf(("setting group %p op to AND...\n", current->parent));
+        DEBUG_printf(("1mimeAddTypeRule: Setting group %p op to AND.",
+                     current->parent));
         current->parent->op = MIME_MAGIC_AND;
       }
 
@@ -246,7 +269,8 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
          if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
            return (-1);
 
-          DEBUG_printf(("creating new AND group %p inside OR group\n", temp));
+          DEBUG_printf(("1mimeAddTypeRule: Creating new AND group %p inside OR "
+                       "group.", temp));
 
           while (current->prev != NULL)
          {
@@ -266,7 +290,7 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
          * This isn't the top rule, so go up one level...
          */
 
-          DEBUG_puts("going up one level");
+          DEBUG_puts("1mimeAddTypeRule: Going up one level.");
          current = current->parent;
        }
       }
@@ -276,7 +300,7 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
     }
     else if (*rule == '!')
     {
-      DEBUG_puts("NOT");
+      DEBUG_puts("1mimeAddTypeRule: NOT");
       invert = 1;
       rule ++;
     }
@@ -287,11 +311,10 @@ mimeAddTypeRule(mime_type_t *mt,  /* I - Type to add to */
       */
 
       ptr = name;
-      while (isalnum(*rule & 255) && (ptr - name) < (sizeof(name) - 1))
+      while (isalnum(*rule & 255) && (size_t)(ptr - name) < (sizeof(name) - 1))
         *ptr++ = *rule++;
 
-      *ptr       = '\0';
-      num_values = 0;
+      *ptr = '\0';
 
       if (*rule == '(')
       {
@@ -301,12 +324,12 @@ mimeAddTypeRule(mime_type_t *mt,  /* I - Type to add to */
 
        rule ++;
        for (num_values = 0;
-            num_values < (sizeof(value) / sizeof(value[0]));
+            num_values < (int)(sizeof(value) / sizeof(value[0]));
             num_values ++)
        {
          ptr = value[num_values];
 
-         while ((ptr - value[num_values]) < (sizeof(value[0]) - 1) &&
+         while ((size_t)(ptr - value[num_values]) < (sizeof(value[0]) - 1) &&
                 *rule != '\0' && *rule != ',' && *rule != ')')
          {
            if (isspace(*rule & 255))
@@ -327,7 +350,7 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
              quote = *rule++;
 
              while (*rule != '\0' && *rule != quote &&
-                    (ptr - value[num_values]) < (sizeof(value[0]) - 1))
+                    (size_t)(ptr - value[num_values]) < (sizeof(value[0]) - 1))
                *ptr++ = *rule++;
 
               if (*rule == quote)
@@ -340,14 +363,14 @@ mimeAddTypeRule(mime_type_t *mt,  /* I - Type to add to */
              rule ++;
 
              while (*rule != '>' && *rule != '\0' &&
-                    (ptr - value[num_values]) < (sizeof(value[0]) - 1))
+                    (size_t)(ptr - value[num_values]) < (sizeof(value[0]) - 1))
              {
                if (isxdigit(rule[0] & 255) && isxdigit(rule[1] & 255))
                {
                  if (isdigit(*rule))
-                   *ptr = (*rule++ - '0') << 4;
+                   *ptr = (char)((*rule++ - '0') << 4);
                  else
-                   *ptr = (tolower(*rule++) - 'a' + 10) << 4;
+                   *ptr = (char)((tolower(*rule++) - 'a' + 10) << 4);
 
                  if (isdigit(*rule))
                    *ptr++ |= *rule++ - '0';
@@ -371,7 +394,10 @@ mimeAddTypeRule(mime_type_t *mt,   /* I - Type to add to */
          length[num_values] = ptr - value[num_values];
 
           if (*rule != ',')
+         {
+           num_values ++;
            break;
+         }
 
           rule ++;
        }
@@ -391,6 +417,8 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
          op = MIME_MAGIC_ASCII;
        else if (!strcmp(name, "printable"))
          op = MIME_MAGIC_PRINTABLE;
+       else if (!strcmp(name, "regex"))
+         op = MIME_MAGIC_REGEX;
        else if (!strcmp(name, "string"))
          op = MIME_MAGIC_STRING;
        else if (!strcmp(name, "istring"))
@@ -405,6 +433,11 @@ mimeAddTypeRule(mime_type_t *mt,   /* I - Type to add to */
          op = MIME_MAGIC_LOCALE;
        else if (!strcmp(name, "contains"))
          op = MIME_MAGIC_CONTAINS;
+       else if (!strcmp(name, "priority") && num_values == 1)
+       {
+         mt->priority = atoi(value[0]);
+         continue;
+       }
        else
          return (-1);
       }
@@ -415,8 +448,7 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
        */
 
        snprintf(value[0], sizeof(value[0]), "*.%s", name);
-       length[0]  = strlen(value[0]);
-       num_values = 1;
+       length[0]  = (int)strlen(value[0]);
        op         = MIME_MAGIC_MATCH;
       }
 
@@ -427,7 +459,7 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
       if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
        return (-1);
 
-      temp->invert = invert;
+      temp->invert = (short)invert;
       if (current != NULL)
       {
        temp->parent  = current->parent;
@@ -444,7 +476,8 @@ mimeAddTypeRule(mime_type_t *mt,    /* I - Type to add to */
         * Add parenthetical grouping...
        */
 
-        DEBUG_printf(("making new OR group %p for parenthesis...\n", temp));
+        DEBUG_printf(("1mimeAddTypeRule: Making new OR group %p for "
+                     "parenthesis.", temp));
 
         temp->op = MIME_MAGIC_OR;
 
@@ -452,28 +485,31 @@ mimeAddTypeRule(mime_type_t *mt,  /* I - Type to add to */
          return (-1);
 
        temp->child->parent = temp;
+       temp->child->invert = temp->invert;
+       temp->invert        = 0;
 
        temp  = temp->child;
         logic = MIME_MAGIC_OR;
       }
 
-      DEBUG_printf(("adding %p: %s, op = %d, logic = %d, invert = %d\n",
-                    temp, name, op, logic, invert));
+      DEBUG_printf(("1mimeAddTypeRule: Adding %p: %s, op=MIME_MAGIC_%s(%d), "
+                   "logic=MIME_MAGIC_%s, invert=%d.", temp, name,
+                   debug_ops[op], op, debug_ops[logic], invert));
 
      /*
       * Fill in data for the rule...
       */
 
       current  = temp;
-      temp->op = op;
+      temp->op = (short)op;
       invert   = 0;
 
       switch (op)
       {
         case MIME_MAGIC_MATCH :
-           if (length[0] > (sizeof(temp->value.matchv) - 1))
+           if ((size_t)length[0] > (sizeof(temp->value.matchv) - 1))
              return (-1);
-           strcpy(temp->value.matchv, value[0]);
+           strlcpy(temp->value.matchv, value[0], sizeof(temp->value.matchv));
            break;
        case MIME_MAGIC_ASCII :
        case MIME_MAGIC_PRINTABLE :
@@ -482,42 +518,51 @@ mimeAddTypeRule(mime_type_t *mt,  /* I - Type to add to */
            if (temp->length > MIME_MAX_BUFFER)
              temp->length = MIME_MAX_BUFFER;
            break;
+       case MIME_MAGIC_REGEX :
+           temp->offset = strtol(value[0], NULL, 0);
+           temp->length = MIME_MAX_BUFFER;
+           if (regcomp(&(temp->value.rev), value[1], REG_NOSUB | REG_EXTENDED))
+             return (-1);
+           break;
        case MIME_MAGIC_STRING :
        case MIME_MAGIC_ISTRING :
            temp->offset = strtol(value[0], NULL, 0);
-           if (length[1] > sizeof(temp->value.stringv))
+           if ((size_t)length[1] > sizeof(temp->value.stringv))
              return (-1);
            temp->length = length[1];
-           memcpy(temp->value.stringv, value[1], length[1]);
+           memcpy(temp->value.stringv, value[1], (size_t)length[1]);
            break;
        case MIME_MAGIC_CHAR :
            temp->offset = strtol(value[0], NULL, 0);
            if (length[1] == 1)
-             temp->value.charv = value[1][0];
+             temp->value.charv = (unsigned char)value[1][0];
            else
-             temp->value.charv = (char)strtol(value[1], NULL, 0);
+             temp->value.charv = (unsigned char)strtol(value[1], NULL, 0);
+
+           DEBUG_printf(("1mimeAddTypeRule: CHAR(%d,0x%02x)", temp->offset,
+                         temp->value.charv));
            break;
        case MIME_MAGIC_SHORT :
            temp->offset       = strtol(value[0], NULL, 0);
-           temp->value.shortv = (short)strtol(value[1], NULL, 0);
+           temp->value.shortv = (unsigned short)strtol(value[1], NULL, 0);
            break;
        case MIME_MAGIC_INT :
            temp->offset     = strtol(value[0], NULL, 0);
-           temp->value.intv = (int)strtol(value[1], NULL, 0);
+           temp->value.intv = (unsigned)strtol(value[1], NULL, 0);
            break;
        case MIME_MAGIC_LOCALE :
-           if (length[0] > (sizeof(temp->value.localev) - 1))
+           if ((size_t)length[0] > (sizeof(temp->value.localev) - 1))
              return (-1);
 
-           strcpy(temp->value.localev, value[0]);
+           strlcpy(temp->value.localev, value[0], sizeof(temp->value.localev));
            break;
        case MIME_MAGIC_CONTAINS :
            temp->offset = strtol(value[0], NULL, 0);
            temp->region = strtol(value[1], NULL, 0);
-           if (length[2] > sizeof(temp->value.stringv))
+           if ((size_t)length[2] > sizeof(temp->value.stringv))
              return (-1);
            temp->length = length[2];
-           memcpy(temp->value.stringv, value[2], length[2]);
+           memcpy(temp->value.stringv, value[2], (size_t)length[2]);
            break;
       }
     }
@@ -541,31 +586,52 @@ mimeFileType(mime_t     *mime,            /* I - MIME database */
 {
   _mime_filebuf_t      fb;             /* File buffer */
   const char           *base;          /* Base filename of file */
-  mime_type_t          *type;          /* File type */
+  mime_type_t          *type,          /* File type */
+                       *best;          /* Best match */
 
 
-  DEBUG_printf(("mimeFileType(mime=%p, pathname=\"%s\", basename=\"%s\", "
-                "compression=%p)\n",
-                mime, pathname ? pathname : "(nil)",
-               filename ? filename : "(nil)",
-               basenamecompression));
+  DEBUG_printf(("mimeFileType(mime=%p, pathname=\"%s\", filename=\"%s\", "
+                "compression=%p)", mime, pathname, filename, compression));
 
  /*
   * Range check input parameters...
   */
 
   if (!mime || !pathname)
+  {
+    DEBUG_puts("1mimeFileType: Returning NULL.");
     return (NULL);
+  }
 
  /*
   * Try to open the file...
   */
 
   if ((fb.fp = cupsFileOpen(pathname, "r")) == NULL)
+  {
+    DEBUG_printf(("1mimeFileType: Unable to open \"%s\": %s", pathname,
+                  strerror(errno)));
+    DEBUG_puts("1mimeFileType: Returning NULL.");
     return (NULL);
+  }
+
+ /*
+  * Then preload the first MIME_MAX_BUFFER bytes of the file into the file
+  * buffer, returning an error if we can't read anything...
+  */
+
+  fb.offset = 0;
+  fb.length = (int)cupsFileRead(fb.fp, (char *)fb.buffer, MIME_MAX_BUFFER);
 
-  fb.offset = -1;
-  fb.length = 0;
+  if (fb.length <= 0)
+  {
+    DEBUG_printf(("1mimeFileType: Unable to read from \"%s\": %s", pathname, strerror(errno)));
+    DEBUG_puts("1mimeFileType: Returning NULL.");
+
+    cupsFileClose(fb.fp);
+
+    return (NULL);
+  }
 
  /*
   * Figure out the base filename (without directory portion)...
@@ -576,33 +642,41 @@ mimeFileType(mime_t     *mime,            /* I - MIME database */
     if ((base = strrchr(filename, '/')) != NULL)
       base ++;
     else
-      filename = filename;
+      base = filename;
   }
   else if ((base = strrchr(pathname, '/')) != NULL)
     base ++;
   else
-    filename = pathname;
+    base = pathname;
 
  /*
   * Then check it against all known types...
   */
 
-  for (type = (mime_type_t *)cupsArrayFirst(mime->types);
+  for (type = (mime_type_t *)cupsArrayFirst(mime->types), best = NULL;
        type;
        type = (mime_type_t *)cupsArrayNext(mime->types))
-    if (checkrules(base, &fb, type->rules))
-      break;
+    if (mime_check_rules(base, &fb, type->rules))
+    {
+      if (!best || type->priority > best->priority)
+        best = type;
+    }
 
  /*
   * Finally, close the file and return a match (if any)...
   */
 
   if (compression)
+  {
     *compression = cupsFileCompression(fb.fp);
+    DEBUG_printf(("1mimeFileType: *compression=%d", *compression));
+  }
 
   cupsFileClose(fb.fp);
 
-  return (type);
+  DEBUG_printf(("1mimeFileType: Returning %p(%s/%s).", best,
+                best ? best->super : "???", best ? best->type : "???"));
+  return (best);
 }
 
 
@@ -615,15 +689,22 @@ mimeType(mime_t     *mime,                /* I - MIME database */
          const char *super,            /* I - Super-type name */
         const char *type)              /* I - Type name */
 {
-  mime_type_t  key;                    /* MIME type search key*/
+  mime_type_t  key,                    /* MIME type search key */
+               *mt;                    /* Matching type */
 
 
+  DEBUG_printf(("mimeType(mime=%p, super=\"%s\", type=\"%s\")", mime, super,
+                type));
+
  /*
   * Range check input...
   */
 
   if (!mime || !super || !type)
+  {
+    DEBUG_puts("1mimeType: Returning NULL.");
     return (NULL);
+  }
 
  /*
   * Lookup the type in the array...
@@ -632,66 +713,51 @@ mimeType(mime_t     *mime,                /* I - MIME database */
   strlcpy(key.super, super, sizeof(key.super));
   strlcpy(key.type, type, sizeof(key.type));
 
-  return ((mime_type_t *)cupsArrayFind(mime->types, &key));
+  mt = (mime_type_t *)cupsArrayFind(mime->types, &key);
+  DEBUG_printf(("1mimeType: Returning %p.", mt));
+  return (mt);
 }
 
 
 /*
- * 'compare_types()' - Compare two MIME super/type names.
+ * 'mime_compare_types()' - Compare two MIME super/type names.
  */
 
 static int                             /* O - Result of comparison */
-compare_types(mime_type_t *t0,         /* I - First type */
-              mime_type_t *t1)         /* I - Second type */
+mime_compare_types(mime_type_t *t0,    /* I - First type */
+                   mime_type_t *t1)    /* I - Second type */
 {
   int  i;                              /* Result of comparison */
 
 
-  if ((i = strcmp(t0->super, t1->super)) == 0)
-    i = strcmp(t0->type, t1->type);
+  if ((i = _cups_strcasecmp(t0->super, t1->super)) == 0)
+    i = _cups_strcasecmp(t0->type, t1->type);
 
   return (i);
 }
 
 
 /*
- * 'checkrules()' - Check each rule in a list.
+ * 'mime_check_rules()' - Check each rule in a list.
  */
 
 static int                             /* O - 1 if match, 0 if no match */
-checkrules(const char      *filename,  /* I - Filename */
-           _mime_filebuf_t *fb,                /* I - File to check */
-           mime_magic_t    *rules)     /* I - Rules to check */
+mime_check_rules(
+    const char      *filename,         /* I - Filename */
+    _mime_filebuf_t *fb,               /* I - File to check */
+    mime_magic_t    *rules)            /* I - Rules to check */
 {
   int          n;                      /* Looping var */
   int          region;                 /* Region to look at */
   int          logic,                  /* Logic to apply */
-               result,                 /* Result of test */
-               intv;                   /* Integer value */
+               result;                 /* Result of test */
+  unsigned     intv;                   /* Integer value */
   short                shortv;                 /* Short value */
   unsigned char        *bufptr;                /* Pointer into buffer */
-#ifdef DEBUG
-  const char   * const debug_tests[] = /* Test names... */
-               {
-                 "NOP",                /* No operation */
-                 "AND",                /* Logical AND of all children */
-                 "OR",                 /* Logical OR of all children */
-                 "MATCH",              /* Filename match */
-                 "ASCII",              /* ASCII characters in range */
-                 "PRINTABLE",          /* Printable characters (32-255) */
-                 "STRING",             /* String matches */
-                 "CHAR",               /* Character/byte matches */
-                 "SHORT",              /* Short/16-bit word matches */
-                 "INT",                /* Integer/32-bit word matches */
-                 "LOCALE"              /* Current locale matches string */
-                 "CONTAINS"            /* File contains a string */
-                 "ISTRING"             /* Case-insensitive string matches */
-               };
-#endif /* DEBUG */
 
 
-  DEBUG_printf(("checkrules(filename=\"%s\", fp=%p, rules=%p)\n", filename,
-                fp, rules));
+  DEBUG_printf(("4mime_check_rules(filename=\"%s\", fb=%p, rules=%p)", filename,
+                fb, rules));
 
   if (rules == NULL)
     return (0);
@@ -712,7 +778,7 @@ checkrules(const char      *filename,       /* I - Filename */
     switch (rules->op)
     {
       case MIME_MAGIC_MATCH :
-          result = patmatch(filename, rules->value.matchv);
+          result = mime_patmatch(filename, rules->value.matchv);
          break;
 
       case MIME_MAGIC_ASCII :
@@ -731,6 +797,8 @@ checkrules(const char      *filename,       /* I - Filename */
            fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
                                      sizeof(fb->buffer));
            fb->offset = rules->offset;
+
+           DEBUG_printf(("4mime_check_rules: MIME_MAGIC_ASCII fb->length=%d", fb->length));
          }
 
          /*
@@ -773,6 +841,8 @@ checkrules(const char      *filename,       /* I - Filename */
            fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
                                      sizeof(fb->buffer));
            fb->offset = rules->offset;
+
+           DEBUG_printf(("4mime_check_rules: MIME_MAGIC_PRINTABLE fb->length=%d", fb->length));
          }
 
          /*
@@ -801,8 +871,54 @@ checkrules(const char      *filename,      /* I - Filename */
          result = (n == 0);
          break;
 
+      case MIME_MAGIC_REGEX :
+          DEBUG_printf(("5mime_check_rules: regex(%d, \"%s\")", rules->offset,
+                       rules->value.stringv));
+
+         /*
+         * Load the buffer if necessary...
+         */
+
+          if (fb->offset < 0 || rules->offset < fb->offset ||
+             (rules->offset + rules->length) > (fb->offset + fb->length))
+         {
+          /*
+           * Reload file buffer...
+           */
+
+            cupsFileSeek(fb->fp, rules->offset);
+           fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
+                                     sizeof(fb->buffer));
+           fb->offset = rules->offset;
+
+           DEBUG_printf(("4mime_check_rules: MIME_MAGIC_REGEX fb->length=%d", fb->length));
+
+            DEBUG_printf(("5mime_check_rules: loaded %d byte fb->buffer at %d, starts "
+                         "with \"%c%c%c%c\".",
+                         fb->length, fb->offset, fb->buffer[0], fb->buffer[1],
+                         fb->buffer[2], fb->buffer[3]));
+         }
+
+         /*
+         * Compare the buffer against the string.  If the file is too
+         * short then don't compare - it can't match...
+         */
+
+          if (fb->length > 0)
+          {
+            char temp[MIME_MAX_BUFFER + 1];
+                                       /* Temporary buffer */
+
+            memcpy(temp, fb->buffer, (size_t)fb->length);
+            temp[fb->length] = '\0';
+            result = !regexec(&(rules->value.rev), temp, 0, NULL, 0);
+          }
+
+          DEBUG_printf(("5mime_check_rules: result=%d", result));
+         break;
+
       case MIME_MAGIC_STRING :
-          DEBUG_printf(("    string(%d, \"%s\")\n", rules->offset,
+          DEBUG_printf(("5mime_check_rules: string(%d, \"%s\")", rules->offset,
                        rules->value.stringv));
 
          /*
@@ -821,8 +937,10 @@ checkrules(const char      *filename,      /* I - Filename */
                                      sizeof(fb->buffer));
            fb->offset = rules->offset;
 
-            DEBUG_printf(("        loaded %d byte fb->buffer at %d, starts "
-                         "with \"%c%c%c%c\"...\n",
+           DEBUG_printf(("4mime_check_rules: MIME_MAGIC_STRING fb->length=%d", fb->length));
+
+            DEBUG_printf(("5mime_check_rules: loaded %d byte fb->buffer at %d, starts "
+                         "with \"%c%c%c%c\".",
                          fb->length, fb->offset, fb->buffer[0], fb->buffer[1],
                          fb->buffer[2], fb->buffer[3]));
          }
@@ -835,9 +953,8 @@ checkrules(const char      *filename,       /* I - Filename */
          if ((rules->offset + rules->length) > (fb->offset + fb->length))
            result = 0;
          else
-            result = (memcmp(fb->buffer + rules->offset - fb->offset,
-                            rules->value.stringv, rules->length) == 0);
-          DEBUG_printf(("    result=%d\n", result));
+            result = !memcmp(fb->buffer + rules->offset - fb->offset, rules->value.stringv, (size_t)rules->length);
+          DEBUG_printf(("5mime_check_rules: result=%d", result));
          break;
 
       case MIME_MAGIC_ISTRING :
@@ -856,6 +973,8 @@ checkrules(const char      *filename,       /* I - Filename */
            fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
                                      sizeof(fb->buffer));
            fb->offset = rules->offset;
+
+           DEBUG_printf(("4mime_check_rules: MIME_MAGIC_ISTRING fb->length=%d", fb->length));
          }
 
          /*
@@ -866,9 +985,7 @@ checkrules(const char      *filename,       /* I - Filename */
          if ((rules->offset + rules->length) > (fb->offset + fb->length))
            result = 0;
          else
-            result = (strncasecmp((char *)fb->buffer + rules->offset -
-                                     fb->offset,
-                                 rules->value.stringv, rules->length) == 0);
+            result = !_cups_strncasecmp((char *)fb->buffer + rules->offset - fb->offset, rules->value.stringv, (size_t)rules->length);
          break;
 
       case MIME_MAGIC_CHAR :
@@ -886,6 +1003,8 @@ checkrules(const char      *filename,      /* I - Filename */
            fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
                                      sizeof(fb->buffer));
            fb->offset = rules->offset;
+
+           DEBUG_printf(("4mime_check_rules: MIME_MAGIC_CHAR fb->length=%d", fb->length));
          }
 
         /*
@@ -916,6 +1035,8 @@ checkrules(const char      *filename,      /* I - Filename */
            fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
                                      sizeof(fb->buffer));
            fb->offset = rules->offset;
+
+           DEBUG_printf(("4mime_check_rules: MIME_MAGIC_SHORT fb->length=%d", fb->length));
          }
 
         /*
@@ -928,7 +1049,7 @@ checkrules(const char      *filename,      /* I - Filename */
          else
          {
            bufptr = fb->buffer + rules->offset - fb->offset;
-           shortv = (bufptr[0] << 8) | bufptr[1];
+           shortv = (short)((bufptr[0] << 8) | bufptr[1]);
            result = (shortv == rules->value.shortv);
          }
          break;
@@ -949,6 +1070,8 @@ checkrules(const char      *filename,      /* I - Filename */
            fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
                                      sizeof(fb->buffer));
            fb->offset = rules->offset;
+
+           DEBUG_printf(("4mime_check_rules: MIME_MAGIC_INT fb->length=%d", fb->length));
          }
 
         /*
@@ -961,19 +1084,16 @@ checkrules(const char      *filename,    /* I - Filename */
          else
          {
            bufptr = fb->buffer + rules->offset - fb->offset;
-           intv   = (((((bufptr[0] << 8) | bufptr[1]) << 8) |
-                      bufptr[2]) << 8) | bufptr[3];
+           intv   = (unsigned)((((((bufptr[0] << 8) | bufptr[1]) << 8) | bufptr[2]) << 8) | bufptr[3]);
            result = (intv == rules->value.intv);
          }
          break;
 
       case MIME_MAGIC_LOCALE :
-#if defined(WIN32) || defined(__EMX__) || defined(__APPLE__)
-          result = (strcmp(rules->value.localev,
-                          setlocale(LC_ALL, "")) == 0);
+#if defined(_WIN32) || defined(__EMX__) || defined(__APPLE__)
+          result = !strcmp(rules->value.localev, setlocale(LC_ALL, ""));
 #else
-          result = (strcmp(rules->value.localev,
-                          setlocale(LC_MESSAGES, "")) == 0);
+          result = !strcmp(rules->value.localev, setlocale(LC_MESSAGES, ""));
 #endif /* __APPLE__ */
          break;
 
@@ -993,6 +1113,8 @@ checkrules(const char      *filename,      /* I - Filename */
            fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
                                      sizeof(fb->buffer));
            fb->offset = rules->offset;
+
+           DEBUG_printf(("4mime_check_rules: MIME_MAGIC_CONTAINS fb->length=%d", fb->length));
          }
 
          /*
@@ -1010,16 +1132,14 @@ checkrules(const char      *filename,   /* I - Filename */
              region = fb->length - rules->length;
 
            for (n = 0; n < region; n ++)
-             if ((result = (memcmp(fb->buffer + rules->offset - fb->offset + n,
-                                   rules->value.stringv,
-                                   rules->length) == 0)) != 0)
+             if ((result = (memcmp(fb->buffer + rules->offset - fb->offset + n, rules->value.stringv, (size_t)rules->length) == 0)) != 0)
                break;
           }
          break;
 
       default :
           if (rules->child != NULL)
-           result = checkrules(filename, fb, rules->child);
+           result = mime_check_rules(filename, fb, rules->child);
          else
            result = 0;
          break;
@@ -1038,8 +1158,8 @@ checkrules(const char      *filename,     /* I - Filename */
     * the the rule set is false...
     */
 
-    DEBUG_printf(("    result of test %p (MIME_MAGIC_%s) is %d\n", rules,
-                  debug_tests[rules->op], result));
+    DEBUG_printf(("5mime_check_rules: result of test %p (MIME_MAGIC_%s) is %d",
+                  rules, debug_ops[rules->op], result));
 
     if ((result && logic == MIME_MAGIC_OR) ||
         (!result && logic == MIME_MAGIC_AND))
@@ -1057,12 +1177,12 @@ checkrules(const char      *filename,   /* I - Filename */
 
 
 /*
- * 'patmatch()' - Pattern matching...
+ * 'mime_patmatch()' - Pattern matching.
  */
 
-static int                     /* O - 1 if match, 0 if no match */
-patmatch(const char *s,                /* I - String to match against */
-         const char *pat)      /* I - Pattern to match against */
+static int                             /* O - 1 if match, 0 if no match */
+mime_patmatch(const char *s,           /* I - String to match against */
+              const char *pat)         /* I - Pattern to match against */
 {
  /*
   * Range check the input...
@@ -1094,7 +1214,7 @@ patmatch(const char *s,           /* I - String to match against */
 
       while (*s != '\0')
       {
-        if (patmatch(s, pat))
+        if (mime_patmatch(s, pat))
          return (1);
 
        s ++;
@@ -1158,8 +1278,3 @@ patmatch(const char *s,           /* I - String to match against */
 
   return (*s == *pat);
 }
-
-
-/*
- * End of "$Id: type.c 5052 2006-02-02 16:21:13Z mike $".
- */