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