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