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