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