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