]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/type.c
1fdbaf58373c4894bfa6d98a5c5e1ff0fe35ab91
2 * MIME typing routines for CUPS.
4 * Copyright © 2020-2024 by OpenPrinting.
5 * Copyright © 2007-2019 by Apple Inc.
6 * Copyright © 1997-2006 by Easy Software Products, all rights reserved.
8 * Licensed under Apache License v2.0. See the file "LICENSE" for more
13 * Include necessary headers...
16 #include <cups/cups.h>
17 #include <cups/string-private.h>
23 * Debug macros that used to be private API...
27 #define DEBUG_printf(...)
34 typedef struct _mime_filebuf_s
/**** File buffer for MIME typing ****/
36 cups_file_t
*fp
; /* File pointer */
37 int offset
, /* Offset in file */
38 length
; /* Length of buffered data */
39 unsigned char buffer
[MIME_MAX_BUFFER
];/* Buffered data */
47 static int mime_compare_types(mime_type_t
*t0
, mime_type_t
*t1
, void *data
);
48 static int mime_check_rules(const char *filename
, _mime_filebuf_t
*fb
,
50 static int mime_patmatch(const char *s
, const char *pat
);
58 static const char * const debug_ops
[] =
60 "NOP", /* No operation */
61 "AND", /* Logical AND of all children */
62 "OR", /* Logical OR of all children */
63 "MATCH", /* Filename match */
64 "ASCII", /* ASCII characters in range */
65 "PRINTABLE", /* Printable characters (32-255) */
66 "STRING", /* String matches */
67 "CHAR", /* Character/byte matches */
68 "SHORT", /* Short/16-bit word matches */
69 "INT", /* Integer/32-bit word matches */
70 "LOCALE", /* Current locale matches string */
71 "CONTAINS", /* File contains a string */
72 "ISTRING", /* Case-insensitive string matches */
73 "REGEX" /* Regular expression matches */
79 * 'mimeAddType()' - Add a MIME type to a database.
82 mime_type_t
* /* O - New (or existing) MIME type */
83 mimeAddType(mime_t
*mime
, /* I - MIME database */
84 const char *super
, /* I - Super-type name */
85 const char *type
) /* I - Type name */
87 mime_type_t
*temp
; /* New MIME type */
88 size_t typelen
; /* Length of type name */
91 DEBUG_printf(("mimeAddType(mime=%p, super=\"%s\", type=\"%s\")", mime
, super
,
95 * Range check input...
98 if (!mime
|| !super
|| !type
)
100 DEBUG_puts("1mimeAddType: Returning NULL (bad arguments).");
105 * See if the type already exists; if so, return the existing type...
108 if ((temp
= mimeType(mime
, super
, type
)) != NULL
)
110 DEBUG_printf("1mimeAddType: Returning %p (existing).", temp
);
115 * The type doesn't exist; add it...
119 mime
->types
= cupsArrayNew((cups_array_func_t
)mime_compare_types
, NULL
);
123 DEBUG_puts("1mimeAddType: Returning NULL (no types).");
127 typelen
= strlen(type
) + 1;
129 if ((temp
= calloc(1, sizeof(mime_type_t
) - MIME_MAX_TYPE
+ typelen
)) == NULL
)
131 DEBUG_puts("1mimeAddType: Returning NULL (out of memory).");
135 cupsCopyString(temp
->super
, super
, sizeof(temp
->super
));
136 memcpy(temp
->type
, type
, typelen
);
137 temp
->priority
= 100;
139 cupsArrayAdd(mime
->types
, temp
);
141 DEBUG_printf("1mimeAddType: Returning %p (new).", temp
);
147 * 'mimeAddTypeRule()' - Add a detection rule for a file type.
150 int /* O - 0 on success, -1 on failure */
151 mimeAddTypeRule(mime_type_t
*mt
, /* I - Type to add to */
152 const char *rule
) /* I - Rule to add */
154 int num_values
, /* Number of values seen */
155 op
, /* Operation code */
156 logic
, /* Logic for next rule */
157 invert
; /* Invert following rule? */
158 char name
[255], /* Name in rule string */
159 value
[3][255], /* Value in rule string */
160 *ptr
, /* Position in name or value */
161 quote
; /* Quote character */
162 int length
[3]; /* Length of each parameter */
163 mime_magic_t
*temp
, /* New rule */
164 *current
; /* Current rule */
167 DEBUG_printf(("mimeAddTypeRule(mt=%p(%s/%s), rule=\"%s\")", mt
,
168 mt
? mt
->super
: "???", mt
? mt
->type
: "???", rule
));
171 * Range check input...
178 * Find the last rule in the top-level of the rules tree.
181 for (current
= mt
->rules
; current
; current
= current
->next
)
186 * Parse the rules string. Most rules are either a file extension or a
187 * comparison function:
190 * function(parameters)
193 logic
= MIME_MAGIC_NOP
;
196 while (*rule
!= '\0')
198 while (isspace(*rule
& 255))
203 DEBUG_puts("1mimeAddTypeRule: New parenthesis group");
204 logic
= MIME_MAGIC_NOP
;
207 else if (*rule
== ')')
209 DEBUG_puts("1mimeAddTypeRule: Close paren...");
210 if (current
== NULL
|| current
->parent
== NULL
)
213 current
= current
->parent
;
215 if (current
->parent
== NULL
)
216 logic
= MIME_MAGIC_OR
;
218 logic
= current
->parent
->op
;
222 else if (*rule
== '+' && current
!= NULL
)
224 if (logic
!= MIME_MAGIC_AND
&&
225 current
->prev
!= NULL
)
228 * OK, we have more than 1 rule in the current tree level... Make a
229 * new group tree and move the previous rule to it...
232 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
235 temp
->op
= MIME_MAGIC_AND
;
236 temp
->child
= current
;
237 temp
->parent
= current
->parent
;
238 current
->prev
->next
= temp
;
239 temp
->prev
= current
->prev
;
241 current
->prev
= NULL
;
242 current
->parent
= temp
;
244 DEBUG_printf("1mimeAddTypeRule: Creating new AND group %p.", temp
);
246 else if (current
->parent
)
248 DEBUG_printf(("1mimeAddTypeRule: Setting group %p op to AND.",
250 current
->parent
->op
= MIME_MAGIC_AND
;
253 logic
= MIME_MAGIC_AND
;
256 else if (*rule
== ',')
258 if (logic
!= MIME_MAGIC_OR
&& current
!= NULL
)
261 * OK, we have two possibilities; either this is the top-level rule or
262 * we have a bunch of AND rules at this level.
265 if (current
->parent
== NULL
)
268 * This is the top-level rule; we have to move *all* of the AND rules
269 * down a level, as AND has precedence over OR.
272 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
275 DEBUG_printf(("1mimeAddTypeRule: Creating new AND group %p inside OR "
278 while (current
->prev
!= NULL
)
280 current
->parent
= temp
;
281 current
= current
->prev
;
284 current
->parent
= temp
;
285 temp
->op
= MIME_MAGIC_AND
;
286 temp
->child
= current
;
288 mt
->rules
= current
= temp
;
293 * This isn't the top rule, so go up one level...
296 DEBUG_puts("1mimeAddTypeRule: Going up one level.");
297 current
= current
->parent
;
301 logic
= MIME_MAGIC_OR
;
304 else if (*rule
== '!')
306 DEBUG_puts("1mimeAddTypeRule: NOT");
310 else if (isalnum(*rule
& 255))
313 * Read an extension name or a function...
317 while (isalnum(*rule
& 255) && (size_t)(ptr
- name
) < (sizeof(name
) - 1))
325 * Read function parameters...
330 num_values
< (int)(sizeof(value
) / sizeof(value
[0]));
333 ptr
= value
[num_values
];
335 while ((size_t)(ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1) &&
336 *rule
!= '\0' && *rule
!= ',' && *rule
!= ')')
338 if (isspace(*rule
& 255))
341 * Ignore whitespace...
347 else if (*rule
== '\"' || *rule
== '\'')
350 * Copy quoted strings literally...
355 while (*rule
!= '\0' && *rule
!= quote
&&
356 (size_t)(ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1))
364 else if (*rule
== '<')
368 while (*rule
!= '>' && *rule
!= '\0' &&
369 (size_t)(ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1))
371 if (isxdigit(rule
[0] & 255) && isxdigit(rule
[1] & 255))
374 *ptr
= (char)((*rule
++ - '0') << 4);
376 *ptr
= (char)((tolower(*rule
++) - 'a' + 10) << 4);
379 *ptr
++ |= *rule
++ - '0';
381 *ptr
++ |= tolower(*rule
++) - 'a' + 10;
397 length
[num_values
] = ptr
- value
[num_values
];
414 * Figure out the function...
417 if (!strcmp(name
, "match"))
418 op
= MIME_MAGIC_MATCH
;
419 else if (!strcmp(name
, "ascii"))
420 op
= MIME_MAGIC_ASCII
;
421 else if (!strcmp(name
, "printable"))
422 op
= MIME_MAGIC_PRINTABLE
;
423 else if (!strcmp(name
, "regex"))
424 op
= MIME_MAGIC_REGEX
;
425 else if (!strcmp(name
, "string"))
426 op
= MIME_MAGIC_STRING
;
427 else if (!strcmp(name
, "istring"))
428 op
= MIME_MAGIC_ISTRING
;
429 else if (!strcmp(name
, "char"))
430 op
= MIME_MAGIC_CHAR
;
431 else if (!strcmp(name
, "short"))
432 op
= MIME_MAGIC_SHORT
;
433 else if (!strcmp(name
, "int"))
435 else if (!strcmp(name
, "locale"))
436 op
= MIME_MAGIC_LOCALE
;
437 else if (!strcmp(name
, "contains"))
438 op
= MIME_MAGIC_CONTAINS
;
439 else if (!strcmp(name
, "priority") && num_values
== 1)
441 mt
->priority
= atoi(value
[0]);
450 * This is just a filename match on the extension...
453 snprintf(value
[0], sizeof(value
[0]), "*.%s", name
);
454 length
[0] = (int)strlen(value
[0]);
455 op
= MIME_MAGIC_MATCH
;
460 * Add a rule for this operation.
463 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
466 temp
->invert
= (short)invert
;
469 temp
->parent
= current
->parent
;
470 current
->next
= temp
;
475 temp
->prev
= current
;
477 if (logic
== MIME_MAGIC_NOP
)
480 * Add parenthetical grouping...
483 DEBUG_printf(("1mimeAddTypeRule: Making new OR group %p for "
484 "parenthesis.", temp
));
486 temp
->op
= MIME_MAGIC_OR
;
488 if ((temp
->child
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
491 temp
->child
->parent
= temp
;
492 temp
->child
->invert
= temp
->invert
;
496 logic
= MIME_MAGIC_OR
;
499 DEBUG_printf(("1mimeAddTypeRule: Adding %p: %s, op=MIME_MAGIC_%s(%d), "
500 "logic=MIME_MAGIC_%s, invert=%d.", temp
, name
,
501 debug_ops
[op
], op
, debug_ops
[logic
], invert
));
504 * Fill in data for the rule...
508 temp
->op
= (short)op
;
513 case MIME_MAGIC_MATCH
:
514 if ((size_t)length
[0] > (sizeof(temp
->value
.matchv
) - 1))
516 cupsCopyString(temp
->value
.matchv
, value
[0], sizeof(temp
->value
.matchv
));
518 case MIME_MAGIC_ASCII
:
519 case MIME_MAGIC_PRINTABLE
:
520 temp
->offset
= strtol(value
[0], NULL
, 0);
521 temp
->length
= strtol(value
[1], NULL
, 0);
522 if (temp
->length
> MIME_MAX_BUFFER
)
523 temp
->length
= MIME_MAX_BUFFER
;
525 case MIME_MAGIC_REGEX
:
526 temp
->offset
= strtol(value
[0], NULL
, 0);
527 temp
->length
= MIME_MAX_BUFFER
;
528 if (regcomp(&(temp
->value
.rev
), value
[1], REG_NOSUB
| REG_EXTENDED
))
531 case MIME_MAGIC_STRING
:
532 case MIME_MAGIC_ISTRING
:
533 temp
->offset
= strtol(value
[0], NULL
, 0);
534 if (num_values
< 2 || (size_t)length
[1] > sizeof(temp
->value
.stringv
))
536 temp
->length
= length
[1];
537 memcpy(temp
->value
.stringv
, value
[1], (size_t)length
[1]);
539 case MIME_MAGIC_CHAR
:
540 temp
->offset
= strtol(value
[0], NULL
, 0);
543 else if (length
[1] == 1)
544 temp
->value
.charv
= (unsigned char)value
[1][0];
546 temp
->value
.charv
= (unsigned char)strtol(value
[1], NULL
, 0);
548 DEBUG_printf(("1mimeAddTypeRule: CHAR(%d,0x%02x)", temp
->offset
,
551 case MIME_MAGIC_SHORT
:
552 temp
->offset
= strtol(value
[0], NULL
, 0);
553 temp
->value
.shortv
= (unsigned short)strtol(value
[1], NULL
, 0);
555 case MIME_MAGIC_INT
:
556 temp
->offset
= strtol(value
[0], NULL
, 0);
557 temp
->value
.intv
= (unsigned)strtol(value
[1], NULL
, 0);
559 case MIME_MAGIC_LOCALE
:
560 if ((size_t)length
[0] > (sizeof(temp
->value
.localev
) - 1))
563 cupsCopyString(temp
->value
.localev
, value
[0], sizeof(temp
->value
.localev
));
565 case MIME_MAGIC_CONTAINS
:
566 temp
->offset
= strtol(value
[0], NULL
, 0);
567 temp
->region
= strtol(value
[1], NULL
, 0);
568 if (num_values
< 3 || (size_t)length
[2] > sizeof(temp
->value
.stringv
))
570 temp
->length
= length
[2];
571 memcpy(temp
->value
.stringv
, value
[2], (size_t)length
[2]);
584 * 'mimeFileType()' - Determine the type of a file.
587 mime_type_t
* /* O - Type of file */
588 mimeFileType(mime_t
*mime
, /* I - MIME database */
589 const char *pathname
, /* I - Name of file to check on disk */
590 const char *filename
, /* I - Original filename or NULL */
591 int *compression
) /* O - Is the file compressed? */
593 _mime_filebuf_t fb
; /* File buffer */
594 const char *base
; /* Base filename of file */
595 mime_type_t
*type
, /* File type */
596 *best
; /* Best match */
599 DEBUG_printf(("mimeFileType(mime=%p, pathname=\"%s\", filename=\"%s\", "
600 "compression=%p)", mime
, pathname
, filename
, compression
));
603 * Range check input parameters...
606 if (!mime
|| !pathname
)
608 DEBUG_puts("1mimeFileType: Returning NULL.");
613 * Try to open the file...
616 if ((fb
.fp
= cupsFileOpen(pathname
, "r")) == NULL
)
618 DEBUG_printf(("1mimeFileType: Unable to open \"%s\": %s", pathname
,
620 DEBUG_puts("1mimeFileType: Returning NULL.");
625 * Then preload the first MIME_MAX_BUFFER bytes of the file into the file
626 * buffer, returning an error if we can't read anything...
630 fb
.length
= (int)cupsFileRead(fb
.fp
, (char *)fb
.buffer
, MIME_MAX_BUFFER
);
634 DEBUG_printf("1mimeFileType: Unable to read from \"%s\": %s", pathname
, strerror(errno
));
635 DEBUG_puts("1mimeFileType: Returning NULL.");
637 cupsFileClose(fb
.fp
);
643 * Figure out the base filename (without directory portion)...
648 if ((base
= strrchr(filename
, '/')) != NULL
)
653 else if ((base
= strrchr(pathname
, '/')) != NULL
)
659 * Then check it against all known types...
662 for (type
= (mime_type_t
*)cupsArrayFirst(mime
->types
), best
= NULL
;
664 type
= (mime_type_t
*)cupsArrayNext(mime
->types
))
665 if (mime_check_rules(base
, &fb
, type
->rules
))
667 if (!best
|| type
->priority
> best
->priority
)
672 * Finally, close the file and return a match (if any)...
677 *compression
= cupsFileCompression(fb
.fp
);
678 DEBUG_printf("1mimeFileType: *compression=%d", *compression
);
681 cupsFileClose(fb
.fp
);
683 DEBUG_printf(("1mimeFileType: Returning %p(%s/%s).", best
,
684 best
? best
->super
: "???", best
? best
->type
: "???"));
690 * 'mimeType()' - Lookup a file type.
693 mime_type_t
* /* O - Matching file type definition */
694 mimeType(mime_t
*mime
, /* I - MIME database */
695 const char *super
, /* I - Super-type name */
696 const char *type
) /* I - Type name */
698 mime_type_t key
, /* MIME type search key */
699 *mt
; /* Matching type */
702 DEBUG_printf(("mimeType(mime=%p, super=\"%s\", type=\"%s\")", mime
, super
,
706 * Range check input...
709 if (!mime
|| !super
|| !type
)
711 DEBUG_puts("1mimeType: Returning NULL.");
716 * Lookup the type in the array...
719 cupsCopyString(key
.super
, super
, sizeof(key
.super
));
720 cupsCopyString(key
.type
, type
, sizeof(key
.type
));
722 mt
= (mime_type_t
*)cupsArrayFind(mime
->types
, &key
);
723 DEBUG_printf("1mimeType: Returning %p.", mt
);
729 * 'mime_compare_types()' - Compare two MIME super/type names.
732 static int /* O - Result of comparison */
733 mime_compare_types(mime_type_t
*t0
, /* I - First type */
734 mime_type_t
*t1
, /* I - Second type */
735 void *data
) /* Unused */
737 int i
; /* Result of comparison */
741 if ((i
= _cups_strcasecmp(t0
->super
, t1
->super
)) == 0)
742 i
= _cups_strcasecmp(t0
->type
, t1
->type
);
749 * 'mime_check_rules()' - Check each rule in a list.
752 static int /* O - 1 if match, 0 if no match */
754 const char *filename
, /* I - Filename */
755 _mime_filebuf_t
*fb
, /* I - File to check */
756 mime_magic_t
*rules
) /* I - Rules to check */
758 int n
; /* Looping var */
759 int region
; /* Region to look at */
760 int logic
, /* Logic to apply */
761 result
; /* Result of test */
762 unsigned intv
; /* Integer value */
763 short shortv
; /* Short value */
764 unsigned char *bufptr
; /* Pointer into buffer */
767 DEBUG_printf(("4mime_check_rules(filename=\"%s\", fb=%p, rules=%p)", filename
,
773 if (rules
->parent
== NULL
)
774 logic
= MIME_MAGIC_OR
;
776 logic
= rules
->parent
->op
;
780 while (rules
!= NULL
)
783 * Compute the result of this rule...
788 case MIME_MAGIC_MATCH
:
789 result
= mime_patmatch(filename
, rules
->value
.matchv
);
792 case MIME_MAGIC_ASCII
:
794 * Load the buffer if necessary...
797 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
798 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
801 * Reload file buffer...
804 if (cupsFileSeek(fb
->fp
, rules
->offset
) < 0)
811 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
, sizeof(fb
->buffer
));
812 fb
->offset
= rules
->offset
;
815 DEBUG_printf("4mime_check_rules: MIME_MAGIC_ASCII fb->length=%d", fb
->length
);
819 * Test for ASCII printable characters plus standard control chars.
822 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
823 n
= fb
->offset
+ fb
->length
- rules
->offset
;
827 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
829 if ((*bufptr
>= 32 && *bufptr
<= 126) ||
830 (*bufptr
>= 8 && *bufptr
<= 13) ||
831 *bufptr
== 26 || *bufptr
== 27)
842 case MIME_MAGIC_PRINTABLE
:
844 * Load the buffer if necessary...
847 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
848 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
851 * Reload file buffer...
854 if (cupsFileSeek(fb
->fp
, rules
->offset
) < 0)
861 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
, sizeof(fb
->buffer
));
862 fb
->offset
= rules
->offset
;
865 DEBUG_printf("4mime_check_rules: MIME_MAGIC_PRINTABLE fb->length=%d", fb
->length
);
869 * Test for 8-bit printable characters plus standard control chars.
872 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
873 n
= fb
->offset
+ fb
->length
- rules
->offset
;
877 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
880 if (*bufptr
>= 128 ||
881 (*bufptr
>= 32 && *bufptr
<= 126) ||
882 (*bufptr
>= 8 && *bufptr
<= 13) ||
883 *bufptr
== 26 || *bufptr
== 27)
894 case MIME_MAGIC_REGEX
:
895 DEBUG_printf(("5mime_check_rules: regex(%d, \"%s\")", rules
->offset
,
896 rules
->value
.stringv
));
899 * Load the buffer if necessary...
902 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
903 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
906 * Reload file buffer...
909 if (cupsFileSeek(fb
->fp
, rules
->offset
) < 0)
916 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
, sizeof(fb
->buffer
));
917 fb
->offset
= rules
->offset
;
920 DEBUG_printf("4mime_check_rules: MIME_MAGIC_REGEX fb->length=%d", fb
->length
);
922 DEBUG_printf(("5mime_check_rules: loaded %d byte fb->buffer at %d, starts "
923 "with \"%c%c%c%c\".",
924 fb
->length
, fb
->offset
, fb
->buffer
[0], fb
->buffer
[1],
925 fb
->buffer
[2], fb
->buffer
[3]));
929 * Compare the buffer against the string. If the file is too
930 * short then don't compare - it can't match...
935 char temp
[MIME_MAX_BUFFER
+ 1];
936 /* Temporary buffer */
938 memcpy(temp
, fb
->buffer
, (size_t)fb
->length
);
939 temp
[fb
->length
] = '\0';
940 result
= !regexec(&(rules
->value
.rev
), temp
, 0, NULL
, 0);
943 DEBUG_printf("5mime_check_rules: result=%d", result
);
946 case MIME_MAGIC_STRING
:
947 DEBUG_printf(("5mime_check_rules: string(%d, \"%s\")", rules
->offset
,
948 rules
->value
.stringv
));
951 * Load the buffer if necessary...
954 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
955 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
958 * Reload file buffer...
961 if (cupsFileSeek(fb
->fp
, rules
->offset
) < 0)
968 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
, sizeof(fb
->buffer
));
969 fb
->offset
= rules
->offset
;
972 DEBUG_printf("4mime_check_rules: MIME_MAGIC_STRING fb->length=%d", fb
->length
);
974 DEBUG_printf(("5mime_check_rules: loaded %d byte fb->buffer at %d, starts "
975 "with \"%c%c%c%c\".",
976 fb
->length
, fb
->offset
, fb
->buffer
[0], fb
->buffer
[1],
977 fb
->buffer
[2], fb
->buffer
[3]));
981 * Compare the buffer against the string. If the file is too
982 * short then don't compare - it can't match...
985 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
988 result
= !memcmp(fb
->buffer
+ rules
->offset
- fb
->offset
, rules
->value
.stringv
, (size_t)rules
->length
);
989 DEBUG_printf("5mime_check_rules: result=%d", result
);
992 case MIME_MAGIC_ISTRING
:
994 * Load the buffer if necessary...
997 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
998 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
1001 * Reload file buffer...
1004 if (cupsFileSeek(fb
->fp
, rules
->offset
) < 0)
1011 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
, sizeof(fb
->buffer
));
1012 fb
->offset
= rules
->offset
;
1015 DEBUG_printf("4mime_check_rules: MIME_MAGIC_ISTRING fb->length=%d", fb
->length
);
1019 * Compare the buffer against the string. If the file is too
1020 * short then don't compare - it can't match...
1023 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
1026 result
= !_cups_strncasecmp((char *)fb
->buffer
+ rules
->offset
- fb
->offset
, rules
->value
.stringv
, (size_t)rules
->length
);
1029 case MIME_MAGIC_CHAR
:
1031 * Load the buffer if necessary...
1034 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
)
1037 * Reload file buffer...
1040 if (cupsFileSeek(fb
->fp
, rules
->offset
) < 0)
1047 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
, sizeof(fb
->buffer
));
1048 fb
->offset
= rules
->offset
;
1051 DEBUG_printf("4mime_check_rules: MIME_MAGIC_CHAR fb->length=%d", fb
->length
);
1055 * Compare the character values; if the file is too short, it
1062 result
= (fb
->buffer
[rules
->offset
- fb
->offset
] == rules
->value
.charv
);
1065 case MIME_MAGIC_SHORT
:
1067 * Load the buffer if necessary...
1070 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
1071 (rules
->offset
+ 2) > (fb
->offset
+ fb
->length
))
1074 * Reload file buffer...
1077 if (cupsFileSeek(fb
->fp
, rules
->offset
) < 0)
1084 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
, sizeof(fb
->buffer
));
1085 fb
->offset
= rules
->offset
;
1088 DEBUG_printf("4mime_check_rules: MIME_MAGIC_SHORT fb->length=%d", fb
->length
);
1092 * Compare the short values; if the file is too short, it
1102 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
1103 shortv
= (short)((bufptr
[0] << 8) | bufptr
[1]);
1104 result
= (shortv
== rules
->value
.shortv
);
1108 case MIME_MAGIC_INT
:
1110 * Load the buffer if necessary...
1113 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
1114 (rules
->offset
+ 4) > (fb
->offset
+ fb
->length
))
1117 * Reload file buffer...
1120 if (cupsFileSeek(fb
->fp
, rules
->offset
) < 0)
1127 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
, sizeof(fb
->buffer
));
1128 fb
->offset
= rules
->offset
;
1131 DEBUG_printf("4mime_check_rules: MIME_MAGIC_INT fb->length=%d", fb
->length
);
1135 * Compare the int values; if the file is too short, it
1145 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
1146 intv
= (unsigned)((bufptr
[0] << 24) | (bufptr
[1] << 16) | (bufptr
[2] << 8) | bufptr
[3]);
1147 result
= (intv
== rules
->value
.intv
);
1151 case MIME_MAGIC_LOCALE
:
1152 #if defined(_WIN32) || defined(__EMX__) || defined(__APPLE__)
1153 result
= !strcmp(rules
->value
.localev
, setlocale(LC_ALL
, ""));
1155 result
= !strcmp(rules
->value
.localev
, setlocale(LC_MESSAGES
, ""));
1156 #endif /* __APPLE__ */
1159 case MIME_MAGIC_CONTAINS
:
1161 * Load the buffer if necessary...
1164 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
1165 (rules
->offset
+ rules
->region
) > (fb
->offset
+ fb
->length
))
1168 * Reload file buffer...
1171 if (cupsFileSeek(fb
->fp
, rules
->offset
) < 0)
1178 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
, sizeof(fb
->buffer
));
1179 fb
->offset
= rules
->offset
;
1182 DEBUG_printf("4mime_check_rules: MIME_MAGIC_CONTAINS fb->length=%d", fb
->length
);
1186 * Compare the buffer against the string. If the file is too
1187 * short then don't compare - it can't match...
1191 if ((rules
->offset
+ rules
->length
) <= (fb
->offset
+ fb
->length
))
1193 if (fb
->length
> rules
->region
)
1194 region
= rules
->region
- rules
->length
;
1196 region
= fb
->length
- rules
->length
;
1198 for (n
= 0; n
< region
; n
++)
1199 if (!memcmp(fb
->buffer
+ rules
->offset
- fb
->offset
+ n
, rules
->value
.stringv
, (size_t)rules
->length
))
1208 if (rules
->child
!= NULL
)
1209 result
= mime_check_rules(filename
, fb
, rules
->child
);
1216 * If the logic is inverted, invert the result...
1223 * OK, now if the current logic is OR and this result is true, this
1224 * rule set is true. If the current logic is AND and this result is false,
1225 * the rule set is false...
1228 DEBUG_printf(("5mime_check_rules: result of test %p (MIME_MAGIC_%s) is %d",
1229 rules
, debug_ops
[rules
->op
], result
));
1231 if ((result
&& logic
== MIME_MAGIC_OR
) ||
1232 (!result
&& logic
== MIME_MAGIC_AND
))
1236 * Otherwise the jury is still out on this one, so move to the next rule.
1239 rules
= rules
->next
;
1247 * 'mime_patmatch()' - Pattern matching.
1250 static int /* O - 1 if match, 0 if no match */
1251 mime_patmatch(const char *s
, /* I - String to match against */
1252 const char *pat
) /* I - Pattern to match against */
1255 * Range check the input...
1258 if (s
== NULL
|| pat
== NULL
)
1262 * Loop through the pattern and match strings, and stop if we come to a
1263 * point where the strings don't match or we find a complete match.
1266 while (*s
!= '\0' && *pat
!= '\0')
1271 * Wildcard - 0 or more characters...
1276 return (1); /* Last pattern char is *, so everything matches... */
1279 * Test all remaining combinations until we get to the end of the string.
1284 if (mime_patmatch(s
, pat
))
1290 else if (*pat
== '?')
1293 * Wildcard - 1 character...
1300 else if (*pat
== '[')
1303 * Match a character from the input set [chars]...
1307 while (*pat
!= ']' && *pat
!= '\0')
1313 if (*pat
== ']' || *pat
== '\0')
1316 while (*pat
!= ']' && *pat
!= '\0')
1324 else if (*pat
== '\\')
1327 * Handle quoted characters...
1334 * Stop if the pattern and string don't match...
1342 * Done parsing the pattern and string; return 1 if the last character
1343 * matches and 0 otherwise...
1346 return (*s
== *pat
);