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