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