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