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