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