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