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