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