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