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