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