Update to file 4.13. Put the contrib files into contrib/file-4 instead
[dragonfly.git] / contrib / file-4 / src / softmagic.c
blob1202f72661888adfaf2d20edbdb12cc89a38cd02
1 /*
2 * Copyright (c) Ian F. Darwin 1986-1995.
3 * Software written by Ian F. Darwin and others;
4 * maintained 1995-present by Christos Zoulas and others.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice immediately at the beginning of the file, without modification,
11 * this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
29 * softmagic - interpret variable magic from MAGIC
32 #include "file.h"
33 #include "magic.h"
34 #include <string.h>
35 #include <ctype.h>
36 #include <stdlib.h>
37 #include <time.h>
38 #include <regex.h>
41 #ifndef lint
42 FILE_RCSID("@(#)$Id: softmagic.c,v 1.72 2004/11/24 17:38:25 christos Exp $")
43 #endif /* lint */
45 private int match(struct magic_set *, struct magic *, uint32_t,
46 const unsigned char *, size_t);
47 private int mget(struct magic_set *, union VALUETYPE *, const unsigned char *,
48 struct magic *, size_t);
49 private int mcheck(struct magic_set *, union VALUETYPE *, struct magic *);
50 private int32_t mprint(struct magic_set *, union VALUETYPE *, struct magic *);
51 private void mdebug(uint32_t, const char *, size_t);
52 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
53 const unsigned char *, size_t, size_t);
54 private int mconvert(struct magic_set *, union VALUETYPE *, struct magic *);
55 private int check_mem(struct magic_set *, unsigned int);
58 * softmagic - lookup one file in database
59 * (already read from MAGIC by apprentice.c).
60 * Passed the name and FILE * of one file to be typed.
62 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
63 protected int
64 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
66 struct mlist *ml;
67 for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next)
68 if (match(ms, ml->magic, ml->nmagic, buf, nbytes))
69 return 1;
71 return 0;
75 * Go through the whole list, stopping if you find a match. Process all
76 * the continuations of that match before returning.
78 * We support multi-level continuations:
80 * At any time when processing a successful top-level match, there is a
81 * current continuation level; it represents the level of the last
82 * successfully matched continuation.
84 * Continuations above that level are skipped as, if we see one, it
85 * means that the continuation that controls them - i.e, the
86 * lower-level continuation preceding them - failed to match.
88 * Continuations below that level are processed as, if we see one,
89 * it means we've finished processing or skipping higher-level
90 * continuations under the control of a successful or unsuccessful
91 * lower-level continuation, and are now seeing the next lower-level
92 * continuation and should process it. The current continuation
93 * level reverts to the level of the one we're seeing.
95 * Continuations at the current level are processed as, if we see
96 * one, there's no lower-level continuation that may have failed.
98 * If a continuation matches, we bump the current continuation level
99 * so that higher-level continuations are processed.
101 private int
102 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
103 const unsigned char *s, size_t nbytes)
105 uint32_t magindex = 0;
106 unsigned int cont_level = 0;
107 int need_separator = 0;
108 union VALUETYPE p;
109 int32_t oldoff = 0;
110 int returnval = 0; /* if a match is found it is set to 1*/
111 int firstline = 1; /* a flag to print X\n X\n- X */
113 if (check_mem(ms, cont_level) == -1)
114 return -1;
116 for (magindex = 0; magindex < nmagic; magindex++) {
117 /* if main entry matches, print it... */
118 int flush = !mget(ms, &p, s, &magic[magindex], nbytes);
119 switch (mcheck(ms, &p, &magic[magindex])) {
120 case -1:
121 return -1;
122 case 0:
123 flush++;
124 break;
125 default:
126 break;
128 if (flush) {
130 * main entry didn't match,
131 * flush its continuations
133 while (magindex < nmagic - 1 &&
134 magic[magindex + 1].cont_level != 0)
135 magindex++;
136 continue;
139 if (!firstline) { /* we found another match */
140 /* put a newline and '-' to do some simple formatting*/
141 if (file_printf(ms, "\n- ") == -1)
142 return -1;
145 if ((ms->c.off[cont_level] = mprint(ms, &p, &magic[magindex]))
146 == -1)
147 return -1;
149 * If we printed something, we'll need to print
150 * a blank before we print something else.
152 if (magic[magindex].desc[0])
153 need_separator = 1;
154 /* and any continuations that match */
155 if (check_mem(ms, ++cont_level) == -1)
156 return -1;
158 while (magic[magindex+1].cont_level != 0 &&
159 ++magindex < nmagic) {
160 if (cont_level < magic[magindex].cont_level)
161 continue;
162 if (cont_level > magic[magindex].cont_level) {
164 * We're at the end of the level
165 * "cont_level" continuations.
167 cont_level = magic[magindex].cont_level;
169 if (magic[magindex].flag & OFFADD) {
170 oldoff=magic[magindex].offset;
171 magic[magindex].offset += ms->c.off[cont_level-1];
173 if (!mget(ms, &p, s, &magic[magindex], nbytes))
174 goto done;
176 switch (mcheck(ms, &p, &magic[magindex])) {
177 case -1:
178 return -1;
179 case 0:
180 break;
181 default:
183 * This continuation matched.
184 * Print its message, with
185 * a blank before it if
186 * the previous item printed
187 * and this item isn't empty.
189 /* space if previous printed */
190 if (need_separator
191 && (magic[magindex].nospflag == 0)
192 && (magic[magindex].desc[0] != '\0')) {
193 if (file_printf(ms, " ") == -1)
194 return -1;
195 need_separator = 0;
197 if ((ms->c.off[cont_level] = mprint(ms, &p,
198 &magic[magindex])) == -1)
199 return -1;
200 if (magic[magindex].desc[0])
201 need_separator = 1;
204 * If we see any continuations
205 * at a higher level,
206 * process them.
208 if (check_mem(ms, ++cont_level) == -1)
209 return -1;
211 done:
212 if (magic[magindex].flag & OFFADD) {
213 magic[magindex].offset = oldoff;
216 firstline = 0;
217 returnval = 1;
218 if ((ms->flags & MAGIC_CONTINUE) == 0) {
219 return 1; /* don't keep searching */
222 return returnval; /* This is hit if -k is set or there is no match */
225 private int
226 check_mem(struct magic_set *ms, unsigned int level)
228 size_t len;
230 if (level < ms->c.len)
231 return 0;
233 len = (ms->c.len += 20) * sizeof(*ms->c.off);
234 ms->c.off = (ms->c.off == NULL) ? malloc(len) : realloc(ms->c.off, len);
235 if (ms->c.off != NULL)
236 return 0;
237 file_oomem(ms);
238 return -1;
241 private int32_t
242 mprint(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
244 uint32_t v;
245 int32_t t=0 ;
248 switch (m->type) {
249 case FILE_BYTE:
250 v = file_signextend(ms, m, (size_t)p->b);
251 if (file_printf(ms, m->desc, (unsigned char) v) == -1)
252 return -1;
253 t = m->offset + sizeof(char);
254 break;
256 case FILE_SHORT:
257 case FILE_BESHORT:
258 case FILE_LESHORT:
259 v = file_signextend(ms, m, (size_t)p->h);
260 if (file_printf(ms, m->desc, (unsigned short) v) == -1)
261 return -1;
262 t = m->offset + sizeof(short);
263 break;
265 case FILE_LONG:
266 case FILE_BELONG:
267 case FILE_LELONG:
268 v = file_signextend(ms, m, p->l);
269 if (file_printf(ms, m->desc, (uint32_t) v) == -1)
270 return -1;
271 t = m->offset + sizeof(int32_t);
272 break;
274 case FILE_STRING:
275 case FILE_PSTRING:
276 case FILE_BESTRING16:
277 case FILE_LESTRING16:
278 if (m->reln == '=') {
279 if (file_printf(ms, m->desc, m->value.s) == -1)
280 return -1;
281 t = m->offset + strlen(m->value.s);
283 else {
284 if (*m->value.s == '\0') {
285 char *cp = strchr(p->s,'\n');
286 if (cp)
287 *cp = '\0';
289 if (file_printf(ms, m->desc, p->s) == -1)
290 return -1;
291 t = m->offset + strlen(p->s);
293 break;
295 case FILE_DATE:
296 case FILE_BEDATE:
297 case FILE_LEDATE:
298 if (file_printf(ms, m->desc, file_fmttime(p->l, 1)) == -1)
299 return -1;
300 t = m->offset + sizeof(time_t);
301 break;
303 case FILE_LDATE:
304 case FILE_BELDATE:
305 case FILE_LELDATE:
306 if (file_printf(ms, m->desc, file_fmttime(p->l, 0)) == -1)
307 return -1;
308 t = m->offset + sizeof(time_t);
309 break;
310 case FILE_REGEX:
311 if (file_printf(ms, m->desc, p->s) == -1)
312 return -1;
313 t = m->offset + strlen(p->s);
314 break;
316 default:
317 file_error(ms, 0, "invalid m->type (%d) in mprint()", m->type);
318 return -1;
320 return(t);
324 * Convert the byte order of the data we are looking at
325 * While we're here, let's apply the mask operation
326 * (unless you have a better idea)
328 private int
329 mconvert(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
331 switch (m->type) {
332 case FILE_BYTE:
333 if (m->mask)
334 switch (m->mask_op&0x7F) {
335 case FILE_OPAND:
336 p->b &= m->mask;
337 break;
338 case FILE_OPOR:
339 p->b |= m->mask;
340 break;
341 case FILE_OPXOR:
342 p->b ^= m->mask;
343 break;
344 case FILE_OPADD:
345 p->b += m->mask;
346 break;
347 case FILE_OPMINUS:
348 p->b -= m->mask;
349 break;
350 case FILE_OPMULTIPLY:
351 p->b *= m->mask;
352 break;
353 case FILE_OPDIVIDE:
354 p->b /= m->mask;
355 break;
356 case FILE_OPMODULO:
357 p->b %= m->mask;
358 break;
360 if (m->mask_op & FILE_OPINVERSE)
361 p->b = ~p->b;
362 return 1;
363 case FILE_SHORT:
364 if (m->mask)
365 switch (m->mask_op&0x7F) {
366 case FILE_OPAND:
367 p->h &= m->mask;
368 break;
369 case FILE_OPOR:
370 p->h |= m->mask;
371 break;
372 case FILE_OPXOR:
373 p->h ^= m->mask;
374 break;
375 case FILE_OPADD:
376 p->h += m->mask;
377 break;
378 case FILE_OPMINUS:
379 p->h -= m->mask;
380 break;
381 case FILE_OPMULTIPLY:
382 p->h *= m->mask;
383 break;
384 case FILE_OPDIVIDE:
385 p->h /= m->mask;
386 break;
387 case FILE_OPMODULO:
388 p->h %= m->mask;
389 break;
391 if (m->mask_op & FILE_OPINVERSE)
392 p->h = ~p->h;
393 return 1;
394 case FILE_LONG:
395 case FILE_DATE:
396 case FILE_LDATE:
397 if (m->mask)
398 switch (m->mask_op&0x7F) {
399 case FILE_OPAND:
400 p->l &= m->mask;
401 break;
402 case FILE_OPOR:
403 p->l |= m->mask;
404 break;
405 case FILE_OPXOR:
406 p->l ^= m->mask;
407 break;
408 case FILE_OPADD:
409 p->l += m->mask;
410 break;
411 case FILE_OPMINUS:
412 p->l -= m->mask;
413 break;
414 case FILE_OPMULTIPLY:
415 p->l *= m->mask;
416 break;
417 case FILE_OPDIVIDE:
418 p->l /= m->mask;
419 break;
420 case FILE_OPMODULO:
421 p->l %= m->mask;
422 break;
424 if (m->mask_op & FILE_OPINVERSE)
425 p->l = ~p->l;
426 return 1;
427 case FILE_STRING:
428 case FILE_BESTRING16:
429 case FILE_LESTRING16:
431 size_t len;
433 /* Null terminate and eat *trailing* return */
434 p->s[sizeof(p->s) - 1] = '\0';
435 len = strlen(p->s);
436 if (len-- && p->s[len] == '\n')
437 p->s[len] = '\0';
438 return 1;
440 case FILE_PSTRING:
442 char *ptr1 = p->s, *ptr2 = ptr1 + 1;
443 size_t len = *p->s;
444 if (len >= sizeof(p->s))
445 len = sizeof(p->s) - 1;
446 while (len--)
447 *ptr1++ = *ptr2++;
448 *ptr1 = '\0';
449 len = strlen(p->s);
450 if (len-- && p->s[len] == '\n')
451 p->s[len] = '\0';
452 return 1;
454 case FILE_BESHORT:
455 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
456 if (m->mask)
457 switch (m->mask_op&0x7F) {
458 case FILE_OPAND:
459 p->h &= m->mask;
460 break;
461 case FILE_OPOR:
462 p->h |= m->mask;
463 break;
464 case FILE_OPXOR:
465 p->h ^= m->mask;
466 break;
467 case FILE_OPADD:
468 p->h += m->mask;
469 break;
470 case FILE_OPMINUS:
471 p->h -= m->mask;
472 break;
473 case FILE_OPMULTIPLY:
474 p->h *= m->mask;
475 break;
476 case FILE_OPDIVIDE:
477 p->h /= m->mask;
478 break;
479 case FILE_OPMODULO:
480 p->h %= m->mask;
481 break;
483 if (m->mask_op & FILE_OPINVERSE)
484 p->h = ~p->h;
485 return 1;
486 case FILE_BELONG:
487 case FILE_BEDATE:
488 case FILE_BELDATE:
489 p->l = (int32_t)
490 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
491 if (m->mask)
492 switch (m->mask_op&0x7F) {
493 case FILE_OPAND:
494 p->l &= m->mask;
495 break;
496 case FILE_OPOR:
497 p->l |= m->mask;
498 break;
499 case FILE_OPXOR:
500 p->l ^= m->mask;
501 break;
502 case FILE_OPADD:
503 p->l += m->mask;
504 break;
505 case FILE_OPMINUS:
506 p->l -= m->mask;
507 break;
508 case FILE_OPMULTIPLY:
509 p->l *= m->mask;
510 break;
511 case FILE_OPDIVIDE:
512 p->l /= m->mask;
513 break;
514 case FILE_OPMODULO:
515 p->l %= m->mask;
516 break;
518 if (m->mask_op & FILE_OPINVERSE)
519 p->l = ~p->l;
520 return 1;
521 case FILE_LESHORT:
522 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
523 if (m->mask)
524 switch (m->mask_op&0x7F) {
525 case FILE_OPAND:
526 p->h &= m->mask;
527 break;
528 case FILE_OPOR:
529 p->h |= m->mask;
530 break;
531 case FILE_OPXOR:
532 p->h ^= m->mask;
533 break;
534 case FILE_OPADD:
535 p->h += m->mask;
536 break;
537 case FILE_OPMINUS:
538 p->h -= m->mask;
539 break;
540 case FILE_OPMULTIPLY:
541 p->h *= m->mask;
542 break;
543 case FILE_OPDIVIDE:
544 p->h /= m->mask;
545 break;
546 case FILE_OPMODULO:
547 p->h %= m->mask;
548 break;
550 if (m->mask_op & FILE_OPINVERSE)
551 p->h = ~p->h;
552 return 1;
553 case FILE_LELONG:
554 case FILE_LEDATE:
555 case FILE_LELDATE:
556 p->l = (int32_t)
557 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
558 if (m->mask)
559 switch (m->mask_op&0x7F) {
560 case FILE_OPAND:
561 p->l &= m->mask;
562 break;
563 case FILE_OPOR:
564 p->l |= m->mask;
565 break;
566 case FILE_OPXOR:
567 p->l ^= m->mask;
568 break;
569 case FILE_OPADD:
570 p->l += m->mask;
571 break;
572 case FILE_OPMINUS:
573 p->l -= m->mask;
574 break;
575 case FILE_OPMULTIPLY:
576 p->l *= m->mask;
577 break;
578 case FILE_OPDIVIDE:
579 p->l /= m->mask;
580 break;
581 case FILE_OPMODULO:
582 p->l %= m->mask;
583 break;
585 if (m->mask_op & FILE_OPINVERSE)
586 p->l = ~p->l;
587 return 1;
588 case FILE_REGEX:
589 return 1;
590 default:
591 file_error(ms, 0, "invalid type %d in mconvert()", m->type);
592 return 0;
597 private void
598 mdebug(uint32_t offset, const char *str, size_t len)
600 (void) fprintf(stderr, "mget @%d: ", offset);
601 file_showstr(stderr, str, len);
602 (void) fputc('\n', stderr);
603 (void) fputc('\n', stderr);
606 private int
607 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
608 const unsigned char *s, size_t offset, size_t nbytes)
610 if (type == FILE_REGEX && indir == 0) {
612 * offset is interpreted as last line to search,
613 * (starting at 1), not as bytes-from start-of-file
615 unsigned char *b, *last = NULL;
616 if ((p->buf = strdup((const char *)s)) == NULL) {
617 file_oomem(ms);
618 return -1;
620 for (b = (unsigned char *)p->buf; offset &&
621 (b = (unsigned char *)strchr((char *)b, '\n')) != NULL;
622 offset--, s++)
623 last = b;
624 if (last != NULL)
625 *last = '\0';
626 return 0;
629 if (indir == 0 && (type == FILE_BESTRING16 || type == FILE_LESTRING16))
631 const char *src = s + offset;
632 const char *esrc = s + nbytes;
633 char *dst = p->s, *edst = &p->s[sizeof(p->s) - 1];
635 if (type == FILE_BESTRING16)
636 src++;
638 for (;src < esrc; src++, dst++) {
639 if (dst < edst)
640 *dst = *src++;
641 else
642 break;
643 if (*dst == '\0')
644 *dst = ' ';
646 *edst = '\0';
647 return 0;
650 if (offset >= nbytes) {
651 (void)memset(p, '\0', sizeof(*p));
652 return 0;
654 if (nbytes - offset < sizeof(*p))
655 nbytes = nbytes - offset;
656 else
657 nbytes = sizeof(*p);
659 (void)memcpy(p, s + offset, nbytes);
662 * the usefulness of padding with zeroes eludes me, it
663 * might even cause problems
665 if (nbytes < sizeof(*p))
666 (void)memset(((char *)p) + nbytes, '\0', sizeof(*p) - nbytes);
667 return 0;
670 private int
671 mget(struct magic_set *ms, union VALUETYPE *p, const unsigned char *s,
672 struct magic *m, size_t nbytes)
674 uint32_t offset = m->offset;
676 if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes) == -1)
677 return -1;
679 /* Verify we have enough data to match magic type */
680 switch (m->type) {
681 case FILE_BYTE:
682 if (nbytes < (offset + 1)) /* should alway be true */
683 return 0;
684 break;
686 case FILE_SHORT:
687 case FILE_BESHORT:
688 case FILE_LESHORT:
689 if (nbytes < (offset + 2))
690 return 0;
691 break;
693 case FILE_LONG:
694 case FILE_BELONG:
695 case FILE_LELONG:
696 case FILE_DATE:
697 case FILE_BEDATE:
698 case FILE_LEDATE:
699 case FILE_LDATE:
700 case FILE_BELDATE:
701 case FILE_LELDATE:
702 if (nbytes < (offset + 4))
703 return 0;
704 break;
706 case FILE_STRING:
707 case FILE_PSTRING:
708 if (nbytes < (offset + m->vallen))
709 return 0;
710 break;
713 if ((ms->flags & MAGIC_DEBUG) != 0) {
714 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
715 file_mdump(m);
718 if (m->flag & INDIR) {
719 switch (m->in_type) {
720 case FILE_BYTE:
721 if (m->in_offset) {
722 switch (m->in_op&0x7F) {
723 case FILE_OPAND:
724 offset = p->b & m->in_offset;
725 break;
726 case FILE_OPOR:
727 offset = p->b | m->in_offset;
728 break;
729 case FILE_OPXOR:
730 offset = p->b ^ m->in_offset;
731 break;
732 case FILE_OPADD:
733 offset = p->b + m->in_offset;
734 break;
735 case FILE_OPMINUS:
736 offset = p->b - m->in_offset;
737 break;
738 case FILE_OPMULTIPLY:
739 offset = p->b * m->in_offset;
740 break;
741 case FILE_OPDIVIDE:
742 offset = p->b / m->in_offset;
743 break;
744 case FILE_OPMODULO:
745 offset = p->b % m->in_offset;
746 break;
748 } else
749 offset = p->b;
750 if (m->in_op & FILE_OPINVERSE)
751 offset = ~offset;
752 break;
753 case FILE_BESHORT:
754 if (m->in_offset) {
755 switch (m->in_op & 0x7F) {
756 case FILE_OPAND:
757 offset = (short)((p->hs[0]<<8)|
758 (p->hs[1])) &
759 m->in_offset;
760 break;
761 case FILE_OPOR:
762 offset = (short)((p->hs[0]<<8)|
763 (p->hs[1])) |
764 m->in_offset;
765 break;
766 case FILE_OPXOR:
767 offset = (short)((p->hs[0]<<8)|
768 (p->hs[1])) ^
769 m->in_offset;
770 break;
771 case FILE_OPADD:
772 offset = (short)((p->hs[0]<<8)|
773 (p->hs[1])) +
774 m->in_offset;
775 break;
776 case FILE_OPMINUS:
777 offset = (short)((p->hs[0]<<8)|
778 (p->hs[1])) -
779 m->in_offset;
780 break;
781 case FILE_OPMULTIPLY:
782 offset = (short)((p->hs[0]<<8)|
783 (p->hs[1])) *
784 m->in_offset;
785 break;
786 case FILE_OPDIVIDE:
787 offset = (short)((p->hs[0]<<8)|
788 (p->hs[1])) /
789 m->in_offset;
790 break;
791 case FILE_OPMODULO:
792 offset = (short)((p->hs[0]<<8)|
793 (p->hs[1])) %
794 m->in_offset;
795 break;
797 } else
798 offset = (short)((p->hs[0]<<8)|
799 (p->hs[1]));
800 if (m->in_op & FILE_OPINVERSE)
801 offset = ~offset;
802 break;
803 case FILE_LESHORT:
804 if (m->in_offset) {
805 switch (m->in_op & 0x7F) {
806 case FILE_OPAND:
807 offset = (short)((p->hs[1]<<8)|
808 (p->hs[0])) &
809 m->in_offset;
810 break;
811 case FILE_OPOR:
812 offset = (short)((p->hs[1]<<8)|
813 (p->hs[0])) |
814 m->in_offset;
815 break;
816 case FILE_OPXOR:
817 offset = (short)((p->hs[1]<<8)|
818 (p->hs[0])) ^
819 m->in_offset;
820 break;
821 case FILE_OPADD:
822 offset = (short)((p->hs[1]<<8)|
823 (p->hs[0])) +
824 m->in_offset;
825 break;
826 case FILE_OPMINUS:
827 offset = (short)((p->hs[1]<<8)|
828 (p->hs[0])) -
829 m->in_offset;
830 break;
831 case FILE_OPMULTIPLY:
832 offset = (short)((p->hs[1]<<8)|
833 (p->hs[0])) *
834 m->in_offset;
835 break;
836 case FILE_OPDIVIDE:
837 offset = (short)((p->hs[1]<<8)|
838 (p->hs[0])) /
839 m->in_offset;
840 break;
841 case FILE_OPMODULO:
842 offset = (short)((p->hs[1]<<8)|
843 (p->hs[0])) %
844 m->in_offset;
845 break;
847 } else
848 offset = (short)((p->hs[1]<<8)|
849 (p->hs[0]));
850 if (m->in_op & FILE_OPINVERSE)
851 offset = ~offset;
852 break;
853 case FILE_SHORT:
854 if (m->in_offset) {
855 switch (m->in_op & 0x7F) {
856 case FILE_OPAND:
857 offset = p->h & m->in_offset;
858 break;
859 case FILE_OPOR:
860 offset = p->h | m->in_offset;
861 break;
862 case FILE_OPXOR:
863 offset = p->h ^ m->in_offset;
864 break;
865 case FILE_OPADD:
866 offset = p->h + m->in_offset;
867 break;
868 case FILE_OPMINUS:
869 offset = p->h - m->in_offset;
870 break;
871 case FILE_OPMULTIPLY:
872 offset = p->h * m->in_offset;
873 break;
874 case FILE_OPDIVIDE:
875 offset = p->h / m->in_offset;
876 break;
877 case FILE_OPMODULO:
878 offset = p->h % m->in_offset;
879 break;
882 else
883 offset = p->h;
884 if (m->in_op & FILE_OPINVERSE)
885 offset = ~offset;
886 break;
887 case FILE_BELONG:
888 if (m->in_offset) {
889 switch (m->in_op & 0x7F) {
890 case FILE_OPAND:
891 offset = (int32_t)((p->hl[0]<<24)|
892 (p->hl[1]<<16)|
893 (p->hl[2]<<8)|
894 (p->hl[3])) &
895 m->in_offset;
896 break;
897 case FILE_OPOR:
898 offset = (int32_t)((p->hl[0]<<24)|
899 (p->hl[1]<<16)|
900 (p->hl[2]<<8)|
901 (p->hl[3])) |
902 m->in_offset;
903 break;
904 case FILE_OPXOR:
905 offset = (int32_t)((p->hl[0]<<24)|
906 (p->hl[1]<<16)|
907 (p->hl[2]<<8)|
908 (p->hl[3])) ^
909 m->in_offset;
910 break;
911 case FILE_OPADD:
912 offset = (int32_t)((p->hl[0]<<24)|
913 (p->hl[1]<<16)|
914 (p->hl[2]<<8)|
915 (p->hl[3])) +
916 m->in_offset;
917 break;
918 case FILE_OPMINUS:
919 offset = (int32_t)((p->hl[0]<<24)|
920 (p->hl[1]<<16)|
921 (p->hl[2]<<8)|
922 (p->hl[3])) -
923 m->in_offset;
924 break;
925 case FILE_OPMULTIPLY:
926 offset = (int32_t)((p->hl[0]<<24)|
927 (p->hl[1]<<16)|
928 (p->hl[2]<<8)|
929 (p->hl[3])) *
930 m->in_offset;
931 break;
932 case FILE_OPDIVIDE:
933 offset = (int32_t)((p->hl[0]<<24)|
934 (p->hl[1]<<16)|
935 (p->hl[2]<<8)|
936 (p->hl[3])) /
937 m->in_offset;
938 break;
939 case FILE_OPMODULO:
940 offset = (int32_t)((p->hl[0]<<24)|
941 (p->hl[1]<<16)|
942 (p->hl[2]<<8)|
943 (p->hl[3])) %
944 m->in_offset;
945 break;
947 } else
948 offset = (int32_t)((p->hl[0]<<24)|
949 (p->hl[1]<<16)|
950 (p->hl[2]<<8)|
951 (p->hl[3]));
952 if (m->in_op & FILE_OPINVERSE)
953 offset = ~offset;
954 break;
955 case FILE_LELONG:
956 if (m->in_offset) {
957 switch (m->in_op & 0x7F) {
958 case FILE_OPAND:
959 offset = (int32_t)((p->hl[3]<<24)|
960 (p->hl[2]<<16)|
961 (p->hl[1]<<8)|
962 (p->hl[0])) &
963 m->in_offset;
964 break;
965 case FILE_OPOR:
966 offset = (int32_t)((p->hl[3]<<24)|
967 (p->hl[2]<<16)|
968 (p->hl[1]<<8)|
969 (p->hl[0])) |
970 m->in_offset;
971 break;
972 case FILE_OPXOR:
973 offset = (int32_t)((p->hl[3]<<24)|
974 (p->hl[2]<<16)|
975 (p->hl[1]<<8)|
976 (p->hl[0])) ^
977 m->in_offset;
978 break;
979 case FILE_OPADD:
980 offset = (int32_t)((p->hl[3]<<24)|
981 (p->hl[2]<<16)|
982 (p->hl[1]<<8)|
983 (p->hl[0])) +
984 m->in_offset;
985 break;
986 case FILE_OPMINUS:
987 offset = (int32_t)((p->hl[3]<<24)|
988 (p->hl[2]<<16)|
989 (p->hl[1]<<8)|
990 (p->hl[0])) -
991 m->in_offset;
992 break;
993 case FILE_OPMULTIPLY:
994 offset = (int32_t)((p->hl[3]<<24)|
995 (p->hl[2]<<16)|
996 (p->hl[1]<<8)|
997 (p->hl[0])) *
998 m->in_offset;
999 break;
1000 case FILE_OPDIVIDE:
1001 offset = (int32_t)((p->hl[3]<<24)|
1002 (p->hl[2]<<16)|
1003 (p->hl[1]<<8)|
1004 (p->hl[0])) /
1005 m->in_offset;
1006 break;
1007 case FILE_OPMODULO:
1008 offset = (int32_t)((p->hl[3]<<24)|
1009 (p->hl[2]<<16)|
1010 (p->hl[1]<<8)|
1011 (p->hl[0])) %
1012 m->in_offset;
1013 break;
1015 } else
1016 offset = (int32_t)((p->hl[3]<<24)|
1017 (p->hl[2]<<16)|
1018 (p->hl[1]<<8)|
1019 (p->hl[0]));
1020 if (m->in_op & FILE_OPINVERSE)
1021 offset = ~offset;
1022 break;
1023 case FILE_LONG:
1024 if (m->in_offset) {
1025 switch (m->in_op & 0x7F) {
1026 case FILE_OPAND:
1027 offset = p->l & m->in_offset;
1028 break;
1029 case FILE_OPOR:
1030 offset = p->l | m->in_offset;
1031 break;
1032 case FILE_OPXOR:
1033 offset = p->l ^ m->in_offset;
1034 break;
1035 case FILE_OPADD:
1036 offset = p->l + m->in_offset;
1037 break;
1038 case FILE_OPMINUS:
1039 offset = p->l - m->in_offset;
1040 break;
1041 case FILE_OPMULTIPLY:
1042 offset = p->l * m->in_offset;
1043 break;
1044 case FILE_OPDIVIDE:
1045 offset = p->l / m->in_offset;
1046 break;
1047 case FILE_OPMODULO:
1048 offset = p->l % m->in_offset;
1049 break;
1050 /* case TOOMANYSWITCHBLOCKS:
1051 * ugh = p->eye % m->strain;
1052 * rub;
1053 * case BEER:
1054 * off = p->tab & m->in_gest;
1055 * sleep;
1058 } else
1059 offset = p->l;
1060 if (m->in_op & FILE_OPINVERSE)
1061 offset = ~offset;
1062 break;
1065 if (mcopy(ms, p, m->type, 0, s, offset, nbytes) == -1)
1066 return -1;
1068 if ((ms->flags & MAGIC_DEBUG) != 0) {
1069 mdebug(offset, (char *)(void *)p,
1070 sizeof(union VALUETYPE));
1071 file_mdump(m);
1074 if (!mconvert(ms, p, m))
1075 return 0;
1076 return 1;
1079 private int
1080 mcheck(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
1082 uint32_t l = m->value.l;
1083 uint32_t v;
1084 int matched;
1086 if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
1087 return 1;
1091 switch (m->type) {
1092 case FILE_BYTE:
1093 v = p->b;
1094 break;
1096 case FILE_SHORT:
1097 case FILE_BESHORT:
1098 case FILE_LESHORT:
1099 v = p->h;
1100 break;
1102 case FILE_LONG:
1103 case FILE_BELONG:
1104 case FILE_LELONG:
1105 case FILE_DATE:
1106 case FILE_BEDATE:
1107 case FILE_LEDATE:
1108 case FILE_LDATE:
1109 case FILE_BELDATE:
1110 case FILE_LELDATE:
1111 v = p->l;
1112 break;
1114 case FILE_STRING:
1115 case FILE_BESTRING16:
1116 case FILE_LESTRING16:
1117 case FILE_PSTRING:
1120 * What we want here is:
1121 * v = strncmp(m->value.s, p->s, m->vallen);
1122 * but ignoring any nulls. bcmp doesn't give -/+/0
1123 * and isn't universally available anyway.
1125 unsigned char *a = (unsigned char*)m->value.s;
1126 unsigned char *b = (unsigned char*)p->s;
1127 int len = m->vallen;
1128 l = 0;
1129 v = 0;
1130 if (0L == m->mask) { /* normal string: do it fast */
1131 while (--len >= 0)
1132 if ((v = *b++ - *a++) != '\0')
1133 break;
1134 } else { /* combine the others */
1135 while (--len >= 0) {
1136 if ((m->mask & STRING_IGNORE_LOWERCASE) &&
1137 islower(*a)) {
1138 if ((v = tolower(*b++) - *a++) != '\0')
1139 break;
1140 } else if ((m->mask & STRING_COMPACT_BLANK) &&
1141 isspace(*a)) {
1142 a++;
1143 if (isspace(*b++)) {
1144 while (isspace(*b))
1145 b++;
1146 } else {
1147 v = 1;
1148 break;
1150 } else if (isspace(*a) &&
1151 (m->mask & STRING_COMPACT_OPTIONAL_BLANK)) {
1152 a++;
1153 while (isspace(*b))
1154 b++;
1155 } else {
1156 if ((v = *b++ - *a++) != '\0')
1157 break;
1161 break;
1163 case FILE_REGEX:
1165 int rc;
1166 regex_t rx;
1167 char errmsg[512];
1169 rc = regcomp(&rx, m->value.s, REG_EXTENDED|REG_NOSUB);
1170 if (rc) {
1171 free(p->buf);
1172 regerror(rc, &rx, errmsg, sizeof(errmsg));
1173 file_error(ms, 0, "regex error %d, (%s)", rc, errmsg);
1174 return -1;
1175 } else {
1176 rc = regexec(&rx, p->buf, 0, 0, 0);
1177 regfree(&rx);
1178 free(p->buf);
1179 return !rc;
1182 default:
1183 file_error(ms, 0, "invalid type %d in mcheck()", m->type);
1184 return -1;
1187 if (m->type != FILE_STRING && m->type != FILE_PSTRING)
1188 v = file_signextend(ms, m, v);
1190 switch (m->reln) {
1191 case 'x':
1192 if ((ms->flags & MAGIC_DEBUG) != 0)
1193 (void) fprintf(stderr, "%u == *any* = 1\n", v);
1194 matched = 1;
1195 break;
1197 case '!':
1198 matched = v != l;
1199 if ((ms->flags & MAGIC_DEBUG) != 0)
1200 (void) fprintf(stderr, "%u != %u = %d\n",
1201 v, l, matched);
1202 break;
1204 case '=':
1205 matched = v == l;
1206 if ((ms->flags & MAGIC_DEBUG) != 0)
1207 (void) fprintf(stderr, "%u == %u = %d\n",
1208 v, l, matched);
1209 break;
1211 case '>':
1212 if (m->flag & UNSIGNED) {
1213 matched = v > l;
1214 if ((ms->flags & MAGIC_DEBUG) != 0)
1215 (void) fprintf(stderr, "%u > %u = %d\n",
1216 v, l, matched);
1218 else {
1219 matched = (int32_t) v > (int32_t) l;
1220 if ((ms->flags & MAGIC_DEBUG) != 0)
1221 (void) fprintf(stderr, "%d > %d = %d\n",
1222 v, l, matched);
1224 break;
1226 case '<':
1227 if (m->flag & UNSIGNED) {
1228 matched = v < l;
1229 if ((ms->flags & MAGIC_DEBUG) != 0)
1230 (void) fprintf(stderr, "%u < %u = %d\n",
1231 v, l, matched);
1233 else {
1234 matched = (int32_t) v < (int32_t) l;
1235 if ((ms->flags & MAGIC_DEBUG) != 0)
1236 (void) fprintf(stderr, "%d < %d = %d\n",
1237 v, l, matched);
1239 break;
1241 case '&':
1242 matched = (v & l) == l;
1243 if ((ms->flags & MAGIC_DEBUG) != 0)
1244 (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
1245 v, l, l, matched);
1246 break;
1248 case '^':
1249 matched = (v & l) != l;
1250 if ((ms->flags & MAGIC_DEBUG) != 0)
1251 (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
1252 v, l, l, matched);
1253 break;
1255 default:
1256 matched = 0;
1257 file_error(ms, 0, "cannot happen: invalid relation `%c'",
1258 m->reln);
1259 return -1;
1262 return matched;