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