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