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