]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/type.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / type.c
1 /*
2 * "$Id: type.c 4613 2005-08-30 12:41:48Z mike $"
3 *
4 * MIME typing routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * mimeAddType() - Add a MIME type to a database.
27 * mimeAddTypeRule() - Add a detection rule for a file type.
28 * mimeFileType() - Determine the type of a file.
29 * mimeType() - Lookup a file type.
30 * compare() - Compare two MIME super/type names.
31 * checkrules() - Check each rule in a list.
32 * patmatch() - Pattern matching...
33 */
34
35 /*
36 * Include necessary headers...
37 */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <ctype.h>
42 #include <locale.h>
43
44 #include <cups/string.h>
45 #include "mime.h"
46 #include <cups/debug.h>
47
48
49 /*
50 * Local functions...
51 */
52
53 static int compare(mime_type_t **, mime_type_t **);
54 static int checkrules(const char *, cups_file_t *, mime_magic_t *);
55 static int patmatch(const char *, const char *);
56
57
58 /*
59 * 'mimeAddType()' - Add a MIME type to a database.
60 */
61
62 mime_type_t * /* O - New (or existing) MIME type */
63 mimeAddType(mime_t *mime, /* I - MIME database */
64 const char *super, /* I - Super-type name */
65 const char *type) /* I - Type name */
66 {
67 mime_type_t *temp, /* New MIME type */
68 **types; /* New MIME types array */
69
70
71 /*
72 * Range check input...
73 */
74
75 if (mime == NULL || super == NULL || type == NULL)
76 return (NULL);
77
78 if (strlen(super) > (MIME_MAX_SUPER - 1) ||
79 strlen(type) > (MIME_MAX_TYPE - 1))
80 return (NULL);
81
82 /*
83 * See if the type already exists; if so, return the existing type...
84 */
85
86 if ((temp = mimeType(mime, super, type)) != NULL)
87 return (temp);
88
89 /*
90 * The type doesn't exist; add it...
91 */
92
93 if ((temp = calloc(1, sizeof(mime_type_t))) == NULL)
94 return (NULL);
95
96 if (mime->num_types == 0)
97 types = (mime_type_t **)malloc(sizeof(mime_type_t *));
98 else
99 types = (mime_type_t **)realloc(mime->types, sizeof(mime_type_t *) * (mime->num_types + 1));
100
101 if (types == NULL)
102 {
103 free(temp);
104 return (NULL);
105 }
106
107 mime->types = types;
108 types += mime->num_types;
109 mime->num_types ++;
110
111 *types = temp;
112 strlcpy(temp->super, super, sizeof(temp->super));
113 if ((temp->type = strdup(type)) == NULL)
114 {
115 mime->num_types --;
116 return (NULL);
117 }
118
119 if (mime->num_types > 1)
120 qsort(mime->types, mime->num_types, sizeof(mime_type_t *),
121 (int (*)(const void *, const void *))compare);
122
123 return (temp);
124 }
125
126
127 /*
128 * 'mimeAddTypeRule()' - Add a detection rule for a file type.
129 */
130
131 int /* O - 0 on success, -1 on failure */
132 mimeAddTypeRule(mime_type_t *mt, /* I - Type to add to */
133 const char *rule) /* I - Rule to add */
134 {
135 int num_values, /* Number of values seen */
136 op, /* Operation code */
137 logic, /* Logic for next rule */
138 invert; /* Invert following rule? */
139 char name[255], /* Name in rule string */
140 value[3][255], /* Value in rule string */
141 *ptr, /* Position in name or value */
142 quote; /* Quote character */
143 int length[3]; /* Length of each parameter */
144 mime_magic_t *temp, /* New rule */
145 *current; /* Current rule */
146
147
148 /*
149 * Range check input...
150 */
151
152 if (mt == NULL || rule == NULL)
153 return (-1);
154
155 /*
156 * Find the last rule in the top-level of the rules tree.
157 */
158
159 for (current = mt->rules; current != NULL; current = current->next)
160 if (current->next == NULL)
161 break;
162
163 /*
164 * Parse the rules string. Most rules are either a file extension or a
165 * comparison function:
166 *
167 * extension
168 * function(parameters)
169 */
170
171 logic = MIME_MAGIC_NOP;
172 invert = 0;
173
174 DEBUG_printf(("%s/%s: %s\n", mt->super, mt->type, rule));
175
176 while (*rule != '\0')
177 {
178 while (isspace(*rule & 255))
179 rule ++;
180
181 if (*rule == '(')
182 {
183 DEBUG_puts("new parenthesis group");
184 logic = MIME_MAGIC_NOP;
185 rule ++;
186 }
187 else if (*rule == ')')
188 {
189 DEBUG_puts("close paren...");
190 if (current == NULL || current->parent == NULL)
191 return (-1);
192
193 current = current->parent;
194
195 if (current->parent == NULL)
196 logic = MIME_MAGIC_OR;
197 else
198 logic = current->parent->op;
199
200 rule ++;
201 }
202 else if (*rule == '+' && current != NULL)
203 {
204 if (logic != MIME_MAGIC_AND &&
205 current != NULL && current->prev != NULL && current->prev->prev != NULL)
206 {
207 /*
208 * OK, we have more than 1 rule in the current tree level... Make a
209 * new group tree and move the previous rule to it...
210 */
211
212 if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
213 return (-1);
214
215 temp->op = MIME_MAGIC_AND;
216 temp->child = current;
217 temp->parent = current->parent;
218 current->prev->next = temp;
219 temp->prev = current->prev;
220
221 current->prev = NULL;
222 current->parent = temp;
223
224 DEBUG_printf(("creating new AND group %p...\n", temp));
225 }
226 else
227 {
228 DEBUG_printf(("setting group %p op to AND...\n", current->parent));
229 current->parent->op = MIME_MAGIC_AND;
230 }
231
232 logic = MIME_MAGIC_AND;
233 rule ++;
234 }
235 else if (*rule == ',')
236 {
237 if (logic != MIME_MAGIC_OR && current != NULL)
238 {
239 /*
240 * OK, we have two possibilities; either this is the top-level rule or
241 * we have a bunch of AND rules at this level.
242 */
243
244 if (current->parent == NULL)
245 {
246 /*
247 * This is the top-level rule; we have to move *all* of the AND rules
248 * down a level, as AND has precedence over OR.
249 */
250
251 if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
252 return (-1);
253
254 DEBUG_printf(("creating new AND group %p inside OR group\n", temp));
255
256 while (current->prev != NULL)
257 {
258 current->parent = temp;
259 current = current->prev;
260 }
261
262 current->parent = temp;
263 temp->op = MIME_MAGIC_AND;
264 temp->child = current;
265
266 mt->rules = current = temp;
267 }
268 else
269 {
270 /*
271 * This isn't the top rule, so go up one level...
272 */
273
274 DEBUG_puts("going up one level");
275 current = current->parent;
276 }
277 }
278
279 logic = MIME_MAGIC_OR;
280 rule ++;
281 }
282 else if (*rule == '!')
283 {
284 DEBUG_puts("NOT");
285 invert = 1;
286 rule ++;
287 }
288 else if (isalnum(*rule & 255))
289 {
290 /*
291 * Read an extension name or a function...
292 */
293
294 for (ptr = name; isalnum(*rule & 255) && (ptr - name) < (sizeof(name) - 1);)
295 *ptr++ = *rule++;
296
297 *ptr = '\0';
298 num_values = 0;
299
300 if (*rule == '(')
301 {
302 /*
303 * Read function parameters...
304 */
305
306 rule ++;
307 for (num_values = 0;
308 num_values < (sizeof(value) / sizeof(value[0]));
309 num_values ++)
310 {
311 ptr = value[num_values];
312
313 while ((ptr - value[num_values]) < (sizeof(value[0]) - 1) &&
314 *rule != '\0' && *rule != ',' && *rule != ')')
315 {
316 if (isspace(*rule & 255))
317 {
318 /*
319 * Ignore whitespace...
320 */
321
322 rule ++;
323 continue;
324 }
325 else if (*rule == '\"' || *rule == '\'')
326 {
327 /*
328 * Copy quoted strings literally...
329 */
330
331 quote = *rule++;
332
333 while (*rule != '\0' && *rule != quote &&
334 (ptr - value[num_values]) < (sizeof(value[0]) - 1))
335 *ptr++ = *rule++;
336
337 if (*rule == quote)
338 rule ++;
339 else
340 return (-1);
341 }
342 else if (*rule == '<')
343 {
344 rule ++;
345
346 while (*rule != '>' && *rule != '\0' &&
347 (ptr - value[num_values]) < (sizeof(value[0]) - 1))
348 {
349 if (isxdigit(rule[0] & 255) && isxdigit(rule[1] & 255))
350 {
351 if (isdigit(*rule))
352 *ptr = (*rule++ - '0') << 4;
353 else
354 *ptr = (tolower(*rule++) - 'a' + 10) << 4;
355
356 if (isdigit(*rule))
357 *ptr++ |= *rule++ - '0';
358 else
359 *ptr++ |= tolower(*rule++) - 'a' + 10;
360 }
361 else
362 return (-1);
363 }
364
365 if (*rule == '>')
366 rule ++;
367 else
368 return (-1);
369 }
370 else
371 *ptr++ = *rule++;
372 }
373
374 *ptr = '\0';
375 length[num_values] = ptr - value[num_values];
376
377 if (*rule != ',')
378 break;
379
380 rule ++;
381 }
382
383 if (*rule != ')')
384 return (-1);
385
386 rule ++;
387
388 /*
389 * Figure out the function...
390 */
391
392 if (strcmp(name, "match") == 0)
393 op = MIME_MAGIC_MATCH;
394 else if (strcmp(name, "ascii") == 0)
395 op = MIME_MAGIC_ASCII;
396 else if (strcmp(name, "printable") == 0)
397 op = MIME_MAGIC_PRINTABLE;
398 else if (strcmp(name, "string") == 0)
399 op = MIME_MAGIC_STRING;
400 else if (strcmp(name, "istring") == 0)
401 op = MIME_MAGIC_ISTRING;
402 else if (strcmp(name, "char") == 0)
403 op = MIME_MAGIC_CHAR;
404 else if (strcmp(name, "short") == 0)
405 op = MIME_MAGIC_SHORT;
406 else if (strcmp(name, "int") == 0)
407 op = MIME_MAGIC_INT;
408 else if (strcmp(name, "locale") == 0)
409 op = MIME_MAGIC_LOCALE;
410 else if (strcmp(name, "contains") == 0)
411 op = MIME_MAGIC_CONTAINS;
412 else
413 return (-1);
414 }
415 else
416 {
417 /*
418 * This is just a filename match on the extension...
419 */
420
421 snprintf(value[0], sizeof(value[0]), "*.%s", name);
422 length[0] = strlen(value[0]);
423 num_values = 1;
424 op = MIME_MAGIC_MATCH;
425 }
426
427 /*
428 * Add a rule for this operation.
429 */
430
431 if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
432 return (-1);
433
434 temp->invert = invert;
435 if (current != NULL)
436 {
437 temp->parent = current->parent;
438 current->next = temp;
439 }
440 else
441 mt->rules = temp;
442
443 temp->prev = current;
444
445 if (logic == MIME_MAGIC_NOP)
446 {
447 /*
448 * Add parenthetical grouping...
449 */
450
451 DEBUG_printf(("making new OR group %p for parenthesis...\n", temp));
452
453 temp->op = MIME_MAGIC_OR;
454
455 if ((temp->child = calloc(1, sizeof(mime_magic_t))) == NULL)
456 return (-1);
457
458 temp->child->parent = temp;
459
460 temp = temp->child;
461 logic = MIME_MAGIC_OR;
462 }
463
464 DEBUG_printf(("adding %p: %s, op = %d, logic = %d, invert = %d\n",
465 temp, name, op, logic, invert));
466
467 /*
468 * Fill in data for the rule...
469 */
470
471 current = temp;
472 temp->op = op;
473 invert = 0;
474
475 switch (op)
476 {
477 case MIME_MAGIC_MATCH :
478 if (length[0] > (sizeof(temp->value.matchv) - 1))
479 return (-1);
480 strcpy(temp->value.matchv, value[0]);
481 break;
482 case MIME_MAGIC_ASCII :
483 case MIME_MAGIC_PRINTABLE :
484 temp->offset = strtol(value[0], NULL, 0);
485 temp->length = strtol(value[1], NULL, 0);
486 if (temp->length > MIME_MAX_BUFFER)
487 temp->length = MIME_MAX_BUFFER;
488 break;
489 case MIME_MAGIC_STRING :
490 case MIME_MAGIC_ISTRING :
491 temp->offset = strtol(value[0], NULL, 0);
492 if (length[1] > sizeof(temp->value.stringv))
493 return (-1);
494 temp->length = length[1];
495 memcpy(temp->value.stringv, value[1], length[1]);
496 break;
497 case MIME_MAGIC_CHAR :
498 temp->offset = strtol(value[0], NULL, 0);
499 if (length[1] == 1)
500 temp->value.charv = value[1][0];
501 else
502 temp->value.charv = (char)strtol(value[1], NULL, 0);
503 break;
504 case MIME_MAGIC_SHORT :
505 temp->offset = strtol(value[0], NULL, 0);
506 temp->value.shortv = (short)strtol(value[1], NULL, 0);
507 break;
508 case MIME_MAGIC_INT :
509 temp->offset = strtol(value[0], NULL, 0);
510 temp->value.intv = (int)strtol(value[1], NULL, 0);
511 break;
512 case MIME_MAGIC_LOCALE :
513 if (length[0] > (sizeof(temp->value.localev) - 1))
514 return (-1);
515
516 strcpy(temp->value.localev, value[0]);
517 break;
518 case MIME_MAGIC_CONTAINS :
519 temp->offset = strtol(value[0], NULL, 0);
520 temp->region = strtol(value[1], NULL, 0);
521 if (length[2] > sizeof(temp->value.stringv))
522 return (-1);
523 temp->length = length[2];
524 memcpy(temp->value.stringv, value[2], length[2]);
525 break;
526 }
527 }
528 else
529 break;
530 }
531
532 return (0);
533 }
534
535
536 /*
537 * 'mimeFileType()' - Determine the type of a file.
538 */
539
540 mime_type_t * /* O - Type of file */
541 mimeFileType(mime_t *mime, /* I - MIME database */
542 const char *pathname, /* I - Name of file to check */
543 int *compression) /* O - Is the file compressed? */
544 {
545 int i; /* Looping var */
546 cups_file_t *fp; /* File pointer */
547 mime_type_t **types; /* File types */
548 const char *filename; /* Base filename of file */
549
550
551 DEBUG_printf(("mimeFileType(mime=%p, pathname=\"%s\", compression=%p)\n",
552 mime, pathname ? pathname : "(nil)", compression));
553
554 /*
555 * Range check input parameters...
556 */
557
558 if (mime == NULL || pathname == NULL)
559 return (NULL);
560
561 /*
562 * Try to open the file...
563 */
564
565 if ((fp = cupsFileOpen(pathname, "r")) == NULL)
566 return (NULL);
567
568 /*
569 * Figure out the filename (without directory portion)...
570 */
571
572 if ((filename = strrchr(pathname, '/')) != NULL)
573 filename ++;
574 else
575 filename = pathname;
576
577 /*
578 * Then check it against all known types...
579 */
580
581 for (i = mime->num_types, types = mime->types; i > 0; i --, types ++)
582 if (checkrules(filename, fp, (*types)->rules))
583 break;
584
585 /*
586 * Finally, close the file and return a match (if any)...
587 */
588
589 if (compression)
590 *compression = cupsFileCompression(fp);
591
592 cupsFileClose(fp);
593
594 if (i > 0)
595 return (*types);
596 else
597 return (NULL);
598 }
599
600
601 /*
602 * 'mimeType()' - Lookup a file type.
603 */
604
605 mime_type_t * /* O - Matching file type definition */
606 mimeType(mime_t *mime, /* I - MIME database */
607 const char *super, /* I - Super-type name */
608 const char *type) /* I - Type name */
609 {
610 mime_type_t key, /* MIME type search key*/
611 *keyptr, /* Key pointer... */
612 **match; /* Matching pointer */
613
614 /*
615 * Range check input...
616 */
617
618 if (mime == NULL || super == NULL || type == NULL)
619 return (NULL);
620
621 if (strlen(super) > (MIME_MAX_SUPER - 1) ||
622 strlen(type) > (MIME_MAX_TYPE - 1))
623 return (NULL);
624
625 if (mime->num_types == 0)
626 return (NULL);
627
628 /*
629 * Lookup the type in the array...
630 */
631
632 strlcpy(key.super, super, sizeof(key.super));
633 key.type = (char *)type;
634
635 keyptr = &key;
636
637 match = (mime_type_t **)bsearch(&keyptr, mime->types, mime->num_types,
638 sizeof(mime_type_t *),
639 (int (*)(const void *, const void *))compare);
640
641 if (match == NULL)
642 return (NULL);
643 else
644 return (*match);
645 }
646
647
648 /*
649 * 'compare()' - Compare two MIME super/type names.
650 */
651
652 static int /* O - Result of comparison */
653 compare(mime_type_t **t0, /* I - First type */
654 mime_type_t **t1) /* I - Second type */
655 {
656 int i; /* Result of comparison */
657
658
659 if ((i = strcasecmp((*t0)->super, (*t1)->super)) == 0)
660 i = strcasecmp((*t0)->type, (*t1)->type);
661
662 return (i);
663 }
664
665
666 /*
667 * 'checkrules()' - Check each rule in a list.
668 */
669
670 static int /* O - 1 if match, 0 if no match */
671 checkrules(const char *filename, /* I - Filename */
672 cups_file_t *fp, /* I - File to check */
673 mime_magic_t *rules) /* I - Rules to check */
674 {
675 int n; /* Looping var */
676 int region; /* Region to look at */
677 int logic, /* Logic to apply */
678 result, /* Result of test */
679 intv; /* Integer value */
680 short shortv; /* Short value */
681 unsigned char buffer[MIME_MAX_BUFFER],/* Input buffer */
682 *bufptr; /* Current buffer position */
683 int bufoffset, /* Offset in file for buffer */
684 buflength; /* Length of data in buffer */
685 #ifdef DEBUG
686 const char * const debug_tests[] = /* Test names... */
687 {
688 "NOP", /* No operation */
689 "AND", /* Logical AND of all children */
690 "OR", /* Logical OR of all children */
691 "MATCH", /* Filename match */
692 "ASCII", /* ASCII characters in range */
693 "PRINTABLE", /* Printable characters (32-255) in range */
694 "STRING", /* String matches */
695 "CHAR", /* Character/byte matches */
696 "SHORT", /* Short/16-bit word matches */
697 "INT", /* Integer/32-bit word matches */
698 "LOCALE" /* Current locale matches string */
699 "CONTAINS" /* File contains a string */
700 "ISTRING" /* Case-insensitive string matches */
701 };
702 #endif /* DEBUG */
703
704
705 DEBUG_printf(("checkrules(filename=\"%s\", fp=%p, rules=%p)\n", filename,
706 fp, rules));
707
708 if (rules == NULL)
709 return (0);
710
711 if (rules->parent == NULL)
712 logic = MIME_MAGIC_OR;
713 else
714 logic = rules->parent->op;
715
716 bufoffset = -1;
717 buflength = 0;
718 result = 0;
719
720 while (rules != NULL)
721 {
722 /*
723 * Compute the result of this rule...
724 */
725
726 switch (rules->op)
727 {
728 case MIME_MAGIC_MATCH :
729 result = patmatch(filename, rules->value.matchv);
730 break;
731
732 case MIME_MAGIC_ASCII :
733 /*
734 * Load the buffer if necessary...
735 */
736
737 if (bufoffset < 0 || rules->offset < bufoffset ||
738 (rules->offset + rules->length) > (bufoffset + buflength))
739 {
740 /*
741 * Reload file buffer...
742 */
743
744 cupsFileSeek(fp, rules->offset);
745 buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer));
746 bufoffset = rules->offset;
747 }
748
749 /*
750 * Test for ASCII printable characters plus standard control chars.
751 */
752
753 if ((rules->offset + rules->length) > (bufoffset + buflength))
754 n = bufoffset + buflength - rules->offset;
755 else
756 n = rules->length;
757
758 bufptr = buffer + rules->offset - bufoffset;
759 while (n > 0)
760 if ((*bufptr >= 32 && *bufptr <= 126) ||
761 (*bufptr >= 8 && *bufptr <= 13) ||
762 *bufptr == 26 || *bufptr == 27)
763 {
764 n --;
765 bufptr ++;
766 }
767 else
768 break;
769
770 result = (n == 0);
771 break;
772
773 case MIME_MAGIC_PRINTABLE :
774 /*
775 * Load the buffer if necessary...
776 */
777
778 if (bufoffset < 0 || rules->offset < bufoffset ||
779 (rules->offset + rules->length) > (bufoffset + buflength))
780 {
781 /*
782 * Reload file buffer...
783 */
784
785 cupsFileSeek(fp, rules->offset);
786 buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer));
787 bufoffset = rules->offset;
788 }
789
790 /*
791 * Test for 8-bit printable characters plus standard control chars.
792 */
793
794 if ((rules->offset + rules->length) > (bufoffset + buflength))
795 n = bufoffset + buflength - rules->offset;
796 else
797 n = rules->length;
798
799 bufptr = buffer + rules->offset - bufoffset;
800
801 while (n > 0)
802 if (*bufptr >= 128 ||
803 (*bufptr >= 32 && *bufptr <= 126) ||
804 (*bufptr >= 8 && *bufptr <= 13) ||
805 *bufptr == 26 || *bufptr == 27)
806 {
807 n --;
808 bufptr ++;
809 }
810 else
811 break;
812
813 result = (n == 0);
814 break;
815
816 case MIME_MAGIC_STRING :
817 DEBUG_printf((" string(%d, \"%s\")\n", rules->offset,
818 rules->value.stringv));
819
820 /*
821 * Load the buffer if necessary...
822 */
823
824 if (bufoffset < 0 || rules->offset < bufoffset ||
825 (rules->offset + rules->length) > (bufoffset + buflength))
826 {
827 /*
828 * Reload file buffer...
829 */
830
831 cupsFileSeek(fp, rules->offset);
832 buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer));
833 bufoffset = rules->offset;
834
835 DEBUG_printf((" loaded %d byte buffer at %d, starts with \"%c%c%c%c\"...\n",
836 buflength, bufoffset, buffer[0], buffer[1],
837 buffer[2], buffer[3]));
838 }
839
840 /*
841 * Compare the buffer against the string. If the file is too
842 * short then don't compare - it can't match...
843 */
844
845 if ((rules->offset + rules->length) > (bufoffset + buflength))
846 result = 0;
847 else
848 result = (memcmp(buffer + rules->offset - bufoffset,
849 rules->value.stringv, rules->length) == 0);
850 DEBUG_printf((" result=%d\n", result));
851 break;
852
853 case MIME_MAGIC_ISTRING :
854 /*
855 * Load the buffer if necessary...
856 */
857
858 if (bufoffset < 0 || rules->offset < bufoffset ||
859 (rules->offset + rules->length) > (bufoffset + buflength))
860 {
861 /*
862 * Reload file buffer...
863 */
864
865 cupsFileSeek(fp, rules->offset);
866 buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer));
867 bufoffset = rules->offset;
868 }
869
870 /*
871 * Compare the buffer against the string. If the file is too
872 * short then don't compare - it can't match...
873 */
874
875 if ((rules->offset + rules->length) > (bufoffset + buflength))
876 result = 0;
877 else
878 result = (strncasecmp((char *)buffer + rules->offset - bufoffset,
879 rules->value.stringv, rules->length) == 0);
880 break;
881
882 case MIME_MAGIC_CHAR :
883 /*
884 * Load the buffer if necessary...
885 */
886
887 if (bufoffset < 0 || rules->offset < bufoffset)
888 {
889 /*
890 * Reload file buffer...
891 */
892
893 cupsFileSeek(fp, rules->offset);
894 buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer));
895 bufoffset = rules->offset;
896 }
897
898 /*
899 * Compare the character values; if the file is too short, it
900 * can't match...
901 */
902
903 if (buflength < 1)
904 result = 0;
905 else
906 result = (buffer[rules->offset - bufoffset] == rules->value.charv);
907 break;
908
909 case MIME_MAGIC_SHORT :
910 /*
911 * Load the buffer if necessary...
912 */
913
914 if (bufoffset < 0 || rules->offset < bufoffset ||
915 (rules->offset + 2) > (bufoffset + buflength))
916 {
917 /*
918 * Reload file buffer...
919 */
920
921 cupsFileSeek(fp, rules->offset);
922 buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer));
923 bufoffset = rules->offset;
924 }
925
926 /*
927 * Compare the short values; if the file is too short, it
928 * can't match...
929 */
930
931 if (buflength < 2)
932 result = 0;
933 else
934 {
935 bufptr = buffer + rules->offset - bufoffset;
936 shortv = (bufptr[0] << 8) | bufptr[1];
937 result = (shortv == rules->value.shortv);
938 }
939 break;
940
941 case MIME_MAGIC_INT :
942 /*
943 * Load the buffer if necessary...
944 */
945
946 if (bufoffset < 0 || rules->offset < bufoffset ||
947 (rules->offset + 4) > (bufoffset + buflength))
948 {
949 /*
950 * Reload file buffer...
951 */
952
953 cupsFileSeek(fp, rules->offset);
954 buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer));
955 bufoffset = rules->offset;
956 }
957
958 /*
959 * Compare the int values; if the file is too short, it
960 * can't match...
961 */
962
963 if (buflength < 4)
964 result = 0;
965 else
966 {
967 bufptr = buffer + rules->offset - bufoffset;
968 intv = (((((bufptr[0] << 8) | bufptr[1]) << 8) | bufptr[2]) << 8) |
969 bufptr[3];;
970 result = (intv == rules->value.intv);
971 }
972 break;
973
974 case MIME_MAGIC_LOCALE :
975 #if defined(WIN32) || defined(__EMX__) || defined(__APPLE__)
976 result = (strcmp(rules->value.localev, setlocale(LC_ALL, "")) == 0);
977 #else
978 result = (strcmp(rules->value.localev, setlocale(LC_MESSAGES, "")) == 0);
979 #endif /* __APPLE__ */
980 break;
981
982 case MIME_MAGIC_CONTAINS :
983 /*
984 * Load the buffer if necessary...
985 */
986
987 if (bufoffset < 0 || rules->offset < bufoffset ||
988 (rules->offset + rules->region) > (bufoffset + buflength))
989 {
990 /*
991 * Reload file buffer...
992 */
993
994 cupsFileSeek(fp, rules->offset);
995 buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer));
996 bufoffset = rules->offset;
997 }
998
999 /*
1000 * Compare the buffer against the string. If the file is too
1001 * short then don't compare - it can't match...
1002 */
1003
1004 if ((rules->offset + rules->length) > (bufoffset + buflength))
1005 result = 0;
1006 else
1007 {
1008 if (buflength > rules->region)
1009 region = rules->region - rules->length;
1010 else
1011 region = buflength - rules->length;
1012
1013 for (n = 0; n < region; n ++)
1014 if ((result = (memcmp(buffer + rules->offset - bufoffset + n,
1015 rules->value.stringv, rules->length) == 0)) != 0)
1016 break;
1017 }
1018 break;
1019
1020 default :
1021 if (rules->child != NULL)
1022 result = checkrules(filename, fp, rules->child);
1023 else
1024 result = 0;
1025 break;
1026 }
1027
1028 /*
1029 * If the logic is inverted, invert the result...
1030 */
1031
1032 if (rules->invert)
1033 result = !result;
1034
1035 /*
1036 * OK, now if the current logic is OR and this result is true, the this
1037 * rule set is true. If the current logic is AND and this result is false,
1038 * the the rule set is false...
1039 */
1040
1041 DEBUG_printf((" result of test %p (MIME_MAGIC_%s) is %d\n", rules,
1042 debug_tests[rules->op], result));
1043
1044 if ((result && logic == MIME_MAGIC_OR) ||
1045 (!result && logic == MIME_MAGIC_AND))
1046 return (result);
1047
1048 /*
1049 * Otherwise the jury is still out on this one, so move to the next rule.
1050 */
1051
1052 rules = rules->next;
1053 }
1054
1055 return (result);
1056 }
1057
1058
1059 /*
1060 * 'patmatch()' - Pattern matching...
1061 */
1062
1063 static int /* O - 1 if match, 0 if no match */
1064 patmatch(const char *s, /* I - String to match against */
1065 const char *pat) /* I - Pattern to match against */
1066 {
1067 /*
1068 * Range check the input...
1069 */
1070
1071 if (s == NULL || pat == NULL)
1072 return (0);
1073
1074 /*
1075 * Loop through the pattern and match strings, and stop if we come to a
1076 * point where the strings don't match or we find a complete match.
1077 */
1078
1079 while (*s != '\0' && *pat != '\0')
1080 {
1081 if (*pat == '*')
1082 {
1083 /*
1084 * Wildcard - 0 or more characters...
1085 */
1086
1087 pat ++;
1088 if (*pat == '\0')
1089 return (1); /* Last pattern char is *, so everything matches now... */
1090
1091 /*
1092 * Test all remaining combinations until we get to the end of the string.
1093 */
1094
1095 while (*s != '\0')
1096 {
1097 if (patmatch(s, pat))
1098 return (1);
1099
1100 s ++;
1101 }
1102 }
1103 else if (*pat == '?')
1104 {
1105 /*
1106 * Wildcard - 1 character...
1107 */
1108
1109 pat ++;
1110 s ++;
1111 continue;
1112 }
1113 else if (*pat == '[')
1114 {
1115 /*
1116 * Match a character from the input set [chars]...
1117 */
1118
1119 pat ++;
1120 while (*pat != ']' && *pat != '\0')
1121 if (*s == *pat)
1122 break;
1123 else
1124 pat ++;
1125
1126 if (*pat == ']' || *pat == '\0')
1127 return (0);
1128
1129 while (*pat != ']' && *pat != '\0')
1130 pat ++;
1131
1132 if (*pat == ']')
1133 pat ++;
1134
1135 continue;
1136 }
1137 else if (*pat == '\\')
1138 {
1139 /*
1140 * Handle quoted characters...
1141 */
1142
1143 pat ++;
1144 }
1145
1146 /*
1147 * Stop if the pattern and string don't match...
1148 */
1149
1150 if (*pat++ != *s++)
1151 return (0);
1152 }
1153
1154 /*
1155 * Done parsing the pattern and string; return 1 if the last character matches
1156 * and 0 otherwise...
1157 */
1158
1159 return (*s == *pat);
1160 }
1161
1162
1163 /*
1164 * End of "$Id: type.c 4613 2005-08-30 12:41:48Z mike $".
1165 */