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