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