Merge from vendor branch BIND:
[dragonfly.git] / contrib / file-4 / src / softmagic.c
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.
15  *  
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.
27  */
28 /*
29  * softmagic - interpret variable magic from MAGIC
30  */
31
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>
39
40
41 #ifndef lint
42 FILE_RCSID("@(#)$Id: softmagic.c,v 1.73 2005/03/06 05:58:22 christos Exp $")
43 #endif  /* lint */
44
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, int);
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);
56
57 /*
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.
61  */
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)
65 {
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;
70
71         return 0;
72 }
73
74 /*
75  * Go through the whole list, stopping if you find a match.  Process all
76  * the continuations of that match before returning.
77  *
78  * We support multi-level continuations:
79  *
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.
83  *
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.
87  *
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.
94  *
95  *      Continuations at the current level are processed as, if we see
96  *      one, there's no lower-level continuation that may have failed.
97  *
98  *      If a continuation matches, we bump the current continuation level
99  *      so that higher-level continuations are processed.
100  */
101 private int
102 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
103     const unsigned char *s, size_t nbytes)
104 {
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 */
112
113         if (check_mem(ms, cont_level) == -1)
114                 return -1;
115
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                     cont_level);
120                 if (flush) {
121                         if (magic[magindex].reln == '!') flush = 0;
122                 } else {        
123                         switch (mcheck(ms, &p, &magic[magindex])) {
124                         case -1:
125                                 return -1;
126                         case 0:
127                                 flush++;
128                                 break;
129                         default:
130                                 break;
131                         }
132                 }
133                 if (flush) {
134                         /* 
135                          * main entry didn't match,
136                          * flush its continuations
137                          */
138                         while (magindex < nmagic - 1 &&
139                                magic[magindex + 1].cont_level != 0)
140                                magindex++;
141                         continue;
142                 }
143
144                 if (!firstline) { /* we found another match */
145                         /* put a newline and '-' to do some simple formatting*/
146                         if (file_printf(ms, "\n- ") == -1)
147                                 return -1;
148                 }
149
150                 if ((ms->c.off[cont_level] = mprint(ms, &p, &magic[magindex]))
151                     == -1)
152                         return -1;
153                 /*
154                  * If we printed something, we'll need to print
155                  * a blank before we print something else.
156                  */
157                 if (magic[magindex].desc[0])
158                         need_separator = 1;
159                 /* and any continuations that match */
160                 if (check_mem(ms, ++cont_level) == -1)
161                         return -1;
162
163                 while (magic[magindex+1].cont_level != 0 && 
164                        ++magindex < nmagic) {
165                         if (cont_level < magic[magindex].cont_level)
166                                 continue;
167                         if (cont_level > magic[magindex].cont_level) {
168                                 /*
169                                  * We're at the end of the level
170                                  * "cont_level" continuations.
171                                  */
172                                 cont_level = magic[magindex].cont_level;
173                         }
174                         oldoff = magic[magindex].offset;
175                         if (magic[magindex].flag & OFFADD) {
176                                 magic[magindex].offset +=
177                                     ms->c.off[cont_level - 1];
178                         }
179
180                         flush = !mget(ms, &p, s, &magic[magindex], nbytes,
181                             cont_level);
182                         if (flush && magic[magindex].reln != '!')
183                                 goto done;
184                                 
185                         switch (flush ? 1 : mcheck(ms, &p, &magic[magindex])) {
186                         case -1:
187                                 return -1;
188                         case 0:
189                                 break;
190                         default:
191                                 /*
192                                  * This continuation matched.
193                                  * Print its message, with
194                                  * a blank before it if
195                                  * the previous item printed
196                                  * and this item isn't empty.
197                                  */
198                                 /* space if previous printed */
199                                 if (need_separator
200                                     && (magic[magindex].nospflag == 0)
201                                    && (magic[magindex].desc[0] != '\0')) {
202                                         if (file_printf(ms, " ") == -1)
203                                                 return -1;
204                                         need_separator = 0;
205                                 }
206                                 if ((ms->c.off[cont_level] = mprint(ms, &p,
207                                     &magic[magindex])) == -1)
208                                         return -1;
209                                 if (magic[magindex].desc[0])
210                                         need_separator = 1;
211
212                                 /*
213                                  * If we see any continuations
214                                  * at a higher level,
215                                  * process them.
216                                  */
217                                 if (check_mem(ms, ++cont_level) == -1)
218                                         return -1;
219                         }
220 done:
221                         magic[magindex].offset = oldoff;
222                 }
223                 firstline = 0;
224                 returnval = 1;
225                 if ((ms->flags & MAGIC_CONTINUE) == 0) {
226                         return 1; /* don't keep searching */
227                 }                       
228         }
229         return returnval;  /* This is hit if -k is set or there is no match */
230 }
231
232 private int
233 check_mem(struct magic_set *ms, unsigned int level)
234 {
235         size_t len;
236
237         if (level < ms->c.len)
238                 return 0;
239
240         len = (ms->c.len += 20) * sizeof(*ms->c.off);
241         ms->c.off = (ms->c.off == NULL) ? malloc(len) : realloc(ms->c.off, len);
242         if (ms->c.off != NULL)
243                 return 0;
244         file_oomem(ms);
245         return -1;
246 }
247
248 private int32_t
249 mprint(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
250 {
251         uint32_t v;
252         int32_t t=0 ;
253
254
255         switch (m->type) {
256         case FILE_BYTE:
257                 v = file_signextend(ms, m, (size_t)p->b);
258                 if (file_printf(ms, m->desc, (unsigned char) v) == -1)
259                         return -1;
260                 t = m->offset + sizeof(char);
261                 break;
262
263         case FILE_SHORT:
264         case FILE_BESHORT:
265         case FILE_LESHORT:
266                 v = file_signextend(ms, m, (size_t)p->h);
267                 if (file_printf(ms, m->desc, (unsigned short) v) == -1)
268                         return -1;
269                 t = m->offset + sizeof(short);
270                 break;
271
272         case FILE_LONG:
273         case FILE_BELONG:
274         case FILE_LELONG:
275                 v = file_signextend(ms, m, p->l);
276                 if (file_printf(ms, m->desc, (uint32_t) v) == -1)
277                         return -1;
278                 t = m->offset + sizeof(int32_t);
279                 break;
280
281         case FILE_STRING:
282         case FILE_PSTRING:
283         case FILE_BESTRING16:
284         case FILE_LESTRING16:
285                 if (m->reln == '=' || m->reln == '!') {
286                         if (file_printf(ms, m->desc, m->value.s) == -1)
287                                 return -1;
288                         t = m->offset + m->vallen;
289                 }
290                 else {
291                         if (*m->value.s == '\0') {
292                                 char *cp = strchr(p->s,'\n');
293                                 if (cp)
294                                         *cp = '\0';
295                         }
296                         if (file_printf(ms, m->desc, p->s) == -1)
297                                 return -1;
298                         t = m->offset + strlen(p->s);
299                 }
300                 break;
301
302         case FILE_DATE:
303         case FILE_BEDATE:
304         case FILE_LEDATE:
305                 if (file_printf(ms, m->desc, file_fmttime(p->l, 1)) == -1)
306                         return -1;
307                 t = m->offset + sizeof(time_t);
308                 break;
309
310         case FILE_LDATE:
311         case FILE_BELDATE:
312         case FILE_LELDATE:
313                 if (file_printf(ms, m->desc, file_fmttime(p->l, 0)) == -1)
314                         return -1;
315                 t = m->offset + sizeof(time_t);
316                 break;
317         case FILE_REGEX:
318                 if (file_printf(ms, m->desc, p->s) == -1)
319                         return -1;
320                 t = m->offset + strlen(p->s);
321                 break;
322         case FILE_SEARCH:
323                 if (file_printf(ms, m->desc, m->value.s) == -1)
324                         return -1;
325                 t = m->offset + m->vallen;
326                 break;
327
328         default:
329                 file_error(ms, 0, "invalid m->type (%d) in mprint()", m->type);
330                 return -1;
331         }
332         return(t);
333 }
334
335 /*
336  * Convert the byte order of the data we are looking at
337  * While we're here, let's apply the mask operation
338  * (unless you have a better idea)
339  */
340 private int
341 mconvert(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
342 {
343         switch (m->type) {
344         case FILE_BYTE:
345                 if (m->mask)
346                         switch (m->mask_op & 0x7F) {
347                         case FILE_OPAND:
348                                 p->b &= m->mask;
349                                 break;
350                         case FILE_OPOR:
351                                 p->b |= m->mask;
352                                 break;
353                         case FILE_OPXOR:
354                                 p->b ^= m->mask;
355                                 break;
356                         case FILE_OPADD:
357                                 p->b += m->mask;
358                                 break;
359                         case FILE_OPMINUS:
360                                 p->b -= m->mask;
361                                 break;
362                         case FILE_OPMULTIPLY:
363                                 p->b *= m->mask;
364                                 break;
365                         case FILE_OPDIVIDE:
366                                 p->b /= m->mask;
367                                 break;
368                         case FILE_OPMODULO:
369                                 p->b %= m->mask;
370                                 break;
371                         }
372                 if (m->mask_op & FILE_OPINVERSE)
373                         p->b = ~p->b;
374                 return 1;
375         case FILE_SHORT:
376                 if (m->mask)
377                         switch (m->mask_op & 0x7F) {
378                         case FILE_OPAND:
379                                 p->h &= m->mask;
380                                 break;
381                         case FILE_OPOR:
382                                 p->h |= m->mask;
383                                 break;
384                         case FILE_OPXOR:
385                                 p->h ^= m->mask;
386                                 break;
387                         case FILE_OPADD:
388                                 p->h += m->mask;
389                                 break;
390                         case FILE_OPMINUS:
391                                 p->h -= m->mask;
392                                 break;
393                         case FILE_OPMULTIPLY:
394                                 p->h *= m->mask;
395                                 break;
396                         case FILE_OPDIVIDE:
397                                 p->h /= m->mask;
398                                 break;
399                         case FILE_OPMODULO:
400                                 p->h %= m->mask;
401                                 break;
402                         }
403                 if (m->mask_op & FILE_OPINVERSE)
404                         p->h = ~p->h;
405                 return 1;
406         case FILE_LONG:
407         case FILE_DATE:
408         case FILE_LDATE:
409                 if (m->mask)
410                         switch (m->mask_op & 0x7F) {
411                         case FILE_OPAND:
412                                 p->l &= m->mask;
413                                 break;
414                         case FILE_OPOR:
415                                 p->l |= m->mask;
416                                 break;
417                         case FILE_OPXOR:
418                                 p->l ^= m->mask;
419                                 break;
420                         case FILE_OPADD:
421                                 p->l += m->mask;
422                                 break;
423                         case FILE_OPMINUS:
424                                 p->l -= m->mask;
425                                 break;
426                         case FILE_OPMULTIPLY:
427                                 p->l *= m->mask;
428                                 break;
429                         case FILE_OPDIVIDE:
430                                 p->l /= m->mask;
431                                 break;
432                         case FILE_OPMODULO:
433                                 p->l %= m->mask;
434                                 break;
435                         }
436                 if (m->mask_op & FILE_OPINVERSE)
437                         p->l = ~p->l;
438                 return 1;
439         case FILE_STRING:
440         case FILE_BESTRING16:
441         case FILE_LESTRING16:
442                 {
443                         size_t len;
444
445                         /* Null terminate and eat *trailing* return */
446                         p->s[sizeof(p->s) - 1] = '\0';
447                         len = strlen(p->s);
448                         if (len-- && p->s[len] == '\n')
449                                 p->s[len] = '\0';
450                         return 1;
451                 }
452         case FILE_PSTRING:
453                 {
454                         char *ptr1 = p->s, *ptr2 = ptr1 + 1;
455                         size_t len = *p->s;
456                         if (len >= sizeof(p->s))
457                                 len = sizeof(p->s) - 1;
458                         while (len--)
459                                 *ptr1++ = *ptr2++;
460                         *ptr1 = '\0';
461                         len = strlen(p->s);
462                         if (len-- && p->s[len] == '\n')
463                                 p->s[len] = '\0';
464                         return 1;
465                 }
466         case FILE_BESHORT:
467                 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
468                 if (m->mask)
469                         switch (m->mask_op&0x7F) {
470                         case FILE_OPAND:
471                                 p->h &= m->mask;
472                                 break;
473                         case FILE_OPOR:
474                                 p->h |= m->mask;
475                                 break;
476                         case FILE_OPXOR:
477                                 p->h ^= m->mask;
478                                 break;
479                         case FILE_OPADD:
480                                 p->h += m->mask;
481                                 break;
482                         case FILE_OPMINUS:
483                                 p->h -= m->mask;
484                                 break;
485                         case FILE_OPMULTIPLY:
486                                 p->h *= m->mask;
487                                 break;
488                         case FILE_OPDIVIDE:
489                                 p->h /= m->mask;
490                                 break;
491                         case FILE_OPMODULO:
492                                 p->h %= m->mask;
493                                 break;
494                         }
495                 if (m->mask_op & FILE_OPINVERSE)
496                         p->h = ~p->h;
497                 return 1;
498         case FILE_BELONG:
499         case FILE_BEDATE:
500         case FILE_BELDATE:
501                 p->l = (int32_t)
502                     ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
503                 if (m->mask)
504                         switch (m->mask_op&0x7F) {
505                         case FILE_OPAND:
506                                 p->l &= m->mask;
507                                 break;
508                         case FILE_OPOR:
509                                 p->l |= m->mask;
510                                 break;
511                         case FILE_OPXOR:
512                                 p->l ^= m->mask;
513                                 break;
514                         case FILE_OPADD:
515                                 p->l += m->mask;
516                                 break;
517                         case FILE_OPMINUS:
518                                 p->l -= m->mask;
519                                 break;
520                         case FILE_OPMULTIPLY:
521                                 p->l *= m->mask;
522                                 break;
523                         case FILE_OPDIVIDE:
524                                 p->l /= m->mask;
525                                 break;
526                         case FILE_OPMODULO:
527                                 p->l %= m->mask;
528                                 break;
529                         }
530                 if (m->mask_op & FILE_OPINVERSE)
531                         p->l = ~p->l;
532                 return 1;
533         case FILE_LESHORT:
534                 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
535                 if (m->mask)
536                         switch (m->mask_op&0x7F) {
537                         case FILE_OPAND:
538                                 p->h &= m->mask;
539                                 break;
540                         case FILE_OPOR:
541                                 p->h |= m->mask;
542                                 break;
543                         case FILE_OPXOR:
544                                 p->h ^= m->mask;
545                                 break;
546                         case FILE_OPADD:
547                                 p->h += m->mask;
548                                 break;
549                         case FILE_OPMINUS:
550                                 p->h -= m->mask;
551                                 break;
552                         case FILE_OPMULTIPLY:
553                                 p->h *= m->mask;
554                                 break;
555                         case FILE_OPDIVIDE:
556                                 p->h /= m->mask;
557                                 break;
558                         case FILE_OPMODULO:
559                                 p->h %= m->mask;
560                                 break;
561                         }
562                 if (m->mask_op & FILE_OPINVERSE)
563                         p->h = ~p->h;
564                 return 1;
565         case FILE_LELONG:
566         case FILE_LEDATE:
567         case FILE_LELDATE:
568                 p->l = (int32_t)
569                     ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
570                 if (m->mask)
571                         switch (m->mask_op&0x7F) {
572                         case FILE_OPAND:
573                                 p->l &= m->mask;
574                                 break;
575                         case FILE_OPOR:
576                                 p->l |= m->mask;
577                                 break;
578                         case FILE_OPXOR:
579                                 p->l ^= m->mask;
580                                 break;
581                         case FILE_OPADD:
582                                 p->l += m->mask;
583                                 break;
584                         case FILE_OPMINUS:
585                                 p->l -= m->mask;
586                                 break;
587                         case FILE_OPMULTIPLY:
588                                 p->l *= m->mask;
589                                 break;
590                         case FILE_OPDIVIDE:
591                                 p->l /= m->mask;
592                                 break;
593                         case FILE_OPMODULO:
594                                 p->l %= m->mask;
595                                 break;
596                         }
597                 if (m->mask_op & FILE_OPINVERSE)
598                         p->l = ~p->l;
599                 return 1;
600         case FILE_REGEX:
601         case FILE_SEARCH:
602                 return 1;
603         default:
604                 file_error(ms, 0, "invalid type %d in mconvert()", m->type);
605                 return 0;
606         }
607 }
608
609
610 private void
611 mdebug(uint32_t offset, const char *str, size_t len)
612 {
613         (void) fprintf(stderr, "mget @%d: ", offset);
614         file_showstr(stderr, str, len);
615         (void) fputc('\n', stderr);
616         (void) fputc('\n', stderr);
617 }
618
619 private int
620 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
621     const unsigned char *s, size_t offset, size_t nbytes)
622 {
623         if (type == FILE_REGEX && indir == 0) {
624                 /*
625                  * offset is interpreted as last line to search,
626                  * (starting at 1), not as bytes-from start-of-file
627                  */
628                 char *b, *c, *last = NULL;
629                 if ((p->buf = strdup((const char *)s)) == NULL) {
630                         file_oomem(ms);
631                         return -1;
632                 }
633                 for (b = p->buf; offset && 
634                     ((b = strchr(c = b, '\n')) || (b = strchr(c, '\r')));
635                     offset--, b++) {
636                         last = b;
637                         if (b[0] == '\r' && b[1] == '\n') b++;
638                 }
639                 if (last != NULL)
640                         *last = '\0';
641                 return 0;
642         }
643
644         if (indir == 0 && (type == FILE_BESTRING16 || type == FILE_LESTRING16))
645         {
646                 const char *src = s + offset;
647                 const char *esrc = s + nbytes;
648                 char *dst = p->s, *edst = &p->s[sizeof(p->s) - 1];
649
650                 if (type == FILE_BESTRING16)
651                         src++;
652
653                 for (;src < esrc; src++, dst++) {
654                         if (dst < edst)
655                                 *dst = *src++;
656                         else
657                                 break;
658                         if (*dst == '\0')
659                                 *dst = ' ';
660                 }
661                 *edst = '\0';
662                 return 0;
663         }
664
665         if (offset >= nbytes) {
666                 (void)memset(p, '\0', sizeof(*p));
667                 return 0;
668         }
669         if (nbytes - offset < sizeof(*p))
670                 nbytes = nbytes - offset;
671         else
672                 nbytes = sizeof(*p);
673
674         (void)memcpy(p, s + offset, nbytes);
675
676         /*
677          * the usefulness of padding with zeroes eludes me, it
678          * might even cause problems
679          */
680         if (nbytes < sizeof(*p))
681                 (void)memset(((char *)p) + nbytes, '\0', sizeof(*p) - nbytes);
682         return 0;
683 }
684
685 private int
686 mget(struct magic_set *ms, union VALUETYPE *p, const unsigned char *s,
687     struct magic *m, size_t nbytes, int cont_level)
688 {
689         uint32_t offset = m->offset;
690
691         if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes) == -1)
692                 return -1;
693
694         if ((ms->flags & MAGIC_DEBUG) != 0) {
695                 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
696                 file_mdump(m);
697         }
698
699         if (m->flag & INDIR) {
700                 int off = m->in_offset;
701                 if (m->in_op & FILE_OPINDIRECT) {
702                         const union VALUETYPE *q =
703                             ((const union VALUETYPE *)(s + offset + off));
704                         switch (m->in_type) {
705                         case FILE_BYTE:
706                                 off = q->b;
707                                 break;
708                         case FILE_SHORT:
709                                 off = q->h;
710                                 break;
711                         case FILE_BESHORT:
712                                 off = (short)((q->hs[0]<<8)|(q->hs[1]));
713                                 break;
714                         case FILE_LESHORT:
715                                 off = (short)((q->hs[1]<<8)|(q->hs[0]));
716                                 break;
717                         case FILE_LONG:
718                                 off = q->l;
719                                 break;
720                         case FILE_BELONG:
721                                 off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
722                                                  (q->hl[2]<<8)|(q->hl[3]));
723                                 break;
724                         case FILE_LELONG:
725                                 off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
726                                                  (q->hl[1]<<8)|(q->hl[0]));
727                                 break;
728                         }
729                 }
730                 switch (m->in_type) {
731                 case FILE_BYTE:
732                         if (nbytes < (offset + 1)) return 0;
733                         if (off) {
734                                 switch (m->in_op & 0x3F) {
735                                 case FILE_OPAND:
736                                         offset = p->b & off;
737                                         break;
738                                 case FILE_OPOR:
739                                         offset = p->b | off;
740                                         break;
741                                 case FILE_OPXOR:
742                                         offset = p->b ^ off;
743                                         break;
744                                 case FILE_OPADD:
745                                         offset = p->b + off;
746                                         break;
747                                 case FILE_OPMINUS:
748                                         offset = p->b - off;
749                                         break;
750                                 case FILE_OPMULTIPLY:
751                                         offset = p->b * off;
752                                         break;
753                                 case FILE_OPDIVIDE:
754                                         offset = p->b / off;
755                                         break;
756                                 case FILE_OPMODULO:
757                                         offset = p->b % off;
758                                         break;
759                                 }
760                         } else
761                                 offset = p->b;
762                         if (m->in_op & FILE_OPINVERSE)
763                                 offset = ~offset;
764                         break;
765                 case FILE_BESHORT:
766                         if (nbytes < (offset + 2))
767                                 return 0;
768                         if (off) {
769                                 switch (m->in_op & 0x7F) {
770                                 case FILE_OPAND:
771                                         offset = (short)((p->hs[0]<<8)|
772                                                          (p->hs[1])) &
773                                                  off;
774                                         break;
775                                 case FILE_OPOR:
776                                         offset = (short)((p->hs[0]<<8)|
777                                                          (p->hs[1])) |
778                                                  off;
779                                         break;
780                                 case FILE_OPXOR:
781                                         offset = (short)((p->hs[0]<<8)|
782                                                          (p->hs[1])) ^
783                                                  off;
784                                         break;
785                                 case FILE_OPADD:
786                                         offset = (short)((p->hs[0]<<8)|
787                                                          (p->hs[1])) +
788                                                  off;
789                                         break;
790                                 case FILE_OPMINUS:
791                                         offset = (short)((p->hs[0]<<8)|
792                                                          (p->hs[1])) -
793                                                  off;
794                                         break;
795                                 case FILE_OPMULTIPLY:
796                                         offset = (short)((p->hs[0]<<8)|
797                                                          (p->hs[1])) *
798                                                  off;
799                                         break;
800                                 case FILE_OPDIVIDE:
801                                         offset = (short)((p->hs[0]<<8)|
802                                                          (p->hs[1])) /
803                                                  off;
804                                         break;
805                                 case FILE_OPMODULO:
806                                         offset = (short)((p->hs[0]<<8)|
807                                                          (p->hs[1])) %
808                                                  off;
809                                         break;
810                                 }
811                         } else
812                                 offset = (short)((p->hs[0]<<8)|
813                                                  (p->hs[1]));
814                         if (m->in_op & FILE_OPINVERSE)
815                                 offset = ~offset;
816                         break;
817                 case FILE_LESHORT:
818                         if (nbytes < (offset + 2))
819                                 return 0;
820                         if (off) {
821                                 switch (m->in_op & 0x7F) {
822                                 case FILE_OPAND:
823                                         offset = (short)((p->hs[1]<<8)|
824                                                          (p->hs[0])) &
825                                                  off;
826                                         break;
827                                 case FILE_OPOR:
828                                         offset = (short)((p->hs[1]<<8)|
829                                                          (p->hs[0])) |
830                                                  off;
831                                         break;
832                                 case FILE_OPXOR:
833                                         offset = (short)((p->hs[1]<<8)|
834                                                          (p->hs[0])) ^
835                                                  off;
836                                         break;
837                                 case FILE_OPADD:
838                                         offset = (short)((p->hs[1]<<8)|
839                                                          (p->hs[0])) +
840                                                  off;
841                                         break;
842                                 case FILE_OPMINUS:
843                                         offset = (short)((p->hs[1]<<8)|
844                                                          (p->hs[0])) -
845                                                  off;
846                                         break;
847                                 case FILE_OPMULTIPLY:
848                                         offset = (short)((p->hs[1]<<8)|
849                                                          (p->hs[0])) *
850                                                  off;
851                                         break;
852                                 case FILE_OPDIVIDE:
853                                         offset = (short)((p->hs[1]<<8)|
854                                                          (p->hs[0])) /
855                                                  off;
856                                         break;
857                                 case FILE_OPMODULO:
858                                         offset = (short)((p->hs[1]<<8)|
859                                                          (p->hs[0])) %
860                                                  off;
861                                         break;
862                                 }
863                         } else
864                                 offset = (short)((p->hs[1]<<8)|
865                                                  (p->hs[0]));
866                         if (m->in_op & FILE_OPINVERSE)
867                                 offset = ~offset;
868                         break;
869                 case FILE_SHORT:
870                         if (nbytes < (offset + 2))
871                                 return 0;
872                         if (off) {
873                                 switch (m->in_op & 0x7F) {
874                                 case FILE_OPAND:
875                                         offset = p->h & off;
876                                         break;
877                                 case FILE_OPOR:
878                                         offset = p->h | off;
879                                         break;
880                                 case FILE_OPXOR:
881                                         offset = p->h ^ off;
882                                         break;
883                                 case FILE_OPADD:
884                                         offset = p->h + off;
885                                         break;
886                                 case FILE_OPMINUS:
887                                         offset = p->h - off;
888                                         break;
889                                 case FILE_OPMULTIPLY:
890                                         offset = p->h * off;
891                                         break;
892                                 case FILE_OPDIVIDE:
893                                         offset = p->h / off;
894                                         break;
895                                 case FILE_OPMODULO:
896                                         offset = p->h % off;
897                                         break;
898                                 }
899                         }
900                         else
901                                 offset = p->h;
902                         if (m->in_op & FILE_OPINVERSE)
903                                 offset = ~offset;
904                         break;
905                 case FILE_BELONG:
906                         if (nbytes < (offset + 4))
907                                 return 0;
908                         if (off) {
909                                 switch (m->in_op & 0x7F) {
910                                 case FILE_OPAND:
911                                         offset = (int32_t)((p->hl[0]<<24)|
912                                                          (p->hl[1]<<16)|
913                                                          (p->hl[2]<<8)|
914                                                          (p->hl[3])) &
915                                                  off;
916                                         break;
917                                 case FILE_OPOR:
918                                         offset = (int32_t)((p->hl[0]<<24)|
919                                                          (p->hl[1]<<16)|
920                                                          (p->hl[2]<<8)|
921                                                          (p->hl[3])) |
922                                                  off;
923                                         break;
924                                 case FILE_OPXOR:
925                                         offset = (int32_t)((p->hl[0]<<24)|
926                                                          (p->hl[1]<<16)|
927                                                          (p->hl[2]<<8)|
928                                                          (p->hl[3])) ^
929                                                  off;
930                                         break;
931                                 case FILE_OPADD:
932                                         offset = (int32_t)((p->hl[0]<<24)|
933                                                          (p->hl[1]<<16)|
934                                                          (p->hl[2]<<8)|
935                                                          (p->hl[3])) +
936                                                  off;
937                                         break;
938                                 case FILE_OPMINUS:
939                                         offset = (int32_t)((p->hl[0]<<24)|
940                                                          (p->hl[1]<<16)|
941                                                          (p->hl[2]<<8)|
942                                                          (p->hl[3])) -
943                                                  off;
944                                         break;
945                                 case FILE_OPMULTIPLY:
946                                         offset = (int32_t)((p->hl[0]<<24)|
947                                                          (p->hl[1]<<16)|
948                                                          (p->hl[2]<<8)|
949                                                          (p->hl[3])) *
950                                                  off;
951                                         break;
952                                 case FILE_OPDIVIDE:
953                                         offset = (int32_t)((p->hl[0]<<24)|
954                                                          (p->hl[1]<<16)|
955                                                          (p->hl[2]<<8)|
956                                                          (p->hl[3])) /
957                                                  off;
958                                         break;
959                                 case FILE_OPMODULO:
960                                         offset = (int32_t)((p->hl[0]<<24)|
961                                                          (p->hl[1]<<16)|
962                                                          (p->hl[2]<<8)|
963                                                          (p->hl[3])) %
964                                                  off;
965                                         break;
966                                 }
967                         } else
968                                 offset = (int32_t)((p->hl[0]<<24)|
969                                                  (p->hl[1]<<16)|
970                                                  (p->hl[2]<<8)|
971                                                  (p->hl[3]));
972                         if (m->in_op & FILE_OPINVERSE)
973                                 offset = ~offset;
974                         break;
975                 case FILE_LELONG:
976                         if (nbytes < (offset + 4))
977                                 return 0;
978                         if (off) {
979                                 switch (m->in_op & 0x7F) {
980                                 case FILE_OPAND:
981                                         offset = (int32_t)((p->hl[3]<<24)|
982                                                          (p->hl[2]<<16)|
983                                                          (p->hl[1]<<8)|
984                                                          (p->hl[0])) &
985                                                  off;
986                                         break;
987                                 case FILE_OPOR:
988                                         offset = (int32_t)((p->hl[3]<<24)|
989                                                          (p->hl[2]<<16)|
990                                                          (p->hl[1]<<8)|
991                                                          (p->hl[0])) |
992                                                  off;
993                                         break;
994                                 case FILE_OPXOR:
995                                         offset = (int32_t)((p->hl[3]<<24)|
996                                                          (p->hl[2]<<16)|
997                                                          (p->hl[1]<<8)|
998                                                          (p->hl[0])) ^
999                                                  off;
1000                                         break;
1001                                 case FILE_OPADD:
1002                                         offset = (int32_t)((p->hl[3]<<24)|
1003                                                          (p->hl[2]<<16)|
1004                                                          (p->hl[1]<<8)|
1005                                                          (p->hl[0])) +
1006                                                  off;
1007                                         break;
1008                                 case FILE_OPMINUS:
1009                                         offset = (int32_t)((p->hl[3]<<24)|
1010                                                          (p->hl[2]<<16)|
1011                                                          (p->hl[1]<<8)|
1012                                                          (p->hl[0])) -
1013                                                  off;
1014                                         break;
1015                                 case FILE_OPMULTIPLY:
1016                                         offset = (int32_t)((p->hl[3]<<24)|
1017                                                          (p->hl[2]<<16)|
1018                                                          (p->hl[1]<<8)|
1019                                                          (p->hl[0])) *
1020                                                  off;
1021                                         break;
1022                                 case FILE_OPDIVIDE:
1023                                         offset = (int32_t)((p->hl[3]<<24)|
1024                                                          (p->hl[2]<<16)|
1025                                                          (p->hl[1]<<8)|
1026                                                          (p->hl[0])) /
1027                                                  off;
1028                                         break;
1029                                 case FILE_OPMODULO:
1030                                         offset = (int32_t)((p->hl[3]<<24)|
1031                                                          (p->hl[2]<<16)|
1032                                                          (p->hl[1]<<8)|
1033                                                          (p->hl[0])) %
1034                                                  off;
1035                                         break;
1036                                 }
1037                         } else
1038                                 offset = (int32_t)((p->hl[3]<<24)|
1039                                                  (p->hl[2]<<16)|
1040                                                  (p->hl[1]<<8)|
1041                                                  (p->hl[0]));
1042                         if (m->in_op & FILE_OPINVERSE)
1043                                 offset = ~offset;
1044                         break;
1045                 case FILE_LONG:
1046                         if (nbytes < (offset + 4))
1047                                 return 0;
1048                         if (off) {
1049                                 switch (m->in_op & 0x7F) {
1050                                 case FILE_OPAND:
1051                                         offset = p->l & off;
1052                                         break;
1053                                 case FILE_OPOR:
1054                                         offset = p->l | off;
1055                                         break;
1056                                 case FILE_OPXOR:
1057                                         offset = p->l ^ off;
1058                                         break;
1059                                 case FILE_OPADD:
1060                                         offset = p->l + off;
1061                                         break;
1062                                 case FILE_OPMINUS:
1063                                         offset = p->l - off;
1064                                         break;
1065                                 case FILE_OPMULTIPLY:
1066                                         offset = p->l * off;
1067                                         break;
1068                                 case FILE_OPDIVIDE:
1069                                         offset = p->l / off;
1070                                         break;
1071                                 case FILE_OPMODULO:
1072                                         offset = p->l % off;
1073                                         break;
1074                         /*      case TOOMANYSWITCHBLOCKS:
1075                          *              ugh = p->eye % m->strain;
1076                          *              rub;
1077                          *      case BEER:
1078                          *              off = p->tab & m->in_gest;
1079                          *              sleep;
1080                          */
1081                                 }
1082                         } else
1083                                 offset = p->l;
1084                         if (m->in_op & FILE_OPINVERSE)
1085                                 offset = ~offset;
1086                         break;
1087                 }
1088
1089                 if (m->flag & INDIROFFADD) offset += ms->c.off[cont_level-1];
1090                 if (mcopy(ms, p, m->type, 0, s, offset, nbytes) == -1)
1091                         return -1;
1092                 m->offset = offset;
1093
1094                 if ((ms->flags & MAGIC_DEBUG) != 0) {
1095                         mdebug(offset, (char *)(void *)p,
1096                             sizeof(union VALUETYPE));
1097                         file_mdump(m);
1098                 }
1099         }
1100
1101         /* Verify we have enough data to match magic type */
1102         switch (m->type) {
1103                 case FILE_BYTE:
1104                         if (nbytes < (offset + 1)) /* should alway be true */
1105                                 return 0;
1106                         break;
1107
1108                 case FILE_SHORT:
1109                 case FILE_BESHORT:
1110                 case FILE_LESHORT:
1111                         if (nbytes < (offset + 2))
1112                                 return 0;
1113                         break;
1114
1115                 case FILE_LONG:
1116                 case FILE_BELONG:
1117                 case FILE_LELONG:
1118                 case FILE_DATE:
1119                 case FILE_BEDATE:
1120                 case FILE_LEDATE:
1121                 case FILE_LDATE:
1122                 case FILE_BELDATE:
1123                 case FILE_LELDATE:
1124                         if (nbytes < (offset + 4))
1125                                 return 0;
1126                         break;
1127
1128                 case FILE_STRING:
1129                 case FILE_PSTRING:
1130                 case FILE_SEARCH:
1131                         if (nbytes < (offset + m->vallen))
1132                                 return 0;
1133                         break;
1134                 default: break;
1135         }
1136
1137         if (m->type == FILE_SEARCH) {
1138                 p->buf = malloc(m->mask + m->vallen);
1139                 if (p->buf == NULL) {
1140                         file_error(ms, errno, "Cannot allocate search buffer");
1141                         return 0;
1142                 }
1143                 (void)memcpy(p->buf, s + offset, m->mask + m->vallen);
1144         }
1145         if (!mconvert(ms, p, m))
1146                 return 0;
1147         return 1;
1148 }
1149
1150 private int
1151 mcheck(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
1152 {
1153         uint32_t l = m->value.l;
1154         uint32_t v;
1155         int matched;
1156
1157         if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
1158                 return 1;
1159         }
1160
1161
1162         switch (m->type) {
1163         case FILE_BYTE:
1164                 v = p->b;
1165                 break;
1166
1167         case FILE_SHORT:
1168         case FILE_BESHORT:
1169         case FILE_LESHORT:
1170                 v = p->h;
1171                 break;
1172
1173         case FILE_LONG:
1174         case FILE_BELONG:
1175         case FILE_LELONG:
1176         case FILE_DATE:
1177         case FILE_BEDATE:
1178         case FILE_LEDATE:
1179         case FILE_LDATE:
1180         case FILE_BELDATE:
1181         case FILE_LELDATE:
1182                 v = p->l;
1183                 break;
1184
1185         case FILE_STRING:
1186         case FILE_BESTRING16:
1187         case FILE_LESTRING16:
1188         case FILE_PSTRING:
1189         {
1190                 /*
1191                  * What we want here is:
1192                  * v = strncmp(m->value.s, p->s, m->vallen);
1193                  * but ignoring any nulls.  bcmp doesn't give -/+/0
1194                  * and isn't universally available anyway.
1195                  */
1196                 unsigned char *a = (unsigned char*)m->value.s;
1197                 unsigned char *b = (unsigned char*)p->s;
1198                 int len = m->vallen;
1199                 l = 0;
1200                 v = 0;
1201                 if (0L == m->mask) { /* normal string: do it fast */
1202                         while (--len >= 0)
1203                                 if ((v = *b++ - *a++) != '\0')
1204                                         break; 
1205                 } else { /* combine the others */
1206                         while (--len >= 0) {
1207                                 if ((m->mask & STRING_IGNORE_LOWERCASE) &&
1208                                     islower(*a)) {
1209                                         if ((v = tolower(*b++) - *a++) != '\0')
1210                                                 break;
1211                                 } else if ((m->mask & STRING_COMPACT_BLANK) && 
1212                                     isspace(*a)) { 
1213                                         a++;
1214                                         if (isspace(*b++)) {
1215                                                 while (isspace(*b))
1216                                                         b++;
1217                                         } else {
1218                                                 v = 1;
1219                                                 break;
1220                                         }
1221                                 } else if (isspace(*a) &&
1222                                     (m->mask & STRING_COMPACT_OPTIONAL_BLANK)) {
1223                                         a++;
1224                                         while (isspace(*b))
1225                                                 b++;
1226                                 } else {
1227                                         if ((v = *b++ - *a++) != '\0')
1228                                                 break;
1229                                 }
1230                         }
1231                 }
1232                 break;
1233         }
1234         case FILE_REGEX:
1235         {
1236                 int rc;
1237                 regex_t rx;
1238                 char errmsg[512];
1239
1240                 rc = regcomp(&rx, m->value.s,
1241                     REG_EXTENDED|REG_NOSUB|REG_NEWLINE|
1242                     ((m->mask & STRING_IGNORE_LOWERCASE) ? REG_ICASE : 0));
1243                 if (rc) {
1244                         free(p->buf);
1245                         regerror(rc, &rx, errmsg, sizeof(errmsg));
1246                         file_error(ms, 0, "regex error %d, (%s)", rc, errmsg);
1247                         return -1;
1248                 } else {
1249                         rc = regexec(&rx, p->buf, 0, 0, 0);
1250                         regfree(&rx);
1251                         free(p->buf);
1252                         return !rc;
1253                 }
1254         }
1255         case FILE_SEARCH:
1256         {
1257                 /*
1258                  * search for a string in a certain range
1259                  */
1260                 unsigned char *a = (unsigned char*)m->value.s;
1261                 unsigned char *b = (unsigned char*)p->buf;
1262                 int len = m->vallen;
1263                 int range = 0;
1264                 l = 0;
1265                 v = 0;
1266                 while (++range <= m->mask) {
1267                         while (len-- > 0 && (v = *b++ - *a++) == 0)
1268                                 continue;
1269                         if (!v) {
1270                                 m->offset += range-1;
1271                                 break;
1272                         }
1273                         len = m->vallen;
1274                         a = (unsigned char*)m->value.s;
1275                         b = (unsigned char*)p->buf + range;
1276                 }
1277                 free(p->buf);
1278                 break;
1279         }
1280         default:
1281                 file_error(ms, 0, "invalid type %d in mcheck()", m->type);
1282                 return -1;
1283         }
1284
1285         if (m->type != FILE_STRING && m->type != FILE_PSTRING)
1286                 v = file_signextend(ms, m, v);
1287
1288         switch (m->reln) {
1289         case 'x':
1290                 if ((ms->flags & MAGIC_DEBUG) != 0)
1291                         (void) fprintf(stderr, "%u == *any* = 1\n", v);
1292                 matched = 1;
1293                 break;
1294
1295         case '!':
1296                 matched = v != l;
1297                 if ((ms->flags & MAGIC_DEBUG) != 0)
1298                         (void) fprintf(stderr, "%u != %u = %d\n",
1299                                        v, l, matched);
1300                 break;
1301
1302         case '=':
1303                 matched = v == l;
1304                 if ((ms->flags & MAGIC_DEBUG) != 0)
1305                         (void) fprintf(stderr, "%u == %u = %d\n",
1306                                        v, l, matched);
1307                 break;
1308
1309         case '>':
1310                 if (m->flag & UNSIGNED) {
1311                         matched = v > l;
1312                         if ((ms->flags & MAGIC_DEBUG) != 0)
1313                                 (void) fprintf(stderr, "%u > %u = %d\n",
1314                                                v, l, matched);
1315                 }
1316                 else {
1317                         matched = (int32_t) v > (int32_t) l;
1318                         if ((ms->flags & MAGIC_DEBUG) != 0)
1319                                 (void) fprintf(stderr, "%d > %d = %d\n",
1320                                                v, l, matched);
1321                 }
1322                 break;
1323
1324         case '<':
1325                 if (m->flag & UNSIGNED) {
1326                         matched = v < l;
1327                         if ((ms->flags & MAGIC_DEBUG) != 0)
1328                                 (void) fprintf(stderr, "%u < %u = %d\n",
1329                                                v, l, matched);
1330                 }
1331                 else {
1332                         matched = (int32_t) v < (int32_t) l;
1333                         if ((ms->flags & MAGIC_DEBUG) != 0)
1334                                 (void) fprintf(stderr, "%d < %d = %d\n",
1335                                                v, l, matched);
1336                 }
1337                 break;
1338
1339         case '&':
1340                 matched = (v & l) == l;
1341                 if ((ms->flags & MAGIC_DEBUG) != 0)
1342                         (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
1343                                        v, l, l, matched);
1344                 break;
1345
1346         case '^':
1347                 matched = (v & l) != l;
1348                 if ((ms->flags & MAGIC_DEBUG) != 0)
1349                         (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
1350                                        v, l, l, matched);
1351                 break;
1352
1353         default:
1354                 matched = 0;
1355                 file_error(ms, 0, "cannot happen: invalid relation `%c'",
1356                     m->reln);
1357                 return -1;
1358         }
1359
1360         return matched;
1361 }