Merge from vendor branch NTPD:
[dragonfly.git] / contrib / file / softmagic.c
1 /*
2  * softmagic - interpret variable magic from MAGIC
3  *
4  * Copyright (c) Ian F. Darwin, 1987.
5  * Written by Ian F. Darwin.
6  *
7  * This software is not subject to any license of the American Telephone
8  * and Telegraph Company or of the Regents of the University of California.
9  *
10  * Permission is granted to anyone to use this software for any purpose on
11  * any computer system, and to alter it and redistribute it freely, subject
12  * to the following restrictions:
13  *
14  * 1. The author is not responsible for the consequences of use of this
15  *    software, no matter how awful, even if they arise from flaws in it.
16  *
17  * 2. The origin of this software must not be misrepresented, either by
18  *    explicit claim or by omission.  Since few users ever read sources,
19  *    credits must appear in the documentation.
20  *
21  * 3. Altered versions must be plainly marked as such, and must not be
22  *    misrepresented as being the original software.  Since few users
23  *    ever read sources, credits must appear in the documentation.
24  *
25  * 4. This notice may not be removed or altered.
26  */
27
28 #include "file.h"
29 #include <string.h>
30 #include <ctype.h>
31 #include <stdlib.h>
32 #include <time.h>
33 #include <regex.h>
34
35
36 #ifndef lint
37 FILE_RCSID("@(#)$Id: softmagic.c,v 1.54 2003/02/25 13:04:32 christos Exp $")
38 #endif  /* lint */
39
40 static int match(struct magic *, uint32_t, unsigned char *, int);
41 static int mget(union VALUETYPE *, unsigned char *, struct magic *, int);
42 static int mcheck(union VALUETYPE *, struct magic *);
43 static int32_t mprint(union VALUETYPE *, struct magic *);
44 static void mdebug(int32_t, char *, int);
45 static int mconvert(union VALUETYPE *, struct magic *);
46
47 extern int kflag;
48
49 /*
50  * softmagic - lookup one file in database 
51  * (already read from MAGIC by apprentice.c).
52  * Passed the name and FILE * of one file to be typed.
53  */
54 /*ARGSUSED1*/           /* nbytes passed for regularity, maybe need later */
55 int
56 softmagic(unsigned char *buf, int nbytes)
57 {
58         struct mlist *ml;
59
60         for (ml = mlist.next; ml != &mlist; ml = ml->next)
61                 if (match(ml->magic, ml->nmagic, buf, nbytes))
62                         return 1;
63
64         return 0;
65 }
66
67 /*
68  * Go through the whole list, stopping if you find a match.  Process all
69  * the continuations of that match before returning.
70  *
71  * We support multi-level continuations:
72  *
73  *      At any time when processing a successful top-level match, there is a
74  *      current continuation level; it represents the level of the last
75  *      successfully matched continuation.
76  *
77  *      Continuations above that level are skipped as, if we see one, it
78  *      means that the continuation that controls them - i.e, the
79  *      lower-level continuation preceding them - failed to match.
80  *
81  *      Continuations below that level are processed as, if we see one,
82  *      it means we've finished processing or skipping higher-level
83  *      continuations under the control of a successful or unsuccessful
84  *      lower-level continuation, and are now seeing the next lower-level
85  *      continuation and should process it.  The current continuation
86  *      level reverts to the level of the one we're seeing.
87  *
88  *      Continuations at the current level are processed as, if we see
89  *      one, there's no lower-level continuation that may have failed.
90  *
91  *      If a continuation matches, we bump the current continuation level
92  *      so that higher-level continuations are processed.
93  */
94 static int
95 match(struct magic *magic, uint32_t nmagic, unsigned char *s, int nbytes)
96 {
97         int magindex = 0;
98         int cont_level = 0;
99         int need_separator = 0;
100         union VALUETYPE p;
101         static int32_t *tmpoff = NULL;
102         static size_t tmplen = 0;
103         int32_t oldoff = 0;
104         int returnval = 0; /* if a match is found it is set to 1*/
105         int firstline = 1; /* a flag to print X\n  X\n- X */
106
107         if (tmpoff == NULL)
108                 if ((tmpoff = (int32_t *) malloc(
109                     (tmplen = 20) * sizeof(*tmpoff))) == NULL)
110                         error("out of memory\n");
111
112         for (magindex = 0; magindex < nmagic; magindex++) {
113                 /* if main entry matches, print it... */
114                 if (!mget(&p, s, &magic[magindex], nbytes) ||
115                     !mcheck(&p, &magic[magindex])) {
116                             /* 
117                              * main entry didn't match,
118                              * flush its continuations
119                              */
120                             while (magindex < nmagic &&
121                                    magic[magindex + 1].cont_level != 0)
122                                    magindex++;
123                             continue;
124                 }
125
126                 if (! firstline) { /* we found another match */
127                         /* put a newline and '-' to do some simple formatting*/
128                         printf("\n- ");
129                 }
130
131                 tmpoff[cont_level] = mprint(&p, &magic[magindex]);
132                 /*
133                  * If we printed something, we'll need to print
134                  * a blank before we print something else.
135                  */
136                 if (magic[magindex].desc[0])
137                         need_separator = 1;
138                 /* and any continuations that match */
139                 if (++cont_level >= tmplen)
140                         if ((tmpoff = (int32_t *) realloc(tmpoff,
141                             (tmplen += 20) * sizeof(*tmpoff))) == NULL)
142                                 error("out of memory\n");
143                 while (magic[magindex+1].cont_level != 0 && 
144                        ++magindex < nmagic) {
145                         if (cont_level >= magic[magindex].cont_level) {
146                                 if (cont_level > magic[magindex].cont_level) {
147                                         /*
148                                          * We're at the end of the level
149                                          * "cont_level" continuations.
150                                          */
151                                         cont_level = magic[magindex].cont_level;
152                                 }
153                                 if (magic[magindex].flag & OFFADD) {
154                                         oldoff=magic[magindex].offset;
155                                         magic[magindex].offset +=
156                                             tmpoff[cont_level-1];
157                                 }
158                                 if (mget(&p, s, &magic[magindex], nbytes) &&
159                                     mcheck(&p, &magic[magindex])) {
160                                         /*
161                                          * This continuation matched.
162                                          * Print its message, with
163                                          * a blank before it if
164                                          * the previous item printed
165                                          * and this item isn't empty.
166                                          */
167                                         /* space if previous printed */
168                                         if (need_separator
169                                            && (magic[magindex].nospflag == 0)
170                                            && (magic[magindex].desc[0] != '\0')
171                                            ) {
172                                                 (void) putchar(' ');
173                                                 need_separator = 0;
174                                         }
175                                         tmpoff[cont_level] =
176                                             mprint(&p, &magic[magindex]);
177                                         if (magic[magindex].desc[0])
178                                                 need_separator = 1;
179
180                                         /*
181                                          * If we see any continuations
182                                          * at a higher level,
183                                          * process them.
184                                          */
185                                         if (++cont_level >= tmplen)
186                                                 if ((tmpoff = 
187                                                     (int32_t *) realloc(tmpoff,
188                                                     (tmplen += 20) 
189                                                     * sizeof(*tmpoff))) == NULL)
190                                                         error("out of memory\n");
191                                 }
192                                 if (magic[magindex].flag & OFFADD) {
193                                          magic[magindex].offset = oldoff;
194                                 }
195                         }
196                 }
197                 firstline = 0;
198                 returnval = 1;
199                 if (!kflag) {
200                         return 1; /* don't keep searching */
201                 }                       
202         }
203         return returnval;  /* This is hit if -k is set or there is no match */
204 }
205
206 static int32_t
207 mprint(union VALUETYPE *p, struct magic *m)
208 {
209         uint32_t v;
210         int32_t t=0 ;
211
212
213         switch (m->type) {
214         case BYTE:
215                 v = signextend(m, p->b);
216                 (void) printf(m->desc, (unsigned char) v);
217                 t = m->offset + sizeof(char);
218                 break;
219
220         case SHORT:
221         case BESHORT:
222         case LESHORT:
223                 v = signextend(m, p->h);
224                 (void) printf(m->desc, (unsigned short) v);
225                 t = m->offset + sizeof(short);
226                 break;
227
228         case LONG:
229         case BELONG:
230         case LELONG:
231                 v = signextend(m, p->l);
232                 (void) printf(m->desc, (uint32_t) v);
233                 t = m->offset + sizeof(int32_t);
234                 break;
235
236         case STRING:
237         case PSTRING:
238                 if (m->reln == '=') {
239                         (void) printf(m->desc, m->value.s);
240                         t = m->offset + strlen(m->value.s);
241                 }
242                 else {
243                         if (*m->value.s == '\0') {
244                                 char *cp = strchr(p->s,'\n');
245                                 if (cp)
246                                         *cp = '\0';
247                         }
248                         (void) printf(m->desc, p->s);
249                         t = m->offset + strlen(p->s);
250                 }
251                 break;
252
253         case DATE:
254         case BEDATE:
255         case LEDATE:
256                 (void) printf(m->desc, fmttime(p->l, 1));
257                 t = m->offset + sizeof(time_t);
258                 break;
259
260         case LDATE:
261         case BELDATE:
262         case LELDATE:
263                 (void) printf(m->desc, fmttime(p->l, 0));
264                 t = m->offset + sizeof(time_t);
265                 break;
266         case REGEX:
267                 (void) printf(m->desc, p->s);
268                 t = m->offset + strlen(p->s);
269                 break;
270
271         default:
272                 error("invalid m->type (%d) in mprint().\n", m->type);
273                 /*NOTREACHED*/
274         }
275         return(t);
276 }
277
278 /*
279  * Convert the byte order of the data we are looking at
280  * While we're here, let's apply the mask operation
281  * (unless you have a better idea)
282  */
283 static int
284 mconvert(union VALUETYPE *p, struct magic *m)
285 {
286         switch (m->type) {
287         case BYTE:
288                 if (m->mask)
289                         switch (m->mask_op&0x7F) {
290                         case OPAND:
291                                 p->b &= m->mask;
292                                 break;
293                         case OPOR:
294                                 p->b |= m->mask;
295                                 break;
296                         case OPXOR:
297                                 p->b ^= m->mask;
298                                 break;
299                         case OPADD:
300                                 p->b += m->mask;
301                                 break;
302                         case OPMINUS:
303                                 p->b -= m->mask;
304                                 break;
305                         case OPMULTIPLY:
306                                 p->b *= m->mask;
307                                 break;
308                         case OPDIVIDE:
309                                 p->b /= m->mask;
310                                 break;
311                         case OPMODULO:
312                                 p->b %= m->mask;
313                                 break;
314                         }
315                 if (m->mask_op & OPINVERSE)
316                         p->b = ~p->b;
317                 return 1;
318         case SHORT:
319                 if (m->mask)
320                         switch (m->mask_op&0x7F) {
321                         case OPAND:
322                                 p->h &= m->mask;
323                                 break;
324                         case OPOR:
325                                 p->h |= m->mask;
326                                 break;
327                         case OPXOR:
328                                 p->h ^= m->mask;
329                                 break;
330                         case OPADD:
331                                 p->h += m->mask;
332                                 break;
333                         case OPMINUS:
334                                 p->h -= m->mask;
335                                 break;
336                         case OPMULTIPLY:
337                                 p->h *= m->mask;
338                                 break;
339                         case OPDIVIDE:
340                                 p->h /= m->mask;
341                                 break;
342                         case OPMODULO:
343                                 p->h %= m->mask;
344                                 break;
345                         }
346                 if (m->mask_op & OPINVERSE)
347                         p->h = ~p->h;
348                 return 1;
349         case LONG:
350         case DATE:
351         case LDATE:
352                 if (m->mask)
353                         switch (m->mask_op&0x7F) {
354                         case OPAND:
355                                 p->l &= m->mask;
356                                 break;
357                         case OPOR:
358                                 p->l |= m->mask;
359                                 break;
360                         case OPXOR:
361                                 p->l ^= m->mask;
362                                 break;
363                         case OPADD:
364                                 p->l += m->mask;
365                                 break;
366                         case OPMINUS:
367                                 p->l -= m->mask;
368                                 break;
369                         case OPMULTIPLY:
370                                 p->l *= m->mask;
371                                 break;
372                         case OPDIVIDE:
373                                 p->l /= m->mask;
374                                 break;
375                         case OPMODULO:
376                                 p->l %= m->mask;
377                                 break;
378                         }
379                 if (m->mask_op & OPINVERSE)
380                         p->l = ~p->l;
381                 return 1;
382         case STRING:
383                 {
384                         int n;
385
386                         /* Null terminate and eat *trailing* return */
387                         p->s[sizeof(p->s) - 1] = '\0';
388                         n = strlen(p->s) - 1;
389                         if (p->s[n] == '\n')
390                                 p->s[n] = '\0';
391                         return 1;
392                 }
393         case PSTRING:
394                 {
395                         char *ptr1 = p->s, *ptr2 = ptr1 + 1;
396                         int n = *p->s;
397                         if (n >= sizeof(p->s))
398                                 n = sizeof(p->s) - 1;
399                         while (n--)
400                                 *ptr1++ = *ptr2++;
401                         *ptr1 = '\0';
402                         n = strlen(p->s) - 1;
403                         if (p->s[n] == '\n')
404                                 p->s[n] = '\0';
405                         return 1;
406                 }
407         case BESHORT:
408                 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
409                 if (m->mask)
410                         switch (m->mask_op&0x7F) {
411                         case OPAND:
412                                 p->h &= m->mask;
413                                 break;
414                         case OPOR:
415                                 p->h |= m->mask;
416                                 break;
417                         case OPXOR:
418                                 p->h ^= m->mask;
419                                 break;
420                         case OPADD:
421                                 p->h += m->mask;
422                                 break;
423                         case OPMINUS:
424                                 p->h -= m->mask;
425                                 break;
426                         case OPMULTIPLY:
427                                 p->h *= m->mask;
428                                 break;
429                         case OPDIVIDE:
430                                 p->h /= m->mask;
431                                 break;
432                         case OPMODULO:
433                                 p->h %= m->mask;
434                                 break;
435                         }
436                 if (m->mask_op & OPINVERSE)
437                         p->h = ~p->h;
438                 return 1;
439         case BELONG:
440         case BEDATE:
441         case BELDATE:
442                 p->l = (int32_t)
443                     ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
444                 if (m->mask)
445                         switch (m->mask_op&0x7F) {
446                         case OPAND:
447                                 p->l &= m->mask;
448                                 break;
449                         case OPOR:
450                                 p->l |= m->mask;
451                                 break;
452                         case OPXOR:
453                                 p->l ^= m->mask;
454                                 break;
455                         case OPADD:
456                                 p->l += m->mask;
457                                 break;
458                         case OPMINUS:
459                                 p->l -= m->mask;
460                                 break;
461                         case OPMULTIPLY:
462                                 p->l *= m->mask;
463                                 break;
464                         case OPDIVIDE:
465                                 p->l /= m->mask;
466                                 break;
467                         case OPMODULO:
468                                 p->l %= m->mask;
469                                 break;
470                         }
471                 if (m->mask_op & OPINVERSE)
472                         p->l = ~p->l;
473                 return 1;
474         case LESHORT:
475                 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
476                 if (m->mask)
477                         switch (m->mask_op&0x7F) {
478                         case OPAND:
479                                 p->h &= m->mask;
480                                 break;
481                         case OPOR:
482                                 p->h |= m->mask;
483                                 break;
484                         case OPXOR:
485                                 p->h ^= m->mask;
486                                 break;
487                         case OPADD:
488                                 p->h += m->mask;
489                                 break;
490                         case OPMINUS:
491                                 p->h -= m->mask;
492                                 break;
493                         case OPMULTIPLY:
494                                 p->h *= m->mask;
495                                 break;
496                         case OPDIVIDE:
497                                 p->h /= m->mask;
498                                 break;
499                         case OPMODULO:
500                                 p->h %= m->mask;
501                                 break;
502                         }
503                 if (m->mask_op & OPINVERSE)
504                         p->h = ~p->h;
505                 return 1;
506         case LELONG:
507         case LEDATE:
508         case LELDATE:
509                 p->l = (int32_t)
510                     ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
511                 if (m->mask)
512                         switch (m->mask_op&0x7F) {
513                         case OPAND:
514                                 p->l &= m->mask;
515                                 break;
516                         case OPOR:
517                                 p->l |= m->mask;
518                                 break;
519                         case OPXOR:
520                                 p->l ^= m->mask;
521                                 break;
522                         case OPADD:
523                                 p->l += m->mask;
524                                 break;
525                         case OPMINUS:
526                                 p->l -= m->mask;
527                                 break;
528                         case OPMULTIPLY:
529                                 p->l *= m->mask;
530                                 break;
531                         case OPDIVIDE:
532                                 p->l /= m->mask;
533                                 break;
534                         case OPMODULO:
535                                 p->l %= m->mask;
536                                 break;
537                         }
538                 if (m->mask_op & OPINVERSE)
539                         p->l = ~p->l;
540                 return 1;
541         case REGEX:
542                 return 1;
543         default:
544                 error("invalid type %d in mconvert().\n", m->type);
545                 return 0;
546         }
547 }
548
549
550 static void
551 mdebug(int32_t offset, char *str, int len)
552 {
553         (void) fprintf(stderr, "mget @%d: ", offset);
554         showstr(stderr, (char *) str, len);
555         (void) fputc('\n', stderr);
556         (void) fputc('\n', stderr);
557 }
558
559 static int
560 mget(union VALUETYPE *p, unsigned char *s, struct magic *m, int nbytes)
561 {
562         int32_t offset = m->offset;
563
564         if (m->type == REGEX) {
565               /*
566                * offset is interpreted as last line to search,
567                * (starting at 1), not as bytes-from start-of-file
568                */
569               unsigned char *last = NULL;
570               p->buf = (char *)s;
571               for (; offset && (s = (unsigned char *)strchr(s, '\n')) != NULL;
572                   offset--, s++)
573                     last = s;
574               if (last != NULL)
575                 *last = '\0';
576         } else if (offset + sizeof(union VALUETYPE) <= nbytes)
577                 memcpy(p, s + offset, sizeof(union VALUETYPE));
578         else {
579                 /*
580                  * the usefulness of padding with zeroes eludes me, it
581                  * might even cause problems
582                  */
583                 int32_t have = nbytes - offset;
584                 memset(p, 0, sizeof(union VALUETYPE));
585                 if (have > 0)
586                         memcpy(p, s + offset, have);
587         }
588
589         if (debug) {
590                 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
591                 mdump(m);
592         }
593
594         if (m->flag & INDIR) {
595                 switch (m->in_type) {
596                 case BYTE:
597                         if (m->in_offset)
598                                 switch (m->in_op&0x7F) {
599                                 case OPAND:
600                                         offset = p->b & m->in_offset;
601                                         break;
602                                 case OPOR:
603                                         offset = p->b | m->in_offset;
604                                         break;
605                                 case OPXOR:
606                                         offset = p->b ^ m->in_offset;
607                                         break;
608                                 case OPADD:
609                                         offset = p->b + m->in_offset;
610                                         break;
611                                 case OPMINUS:
612                                         offset = p->b - m->in_offset;
613                                         break;
614                                 case OPMULTIPLY:
615                                         offset = p->b * m->in_offset;
616                                         break;
617                                 case OPDIVIDE:
618                                         offset = p->b / m->in_offset;
619                                         break;
620                                 case OPMODULO:
621                                         offset = p->b % m->in_offset;
622                                         break;
623                                 }
624                         if (m->in_op & OPINVERSE)
625                                 offset = ~offset;
626                         break;
627                 case BESHORT:
628                         if (m->in_offset)
629                                 switch (m->in_op&0x7F) {
630                                 case OPAND:
631                                         offset = (short)((p->hs[0]<<8)|
632                                                          (p->hs[1])) &
633                                                  m->in_offset;
634                                         break;
635                                 case OPOR:
636                                         offset = (short)((p->hs[0]<<8)|
637                                                          (p->hs[1])) |
638                                                  m->in_offset;
639                                         break;
640                                 case OPXOR:
641                                         offset = (short)((p->hs[0]<<8)|
642                                                          (p->hs[1])) ^
643                                                  m->in_offset;
644                                         break;
645                                 case OPADD:
646                                         offset = (short)((p->hs[0]<<8)|
647                                                          (p->hs[1])) +
648                                                  m->in_offset;
649                                         break;
650                                 case OPMINUS:
651                                         offset = (short)((p->hs[0]<<8)|
652                                                          (p->hs[1])) -
653                                                  m->in_offset;
654                                         break;
655                                 case OPMULTIPLY:
656                                         offset = (short)((p->hs[0]<<8)|
657                                                          (p->hs[1])) *
658                                                  m->in_offset;
659                                         break;
660                                 case OPDIVIDE:
661                                         offset = (short)((p->hs[0]<<8)|
662                                                          (p->hs[1])) /
663                                                  m->in_offset;
664                                         break;
665                                 case OPMODULO:
666                                         offset = (short)((p->hs[0]<<8)|
667                                                          (p->hs[1])) %
668                                                  m->in_offset;
669                                         break;
670                                 }
671                         if (m->in_op & OPINVERSE)
672                                 offset = ~offset;
673                         break;
674                 case LESHORT:
675                         if (m->in_offset)
676                                 switch (m->in_op&0x7F) {
677                                 case OPAND:
678                                         offset = (short)((p->hs[1]<<8)|
679                                                          (p->hs[0])) &
680                                                  m->in_offset;
681                                         break;
682                                 case OPOR:
683                                         offset = (short)((p->hs[1]<<8)|
684                                                          (p->hs[0])) |
685                                                  m->in_offset;
686                                         break;
687                                 case OPXOR:
688                                         offset = (short)((p->hs[1]<<8)|
689                                                          (p->hs[0])) ^
690                                                  m->in_offset;
691                                         break;
692                                 case OPADD:
693                                         offset = (short)((p->hs[1]<<8)|
694                                                          (p->hs[0])) +
695                                                  m->in_offset;
696                                         break;
697                                 case OPMINUS:
698                                         offset = (short)((p->hs[1]<<8)|
699                                                          (p->hs[0])) -
700                                                  m->in_offset;
701                                         break;
702                                 case OPMULTIPLY:
703                                         offset = (short)((p->hs[1]<<8)|
704                                                          (p->hs[0])) *
705                                                  m->in_offset;
706                                         break;
707                                 case OPDIVIDE:
708                                         offset = (short)((p->hs[1]<<8)|
709                                                          (p->hs[0])) /
710                                                  m->in_offset;
711                                         break;
712                                 case OPMODULO:
713                                         offset = (short)((p->hs[1]<<8)|
714                                                          (p->hs[0])) %
715                                                  m->in_offset;
716                                         break;
717                                 }
718                         if (m->in_op & OPINVERSE)
719                                 offset = ~offset;
720                         break;
721                 case SHORT:
722                         if (m->in_offset)
723                                 switch (m->in_op&0x7F) {
724                                 case OPAND:
725                                         offset = p->h & m->in_offset;
726                                         break;
727                                 case OPOR:
728                                         offset = p->h | m->in_offset;
729                                         break;
730                                 case OPXOR:
731                                         offset = p->h ^ m->in_offset;
732                                         break;
733                                 case OPADD:
734                                         offset = p->h + m->in_offset;
735                                         break;
736                                 case OPMINUS:
737                                         offset = p->h - m->in_offset;
738                                         break;
739                                 case OPMULTIPLY:
740                                         offset = p->h * m->in_offset;
741                                         break;
742                                 case OPDIVIDE:
743                                         offset = p->h / m->in_offset;
744                                         break;
745                                 case OPMODULO:
746                                         offset = p->h % m->in_offset;
747                                         break;
748                                 }
749                         if (m->in_op & OPINVERSE)
750                                 offset = ~offset;
751                         break;
752                 case BELONG:
753                         if (m->in_offset)
754                                 switch (m->in_op&0x7F) {
755                                 case OPAND:
756                                         offset = (int32_t)((p->hl[0]<<24)|
757                                                          (p->hl[1]<<16)|
758                                                          (p->hl[2]<<8)|
759                                                          (p->hl[3])) &
760                                                  m->in_offset;
761                                         break;
762                                 case OPOR:
763                                         offset = (int32_t)((p->hl[0]<<24)|
764                                                          (p->hl[1]<<16)|
765                                                          (p->hl[2]<<8)|
766                                                          (p->hl[3])) |
767                                                  m->in_offset;
768                                         break;
769                                 case OPXOR:
770                                         offset = (int32_t)((p->hl[0]<<24)|
771                                                          (p->hl[1]<<16)|
772                                                          (p->hl[2]<<8)|
773                                                          (p->hl[3])) ^
774                                                  m->in_offset;
775                                         break;
776                                 case OPADD:
777                                         offset = (int32_t)((p->hl[0]<<24)|
778                                                          (p->hl[1]<<16)|
779                                                          (p->hl[2]<<8)|
780                                                          (p->hl[3])) +
781                                                  m->in_offset;
782                                         break;
783                                 case OPMINUS:
784                                         offset = (int32_t)((p->hl[0]<<24)|
785                                                          (p->hl[1]<<16)|
786                                                          (p->hl[2]<<8)|
787                                                          (p->hl[3])) -
788                                                  m->in_offset;
789                                         break;
790                                 case OPMULTIPLY:
791                                         offset = (int32_t)((p->hl[0]<<24)|
792                                                          (p->hl[1]<<16)|
793                                                          (p->hl[2]<<8)|
794                                                          (p->hl[3])) *
795                                                  m->in_offset;
796                                         break;
797                                 case OPDIVIDE:
798                                         offset = (int32_t)((p->hl[0]<<24)|
799                                                          (p->hl[1]<<16)|
800                                                          (p->hl[2]<<8)|
801                                                          (p->hl[3])) /
802                                                  m->in_offset;
803                                         break;
804                                 case OPMODULO:
805                                         offset = (int32_t)((p->hl[0]<<24)|
806                                                          (p->hl[1]<<16)|
807                                                          (p->hl[2]<<8)|
808                                                          (p->hl[3])) %
809                                                  m->in_offset;
810                                         break;
811                                 }
812                         if (m->in_op & OPINVERSE)
813                                 offset = ~offset;
814                         break;
815                 case LELONG:
816                         if (m->in_offset)
817                                 switch (m->in_op&0x7F) {
818                                 case OPAND:
819                                         offset = (int32_t)((p->hl[3]<<24)|
820                                                          (p->hl[2]<<16)|
821                                                          (p->hl[1]<<8)|
822                                                          (p->hl[0])) &
823                                                  m->in_offset;
824                                         break;
825                                 case OPOR:
826                                         offset = (int32_t)((p->hl[3]<<24)|
827                                                          (p->hl[2]<<16)|
828                                                          (p->hl[1]<<8)|
829                                                          (p->hl[0])) |
830                                                  m->in_offset;
831                                         break;
832                                 case OPXOR:
833                                         offset = (int32_t)((p->hl[3]<<24)|
834                                                          (p->hl[2]<<16)|
835                                                          (p->hl[1]<<8)|
836                                                          (p->hl[0])) ^
837                                                  m->in_offset;
838                                         break;
839                                 case OPADD:
840                                         offset = (int32_t)((p->hl[3]<<24)|
841                                                          (p->hl[2]<<16)|
842                                                          (p->hl[1]<<8)|
843                                                          (p->hl[0])) +
844                                                  m->in_offset;
845                                         break;
846                                 case OPMINUS:
847                                         offset = (int32_t)((p->hl[3]<<24)|
848                                                          (p->hl[2]<<16)|
849                                                          (p->hl[1]<<8)|
850                                                          (p->hl[0])) -
851                                                  m->in_offset;
852                                         break;
853                                 case OPMULTIPLY:
854                                         offset = (int32_t)((p->hl[3]<<24)|
855                                                          (p->hl[2]<<16)|
856                                                          (p->hl[1]<<8)|
857                                                          (p->hl[0])) *
858                                                  m->in_offset;
859                                         break;
860                                 case OPDIVIDE:
861                                         offset = (int32_t)((p->hl[3]<<24)|
862                                                          (p->hl[2]<<16)|
863                                                          (p->hl[1]<<8)|
864                                                          (p->hl[0])) /
865                                                  m->in_offset;
866                                         break;
867                                 case OPMODULO:
868                                         offset = (int32_t)((p->hl[3]<<24)|
869                                                          (p->hl[2]<<16)|
870                                                          (p->hl[1]<<8)|
871                                                          (p->hl[0])) %
872                                                  m->in_offset;
873                                         break;
874                                 }
875                         if (m->in_op & OPINVERSE)
876                                 offset = ~offset;
877                         break;
878                 case LONG:
879                         if (m->in_offset)
880                                 switch (m->in_op&0x7F) {
881                                 case OPAND:
882                                         offset = p->l & m->in_offset;
883                                         break;
884                                 case OPOR:
885                                         offset = p->l | m->in_offset;
886                                         break;
887                                 case OPXOR:
888                                         offset = p->l ^ m->in_offset;
889                                         break;
890                                 case OPADD:
891                                         offset = p->l + m->in_offset;
892                                         break;
893                                 case OPMINUS:
894                                         offset = p->l - m->in_offset;
895                                         break;
896                                 case OPMULTIPLY:
897                                         offset = p->l * m->in_offset;
898                                         break;
899                                 case OPDIVIDE:
900                                         offset = p->l / m->in_offset;
901                                         break;
902                                 case OPMODULO:
903                                         offset = p->l % m->in_offset;
904                                         break;
905                         /*      case TOOMANYSWITCHBLOCKS:
906                          *              ugh = p->eye % m->strain;
907                          *              rub;
908                          *      case BEER:
909                          *              off = p->tab & m->in_gest;
910                          *              sleep;
911                          */
912                                 }
913                         if (m->in_op & OPINVERSE)
914                                 offset = ~offset;
915                         break;
916                 }
917
918                 if (offset + sizeof(union VALUETYPE) > nbytes)
919                         return 0;
920
921                 memcpy(p, s + offset, sizeof(union VALUETYPE));
922
923                 if (debug) {
924                         mdebug(offset, (char *) p, sizeof(union VALUETYPE));
925                         mdump(m);
926                 }
927         }
928         if (!mconvert(p, m))
929           return 0;
930         return 1;
931 }
932
933 static int
934 mcheck(union VALUETYPE *p, struct magic *m)
935 {
936         uint32_t l = m->value.l;
937         uint32_t v;
938         int matched;
939
940         if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
941                 fprintf(stderr, "BOINK");
942                 return 1;
943         }
944
945
946         switch (m->type) {
947         case BYTE:
948                 v = p->b;
949                 break;
950
951         case SHORT:
952         case BESHORT:
953         case LESHORT:
954                 v = p->h;
955                 break;
956
957         case LONG:
958         case BELONG:
959         case LELONG:
960         case DATE:
961         case BEDATE:
962         case LEDATE:
963         case LDATE:
964         case BELDATE:
965         case LELDATE:
966                 v = p->l;
967                 break;
968
969         case STRING:
970         case PSTRING:
971         {
972                 /*
973                  * What we want here is:
974                  * v = strncmp(m->value.s, p->s, m->vallen);
975                  * but ignoring any nulls.  bcmp doesn't give -/+/0
976                  * and isn't universally available anyway.
977                  */
978                 unsigned char *a = (unsigned char*)m->value.s;
979                 unsigned char *b = (unsigned char*)p->s;
980                 int len = m->vallen;
981                 l = 0;
982                 v = 0;
983                 if (0L == m->mask) { /* normal string: do it fast */
984                         while (--len >= 0)
985                                 if ((v = *b++ - *a++) != '\0')
986                                         break; 
987                 } else { /* combine the others */
988                         while (--len >= 0) {
989                                 if ((m->mask & STRING_IGNORE_LOWERCASE) &&
990                                     islower(*a)) {
991                                         if ((v = tolower(*b++) - *a++) != '\0')
992                                                 break;
993                                 } else if ((m->mask & STRING_COMPACT_BLANK) && 
994                                     isspace(*a)) { 
995                                         a++;
996                                         if (isspace(*b++)) {
997                                                 while (isspace(*b))
998                                                         b++;
999                                         } else {
1000                                                 v = 1;
1001                                                 break;
1002                                         }
1003                                 } else if (isspace(*a) &&
1004                                     (m->mask & STRING_COMPACT_OPTIONAL_BLANK)) {
1005                                         a++;
1006                                         while (isspace(*b))
1007                                                 b++;
1008                                 } else {
1009                                         if ((v = *b++ - *a++) != '\0')
1010                                                 break;
1011                                 }
1012                         }
1013                 }
1014                 break;
1015         }
1016         case REGEX:
1017         {
1018                 int rc;
1019                 regex_t rx;
1020                 char errmsg[512];
1021
1022                 rc = regcomp(&rx, m->value.s, REG_EXTENDED|REG_NOSUB);
1023                 if (rc) {
1024                         regerror(rc, &rx, errmsg, sizeof(errmsg));
1025                         error("regex error %d, (%s)\n", rc, errmsg);
1026                 } else {
1027                         rc = regexec(&rx, p->buf, 0, 0, 0);
1028                         return !rc;
1029                 }
1030         }
1031         default:
1032                 error("invalid type %d in mcheck().\n", m->type);
1033                 return 0;/*NOTREACHED*/
1034         }
1035
1036         if(m->type != STRING && m->type != PSTRING)
1037                 v = signextend(m, v);
1038
1039         switch (m->reln) {
1040         case 'x':
1041                 if (debug)
1042                         (void) fprintf(stderr, "%u == *any* = 1\n", v);
1043                 matched = 1;
1044                 break;
1045
1046         case '!':
1047                 matched = v != l;
1048                 if (debug)
1049                         (void) fprintf(stderr, "%u != %u = %d\n",
1050                                        v, l, matched);
1051                 break;
1052
1053         case '=':
1054                 matched = v == l;
1055                 if (debug)
1056                         (void) fprintf(stderr, "%u == %u = %d\n",
1057                                        v, l, matched);
1058                 break;
1059
1060         case '>':
1061                 if (m->flag & UNSIGNED) {
1062                         matched = v > l;
1063                         if (debug)
1064                                 (void) fprintf(stderr, "%u > %u = %d\n",
1065                                                v, l, matched);
1066                 }
1067                 else {
1068                         matched = (int32_t) v > (int32_t) l;
1069                         if (debug)
1070                                 (void) fprintf(stderr, "%d > %d = %d\n",
1071                                                v, l, matched);
1072                 }
1073                 break;
1074
1075         case '<':
1076                 if (m->flag & UNSIGNED) {
1077                         matched = v < l;
1078                         if (debug)
1079                                 (void) fprintf(stderr, "%u < %u = %d\n",
1080                                                v, l, matched);
1081                 }
1082                 else {
1083                         matched = (int32_t) v < (int32_t) l;
1084                         if (debug)
1085                                 (void) fprintf(stderr, "%d < %d = %d\n",
1086                                                v, l, matched);
1087                 }
1088                 break;
1089
1090         case '&':
1091                 matched = (v & l) == l;
1092                 if (debug)
1093                         (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
1094                                        v, l, l, matched);
1095                 break;
1096
1097         case '^':
1098                 matched = (v & l) != l;
1099                 if (debug)
1100                         (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
1101                                        v, l, l, matched);
1102                 break;
1103
1104         default:
1105                 matched = 0;
1106                 error("mcheck: can't happen: invalid relation %d.\n", m->reln);
1107                 break;/*NOTREACHED*/
1108         }
1109
1110         return matched;
1111 }