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