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