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