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