Remove old versions of file.
[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
39
40 #ifndef lint
41 FILE_RCSID("@(#)$File: softmagic.c,v 1.103 2007/12/27 16:35:59 christos Exp $")
42 #endif  /* lint */
43
44 private int match(struct magic_set *, struct magic *, uint32_t,
45     const unsigned char *, size_t);
46 private int mget(struct magic_set *, const unsigned char *,
47     struct magic *, size_t, unsigned int);
48 private int magiccheck(struct magic_set *, struct magic *);
49 private int32_t mprint(struct magic_set *, struct magic *);
50 private void mdebug(uint32_t, const char *, size_t);
51 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
52     const unsigned char *, uint32_t, size_t, size_t);
53 private int mconvert(struct magic_set *, struct magic *);
54 private int print_sep(struct magic_set *, int);
55 private void cvt_8(union VALUETYPE *, const struct magic *);
56 private void cvt_16(union VALUETYPE *, const struct magic *);
57 private void cvt_32(union VALUETYPE *, const struct magic *);
58 private void cvt_64(union VALUETYPE *, const struct magic *);
59
60 /*
61  * softmagic - lookup one file in parsed, in-memory copy of database
62  * Passed the name and FILE * of one file to be typed.
63  */
64 /*ARGSUSED1*/           /* nbytes passed for regularity, maybe need later */
65 protected int
66 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
67 {
68         struct mlist *ml;
69         int rv;
70         for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next)
71                 if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes)) != 0)
72                         return rv;
73
74         return 0;
75 }
76
77 /*
78  * Go through the whole list, stopping if you find a match.  Process all
79  * the continuations of that match before returning.
80  *
81  * We support multi-level continuations:
82  *
83  *      At any time when processing a successful top-level match, there is a
84  *      current continuation level; it represents the level of the last
85  *      successfully matched continuation.
86  *
87  *      Continuations above that level are skipped as, if we see one, it
88  *      means that the continuation that controls them - i.e, the
89  *      lower-level continuation preceding them - failed to match.
90  *
91  *      Continuations below that level are processed as, if we see one,
92  *      it means we've finished processing or skipping higher-level
93  *      continuations under the control of a successful or unsuccessful
94  *      lower-level continuation, and are now seeing the next lower-level
95  *      continuation and should process it.  The current continuation
96  *      level reverts to the level of the one we're seeing.
97  *
98  *      Continuations at the current level are processed as, if we see
99  *      one, there's no lower-level continuation that may have failed.
100  *
101  *      If a continuation matches, we bump the current continuation level
102  *      so that higher-level continuations are processed.
103  */
104 private int
105 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
106     const unsigned char *s, size_t nbytes)
107 {
108         uint32_t magindex = 0;
109         unsigned int cont_level = 0;
110         int need_separator = 0;
111         int returnval = 0; /* if a match is found it is set to 1*/
112         int firstline = 1; /* a flag to print X\n  X\n- X */
113         int printed_something = 0;
114
115         if (file_check_mem(ms, cont_level) == -1)
116                 return -1;
117
118         for (magindex = 0; magindex < nmagic; magindex++) {
119                 int flush;
120
121                 ms->offset = magic[magindex].offset;
122                 ms->line = magic[magindex].lineno;
123
124                 /* if main entry matches, print it... */
125                 flush = !mget(ms, s, &magic[magindex], nbytes, cont_level);
126                 if (flush) {
127                         if (magic[magindex].reln == '!')
128                                 flush = 0;
129                 } else {        
130                         switch (magiccheck(ms, &magic[magindex])) {
131                         case -1:
132                                 return -1;
133                         case 0:
134                                 flush++;
135                                 break;
136                         default:
137                                 break;
138                         }
139                 }
140                 if (flush) {
141                         /* 
142                          * main entry didn't match,
143                          * flush its continuations
144                          */
145                         while (magindex < nmagic - 1 &&
146                             magic[magindex + 1].cont_level != 0)
147                                 magindex++;
148                         continue;
149                 }
150
151                 /*
152                  * If we are going to print something, we'll need to print
153                  * a blank before we print something else.
154                  */
155                 if (magic[magindex].desc[0]) {
156                         need_separator = 1;
157                         printed_something = 1;
158                         if (print_sep(ms, firstline) == -1)
159                                 return -1;
160                 }
161
162                 if ((ms->c.li[cont_level].off = mprint(ms, &magic[magindex]))
163                     == -1)
164                         return -1;
165
166                 /* and any continuations that match */
167                 if (file_check_mem(ms, ++cont_level) == -1)
168                         return -1;
169
170                 while (magic[magindex+1].cont_level != 0 &&
171                     ++magindex < nmagic) {
172                         ms->line = magic[magindex].lineno; /* for messages */
173
174                         if (cont_level < magic[magindex].cont_level)
175                                 continue;
176                         if (cont_level > magic[magindex].cont_level) {
177                                 /*
178                                  * We're at the end of the level
179                                  * "cont_level" continuations.
180                                  */
181                                 cont_level = magic[magindex].cont_level;
182                         }
183                         ms->offset = magic[magindex].offset;
184                         if (magic[magindex].flag & OFFADD) {
185                                 ms->offset +=
186                                     ms->c.li[cont_level - 1].off;
187                         }
188
189 #ifdef ENABLE_CONDITIONALS
190                         if (magic[magindex].cond == COND_ELSE ||
191                             magic[magindex].cond == COND_ELIF) {
192                                 if (ms->c.li[cont_level].last_match == 1)
193                                         continue;
194                         }
195 #endif
196                         flush = !mget(ms, s, &magic[magindex], nbytes,
197                             cont_level);
198                         if (flush && magic[magindex].reln != '!')
199                                 continue;
200                                 
201                         switch (flush ? 1 : magiccheck(ms, &magic[magindex])) {
202                         case -1:
203                                 return -1;
204                         case 0:
205 #ifdef ENABLE_CONDITIONALS
206                                 ms->c.li[cont_level].last_match = 0;
207 #endif
208                                 break;
209                         default:
210 #ifdef ENABLE_CONDITIONALS
211                                 ms->c.li[cont_level].last_match = 1;
212 #endif
213                                 if (magic[magindex].type != FILE_DEFAULT)
214                                         ms->c.li[cont_level].got_match = 1;
215                                 else if (ms->c.li[cont_level].got_match) {
216                                         ms->c.li[cont_level].got_match = 0;
217                                         break;
218                                 }
219                                 /*
220                                  * If we are going to print something,
221                                  * make sure that we have a separator first.
222                                  */
223                                 if (magic[magindex].desc[0]) {
224                                         printed_something = 1;
225                                         if (print_sep(ms, firstline) == -1)
226                                                 return -1;
227                                 }
228                                 /*
229                                  * This continuation matched.  Print
230                                  * its message, with a blank before it
231                                  * if the previous item printed and
232                                  * this item isn't empty.
233                                  */
234                                 /* space if previous printed */
235                                 if (need_separator
236                                     && (magic[magindex].nospflag == 0)
237                                     && (magic[magindex].desc[0] != '\0')) {
238                                         if (file_printf(ms, " ") == -1)
239                                                 return -1;
240                                         need_separator = 0;
241                                 }
242                                 if ((ms->c.li[cont_level].off = mprint(ms, &magic[magindex])) == -1)
243                                         return -1;
244                                 if (magic[magindex].desc[0])
245                                         need_separator = 1;
246
247                                 /*
248                                  * If we see any continuations
249                                  * at a higher level,
250                                  * process them.
251                                  */
252                                 if (file_check_mem(ms, ++cont_level) == -1)
253                                         return -1;
254                                 break;
255                         }
256                 }
257                 if (printed_something) {
258                         firstline = 0;
259                         returnval = 1;
260                 }
261                 if ((ms->flags & MAGIC_CONTINUE) == 0 && printed_something) {
262                         return 1; /* don't keep searching */
263                 }                       
264         }
265         return returnval;  /* This is hit if -k is set or there is no match */
266 }
267
268 private int
269 check_fmt(struct magic_set *ms, struct magic *m)
270 {
271         regex_t rx;
272         int rc;
273
274         if (strchr(m->desc, '%') == NULL)
275                 return 0;
276
277         rc = regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
278         if (rc) {
279                 char errmsg[512];
280                 (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
281                 file_magerror(ms, "regex error %d, (%s)", rc, errmsg);
282                 return -1;
283         } else {
284                 rc = regexec(&rx, m->desc, 0, 0, 0);
285                 regfree(&rx);
286                 return !rc;
287         }
288 }
289
290 #ifndef HAVE_STRNDUP
291 char * strndup(const char *, size_t);
292
293 char *
294 strndup(const char *str, size_t n)
295 {
296         size_t len;
297         char *copy;
298
299         len = strlen(str);
300         if (len > n)
301                 len = n;
302         if (!(copy = malloc(len + 1)))
303                 return (NULL);
304         (void) memcpy(copy, str, len + 1);
305         copy[len] = '\0';
306         return (copy);
307 }
308 #endif /* HAVE_STRNDUP */
309
310 private int32_t
311 mprint(struct magic_set *ms, struct magic *m)
312 {
313         uint64_t v;
314         float vf;
315         double vd;
316         int64_t t = 0;
317         char buf[512];
318         union VALUETYPE *p = &ms->ms_value;
319
320         switch (m->type) {
321         case FILE_BYTE:
322                 v = file_signextend(ms, m, (uint64_t)p->b);
323                 switch (check_fmt(ms, m)) {
324                 case -1:
325                         return -1;
326                 case 1:
327                         if (snprintf(buf, sizeof(buf), "%c",
328                             (unsigned char)v) < 0)
329                                 return -1;
330                         if (file_printf(ms, m->desc, buf) == -1)
331                                 return -1;
332                         break;
333                 default:
334                         if (file_printf(ms, m->desc, (unsigned char) v) == -1)
335                                 return -1;
336                         break;
337                 }
338                 t = ms->offset + sizeof(char);
339                 break;
340
341         case FILE_SHORT:
342         case FILE_BESHORT:
343         case FILE_LESHORT:
344                 v = file_signextend(ms, m, (uint64_t)p->h);
345                 switch (check_fmt(ms, m)) {
346                 case -1:
347                         return -1;
348                 case 1:
349                         if (snprintf(buf, sizeof(buf), "%hu",
350                             (unsigned short)v) < 0)
351                                 return -1;
352                         if (file_printf(ms, m->desc, buf) == -1)
353                                 return -1;
354                         break;
355                 default:
356                         if (file_printf(ms, m->desc, (unsigned short) v) == -1)
357                                 return -1;
358                         break;
359                 }
360                 t = ms->offset + sizeof(short);
361                 break;
362
363         case FILE_LONG:
364         case FILE_BELONG:
365         case FILE_LELONG:
366         case FILE_MELONG:
367                 v = file_signextend(ms, m, (uint64_t)p->l);
368                 switch (check_fmt(ms, m)) {
369                 case -1:
370                         return -1;
371                 case 1:
372                         if (snprintf(buf, sizeof(buf), "%u", (uint32_t)v) < 0)
373                                 return -1;
374                         if (file_printf(ms, m->desc, buf) == -1)
375                                 return -1;
376                         break;
377                 default:
378                         if (file_printf(ms, m->desc, (uint32_t) v) == -1)
379                                 return -1;
380                         break;
381                 }
382                 t = ms->offset + sizeof(int32_t);
383                 break;
384
385         case FILE_QUAD:
386         case FILE_BEQUAD:
387         case FILE_LEQUAD:
388                 v = file_signextend(ms, m, p->q);
389                 if (file_printf(ms, m->desc, (uint64_t) v) == -1)
390                         return -1;
391                 t = ms->offset + sizeof(int64_t);
392                 break;
393
394         case FILE_STRING:
395         case FILE_PSTRING:
396         case FILE_BESTRING16:
397         case FILE_LESTRING16:
398                 if (m->reln == '=' || m->reln == '!') {
399                         if (file_printf(ms, m->desc, m->value.s) == -1)
400                                 return -1;
401                         t = ms->offset + m->vallen;
402                 }
403                 else {
404                         if (*m->value.s == '\0')
405                                 p->s[strcspn(p->s, "\n")] = '\0';
406                         if (file_printf(ms, m->desc, p->s) == -1)
407                                 return -1;
408                         t = ms->offset + strlen(p->s);
409                 }
410                 break;
411
412         case FILE_DATE:
413         case FILE_BEDATE:
414         case FILE_LEDATE:
415         case FILE_MEDATE:
416                 if (file_printf(ms, m->desc, file_fmttime(p->l, 1)) == -1)
417                         return -1;
418                 t = ms->offset + sizeof(time_t);
419                 break;
420
421         case FILE_LDATE:
422         case FILE_BELDATE:
423         case FILE_LELDATE:
424         case FILE_MELDATE:
425                 if (file_printf(ms, m->desc, file_fmttime(p->l, 0)) == -1)
426                         return -1;
427                 t = ms->offset + sizeof(time_t);
428                 break;
429
430         case FILE_QDATE:
431         case FILE_BEQDATE:
432         case FILE_LEQDATE:
433                 if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q, 1))
434                     == -1)
435                         return -1;
436                 t = ms->offset + sizeof(uint64_t);
437                 break;
438
439         case FILE_QLDATE:
440         case FILE_BEQLDATE:
441         case FILE_LEQLDATE:
442                 if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q, 0))
443                     == -1)
444                         return -1;
445                 t = ms->offset + sizeof(uint64_t);
446                 break;
447
448         case FILE_FLOAT:
449         case FILE_BEFLOAT:
450         case FILE_LEFLOAT:
451                 vf = p->f;
452                 switch (check_fmt(ms, m)) {
453                 case -1:
454                         return -1;
455                 case 1:
456                         if (snprintf(buf, sizeof(buf), "%g", vf) < 0)
457                                 return -1;
458                         if (file_printf(ms, m->desc, buf) == -1)
459                                 return -1;
460                         break;
461                 default:
462                         if (file_printf(ms, m->desc, vf) == -1)
463                                 return -1;
464                         break;
465                 }
466                 t = ms->offset + sizeof(float);
467                 break;
468
469         case FILE_DOUBLE:
470         case FILE_BEDOUBLE:
471         case FILE_LEDOUBLE:
472                 vd = p->d;
473                 switch (check_fmt(ms, m)) {
474                 case -1:
475                         return -1;
476                 case 1:
477                         if (snprintf(buf, sizeof(buf), "%g", vd) < 0)
478                                 return -1;
479                         if (file_printf(ms, m->desc, buf) == -1)
480                                 return -1;
481                         break;
482                 default:
483                         if (file_printf(ms, m->desc, vd) == -1)
484                                 return -1;
485                         break;
486                 }
487                 t = ms->offset + sizeof(double);
488                 break;
489
490         case FILE_REGEX: {
491                 char *cp;
492                 int rval;
493
494                 cp = strndup((const char *)ms->search.s, ms->search.rm_len);
495                 if (cp == NULL) {
496                         file_oomem(ms, ms->search.rm_len);
497                         return -1;
498                 }
499                 rval = file_printf(ms, m->desc, cp);
500                 free(cp);
501
502                 if (rval == -1)
503                         return -1;
504
505                 if ((m->str_flags & REGEX_OFFSET_START))
506                         t = ms->search.offset;
507                 else
508                         t = ms->search.offset + ms->search.rm_len;
509                 break;
510         }
511
512         case FILE_SEARCH:
513                 if (file_printf(ms, m->desc, m->value.s) == -1)
514                         return -1;
515                 if ((m->str_flags & REGEX_OFFSET_START))
516                         t = ms->search.offset;
517                 else
518                         t = ms->search.offset + m->vallen;
519                 break;
520
521         case FILE_DEFAULT:
522                 if (file_printf(ms, m->desc, m->value.s) == -1)
523                         return -1;
524                 t = ms->offset;
525                 break;
526
527         default:
528                 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
529                 return -1;
530         }
531         return(t);
532 }
533
534
535 #define DO_CVT(fld, cast) \
536         if (m->num_mask) \
537                 switch (m->mask_op & FILE_OPS_MASK) { \
538                 case FILE_OPAND: \
539                         p->fld &= cast m->num_mask; \
540                         break; \
541                 case FILE_OPOR: \
542                         p->fld |= cast m->num_mask; \
543                         break; \
544                 case FILE_OPXOR: \
545                         p->fld ^= cast m->num_mask; \
546                         break; \
547                 case FILE_OPADD: \
548                         p->fld += cast m->num_mask; \
549                         break; \
550                 case FILE_OPMINUS: \
551                         p->fld -= cast m->num_mask; \
552                         break; \
553                 case FILE_OPMULTIPLY: \
554                         p->fld *= cast m->num_mask; \
555                         break; \
556                 case FILE_OPDIVIDE: \
557                         p->fld /= cast m->num_mask; \
558                         break; \
559                 case FILE_OPMODULO: \
560                         p->fld %= cast m->num_mask; \
561                         break; \
562                 } \
563         if (m->mask_op & FILE_OPINVERSE) \
564                 p->fld = ~p->fld \
565
566 private void
567 cvt_8(union VALUETYPE *p, const struct magic *m)
568 {
569         DO_CVT(b, (uint8_t));
570 }
571
572 private void
573 cvt_16(union VALUETYPE *p, const struct magic *m)
574 {
575         DO_CVT(h, (uint16_t));
576 }
577
578 private void
579 cvt_32(union VALUETYPE *p, const struct magic *m)
580 {
581         DO_CVT(l, (uint32_t));
582 }
583
584 private void
585 cvt_64(union VALUETYPE *p, const struct magic *m)
586 {
587         DO_CVT(q, (uint64_t));
588 }
589
590 #define DO_CVT2(fld, cast) \
591         if (m->num_mask) \
592                 switch (m->mask_op & FILE_OPS_MASK) { \
593                 case FILE_OPADD: \
594                         p->fld += cast m->num_mask; \
595                         break; \
596                 case FILE_OPMINUS: \
597                         p->fld -= cast m->num_mask; \
598                         break; \
599                 case FILE_OPMULTIPLY: \
600                         p->fld *= cast m->num_mask; \
601                         break; \
602                 case FILE_OPDIVIDE: \
603                         p->fld /= cast m->num_mask; \
604                         break; \
605                 } \
606
607 private void
608 cvt_float(union VALUETYPE *p, const struct magic *m)
609 {
610         DO_CVT2(f, (float));
611 }
612
613 private void
614 cvt_double(union VALUETYPE *p, const struct magic *m)
615 {
616         DO_CVT2(d, (double));
617 }
618
619 /*
620  * Convert the byte order of the data we are looking at
621  * While we're here, let's apply the mask operation
622  * (unless you have a better idea)
623  */
624 private int
625 mconvert(struct magic_set *ms, struct magic *m)
626 {
627         union VALUETYPE *p = &ms->ms_value;
628
629         switch (m->type) {
630         case FILE_BYTE:
631                 cvt_8(p, m);
632                 return 1;
633         case FILE_SHORT:
634                 cvt_16(p, m);
635                 return 1;
636         case FILE_LONG:
637         case FILE_DATE:
638         case FILE_LDATE:
639                 cvt_32(p, m);
640                 return 1;
641         case FILE_QUAD:
642         case FILE_QDATE:
643         case FILE_QLDATE:
644                 cvt_64(p, m);
645                 return 1;
646         case FILE_STRING:
647         case FILE_BESTRING16:
648         case FILE_LESTRING16: {
649                 size_t len;
650                 
651                 /* Null terminate and eat *trailing* return */
652                 p->s[sizeof(p->s) - 1] = '\0';
653                 len = strlen(p->s);
654                 if (len-- && p->s[len] == '\n')
655                         p->s[len] = '\0';
656                 return 1;
657         }
658         case FILE_PSTRING: {
659                 char *ptr1 = p->s, *ptr2 = ptr1 + 1;
660                 size_t len = *p->s;
661                 if (len >= sizeof(p->s))
662                         len = sizeof(p->s) - 1;
663                 while (len--)
664                         *ptr1++ = *ptr2++;
665                 *ptr1 = '\0';
666                 len = strlen(p->s);
667                 if (len-- && p->s[len] == '\n')
668                         p->s[len] = '\0';
669                 return 1;
670         }
671         case FILE_BESHORT:
672                 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
673                 cvt_16(p, m);
674                 return 1;
675         case FILE_BELONG:
676         case FILE_BEDATE:
677         case FILE_BELDATE:
678                 p->l = (int32_t)
679                     ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
680                 cvt_32(p, m);
681                 return 1;
682         case FILE_BEQUAD:
683         case FILE_BEQDATE:
684         case FILE_BEQLDATE:
685                 p->q = (int64_t)
686                     (((int64_t)p->hq[0]<<56)|((int64_t)p->hq[1]<<48)|
687                      ((int64_t)p->hq[2]<<40)|((int64_t)p->hq[3]<<32)|
688                      (p->hq[4]<<24)|(p->hq[5]<<16)|(p->hq[6]<<8)|(p->hq[7]));
689                 cvt_64(p, m);
690                 return 1;
691         case FILE_LESHORT:
692                 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
693                 cvt_16(p, m);
694                 return 1;
695         case FILE_LELONG:
696         case FILE_LEDATE:
697         case FILE_LELDATE:
698                 p->l = (int32_t)
699                     ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
700                 cvt_32(p, m);
701                 return 1;
702         case FILE_LEQUAD:
703         case FILE_LEQDATE:
704         case FILE_LEQLDATE:
705                 p->q = (int64_t)
706                     (((int64_t)p->hq[7]<<56)|((int64_t)p->hq[6]<<48)|
707                      ((int64_t)p->hq[5]<<40)|((int64_t)p->hq[4]<<32)|
708                      (p->hq[3]<<24)|(p->hq[2]<<16)|(p->hq[1]<<8)|(p->hq[0]));
709                 cvt_64(p, m);
710                 return 1;
711         case FILE_MELONG:
712         case FILE_MEDATE:
713         case FILE_MELDATE:
714                 p->l = (int32_t)
715                     ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2]));
716                 cvt_32(p, m);
717                 return 1;
718         case FILE_FLOAT:
719                 cvt_float(p, m);
720                 return 1;
721         case FILE_BEFLOAT:
722                 p->l =  ((uint32_t)p->hl[0]<<24)|((uint32_t)p->hl[1]<<16)|
723                         ((uint32_t)p->hl[2]<<8) |((uint32_t)p->hl[3]);
724                 cvt_float(p, m);
725                 return 1;
726         case FILE_LEFLOAT:
727                 p->l =  ((uint32_t)p->hl[3]<<24)|((uint32_t)p->hl[2]<<16)|
728                         ((uint32_t)p->hl[1]<<8) |((uint32_t)p->hl[0]);
729                 cvt_float(p, m);
730                 return 1;
731         case FILE_DOUBLE:
732                 cvt_double(p, m);
733                 return 1;
734         case FILE_BEDOUBLE:
735                 p->q =  ((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
736                         ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
737                         ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
738                         ((uint64_t)p->hq[6]<<8) |((uint64_t)p->hq[7]);
739                 cvt_double(p, m);
740                 return 1;
741         case FILE_LEDOUBLE:
742                 p->q =  ((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
743                         ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
744                         ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
745                         ((uint64_t)p->hq[1]<<8) |((uint64_t)p->hq[0]);
746                 cvt_double(p, m);
747                 return 1;
748         case FILE_REGEX:
749         case FILE_SEARCH:
750         case FILE_DEFAULT:
751                 return 1;
752         default:
753                 file_magerror(ms, "invalid type %d in mconvert()", m->type);
754                 return 0;
755         }
756 }
757
758
759 private void
760 mdebug(uint32_t offset, const char *str, size_t len)
761 {
762         (void) fprintf(stderr, "mget @%d: ", offset);
763         file_showstr(stderr, str, len);
764         (void) fputc('\n', stderr);
765         (void) fputc('\n', stderr);
766 }
767
768 private int
769 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
770     const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
771 {
772         /*
773          * Note: FILE_SEARCH and FILE_REGEX do not actually copy
774          * anything, but setup pointers into the source
775          */
776         if (indir == 0) {
777                 switch (type) {
778                 case FILE_SEARCH:
779                         ms->search.s = (const char *)s + offset;
780                         ms->search.s_len = nbytes - offset;
781                         return 0;
782
783                 case FILE_REGEX: {
784                         /*
785                          * offset is interpreted as last line to search,
786                          * (starting at 1), not as bytes-from start-of-file
787                          */
788                         const char *b;
789                         const char *c;
790                         const char *last;       /* end of search region */
791                         const char *buf;        /* start of search region */
792                         size_t lines;
793
794                         if (s == NULL) {
795                                 ms->search.s_len = 0;
796                                 ms->search.s = NULL;
797                                 return 0;
798                         }
799                         buf = (const char *)s + offset;
800                         last = (const char *)s + nbytes;
801                         /* mget() guarantees buf <= last */
802                         for (lines = linecnt, b = buf;
803                              lines && ((b = strchr(c = b, '\n')) || (b = strchr(c, '\r')));
804                              lines--, b++) {
805                                 last = b;
806                                 if (b[0] == '\r' && b[1] == '\n')
807                                         b++;
808                         }
809                         if (lines)
810                                 last = (const char *)s + nbytes;
811                         
812                         ms->search.s = buf;
813                         ms->search.s_len = last - buf;
814                         ms->search.offset = offset;
815                         ms->search.rm_len = 0;
816                         return 0;
817                 }
818                 case FILE_BESTRING16:
819                 case FILE_LESTRING16: {
820                         const unsigned char *src = s + offset;
821                         const unsigned char *esrc = s + nbytes;
822                         char *dst = p->s;
823                         char *edst = &p->s[sizeof(p->s) - 1];
824                         
825                         if (type == FILE_BESTRING16)
826                                 src++;
827                         
828                         /* check for pointer overflow */
829                         if (src < s) {
830                                 file_magerror(ms, "invalid offset %zu in mcopy()",
831                                     offset);
832                                 return -1;
833                         }
834                         for (/*EMPTY*/; src < esrc; src += 2, dst++) {
835                                 if (dst < edst)
836                                         *dst = *src;
837                                 else
838                                         break;
839                                 if (*dst == '\0') {
840                                         if (type == FILE_BESTRING16 ?
841                                             *(src - 1) != '\0' :
842                                             *(src + 1) != '\0')
843                                                 *dst = ' ';
844                                 }
845                         }
846                         *edst = '\0';
847                         return 0;
848                 }
849                 case FILE_STRING:       /* XXX - these two should not need */
850                 case FILE_PSTRING:      /* to copy anything, but do anyway. */
851                 default:
852                         break;
853                 }
854         }
855
856         if (offset >= nbytes) {
857                 (void)memset(p, '\0', sizeof(*p));
858                 return 0;
859         }
860         if (nbytes - offset < sizeof(*p))
861                 nbytes = nbytes - offset;
862         else
863                 nbytes = sizeof(*p);
864
865         (void)memcpy(p, s + offset, nbytes);
866
867         /*
868          * the usefulness of padding with zeroes eludes me, it
869          * might even cause problems
870          */
871         if (nbytes < sizeof(*p))
872                 (void)memset(((char *)(void *)p) + nbytes, '\0',
873                     sizeof(*p) - nbytes);
874         return 0;
875 }
876
877 private int
878 mget(struct magic_set *ms, const unsigned char *s,
879     struct magic *m, size_t nbytes, unsigned int cont_level)
880 {
881         uint32_t offset = ms->offset;
882         uint32_t count = m->str_count;
883         union VALUETYPE *p = &ms->ms_value;
884
885         if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1)
886                 return -1;
887
888         if ((ms->flags & MAGIC_DEBUG) != 0) {
889                 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
890                 file_mdump(m);
891         }
892
893         if (m->flag & INDIR) {
894                 int off = m->in_offset;
895                 if (m->in_op & FILE_OPINDIRECT) {
896                         const union VALUETYPE *q =
897                             ((const void *)(s + offset + off));
898                         switch (m->in_type) {
899                         case FILE_BYTE:
900                                 off = q->b;
901                                 break;
902                         case FILE_SHORT:
903                                 off = q->h;
904                                 break;
905                         case FILE_BESHORT:
906                                 off = (short)((q->hs[0]<<8)|(q->hs[1]));
907                                 break;
908                         case FILE_LESHORT:
909                                 off = (short)((q->hs[1]<<8)|(q->hs[0]));
910                                 break;
911                         case FILE_LONG:
912                                 off = q->l;
913                                 break;
914                         case FILE_BELONG:
915                                 off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
916                                                  (q->hl[2]<<8)|(q->hl[3]));
917                                 break;
918                         case FILE_LELONG:
919                                 off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
920                                                  (q->hl[1]<<8)|(q->hl[0]));
921                                 break;
922                         case FILE_MELONG:
923                                 off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
924                                                  (q->hl[3]<<8)|(q->hl[2]));
925                                 break;
926                         }
927                 }
928                 switch (m->in_type) {
929                 case FILE_BYTE:
930                         if (nbytes < (offset + 1))
931                                 return 0;
932                         if (off) {
933                                 switch (m->in_op & FILE_OPS_MASK) {
934                                 case FILE_OPAND:
935                                         offset = p->b & off;
936                                         break;
937                                 case FILE_OPOR:
938                                         offset = p->b | off;
939                                         break;
940                                 case FILE_OPXOR:
941                                         offset = p->b ^ off;
942                                         break;
943                                 case FILE_OPADD:
944                                         offset = p->b + off;
945                                         break;
946                                 case FILE_OPMINUS:
947                                         offset = p->b - off;
948                                         break;
949                                 case FILE_OPMULTIPLY:
950                                         offset = p->b * off;
951                                         break;
952                                 case FILE_OPDIVIDE:
953                                         offset = p->b / off;
954                                         break;
955                                 case FILE_OPMODULO:
956                                         offset = p->b % off;
957                                         break;
958                                 }
959                         } else
960                                 offset = p->b;
961                         if (m->in_op & FILE_OPINVERSE)
962                                 offset = ~offset;
963                         break;
964                 case FILE_BESHORT:
965                         if (nbytes < (offset + 2))
966                                 return 0;
967                         if (off) {
968                                 switch (m->in_op & FILE_OPS_MASK) {
969                                 case FILE_OPAND:
970                                         offset = (short)((p->hs[0]<<8)|
971                                                          (p->hs[1])) &
972                                                  off;
973                                         break;
974                                 case FILE_OPOR:
975                                         offset = (short)((p->hs[0]<<8)|
976                                                          (p->hs[1])) |
977                                                  off;
978                                         break;
979                                 case FILE_OPXOR:
980                                         offset = (short)((p->hs[0]<<8)|
981                                                          (p->hs[1])) ^
982                                                  off;
983                                         break;
984                                 case FILE_OPADD:
985                                         offset = (short)((p->hs[0]<<8)|
986                                                          (p->hs[1])) +
987                                                  off;
988                                         break;
989                                 case FILE_OPMINUS:
990                                         offset = (short)((p->hs[0]<<8)|
991                                                          (p->hs[1])) -
992                                                  off;
993                                         break;
994                                 case FILE_OPMULTIPLY:
995                                         offset = (short)((p->hs[0]<<8)|
996                                                          (p->hs[1])) *
997                                                  off;
998                                         break;
999                                 case FILE_OPDIVIDE:
1000                                         offset = (short)((p->hs[0]<<8)|
1001                                                          (p->hs[1])) /
1002                                                  off;
1003                                         break;
1004                                 case FILE_OPMODULO:
1005                                         offset = (short)((p->hs[0]<<8)|
1006                                                          (p->hs[1])) %
1007                                                  off;
1008                                         break;
1009                                 }
1010                         } else
1011                                 offset = (short)((p->hs[0]<<8)|
1012                                                  (p->hs[1]));
1013                         if (m->in_op & FILE_OPINVERSE)
1014                                 offset = ~offset;
1015                         break;
1016                 case FILE_LESHORT:
1017                         if (nbytes < (offset + 2))
1018                                 return 0;
1019                         if (off) {
1020                                 switch (m->in_op & FILE_OPS_MASK) {
1021                                 case FILE_OPAND:
1022                                         offset = (short)((p->hs[1]<<8)|
1023                                                          (p->hs[0])) &
1024                                                  off;
1025                                         break;
1026                                 case FILE_OPOR:
1027                                         offset = (short)((p->hs[1]<<8)|
1028                                                          (p->hs[0])) |
1029                                                  off;
1030                                         break;
1031                                 case FILE_OPXOR:
1032                                         offset = (short)((p->hs[1]<<8)|
1033                                                          (p->hs[0])) ^
1034                                                  off;
1035                                         break;
1036                                 case FILE_OPADD:
1037                                         offset = (short)((p->hs[1]<<8)|
1038                                                          (p->hs[0])) +
1039                                                  off;
1040                                         break;
1041                                 case FILE_OPMINUS:
1042                                         offset = (short)((p->hs[1]<<8)|
1043                                                          (p->hs[0])) -
1044                                                  off;
1045                                         break;
1046                                 case FILE_OPMULTIPLY:
1047                                         offset = (short)((p->hs[1]<<8)|
1048                                                          (p->hs[0])) *
1049                                                  off;
1050                                         break;
1051                                 case FILE_OPDIVIDE:
1052                                         offset = (short)((p->hs[1]<<8)|
1053                                                          (p->hs[0])) /
1054                                                  off;
1055                                         break;
1056                                 case FILE_OPMODULO:
1057                                         offset = (short)((p->hs[1]<<8)|
1058                                                          (p->hs[0])) %
1059                                                  off;
1060                                         break;
1061                                 }
1062                         } else
1063                                 offset = (short)((p->hs[1]<<8)|
1064                                                  (p->hs[0]));
1065                         if (m->in_op & FILE_OPINVERSE)
1066                                 offset = ~offset;
1067                         break;
1068                 case FILE_SHORT:
1069                         if (nbytes < (offset + 2))
1070                                 return 0;
1071                         if (off) {
1072                                 switch (m->in_op & FILE_OPS_MASK) {
1073                                 case FILE_OPAND:
1074                                         offset = p->h & off;
1075                                         break;
1076                                 case FILE_OPOR:
1077                                         offset = p->h | off;
1078                                         break;
1079                                 case FILE_OPXOR:
1080                                         offset = p->h ^ off;
1081                                         break;
1082                                 case FILE_OPADD:
1083                                         offset = p->h + off;
1084                                         break;
1085                                 case FILE_OPMINUS:
1086                                         offset = p->h - off;
1087                                         break;
1088                                 case FILE_OPMULTIPLY:
1089                                         offset = p->h * off;
1090                                         break;
1091                                 case FILE_OPDIVIDE:
1092                                         offset = p->h / off;
1093                                         break;
1094                                 case FILE_OPMODULO:
1095                                         offset = p->h % off;
1096                                         break;
1097                                 }
1098                         }
1099                         else
1100                                 offset = p->h;
1101                         if (m->in_op & FILE_OPINVERSE)
1102                                 offset = ~offset;
1103                         break;
1104                 case FILE_BELONG:
1105                         if (nbytes < (offset + 4))
1106                                 return 0;
1107                         if (off) {
1108                                 switch (m->in_op & FILE_OPS_MASK) {
1109                                 case FILE_OPAND:
1110                                         offset = (int32_t)((p->hl[0]<<24)|
1111                                                          (p->hl[1]<<16)|
1112                                                          (p->hl[2]<<8)|
1113                                                          (p->hl[3])) &
1114                                                  off;
1115                                         break;
1116                                 case FILE_OPOR:
1117                                         offset = (int32_t)((p->hl[0]<<24)|
1118                                                          (p->hl[1]<<16)|
1119                                                          (p->hl[2]<<8)|
1120                                                          (p->hl[3])) |
1121                                                  off;
1122                                         break;
1123                                 case FILE_OPXOR:
1124                                         offset = (int32_t)((p->hl[0]<<24)|
1125                                                          (p->hl[1]<<16)|
1126                                                          (p->hl[2]<<8)|
1127                                                          (p->hl[3])) ^
1128                                                  off;
1129                                         break;
1130                                 case FILE_OPADD:
1131                                         offset = (int32_t)((p->hl[0]<<24)|
1132                                                          (p->hl[1]<<16)|
1133                                                          (p->hl[2]<<8)|
1134                                                          (p->hl[3])) +
1135                                                  off;
1136                                         break;
1137                                 case FILE_OPMINUS:
1138                                         offset = (int32_t)((p->hl[0]<<24)|
1139                                                          (p->hl[1]<<16)|
1140                                                          (p->hl[2]<<8)|
1141                                                          (p->hl[3])) -
1142                                                  off;
1143                                         break;
1144                                 case FILE_OPMULTIPLY:
1145                                         offset = (int32_t)((p->hl[0]<<24)|
1146                                                          (p->hl[1]<<16)|
1147                                                          (p->hl[2]<<8)|
1148                                                          (p->hl[3])) *
1149                                                  off;
1150                                         break;
1151                                 case FILE_OPDIVIDE:
1152                                         offset = (int32_t)((p->hl[0]<<24)|
1153                                                          (p->hl[1]<<16)|
1154                                                          (p->hl[2]<<8)|
1155                                                          (p->hl[3])) /
1156                                                  off;
1157                                         break;
1158                                 case FILE_OPMODULO:
1159                                         offset = (int32_t)((p->hl[0]<<24)|
1160                                                          (p->hl[1]<<16)|
1161                                                          (p->hl[2]<<8)|
1162                                                          (p->hl[3])) %
1163                                                  off;
1164                                         break;
1165                                 }
1166                         } else
1167                                 offset = (int32_t)((p->hl[0]<<24)|
1168                                                  (p->hl[1]<<16)|
1169                                                  (p->hl[2]<<8)|
1170                                                  (p->hl[3]));
1171                         if (m->in_op & FILE_OPINVERSE)
1172                                 offset = ~offset;
1173                         break;
1174                 case FILE_LELONG:
1175                         if (nbytes < (offset + 4))
1176                                 return 0;
1177                         if (off) {
1178                                 switch (m->in_op & FILE_OPS_MASK) {
1179                                 case FILE_OPAND:
1180                                         offset = (int32_t)((p->hl[3]<<24)|
1181                                                          (p->hl[2]<<16)|
1182                                                          (p->hl[1]<<8)|
1183                                                          (p->hl[0])) &
1184                                                  off;
1185                                         break;
1186                                 case FILE_OPOR:
1187                                         offset = (int32_t)((p->hl[3]<<24)|
1188                                                          (p->hl[2]<<16)|
1189                                                          (p->hl[1]<<8)|
1190                                                          (p->hl[0])) |
1191                                                  off;
1192                                         break;
1193                                 case FILE_OPXOR:
1194                                         offset = (int32_t)((p->hl[3]<<24)|
1195                                                          (p->hl[2]<<16)|
1196                                                          (p->hl[1]<<8)|
1197                                                          (p->hl[0])) ^
1198                                                  off;
1199                                         break;
1200                                 case FILE_OPADD:
1201                                         offset = (int32_t)((p->hl[3]<<24)|
1202                                                          (p->hl[2]<<16)|
1203                                                          (p->hl[1]<<8)|
1204                                                          (p->hl[0])) +
1205                                                  off;
1206                                         break;
1207                                 case FILE_OPMINUS:
1208                                         offset = (int32_t)((p->hl[3]<<24)|
1209                                                          (p->hl[2]<<16)|
1210                                                          (p->hl[1]<<8)|
1211                                                          (p->hl[0])) -
1212                                                  off;
1213                                         break;
1214                                 case FILE_OPMULTIPLY:
1215                                         offset = (int32_t)((p->hl[3]<<24)|
1216                                                          (p->hl[2]<<16)|
1217                                                          (p->hl[1]<<8)|
1218                                                          (p->hl[0])) *
1219                                                  off;
1220                                         break;
1221                                 case FILE_OPDIVIDE:
1222                                         offset = (int32_t)((p->hl[3]<<24)|
1223                                                          (p->hl[2]<<16)|
1224                                                          (p->hl[1]<<8)|
1225                                                          (p->hl[0])) /
1226                                                  off;
1227                                         break;
1228                                 case FILE_OPMODULO:
1229                                         offset = (int32_t)((p->hl[3]<<24)|
1230                                                          (p->hl[2]<<16)|
1231                                                          (p->hl[1]<<8)|
1232                                                          (p->hl[0])) %
1233                                                  off;
1234                                         break;
1235                                 }
1236                         } else
1237                                 offset = (int32_t)((p->hl[3]<<24)|
1238                                                  (p->hl[2]<<16)|
1239                                                  (p->hl[1]<<8)|
1240                                                  (p->hl[0]));
1241                         if (m->in_op & FILE_OPINVERSE)
1242                                 offset = ~offset;
1243                         break;
1244                 case FILE_MELONG:
1245                         if (nbytes < (offset + 4))
1246                                 return 0;
1247                         if (off) {
1248                                 switch (m->in_op & FILE_OPS_MASK) {
1249                                 case FILE_OPAND:
1250                                         offset = (int32_t)((p->hl[1]<<24)|
1251                                                          (p->hl[0]<<16)|
1252                                                          (p->hl[3]<<8)|
1253                                                          (p->hl[2])) &
1254                                                  off;
1255                                         break;
1256                                 case FILE_OPOR:
1257                                         offset = (int32_t)((p->hl[1]<<24)|
1258                                                          (p->hl[0]<<16)|
1259                                                          (p->hl[3]<<8)|
1260                                                          (p->hl[2])) |
1261                                                  off;
1262                                         break;
1263                                 case FILE_OPXOR:
1264                                         offset = (int32_t)((p->hl[1]<<24)|
1265                                                          (p->hl[0]<<16)|
1266                                                          (p->hl[3]<<8)|
1267                                                          (p->hl[2])) ^
1268                                                  off;
1269                                         break;
1270                                 case FILE_OPADD:
1271                                         offset = (int32_t)((p->hl[1]<<24)|
1272                                                          (p->hl[0]<<16)|
1273                                                          (p->hl[3]<<8)|
1274                                                          (p->hl[2])) +
1275                                                  off;
1276                                         break;
1277                                 case FILE_OPMINUS:
1278                                         offset = (int32_t)((p->hl[1]<<24)|
1279                                                          (p->hl[0]<<16)|
1280                                                          (p->hl[3]<<8)|
1281                                                          (p->hl[2])) -
1282                                                  off;
1283                                         break;
1284                                 case FILE_OPMULTIPLY:
1285                                         offset = (int32_t)((p->hl[1]<<24)|
1286                                                          (p->hl[0]<<16)|
1287                                                          (p->hl[3]<<8)|
1288                                                          (p->hl[2])) *
1289                                                  off;
1290                                         break;
1291                                 case FILE_OPDIVIDE:
1292                                         offset = (int32_t)((p->hl[1]<<24)|
1293                                                          (p->hl[0]<<16)|
1294                                                          (p->hl[3]<<8)|
1295                                                          (p->hl[2])) /
1296                                                  off;
1297                                         break;
1298                                 case FILE_OPMODULO:
1299                                         offset = (int32_t)((p->hl[1]<<24)|
1300                                                          (p->hl[0]<<16)|
1301                                                          (p->hl[3]<<8)|
1302                                                          (p->hl[2])) %
1303                                                  off;
1304                                         break;
1305                                 }
1306                         } else
1307                                 offset = (int32_t)((p->hl[1]<<24)|
1308                                                  (p->hl[0]<<16)|
1309                                                  (p->hl[3]<<8)|
1310                                                  (p->hl[2]));
1311                         if (m->in_op & FILE_OPINVERSE)
1312                                 offset = ~offset;
1313                         break;
1314                 case FILE_LONG:
1315                         if (nbytes < (offset + 4))
1316                                 return 0;
1317                         if (off) {
1318                                 switch (m->in_op & FILE_OPS_MASK) {
1319                                 case FILE_OPAND:
1320                                         offset = p->l & off;
1321                                         break;
1322                                 case FILE_OPOR:
1323                                         offset = p->l | off;
1324                                         break;
1325                                 case FILE_OPXOR:
1326                                         offset = p->l ^ off;
1327                                         break;
1328                                 case FILE_OPADD:
1329                                         offset = p->l + off;
1330                                         break;
1331                                 case FILE_OPMINUS:
1332                                         offset = p->l - off;
1333                                         break;
1334                                 case FILE_OPMULTIPLY:
1335                                         offset = p->l * off;
1336                                         break;
1337                                 case FILE_OPDIVIDE:
1338                                         offset = p->l / off;
1339                                         break;
1340                                 case FILE_OPMODULO:
1341                                         offset = p->l % off;
1342                                         break;
1343                         /*      case TOOMANYSWITCHBLOCKS:
1344                          *              ugh = p->eye % m->strain;
1345                          *              rub;
1346                          *      case BEER:
1347                          *              off = p->tab & m->in_gest;
1348                          *              sleep;
1349                          */
1350                                 }
1351                         } else
1352                                 offset = p->l;
1353                         if (m->in_op & FILE_OPINVERSE)
1354                                 offset = ~offset;
1355                         break;
1356                 }
1357
1358                 if (m->flag & INDIROFFADD)
1359                         offset += ms->c.li[cont_level-1].off;
1360                 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
1361                         return -1;
1362                 ms->offset = offset;
1363
1364                 if ((ms->flags & MAGIC_DEBUG) != 0) {
1365                         mdebug(offset, (char *)(void *)p,
1366                             sizeof(union VALUETYPE));
1367                         file_mdump(m);
1368                 }
1369         }
1370
1371         /* Verify we have enough data to match magic type */
1372         switch (m->type) {
1373         case FILE_BYTE:
1374                 if (nbytes < (offset + 1)) /* should alway be true */
1375                         return 0;
1376                 break;
1377                 
1378         case FILE_SHORT:
1379         case FILE_BESHORT:
1380         case FILE_LESHORT:
1381                 if (nbytes < (offset + 2))
1382                         return 0;
1383                 break;
1384                 
1385         case FILE_LONG:
1386         case FILE_BELONG:
1387         case FILE_LELONG:
1388         case FILE_MELONG:
1389         case FILE_DATE:
1390         case FILE_BEDATE:
1391         case FILE_LEDATE:
1392         case FILE_MEDATE:
1393         case FILE_LDATE:
1394         case FILE_BELDATE:
1395         case FILE_LELDATE:
1396         case FILE_MELDATE:
1397         case FILE_FLOAT:
1398         case FILE_BEFLOAT:
1399         case FILE_LEFLOAT:
1400                 if (nbytes < (offset + 4))
1401                         return 0;
1402                 break;
1403                 
1404         case FILE_DOUBLE:
1405         case FILE_BEDOUBLE:
1406         case FILE_LEDOUBLE:
1407                 if (nbytes < (offset + 8))
1408                         return 0;
1409                 break;
1410
1411         case FILE_STRING:
1412         case FILE_PSTRING:
1413         case FILE_SEARCH:
1414                 if (nbytes < (offset + m->vallen))
1415                         return 0;
1416                 break;
1417
1418         case FILE_REGEX:
1419                 if (nbytes < offset)
1420                         return 0;
1421                 break;
1422
1423         case FILE_DEFAULT:      /* nothing to check */
1424         default:
1425                 break;
1426         }
1427         if (!mconvert(ms, m))
1428                 return 0;
1429         return 1;
1430 }
1431
1432 private uint64_t
1433 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1434 {
1435         /*
1436          * Convert the source args to unsigned here so that (1) the
1437          * compare will be unsigned as it is in strncmp() and (2) so
1438          * the ctype functions will work correctly without extra
1439          * casting.
1440          */
1441         const unsigned char *a = (const unsigned char *)s1;
1442         const unsigned char *b = (const unsigned char *)s2;
1443         uint64_t v;
1444
1445         /*
1446          * What we want here is:
1447          * v = strncmp(m->value.s, p->s, m->vallen);
1448          * but ignoring any nulls.  bcmp doesn't give -/+/0
1449          * and isn't universally available anyway.
1450          */
1451         v = 0;
1452         if (0L == flags) { /* normal string: do it fast */
1453                 while (len-- > 0)
1454                         if ((v = *b++ - *a++) != '\0')
1455                                 break; 
1456         }
1457         else { /* combine the others */
1458                 while (len-- > 0) {
1459                         if ((flags & STRING_IGNORE_LOWERCASE) &&
1460                             islower(*a)) {
1461                                 if ((v = tolower(*b++) - *a++) != '\0')
1462                                         break;
1463                         }
1464                         else if ((flags & STRING_IGNORE_UPPERCASE) &&
1465                             isupper(*a)) {
1466                                 if ((v = toupper(*b++) - *a++) != '\0')
1467                                         break;
1468                         }
1469                         else if ((flags & STRING_COMPACT_BLANK) && 
1470                             isspace(*a)) { 
1471                                 a++;
1472                                 if (isspace(*b++)) {
1473                                         while (isspace(*b))
1474                                                 b++;
1475                                 }
1476                                 else {
1477                                         v = 1;
1478                                         break;
1479                                 }
1480                         }
1481                         else if ((flags & STRING_COMPACT_OPTIONAL_BLANK) &&
1482                             isspace(*a)) {
1483                                 a++;
1484                                 while (isspace(*b))
1485                                         b++;
1486                         }
1487                         else {
1488                                 if ((v = *b++ - *a++) != '\0')
1489                                         break;
1490                         }
1491                 }
1492         }
1493         return v;
1494 }
1495
1496 private uint64_t
1497 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1498 {
1499         /*
1500          * XXX - The 16-bit string compare probably needs to be done
1501          * differently, especially if the flags are to be supported.
1502          * At the moment, I am unsure.
1503          */
1504         flags = 0;
1505         return file_strncmp(a, b, len, flags);
1506 }
1507
1508 private int
1509 magiccheck(struct magic_set *ms, struct magic *m)
1510 {
1511         uint64_t l = m->value.q;
1512         uint64_t v;
1513         float fl, fv;
1514         double dl, dv;
1515         int matched;
1516         union VALUETYPE *p = &ms->ms_value;
1517
1518         switch (m->type) {
1519         case FILE_BYTE:
1520                 v = p->b;
1521                 break;
1522
1523         case FILE_SHORT:
1524         case FILE_BESHORT:
1525         case FILE_LESHORT:
1526                 v = p->h;
1527                 break;
1528
1529         case FILE_LONG:
1530         case FILE_BELONG:
1531         case FILE_LELONG:
1532         case FILE_MELONG:
1533         case FILE_DATE:
1534         case FILE_BEDATE:
1535         case FILE_LEDATE:
1536         case FILE_MEDATE:
1537         case FILE_LDATE:
1538         case FILE_BELDATE:
1539         case FILE_LELDATE:
1540         case FILE_MELDATE:
1541                 v = p->l;
1542                 break;
1543
1544         case FILE_QUAD:
1545         case FILE_LEQUAD:
1546         case FILE_BEQUAD:
1547         case FILE_QDATE:
1548         case FILE_BEQDATE:
1549         case FILE_LEQDATE:
1550         case FILE_QLDATE:
1551         case FILE_BEQLDATE:
1552         case FILE_LEQLDATE:
1553                 v = p->q;
1554                 break;
1555
1556         case FILE_FLOAT:
1557         case FILE_BEFLOAT:
1558         case FILE_LEFLOAT:
1559                 fl = m->value.f;
1560                 fv = p->f;
1561                 switch (m->reln) {
1562                 case 'x':
1563                         matched = 1;
1564                         break;
1565         
1566                 case '!':
1567                         matched = fv != fl;
1568                         break;
1569         
1570                 case '=':
1571                         matched = fv == fl;
1572                         break;
1573         
1574                 case '>':
1575                         matched = fv > fl;
1576                         break;
1577         
1578                 case '<':
1579                         matched = fv < fl;
1580                         break;
1581         
1582                 default:
1583                         matched = 0;
1584                         file_magerror(ms, "cannot happen with float: invalid relation `%c'", m->reln);
1585                         return -1;
1586                 }
1587                 return matched;
1588
1589         case FILE_DOUBLE:
1590         case FILE_BEDOUBLE:
1591         case FILE_LEDOUBLE:
1592                 dl = m->value.d;
1593                 dv = p->d;
1594                 switch (m->reln) {
1595                 case 'x':
1596                         matched = 1;
1597                         break;
1598         
1599                 case '!':
1600                         matched = dv != dl;
1601                         break;
1602         
1603                 case '=':
1604                         matched = dv == dl;
1605                         break;
1606         
1607                 case '>':
1608                         matched = dv > dl;
1609                         break;
1610         
1611                 case '<':
1612                         matched = dv < dl;
1613                         break;
1614         
1615                 default:
1616                         matched = 0;
1617                         file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1618                         return -1;
1619                 }
1620                 return matched;
1621
1622         case FILE_DEFAULT:
1623                 l = 0;
1624                 v = 0;
1625                 break;
1626
1627         case FILE_STRING:
1628         case FILE_PSTRING:
1629                 l = 0;
1630                 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1631                 break;
1632
1633         case FILE_BESTRING16:
1634         case FILE_LESTRING16:
1635                 l = 0;
1636                 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1637                 break;
1638
1639         case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1640                 size_t slen;
1641                 size_t idx;
1642
1643                 if (ms->search.s == NULL)
1644                         return 0;
1645
1646                 slen = MIN(m->vallen, sizeof(m->value.s));
1647                 l = 0;
1648                 v = 0;
1649                 ms->search.offset = m->offset;
1650
1651                 for (idx = 0; m->str_count == 0 || idx < m->str_count; idx++) {
1652                         if (slen + idx > ms->search.s_len)
1653                                 break;
1654
1655                         v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags);
1656                         if (v == 0) {   /* found match */
1657                                 ms->search.offset = m->offset + idx;
1658                                 break;
1659                         }
1660                 }
1661                 break;
1662         }
1663         case FILE_REGEX: {
1664                 int rc;
1665                 regex_t rx;
1666                 char errmsg[512];
1667
1668                 if (ms->search.s == NULL)
1669                         return 0;
1670
1671                 l = 0;
1672                 rc = regcomp(&rx, m->value.s,
1673                     REG_EXTENDED|REG_NEWLINE|
1674                     ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
1675                 if (rc) {
1676                         (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
1677                         file_magerror(ms, "regex error %d, (%s)",
1678                             rc, errmsg);
1679                         v = (uint64_t)-1;
1680                 }
1681                 else {
1682                         regmatch_t pmatch[1];
1683 #ifndef REG_STARTEND
1684 #define REG_STARTEND    0
1685                         size_t l = ms->search.s_len - 1;
1686                         char c = ms->search.s[l];
1687                         ((char *)(intptr_t)ms->search.s)[l] = '\0';
1688 #else
1689                         pmatch[0].rm_so = 0;
1690                         pmatch[0].rm_eo = ms->search.s_len;
1691 #endif
1692                         rc = regexec(&rx, (const char *)ms->search.s,
1693                             1, pmatch, REG_STARTEND);
1694 #if REG_STARTEND == 0
1695                         ((char *)(intptr_t)ms->search.s)[l] = c;
1696 #endif
1697                         switch (rc) {
1698                         case 0:
1699                                 ms->search.s += (int)pmatch[0].rm_so;
1700                                 ms->search.offset += (size_t)pmatch[0].rm_so;
1701                                 ms->search.rm_len =
1702                                     (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so);
1703                                 v = 0;
1704                                 break;
1705
1706                         case REG_NOMATCH:
1707                                 v = 1;
1708                                 break;
1709
1710                         default:
1711                                 (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
1712                                 file_magerror(ms, "regexec error %d, (%s)",
1713                                     rc, errmsg);
1714                                 v = (uint64_t)-1;
1715                                 break;
1716                         }
1717                         regfree(&rx);
1718                 }
1719                 if (v == (uint64_t)-1)
1720                         return -1;
1721                 break;
1722         }
1723         default:
1724                 file_magerror(ms, "invalid type %d in magiccheck()", m->type);
1725                 return -1;
1726         }
1727
1728         v = file_signextend(ms, m, v);
1729
1730         switch (m->reln) {
1731         case 'x':
1732                 if ((ms->flags & MAGIC_DEBUG) != 0)
1733                         (void) fprintf(stderr, "%llu == *any* = 1\n",
1734                             (unsigned long long)v);
1735                 matched = 1;
1736                 break;
1737
1738         case '!':
1739                 matched = v != l;
1740                 if ((ms->flags & MAGIC_DEBUG) != 0)
1741                         (void) fprintf(stderr, "%llu != %llu = %d\n",
1742                             (unsigned long long)v, (unsigned long long)l,
1743                             matched);
1744                 break;
1745
1746         case '=':
1747                 matched = v == l;
1748                 if ((ms->flags & MAGIC_DEBUG) != 0)
1749                         (void) fprintf(stderr, "%llu == %llu = %d\n",
1750                             (unsigned long long)v, (unsigned long long)l,
1751                             matched);
1752                 break;
1753
1754         case '>':
1755                 if (m->flag & UNSIGNED) {
1756                         matched = v > l;
1757                         if ((ms->flags & MAGIC_DEBUG) != 0)
1758                                 (void) fprintf(stderr, "%llu > %llu = %d\n",
1759                                     (unsigned long long)v,
1760                                     (unsigned long long)l, matched);
1761                 }
1762                 else {
1763                         matched = (int64_t) v > (int64_t) l;
1764                         if ((ms->flags & MAGIC_DEBUG) != 0)
1765                                 (void) fprintf(stderr, "%lld > %lld = %d\n",
1766                                     (long long)v, (long long)l, matched);
1767                 }
1768                 break;
1769
1770         case '<':
1771                 if (m->flag & UNSIGNED) {
1772                         matched = v < l;
1773                         if ((ms->flags & MAGIC_DEBUG) != 0)
1774                                 (void) fprintf(stderr, "%llu < %llu = %d\n",
1775                                     (unsigned long long)v,
1776                                     (unsigned long long)l, matched);
1777                 }
1778                 else {
1779                         matched = (int64_t) v < (int64_t) l;
1780                         if ((ms->flags & MAGIC_DEBUG) != 0)
1781                                 (void) fprintf(stderr, "%lld < %lld = %d\n",
1782                                        (long long)v, (long long)l, matched);
1783                 }
1784                 break;
1785
1786         case '&':
1787                 matched = (v & l) == l;
1788                 if ((ms->flags & MAGIC_DEBUG) != 0)
1789                         (void) fprintf(stderr, "((%llx & %llx) == %llx) = %d\n",
1790                             (unsigned long long)v, (unsigned long long)l,
1791                             (unsigned long long)l, matched);
1792                 break;
1793
1794         case '^':
1795                 matched = (v & l) != l;
1796                 if ((ms->flags & MAGIC_DEBUG) != 0)
1797                         (void) fprintf(stderr, "((%llx & %llx) != %llx) = %d\n",
1798                             (unsigned long long)v, (unsigned long long)l,
1799                             (unsigned long long)l, matched);
1800                 break;
1801
1802         default:
1803                 matched = 0;
1804                 file_magerror(ms, "cannot happen: invalid relation `%c'",
1805                     m->reln);
1806                 return -1;
1807         }
1808
1809         return matched;
1810 }
1811
1812 private int
1813 print_sep(struct magic_set *ms, int firstline)
1814 {
1815         if (firstline)
1816                 return 0;
1817         /*
1818          * we found another match 
1819          * put a newline and '-' to do some simple formatting
1820          */
1821         return file_printf(ms, "\n- ");
1822 }