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