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