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