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