Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / file / dist / src / softmagic.c
blob982b54dbb6547c76f34c404ca98cf2944b372ba3
1 /* $NetBSD: softmagic.c,v 1.1.1.1 2009/05/08 16:35:06 christos Exp $ */
3 /*
4 * Copyright (c) Ian F. Darwin 1986-1995.
5 * Software written by Ian F. Darwin and others;
6 * maintained 1995-present by Christos Zoulas and others.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice immediately at the beginning of the file, without modification,
13 * this list of conditions, and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
31 * softmagic - interpret variable magic from MAGIC
34 #include "file.h"
36 #ifndef lint
37 #if 0
38 FILE_RCSID("@(#)$File: softmagic.c,v 1.135 2009/03/27 22:42:49 christos Exp $")
39 #else
40 __RCSID("$NetBSD: softmagic.c,v 1.1.1.1 2009/05/08 16:35:06 christos Exp $");
41 #endif
42 #endif /* lint */
44 #include "magic.h"
45 #include <string.h>
46 #include <ctype.h>
47 #include <stdlib.h>
48 #include <time.h>
51 private int match(struct magic_set *, struct magic *, uint32_t,
52 const unsigned char *, size_t, int);
53 private int mget(struct magic_set *, const unsigned char *,
54 struct magic *, size_t, unsigned int);
55 private int magiccheck(struct magic_set *, struct magic *);
56 private int32_t mprint(struct magic_set *, struct magic *);
57 private int32_t moffset(struct magic_set *, struct magic *);
58 private void mdebug(uint32_t, const char *, size_t);
59 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
60 const unsigned char *, uint32_t, size_t, size_t);
61 private int mconvert(struct magic_set *, struct magic *);
62 private int print_sep(struct magic_set *, int);
63 private int handle_annotation(struct magic_set *, struct magic *);
64 private void cvt_8(union VALUETYPE *, const struct magic *);
65 private void cvt_16(union VALUETYPE *, const struct magic *);
66 private void cvt_32(union VALUETYPE *, const struct magic *);
67 private void cvt_64(union VALUETYPE *, const struct magic *);
70 * softmagic - lookup one file in parsed, in-memory copy of database
71 * Passed the name and FILE * of one file to be typed.
73 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
74 protected int
75 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, int mode)
77 struct mlist *ml;
78 int rv;
79 for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next)
80 if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, mode)) != 0)
81 return rv;
83 return 0;
87 * Go through the whole list, stopping if you find a match. Process all
88 * the continuations of that match before returning.
90 * We support multi-level continuations:
92 * At any time when processing a successful top-level match, there is a
93 * current continuation level; it represents the level of the last
94 * successfully matched continuation.
96 * Continuations above that level are skipped as, if we see one, it
97 * means that the continuation that controls them - i.e, the
98 * lower-level continuation preceding them - failed to match.
100 * Continuations below that level are processed as, if we see one,
101 * it means we've finished processing or skipping higher-level
102 * continuations under the control of a successful or unsuccessful
103 * lower-level continuation, and are now seeing the next lower-level
104 * continuation and should process it. The current continuation
105 * level reverts to the level of the one we're seeing.
107 * Continuations at the current level are processed as, if we see
108 * one, there's no lower-level continuation that may have failed.
110 * If a continuation matches, we bump the current continuation level
111 * so that higher-level continuations are processed.
113 private int
114 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
115 const unsigned char *s, size_t nbytes, int mode)
117 uint32_t magindex = 0;
118 unsigned int cont_level = 0;
119 int need_separator = 0;
120 int returnval = 0, e; /* if a match is found it is set to 1*/
121 int firstline = 1; /* a flag to print X\n X\n- X */
122 int printed_something = 0;
123 int print = (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0;
125 if (file_check_mem(ms, cont_level) == -1)
126 return -1;
128 for (magindex = 0; magindex < nmagic; magindex++) {
129 int flush = 0;
130 struct magic *m = &magic[magindex];
132 if ((m->flag & BINTEST) != mode) {
133 /* Skip sub-tests */
134 while (magic[magindex + 1].cont_level != 0 &&
135 ++magindex < nmagic)
136 continue;
137 continue; /* Skip to next top-level test*/
140 ms->offset = m->offset;
141 ms->line = m->lineno;
143 /* if main entry matches, print it... */
144 switch (mget(ms, s, m, nbytes, cont_level)) {
145 case -1:
146 return -1;
147 case 0:
148 flush = m->reln != '!';
149 break;
150 default:
151 if (m->type == FILE_INDIRECT)
152 returnval = 1;
154 switch (magiccheck(ms, m)) {
155 case -1:
156 return -1;
157 case 0:
158 flush++;
159 break;
160 default:
161 flush = 0;
162 break;
164 break;
166 if (flush) {
168 * main entry didn't match,
169 * flush its continuations
171 while (magindex < nmagic - 1 &&
172 magic[magindex + 1].cont_level != 0)
173 magindex++;
174 continue;
178 * If we are going to print something, we'll need to print
179 * a blank before we print something else.
181 if (*m->desc) {
182 need_separator = 1;
183 printed_something = 1;
184 if ((e = handle_annotation(ms, m)) != 0)
185 return e;
186 if (print_sep(ms, firstline) == -1)
187 return -1;
191 if (print && mprint(ms, m) == -1)
192 return -1;
194 ms->c.li[cont_level].off = moffset(ms, m);
196 /* and any continuations that match */
197 if (file_check_mem(ms, ++cont_level) == -1)
198 return -1;
200 while (magic[magindex+1].cont_level != 0 &&
201 ++magindex < nmagic) {
202 m = &magic[magindex];
203 ms->line = m->lineno; /* for messages */
205 if (cont_level < m->cont_level)
206 continue;
207 if (cont_level > m->cont_level) {
209 * We're at the end of the level
210 * "cont_level" continuations.
212 cont_level = m->cont_level;
214 ms->offset = m->offset;
215 if (m->flag & OFFADD) {
216 ms->offset +=
217 ms->c.li[cont_level - 1].off;
220 #ifdef ENABLE_CONDITIONALS
221 if (m->cond == COND_ELSE ||
222 m->cond == COND_ELIF) {
223 if (ms->c.li[cont_level].last_match == 1)
224 continue;
226 #endif
227 switch (mget(ms, s, m, nbytes, cont_level)) {
228 case -1:
229 return -1;
230 case 0:
231 if (m->reln != '!')
232 continue;
233 flush = 1;
234 break;
235 default:
236 if (m->type == FILE_INDIRECT)
237 returnval = 1;
238 flush = 0;
239 break;
242 switch (flush ? 1 : magiccheck(ms, m)) {
243 case -1:
244 return -1;
245 case 0:
246 #ifdef ENABLE_CONDITIONALS
247 ms->c.li[cont_level].last_match = 0;
248 #endif
249 break;
250 default:
251 #ifdef ENABLE_CONDITIONALS
252 ms->c.li[cont_level].last_match = 1;
253 #endif
254 if (m->type != FILE_DEFAULT)
255 ms->c.li[cont_level].got_match = 1;
256 else if (ms->c.li[cont_level].got_match) {
257 ms->c.li[cont_level].got_match = 0;
258 break;
261 * If we are going to print something,
262 * make sure that we have a separator first.
264 if (*m->desc) {
265 if ((e = handle_annotation(ms, m)) != 0)
266 return e;
267 if (!printed_something) {
268 printed_something = 1;
269 if (print_sep(ms, firstline)
270 == -1)
271 return -1;
275 * This continuation matched. Print
276 * its message, with a blank before it
277 * if the previous item printed and
278 * this item isn't empty.
280 /* space if previous printed */
281 if (need_separator
282 && ((m->flag & NOSPACE) == 0)
283 && *m->desc) {
284 if (print &&
285 file_printf(ms, " ") == -1)
286 return -1;
287 need_separator = 0;
289 if (print && mprint(ms, m) == -1)
290 return -1;
292 ms->c.li[cont_level].off = moffset(ms, m);
294 if (*m->desc)
295 need_separator = 1;
298 * If we see any continuations
299 * at a higher level,
300 * process them.
302 if (file_check_mem(ms, ++cont_level) == -1)
303 return -1;
304 break;
307 if (printed_something) {
308 firstline = 0;
309 if (print)
310 returnval = 1;
312 if ((ms->flags & MAGIC_CONTINUE) == 0 && printed_something) {
313 return returnval; /* don't keep searching */
316 return returnval; /* This is hit if -k is set or there is no match */
319 private int
320 check_fmt(struct magic_set *ms, struct magic *m)
322 regex_t rx;
323 int rc;
325 if (strchr(m->desc, '%') == NULL)
326 return 0;
328 rc = regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
329 if (rc) {
330 char errmsg[512];
331 (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
332 file_magerror(ms, "regex error %d, (%s)", rc, errmsg);
333 return -1;
334 } else {
335 rc = regexec(&rx, m->desc, 0, 0, 0);
336 regfree(&rx);
337 return !rc;
341 #ifndef HAVE_STRNDUP
342 char * strndup(const char *, size_t);
344 char *
345 strndup(const char *str, size_t n)
347 size_t len;
348 char *copy;
350 for (len = 0; len < n && str[len]; len++)
351 continue;
352 if ((copy = malloc(len + 1)) == NULL)
353 return NULL;
354 (void)memcpy(copy, str, len);
355 copy[len] = '\0';
356 return copy;
358 #endif /* HAVE_STRNDUP */
360 private int32_t
361 mprint(struct magic_set *ms, struct magic *m)
363 uint64_t v;
364 float vf;
365 double vd;
366 int64_t t = 0;
367 char buf[128];
368 union VALUETYPE *p = &ms->ms_value;
370 switch (m->type) {
371 case FILE_BYTE:
372 v = file_signextend(ms, m, (uint64_t)p->b);
373 switch (check_fmt(ms, m)) {
374 case -1:
375 return -1;
376 case 1:
377 (void)snprintf(buf, sizeof(buf), "%c",
378 (unsigned char)v);
379 if (file_printf(ms, m->desc, buf) == -1)
380 return -1;
381 break;
382 default:
383 if (file_printf(ms, m->desc, (unsigned char) v) == -1)
384 return -1;
385 break;
387 t = ms->offset + sizeof(char);
388 break;
390 case FILE_SHORT:
391 case FILE_BESHORT:
392 case FILE_LESHORT:
393 v = file_signextend(ms, m, (uint64_t)p->h);
394 switch (check_fmt(ms, m)) {
395 case -1:
396 return -1;
397 case 1:
398 (void)snprintf(buf, sizeof(buf), "%hu",
399 (unsigned short)v);
400 if (file_printf(ms, m->desc, buf) == -1)
401 return -1;
402 break;
403 default:
404 if (
405 file_printf(ms, m->desc, (unsigned short) v) == -1)
406 return -1;
407 break;
409 t = ms->offset + sizeof(short);
410 break;
412 case FILE_LONG:
413 case FILE_BELONG:
414 case FILE_LELONG:
415 case FILE_MELONG:
416 v = file_signextend(ms, m, (uint64_t)p->l);
417 switch (check_fmt(ms, m)) {
418 case -1:
419 return -1;
420 case 1:
421 (void)snprintf(buf, sizeof(buf), "%u", (uint32_t)v);
422 if (file_printf(ms, m->desc, buf) == -1)
423 return -1;
424 break;
425 default:
426 if (file_printf(ms, m->desc, (uint32_t) v) == -1)
427 return -1;
428 break;
430 t = ms->offset + sizeof(int32_t);
431 break;
433 case FILE_QUAD:
434 case FILE_BEQUAD:
435 case FILE_LEQUAD:
436 v = file_signextend(ms, m, p->q);
437 if (file_printf(ms, m->desc, (uint64_t) v) == -1)
438 return -1;
439 t = ms->offset + sizeof(int64_t);
440 break;
442 case FILE_STRING:
443 case FILE_PSTRING:
444 case FILE_BESTRING16:
445 case FILE_LESTRING16:
446 if (m->reln == '=' || m->reln == '!') {
447 if (file_printf(ms, m->desc, m->value.s) == -1)
448 return -1;
449 t = ms->offset + m->vallen;
451 else {
452 if (*m->value.s == '\0')
453 p->s[strcspn(p->s, "\n")] = '\0';
454 if (file_printf(ms, m->desc, p->s) == -1)
455 return -1;
456 t = ms->offset + strlen(p->s);
457 if (m->type == FILE_PSTRING)
458 t++;
460 break;
462 case FILE_DATE:
463 case FILE_BEDATE:
464 case FILE_LEDATE:
465 case FILE_MEDATE:
466 if (file_printf(ms, m->desc, file_fmttime(p->l, 1)) == -1)
467 return -1;
468 t = ms->offset + sizeof(time_t);
469 break;
471 case FILE_LDATE:
472 case FILE_BELDATE:
473 case FILE_LELDATE:
474 case FILE_MELDATE:
475 if (file_printf(ms, m->desc, file_fmttime(p->l, 0)) == -1)
476 return -1;
477 t = ms->offset + sizeof(time_t);
478 break;
480 case FILE_QDATE:
481 case FILE_BEQDATE:
482 case FILE_LEQDATE:
483 if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q,
484 1)) == -1)
485 return -1;
486 t = ms->offset + sizeof(uint64_t);
487 break;
489 case FILE_QLDATE:
490 case FILE_BEQLDATE:
491 case FILE_LEQLDATE:
492 if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q,
493 0)) == -1)
494 return -1;
495 t = ms->offset + sizeof(uint64_t);
496 break;
498 case FILE_FLOAT:
499 case FILE_BEFLOAT:
500 case FILE_LEFLOAT:
501 vf = p->f;
502 switch (check_fmt(ms, m)) {
503 case -1:
504 return -1;
505 case 1:
506 (void)snprintf(buf, sizeof(buf), "%g", vf);
507 if (file_printf(ms, m->desc, buf) == -1)
508 return -1;
509 break;
510 default:
511 if (file_printf(ms, m->desc, vf) == -1)
512 return -1;
513 break;
515 t = ms->offset + sizeof(float);
516 break;
518 case FILE_DOUBLE:
519 case FILE_BEDOUBLE:
520 case FILE_LEDOUBLE:
521 vd = p->d;
522 switch (check_fmt(ms, m)) {
523 case -1:
524 return -1;
525 case 1:
526 (void)snprintf(buf, sizeof(buf), "%g", vd);
527 if (file_printf(ms, m->desc, buf) == -1)
528 return -1;
529 break;
530 default:
531 if (file_printf(ms, m->desc, vd) == -1)
532 return -1;
533 break;
535 t = ms->offset + sizeof(double);
536 break;
538 case FILE_REGEX: {
539 char *cp;
540 int rval;
542 cp = strndup((const char *)ms->search.s, ms->search.rm_len);
543 if (cp == NULL) {
544 file_oomem(ms, ms->search.rm_len);
545 return -1;
547 rval = file_printf(ms, m->desc, cp);
548 free(cp);
550 if (rval == -1)
551 return -1;
553 if ((m->str_flags & REGEX_OFFSET_START))
554 t = ms->search.offset;
555 else
556 t = ms->search.offset + ms->search.rm_len;
557 break;
560 case FILE_SEARCH:
561 if (file_printf(ms, m->desc, m->value.s) == -1)
562 return -1;
563 if ((m->str_flags & REGEX_OFFSET_START))
564 t = ms->search.offset;
565 else
566 t = ms->search.offset + m->vallen;
567 break;
569 case FILE_DEFAULT:
570 if (file_printf(ms, m->desc, m->value.s) == -1)
571 return -1;
572 t = ms->offset;
573 break;
575 case FILE_INDIRECT:
576 t = ms->offset;
577 break;
579 default:
580 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
581 return -1;
583 return (int32_t)t;
586 private int32_t
587 moffset(struct magic_set *ms, struct magic *m)
589 switch (m->type) {
590 case FILE_BYTE:
591 return CAST(int32_t, (ms->offset + sizeof(char)));
593 case FILE_SHORT:
594 case FILE_BESHORT:
595 case FILE_LESHORT:
596 return CAST(int32_t, (ms->offset + sizeof(short)));
598 case FILE_LONG:
599 case FILE_BELONG:
600 case FILE_LELONG:
601 case FILE_MELONG:
602 return CAST(int32_t, (ms->offset + sizeof(int32_t)));
604 case FILE_QUAD:
605 case FILE_BEQUAD:
606 case FILE_LEQUAD:
607 return CAST(int32_t, (ms->offset + sizeof(int64_t)));
609 case FILE_STRING:
610 case FILE_PSTRING:
611 case FILE_BESTRING16:
612 case FILE_LESTRING16:
613 if (m->reln == '=' || m->reln == '!')
614 return ms->offset + m->vallen;
615 else {
616 union VALUETYPE *p = &ms->ms_value;
617 uint32_t t;
619 if (*m->value.s == '\0')
620 p->s[strcspn(p->s, "\n")] = '\0';
621 t = CAST(uint32_t, (ms->offset + strlen(p->s)));
622 if (m->type == FILE_PSTRING)
623 t++;
624 return t;
627 case FILE_DATE:
628 case FILE_BEDATE:
629 case FILE_LEDATE:
630 case FILE_MEDATE:
631 return CAST(int32_t, (ms->offset + sizeof(time_t)));
633 case FILE_LDATE:
634 case FILE_BELDATE:
635 case FILE_LELDATE:
636 case FILE_MELDATE:
637 return CAST(int32_t, (ms->offset + sizeof(time_t)));
639 case FILE_QDATE:
640 case FILE_BEQDATE:
641 case FILE_LEQDATE:
642 return CAST(int32_t, (ms->offset + sizeof(uint64_t)));
644 case FILE_QLDATE:
645 case FILE_BEQLDATE:
646 case FILE_LEQLDATE:
647 return CAST(int32_t, (ms->offset + sizeof(uint64_t)));
649 case FILE_FLOAT:
650 case FILE_BEFLOAT:
651 case FILE_LEFLOAT:
652 return CAST(int32_t, (ms->offset + sizeof(float)));
654 case FILE_DOUBLE:
655 case FILE_BEDOUBLE:
656 case FILE_LEDOUBLE:
657 return CAST(int32_t, (ms->offset + sizeof(double)));
659 case FILE_REGEX:
660 if ((m->str_flags & REGEX_OFFSET_START) != 0)
661 return CAST(int32_t, ms->search.offset);
662 else
663 return CAST(int32_t, (ms->search.offset +
664 ms->search.rm_len));
666 case FILE_SEARCH:
667 if ((m->str_flags & REGEX_OFFSET_START) != 0)
668 return CAST(int32_t, ms->search.offset);
669 else
670 return CAST(int32_t, (ms->search.offset + m->vallen));
672 case FILE_DEFAULT:
673 return ms->offset;
675 case FILE_INDIRECT:
676 return ms->offset;
678 default:
679 return 0;
683 #define DO_CVT(fld, cast) \
684 if (m->num_mask) \
685 switch (m->mask_op & FILE_OPS_MASK) { \
686 case FILE_OPAND: \
687 p->fld &= cast m->num_mask; \
688 break; \
689 case FILE_OPOR: \
690 p->fld |= cast m->num_mask; \
691 break; \
692 case FILE_OPXOR: \
693 p->fld ^= cast m->num_mask; \
694 break; \
695 case FILE_OPADD: \
696 p->fld += cast m->num_mask; \
697 break; \
698 case FILE_OPMINUS: \
699 p->fld -= cast m->num_mask; \
700 break; \
701 case FILE_OPMULTIPLY: \
702 p->fld *= cast m->num_mask; \
703 break; \
704 case FILE_OPDIVIDE: \
705 p->fld /= cast m->num_mask; \
706 break; \
707 case FILE_OPMODULO: \
708 p->fld %= cast m->num_mask; \
709 break; \
711 if (m->mask_op & FILE_OPINVERSE) \
712 p->fld = ~p->fld \
714 private void
715 cvt_8(union VALUETYPE *p, const struct magic *m)
717 DO_CVT(b, (uint8_t));
720 private void
721 cvt_16(union VALUETYPE *p, const struct magic *m)
723 DO_CVT(h, (uint16_t));
726 private void
727 cvt_32(union VALUETYPE *p, const struct magic *m)
729 DO_CVT(l, (uint32_t));
732 private void
733 cvt_64(union VALUETYPE *p, const struct magic *m)
735 DO_CVT(q, (uint64_t));
738 #define DO_CVT2(fld, cast) \
739 if (m->num_mask) \
740 switch (m->mask_op & FILE_OPS_MASK) { \
741 case FILE_OPADD: \
742 p->fld += cast m->num_mask; \
743 break; \
744 case FILE_OPMINUS: \
745 p->fld -= cast m->num_mask; \
746 break; \
747 case FILE_OPMULTIPLY: \
748 p->fld *= cast m->num_mask; \
749 break; \
750 case FILE_OPDIVIDE: \
751 p->fld /= cast m->num_mask; \
752 break; \
755 private void
756 cvt_float(union VALUETYPE *p, const struct magic *m)
758 DO_CVT2(f, (float));
761 private void
762 cvt_double(union VALUETYPE *p, const struct magic *m)
764 DO_CVT2(d, (double));
768 * Convert the byte order of the data we are looking at
769 * While we're here, let's apply the mask operation
770 * (unless you have a better idea)
772 private int
773 mconvert(struct magic_set *ms, struct magic *m)
775 union VALUETYPE *p = &ms->ms_value;
777 switch (m->type) {
778 case FILE_BYTE:
779 cvt_8(p, m);
780 return 1;
781 case FILE_SHORT:
782 cvt_16(p, m);
783 return 1;
784 case FILE_LONG:
785 case FILE_DATE:
786 case FILE_LDATE:
787 cvt_32(p, m);
788 return 1;
789 case FILE_QUAD:
790 case FILE_QDATE:
791 case FILE_QLDATE:
792 cvt_64(p, m);
793 return 1;
794 case FILE_STRING:
795 case FILE_BESTRING16:
796 case FILE_LESTRING16: {
797 /* Null terminate and eat *trailing* return */
798 p->s[sizeof(p->s) - 1] = '\0';
799 #if 0
800 /* Why? breaks magic numbers that end with \xa */
801 len = strlen(p->s);
802 if (len-- && p->s[len] == '\n')
803 p->s[len] = '\0';
804 #endif
805 return 1;
807 case FILE_PSTRING: {
808 char *ptr1 = p->s, *ptr2 = ptr1 + 1;
809 size_t len = *p->s;
810 if (len >= sizeof(p->s))
811 len = sizeof(p->s) - 1;
812 while (len--)
813 *ptr1++ = *ptr2++;
814 *ptr1 = '\0';
815 #if 0
816 /* Why? breaks magic numbers that end with \xa */
817 len = strlen(p->s);
818 if (len-- && p->s[len] == '\n')
819 p->s[len] = '\0';
820 #endif
821 return 1;
823 case FILE_BESHORT:
824 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
825 cvt_16(p, m);
826 return 1;
827 case FILE_BELONG:
828 case FILE_BEDATE:
829 case FILE_BELDATE:
830 p->l = (int32_t)
831 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
832 cvt_32(p, m);
833 return 1;
834 case FILE_BEQUAD:
835 case FILE_BEQDATE:
836 case FILE_BEQLDATE:
837 p->q = (uint64_t)
838 (((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
839 ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
840 ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
841 ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7]));
842 cvt_64(p, m);
843 return 1;
844 case FILE_LESHORT:
845 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
846 cvt_16(p, m);
847 return 1;
848 case FILE_LELONG:
849 case FILE_LEDATE:
850 case FILE_LELDATE:
851 p->l = (int32_t)
852 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
853 cvt_32(p, m);
854 return 1;
855 case FILE_LEQUAD:
856 case FILE_LEQDATE:
857 case FILE_LEQLDATE:
858 p->q = (uint64_t)
859 (((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
860 ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
861 ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
862 ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0]));
863 cvt_64(p, m);
864 return 1;
865 case FILE_MELONG:
866 case FILE_MEDATE:
867 case FILE_MELDATE:
868 p->l = (int32_t)
869 ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2]));
870 cvt_32(p, m);
871 return 1;
872 case FILE_FLOAT:
873 cvt_float(p, m);
874 return 1;
875 case FILE_BEFLOAT:
876 p->l = ((uint32_t)p->hl[0]<<24)|((uint32_t)p->hl[1]<<16)|
877 ((uint32_t)p->hl[2]<<8) |((uint32_t)p->hl[3]);
878 cvt_float(p, m);
879 return 1;
880 case FILE_LEFLOAT:
881 p->l = ((uint32_t)p->hl[3]<<24)|((uint32_t)p->hl[2]<<16)|
882 ((uint32_t)p->hl[1]<<8) |((uint32_t)p->hl[0]);
883 cvt_float(p, m);
884 return 1;
885 case FILE_DOUBLE:
886 cvt_double(p, m);
887 return 1;
888 case FILE_BEDOUBLE:
889 p->q = ((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
890 ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
891 ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
892 ((uint64_t)p->hq[6]<<8) |((uint64_t)p->hq[7]);
893 cvt_double(p, m);
894 return 1;
895 case FILE_LEDOUBLE:
896 p->q = ((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
897 ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
898 ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
899 ((uint64_t)p->hq[1]<<8) |((uint64_t)p->hq[0]);
900 cvt_double(p, m);
901 return 1;
902 case FILE_REGEX:
903 case FILE_SEARCH:
904 case FILE_DEFAULT:
905 return 1;
906 default:
907 file_magerror(ms, "invalid type %d in mconvert()", m->type);
908 return 0;
913 private void
914 mdebug(uint32_t offset, const char *str, size_t len)
916 (void) fprintf(stderr, "mget @%d: ", offset);
917 file_showstr(stderr, str, len);
918 (void) fputc('\n', stderr);
919 (void) fputc('\n', stderr);
922 private int
923 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
924 const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
927 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
928 * anything, but setup pointers into the source
930 if (indir == 0) {
931 switch (type) {
932 case FILE_SEARCH:
933 ms->search.s = CAST(const char *, s) + offset;
934 ms->search.s_len = nbytes - offset;
935 ms->search.offset = offset;
936 return 0;
938 case FILE_REGEX: {
939 const char *b;
940 const char *c;
941 const char *last; /* end of search region */
942 const char *buf; /* start of search region */
943 const char *end;
944 size_t lines;
946 if (s == NULL) {
947 ms->search.s_len = 0;
948 ms->search.s = NULL;
949 return 0;
951 buf = CAST(const char *, s) + offset;
952 end = last = CAST(const char *, s) + nbytes;
953 /* mget() guarantees buf <= last */
954 for (lines = linecnt, b = buf; lines &&
955 ((b = memchr(c = b, '\n', CAST(size_t, (end - b))))
956 || (b = memchr(c, '\r', CAST(size_t, (end - c)))));
957 lines--, b++) {
958 last = b;
959 if (b[0] == '\r' && b[1] == '\n')
960 b++;
962 if (lines)
963 last = CAST(const char *, s) + nbytes;
965 ms->search.s = buf;
966 ms->search.s_len = last - buf;
967 ms->search.offset = offset;
968 ms->search.rm_len = 0;
969 return 0;
971 case FILE_BESTRING16:
972 case FILE_LESTRING16: {
973 const unsigned char *src = s + offset;
974 const unsigned char *esrc = s + nbytes;
975 char *dst = p->s;
976 char *edst = &p->s[sizeof(p->s) - 1];
978 if (type == FILE_BESTRING16)
979 src++;
981 /* check for pointer overflow */
982 if (src < s) {
983 file_magerror(ms, "invalid offset %u in mcopy()",
984 offset);
985 return -1;
987 for (/*EMPTY*/; src < esrc; src += 2, dst++) {
988 if (dst < edst)
989 *dst = *src;
990 else
991 break;
992 if (*dst == '\0') {
993 if (type == FILE_BESTRING16 ?
994 *(src - 1) != '\0' :
995 *(src + 1) != '\0')
996 *dst = ' ';
999 *edst = '\0';
1000 return 0;
1002 case FILE_STRING: /* XXX - these two should not need */
1003 case FILE_PSTRING: /* to copy anything, but do anyway. */
1004 default:
1005 break;
1009 if (offset >= nbytes) {
1010 (void)memset(p, '\0', sizeof(*p));
1011 return 0;
1013 if (nbytes - offset < sizeof(*p))
1014 nbytes = nbytes - offset;
1015 else
1016 nbytes = sizeof(*p);
1018 (void)memcpy(p, s + offset, nbytes);
1021 * the usefulness of padding with zeroes eludes me, it
1022 * might even cause problems
1024 if (nbytes < sizeof(*p))
1025 (void)memset(((char *)(void *)p) + nbytes, '\0',
1026 sizeof(*p) - nbytes);
1027 return 0;
1030 private int
1031 mget(struct magic_set *ms, const unsigned char *s,
1032 struct magic *m, size_t nbytes, unsigned int cont_level)
1034 uint32_t offset = ms->offset;
1035 uint32_t count = m->str_range;
1036 union VALUETYPE *p = &ms->ms_value;
1038 if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1)
1039 return -1;
1041 if ((ms->flags & MAGIC_DEBUG) != 0) {
1042 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1043 #ifndef COMPILE_ONLY
1044 file_mdump(m);
1045 #endif
1048 if (m->flag & INDIR) {
1049 int off = m->in_offset;
1050 if (m->in_op & FILE_OPINDIRECT) {
1051 const union VALUETYPE *q = CAST(const union VALUETYPE *,
1052 ((const void *)(s + offset + off)));
1053 switch (m->in_type) {
1054 case FILE_BYTE:
1055 off = q->b;
1056 break;
1057 case FILE_SHORT:
1058 off = q->h;
1059 break;
1060 case FILE_BESHORT:
1061 off = (short)((q->hs[0]<<8)|(q->hs[1]));
1062 break;
1063 case FILE_LESHORT:
1064 off = (short)((q->hs[1]<<8)|(q->hs[0]));
1065 break;
1066 case FILE_LONG:
1067 off = q->l;
1068 break;
1069 case FILE_BELONG:
1070 case FILE_BEID3:
1071 off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
1072 (q->hl[2]<<8)|(q->hl[3]));
1073 break;
1074 case FILE_LEID3:
1075 case FILE_LELONG:
1076 off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
1077 (q->hl[1]<<8)|(q->hl[0]));
1078 break;
1079 case FILE_MELONG:
1080 off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
1081 (q->hl[3]<<8)|(q->hl[2]));
1082 break;
1085 switch (m->in_type) {
1086 case FILE_BYTE:
1087 if (nbytes < (offset + 1))
1088 return 0;
1089 if (off) {
1090 switch (m->in_op & FILE_OPS_MASK) {
1091 case FILE_OPAND:
1092 offset = p->b & off;
1093 break;
1094 case FILE_OPOR:
1095 offset = p->b | off;
1096 break;
1097 case FILE_OPXOR:
1098 offset = p->b ^ off;
1099 break;
1100 case FILE_OPADD:
1101 offset = p->b + off;
1102 break;
1103 case FILE_OPMINUS:
1104 offset = p->b - off;
1105 break;
1106 case FILE_OPMULTIPLY:
1107 offset = p->b * off;
1108 break;
1109 case FILE_OPDIVIDE:
1110 offset = p->b / off;
1111 break;
1112 case FILE_OPMODULO:
1113 offset = p->b % off;
1114 break;
1116 } else
1117 offset = p->b;
1118 if (m->in_op & FILE_OPINVERSE)
1119 offset = ~offset;
1120 break;
1121 case FILE_BESHORT:
1122 if (nbytes < (offset + 2))
1123 return 0;
1124 if (off) {
1125 switch (m->in_op & FILE_OPS_MASK) {
1126 case FILE_OPAND:
1127 offset = (short)((p->hs[0]<<8)|
1128 (p->hs[1])) &
1129 off;
1130 break;
1131 case FILE_OPOR:
1132 offset = (short)((p->hs[0]<<8)|
1133 (p->hs[1])) |
1134 off;
1135 break;
1136 case FILE_OPXOR:
1137 offset = (short)((p->hs[0]<<8)|
1138 (p->hs[1])) ^
1139 off;
1140 break;
1141 case FILE_OPADD:
1142 offset = (short)((p->hs[0]<<8)|
1143 (p->hs[1])) +
1144 off;
1145 break;
1146 case FILE_OPMINUS:
1147 offset = (short)((p->hs[0]<<8)|
1148 (p->hs[1])) -
1149 off;
1150 break;
1151 case FILE_OPMULTIPLY:
1152 offset = (short)((p->hs[0]<<8)|
1153 (p->hs[1])) *
1154 off;
1155 break;
1156 case FILE_OPDIVIDE:
1157 offset = (short)((p->hs[0]<<8)|
1158 (p->hs[1])) /
1159 off;
1160 break;
1161 case FILE_OPMODULO:
1162 offset = (short)((p->hs[0]<<8)|
1163 (p->hs[1])) %
1164 off;
1165 break;
1167 } else
1168 offset = (short)((p->hs[0]<<8)|
1169 (p->hs[1]));
1170 if (m->in_op & FILE_OPINVERSE)
1171 offset = ~offset;
1172 break;
1173 case FILE_LESHORT:
1174 if (nbytes < (offset + 2))
1175 return 0;
1176 if (off) {
1177 switch (m->in_op & FILE_OPS_MASK) {
1178 case FILE_OPAND:
1179 offset = (short)((p->hs[1]<<8)|
1180 (p->hs[0])) &
1181 off;
1182 break;
1183 case FILE_OPOR:
1184 offset = (short)((p->hs[1]<<8)|
1185 (p->hs[0])) |
1186 off;
1187 break;
1188 case FILE_OPXOR:
1189 offset = (short)((p->hs[1]<<8)|
1190 (p->hs[0])) ^
1191 off;
1192 break;
1193 case FILE_OPADD:
1194 offset = (short)((p->hs[1]<<8)|
1195 (p->hs[0])) +
1196 off;
1197 break;
1198 case FILE_OPMINUS:
1199 offset = (short)((p->hs[1]<<8)|
1200 (p->hs[0])) -
1201 off;
1202 break;
1203 case FILE_OPMULTIPLY:
1204 offset = (short)((p->hs[1]<<8)|
1205 (p->hs[0])) *
1206 off;
1207 break;
1208 case FILE_OPDIVIDE:
1209 offset = (short)((p->hs[1]<<8)|
1210 (p->hs[0])) /
1211 off;
1212 break;
1213 case FILE_OPMODULO:
1214 offset = (short)((p->hs[1]<<8)|
1215 (p->hs[0])) %
1216 off;
1217 break;
1219 } else
1220 offset = (short)((p->hs[1]<<8)|
1221 (p->hs[0]));
1222 if (m->in_op & FILE_OPINVERSE)
1223 offset = ~offset;
1224 break;
1225 case FILE_SHORT:
1226 if (nbytes < (offset + 2))
1227 return 0;
1228 if (off) {
1229 switch (m->in_op & FILE_OPS_MASK) {
1230 case FILE_OPAND:
1231 offset = p->h & off;
1232 break;
1233 case FILE_OPOR:
1234 offset = p->h | off;
1235 break;
1236 case FILE_OPXOR:
1237 offset = p->h ^ off;
1238 break;
1239 case FILE_OPADD:
1240 offset = p->h + off;
1241 break;
1242 case FILE_OPMINUS:
1243 offset = p->h - off;
1244 break;
1245 case FILE_OPMULTIPLY:
1246 offset = p->h * off;
1247 break;
1248 case FILE_OPDIVIDE:
1249 offset = p->h / off;
1250 break;
1251 case FILE_OPMODULO:
1252 offset = p->h % off;
1253 break;
1256 else
1257 offset = p->h;
1258 if (m->in_op & FILE_OPINVERSE)
1259 offset = ~offset;
1260 break;
1261 case FILE_BELONG:
1262 case FILE_BEID3:
1263 if (nbytes < (offset + 4))
1264 return 0;
1265 if (off) {
1266 switch (m->in_op & FILE_OPS_MASK) {
1267 case FILE_OPAND:
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_OPOR:
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_OPXOR:
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_OPADD:
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_OPMINUS:
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_OPMULTIPLY:
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_OPDIVIDE:
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;
1316 case FILE_OPMODULO:
1317 offset = (int32_t)((p->hl[0]<<24)|
1318 (p->hl[1]<<16)|
1319 (p->hl[2]<<8)|
1320 (p->hl[3])) %
1321 off;
1322 break;
1324 } else
1325 offset = (int32_t)((p->hl[0]<<24)|
1326 (p->hl[1]<<16)|
1327 (p->hl[2]<<8)|
1328 (p->hl[3]));
1329 if (m->in_op & FILE_OPINVERSE)
1330 offset = ~offset;
1331 break;
1332 case FILE_LELONG:
1333 case FILE_LEID3:
1334 if (nbytes < (offset + 4))
1335 return 0;
1336 if (off) {
1337 switch (m->in_op & FILE_OPS_MASK) {
1338 case FILE_OPAND:
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_OPOR:
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_OPXOR:
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_OPADD:
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_OPMINUS:
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_OPMULTIPLY:
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_OPDIVIDE:
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;
1387 case FILE_OPMODULO:
1388 offset = (int32_t)((p->hl[3]<<24)|
1389 (p->hl[2]<<16)|
1390 (p->hl[1]<<8)|
1391 (p->hl[0])) %
1392 off;
1393 break;
1395 } else
1396 offset = (int32_t)((p->hl[3]<<24)|
1397 (p->hl[2]<<16)|
1398 (p->hl[1]<<8)|
1399 (p->hl[0]));
1400 if (m->in_op & FILE_OPINVERSE)
1401 offset = ~offset;
1402 break;
1403 case FILE_MELONG:
1404 if (nbytes < (offset + 4))
1405 return 0;
1406 if (off) {
1407 switch (m->in_op & FILE_OPS_MASK) {
1408 case FILE_OPAND:
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_OPOR:
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_OPXOR:
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_OPADD:
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_OPMINUS:
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_OPMULTIPLY:
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_OPDIVIDE:
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;
1457 case FILE_OPMODULO:
1458 offset = (int32_t)((p->hl[1]<<24)|
1459 (p->hl[0]<<16)|
1460 (p->hl[3]<<8)|
1461 (p->hl[2])) %
1462 off;
1463 break;
1465 } else
1466 offset = (int32_t)((p->hl[1]<<24)|
1467 (p->hl[0]<<16)|
1468 (p->hl[3]<<8)|
1469 (p->hl[2]));
1470 if (m->in_op & FILE_OPINVERSE)
1471 offset = ~offset;
1472 break;
1473 case FILE_LONG:
1474 if (nbytes < (offset + 4))
1475 return 0;
1476 if (off) {
1477 switch (m->in_op & FILE_OPS_MASK) {
1478 case FILE_OPAND:
1479 offset = p->l & off;
1480 break;
1481 case FILE_OPOR:
1482 offset = p->l | off;
1483 break;
1484 case FILE_OPXOR:
1485 offset = p->l ^ off;
1486 break;
1487 case FILE_OPADD:
1488 offset = p->l + off;
1489 break;
1490 case FILE_OPMINUS:
1491 offset = p->l - off;
1492 break;
1493 case FILE_OPMULTIPLY:
1494 offset = p->l * off;
1495 break;
1496 case FILE_OPDIVIDE:
1497 offset = p->l / off;
1498 break;
1499 case FILE_OPMODULO:
1500 offset = p->l % off;
1501 break;
1503 } else
1504 offset = p->l;
1505 if (m->in_op & FILE_OPINVERSE)
1506 offset = ~offset;
1507 break;
1510 switch (m->in_type) {
1511 case FILE_LEID3:
1512 case FILE_BEID3:
1513 offset = ((((offset >> 0) & 0x7f) << 0) |
1514 (((offset >> 8) & 0x7f) << 7) |
1515 (((offset >> 16) & 0x7f) << 14) |
1516 (((offset >> 24) & 0x7f) << 21)) + 10;
1517 break;
1518 default:
1519 break;
1522 if (m->flag & INDIROFFADD) {
1523 offset += ms->c.li[cont_level-1].off;
1525 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
1526 return -1;
1527 ms->offset = offset;
1529 if ((ms->flags & MAGIC_DEBUG) != 0) {
1530 mdebug(offset, (char *)(void *)p,
1531 sizeof(union VALUETYPE));
1532 #ifndef COMPILE_ONLY
1533 file_mdump(m);
1534 #endif
1538 /* Verify we have enough data to match magic type */
1539 switch (m->type) {
1540 case FILE_BYTE:
1541 if (nbytes < (offset + 1)) /* should alway be true */
1542 return 0;
1543 break;
1545 case FILE_SHORT:
1546 case FILE_BESHORT:
1547 case FILE_LESHORT:
1548 if (nbytes < (offset + 2))
1549 return 0;
1550 break;
1552 case FILE_LONG:
1553 case FILE_BELONG:
1554 case FILE_LELONG:
1555 case FILE_MELONG:
1556 case FILE_DATE:
1557 case FILE_BEDATE:
1558 case FILE_LEDATE:
1559 case FILE_MEDATE:
1560 case FILE_LDATE:
1561 case FILE_BELDATE:
1562 case FILE_LELDATE:
1563 case FILE_MELDATE:
1564 case FILE_FLOAT:
1565 case FILE_BEFLOAT:
1566 case FILE_LEFLOAT:
1567 if (nbytes < (offset + 4))
1568 return 0;
1569 break;
1571 case FILE_DOUBLE:
1572 case FILE_BEDOUBLE:
1573 case FILE_LEDOUBLE:
1574 if (nbytes < (offset + 8))
1575 return 0;
1576 break;
1578 case FILE_STRING:
1579 case FILE_PSTRING:
1580 case FILE_SEARCH:
1581 if (nbytes < (offset + m->vallen))
1582 return 0;
1583 break;
1585 case FILE_REGEX:
1586 if (nbytes < offset)
1587 return 0;
1588 break;
1590 case FILE_INDIRECT:
1591 if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 &&
1592 file_printf(ms, m->desc) == -1)
1593 return -1;
1594 if (nbytes < offset)
1595 return 0;
1596 return file_softmagic(ms, s + offset, nbytes - offset,
1597 BINTEST);
1599 case FILE_DEFAULT: /* nothing to check */
1600 default:
1601 break;
1603 if (!mconvert(ms, m))
1604 return 0;
1605 return 1;
1608 private uint64_t
1609 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1612 * Convert the source args to unsigned here so that (1) the
1613 * compare will be unsigned as it is in strncmp() and (2) so
1614 * the ctype functions will work correctly without extra
1615 * casting.
1617 const unsigned char *a = (const unsigned char *)s1;
1618 const unsigned char *b = (const unsigned char *)s2;
1619 uint64_t v;
1622 * What we want here is v = strncmp(s1, s2, len),
1623 * but ignoring any nulls.
1625 v = 0;
1626 if (0L == flags) { /* normal string: do it fast */
1627 while (len-- > 0)
1628 if ((v = *b++ - *a++) != '\0')
1629 break;
1631 else { /* combine the others */
1632 while (len-- > 0) {
1633 if ((flags & STRING_IGNORE_LOWERCASE) &&
1634 islower(*a)) {
1635 if ((v = tolower(*b++) - *a++) != '\0')
1636 break;
1638 else if ((flags & STRING_IGNORE_UPPERCASE) &&
1639 isupper(*a)) {
1640 if ((v = toupper(*b++) - *a++) != '\0')
1641 break;
1643 else if ((flags & STRING_COMPACT_BLANK) &&
1644 isspace(*a)) {
1645 a++;
1646 if (isspace(*b++)) {
1647 while (isspace(*b))
1648 b++;
1650 else {
1651 v = 1;
1652 break;
1655 else if ((flags & STRING_COMPACT_OPTIONAL_BLANK) &&
1656 isspace(*a)) {
1657 a++;
1658 while (isspace(*b))
1659 b++;
1661 else {
1662 if ((v = *b++ - *a++) != '\0')
1663 break;
1667 return v;
1670 private uint64_t
1671 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1674 * XXX - The 16-bit string compare probably needs to be done
1675 * differently, especially if the flags are to be supported.
1676 * At the moment, I am unsure.
1678 flags = 0;
1679 return file_strncmp(a, b, len, flags);
1682 private int
1683 magiccheck(struct magic_set *ms, struct magic *m)
1685 uint64_t l = m->value.q;
1686 uint64_t v;
1687 float fl, fv;
1688 double dl, dv;
1689 int matched;
1690 union VALUETYPE *p = &ms->ms_value;
1692 switch (m->type) {
1693 case FILE_BYTE:
1694 v = p->b;
1695 break;
1697 case FILE_SHORT:
1698 case FILE_BESHORT:
1699 case FILE_LESHORT:
1700 v = p->h;
1701 break;
1703 case FILE_LONG:
1704 case FILE_BELONG:
1705 case FILE_LELONG:
1706 case FILE_MELONG:
1707 case FILE_DATE:
1708 case FILE_BEDATE:
1709 case FILE_LEDATE:
1710 case FILE_MEDATE:
1711 case FILE_LDATE:
1712 case FILE_BELDATE:
1713 case FILE_LELDATE:
1714 case FILE_MELDATE:
1715 v = p->l;
1716 break;
1718 case FILE_QUAD:
1719 case FILE_LEQUAD:
1720 case FILE_BEQUAD:
1721 case FILE_QDATE:
1722 case FILE_BEQDATE:
1723 case FILE_LEQDATE:
1724 case FILE_QLDATE:
1725 case FILE_BEQLDATE:
1726 case FILE_LEQLDATE:
1727 v = p->q;
1728 break;
1730 case FILE_FLOAT:
1731 case FILE_BEFLOAT:
1732 case FILE_LEFLOAT:
1733 fl = m->value.f;
1734 fv = p->f;
1735 switch (m->reln) {
1736 case 'x':
1737 matched = 1;
1738 break;
1740 case '!':
1741 matched = fv != fl;
1742 break;
1744 case '=':
1745 matched = fv == fl;
1746 break;
1748 case '>':
1749 matched = fv > fl;
1750 break;
1752 case '<':
1753 matched = fv < fl;
1754 break;
1756 default:
1757 matched = 0;
1758 file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1759 m->reln);
1760 return -1;
1762 return matched;
1764 case FILE_DOUBLE:
1765 case FILE_BEDOUBLE:
1766 case FILE_LEDOUBLE:
1767 dl = m->value.d;
1768 dv = p->d;
1769 switch (m->reln) {
1770 case 'x':
1771 matched = 1;
1772 break;
1774 case '!':
1775 matched = dv != dl;
1776 break;
1778 case '=':
1779 matched = dv == dl;
1780 break;
1782 case '>':
1783 matched = dv > dl;
1784 break;
1786 case '<':
1787 matched = dv < dl;
1788 break;
1790 default:
1791 matched = 0;
1792 file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1793 return -1;
1795 return matched;
1797 case FILE_DEFAULT:
1798 l = 0;
1799 v = 0;
1800 break;
1802 case FILE_STRING:
1803 case FILE_PSTRING:
1804 l = 0;
1805 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1806 break;
1808 case FILE_BESTRING16:
1809 case FILE_LESTRING16:
1810 l = 0;
1811 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1812 break;
1814 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1815 size_t slen;
1816 size_t idx;
1818 if (ms->search.s == NULL)
1819 return 0;
1821 slen = MIN(m->vallen, sizeof(m->value.s));
1822 l = 0;
1823 v = 0;
1825 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1826 if (slen + idx > ms->search.s_len)
1827 break;
1829 v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags);
1830 if (v == 0) { /* found match */
1831 ms->search.offset += idx;
1832 break;
1835 break;
1837 case FILE_REGEX: {
1838 int rc;
1839 regex_t rx;
1840 char errmsg[512];
1842 if (ms->search.s == NULL)
1843 return 0;
1845 l = 0;
1846 rc = regcomp(&rx, m->value.s,
1847 REG_EXTENDED|REG_NEWLINE|
1848 ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
1849 if (rc) {
1850 (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
1851 file_magerror(ms, "regex error %d, (%s)",
1852 rc, errmsg);
1853 v = (uint64_t)-1;
1855 else {
1856 regmatch_t pmatch[1];
1857 #ifndef REG_STARTEND
1858 #define REG_STARTEND 0
1859 size_t l = ms->search.s_len - 1;
1860 char c = ms->search.s[l];
1861 ((char *)(intptr_t)ms->search.s)[l] = '\0';
1862 #else
1863 pmatch[0].rm_so = 0;
1864 pmatch[0].rm_eo = ms->search.s_len;
1865 #endif
1866 rc = regexec(&rx, (const char *)ms->search.s,
1867 1, pmatch, REG_STARTEND);
1868 #if REG_STARTEND == 0
1869 ((char *)(intptr_t)ms->search.s)[l] = c;
1870 #endif
1871 switch (rc) {
1872 case 0:
1873 ms->search.s += (int)pmatch[0].rm_so;
1874 ms->search.offset += (size_t)pmatch[0].rm_so;
1875 ms->search.rm_len =
1876 (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so);
1877 v = 0;
1878 break;
1880 case REG_NOMATCH:
1881 v = 1;
1882 break;
1884 default:
1885 (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
1886 file_magerror(ms, "regexec error %d, (%s)",
1887 rc, errmsg);
1888 v = (uint64_t)-1;
1889 break;
1891 regfree(&rx);
1893 if (v == (uint64_t)-1)
1894 return -1;
1895 break;
1897 case FILE_INDIRECT:
1898 return 1;
1899 default:
1900 file_magerror(ms, "invalid type %d in magiccheck()", m->type);
1901 return -1;
1904 v = file_signextend(ms, m, v);
1906 switch (m->reln) {
1907 case 'x':
1908 if ((ms->flags & MAGIC_DEBUG) != 0)
1909 (void) fprintf(stderr, "%llu == *any* = 1\n",
1910 (unsigned long long)v);
1911 matched = 1;
1912 break;
1914 case '!':
1915 matched = v != l;
1916 if ((ms->flags & MAGIC_DEBUG) != 0)
1917 (void) fprintf(stderr, "%llu != %llu = %d\n",
1918 (unsigned long long)v, (unsigned long long)l,
1919 matched);
1920 break;
1922 case '=':
1923 matched = v == l;
1924 if ((ms->flags & MAGIC_DEBUG) != 0)
1925 (void) fprintf(stderr, "%llu == %llu = %d\n",
1926 (unsigned long long)v, (unsigned long long)l,
1927 matched);
1928 break;
1930 case '>':
1931 if (m->flag & UNSIGNED) {
1932 matched = v > l;
1933 if ((ms->flags & MAGIC_DEBUG) != 0)
1934 (void) fprintf(stderr, "%llu > %llu = %d\n",
1935 (unsigned long long)v,
1936 (unsigned long long)l, matched);
1938 else {
1939 matched = (int64_t) v > (int64_t) l;
1940 if ((ms->flags & MAGIC_DEBUG) != 0)
1941 (void) fprintf(stderr, "%lld > %lld = %d\n",
1942 (long long)v, (long long)l, matched);
1944 break;
1946 case '<':
1947 if (m->flag & UNSIGNED) {
1948 matched = v < l;
1949 if ((ms->flags & MAGIC_DEBUG) != 0)
1950 (void) fprintf(stderr, "%llu < %llu = %d\n",
1951 (unsigned long long)v,
1952 (unsigned long long)l, matched);
1954 else {
1955 matched = (int64_t) v < (int64_t) l;
1956 if ((ms->flags & MAGIC_DEBUG) != 0)
1957 (void) fprintf(stderr, "%lld < %lld = %d\n",
1958 (long long)v, (long long)l, matched);
1960 break;
1962 case '&':
1963 matched = (v & l) == l;
1964 if ((ms->flags & MAGIC_DEBUG) != 0)
1965 (void) fprintf(stderr, "((%llx & %llx) == %llx) = %d\n",
1966 (unsigned long long)v, (unsigned long long)l,
1967 (unsigned long long)l, matched);
1968 break;
1970 case '^':
1971 matched = (v & l) != l;
1972 if ((ms->flags & MAGIC_DEBUG) != 0)
1973 (void) fprintf(stderr, "((%llx & %llx) != %llx) = %d\n",
1974 (unsigned long long)v, (unsigned long long)l,
1975 (unsigned long long)l, matched);
1976 break;
1978 default:
1979 matched = 0;
1980 file_magerror(ms, "cannot happen: invalid relation `%c'",
1981 m->reln);
1982 return -1;
1985 return matched;
1988 private int
1989 handle_annotation(struct magic_set *ms, struct magic *m)
1991 if (ms->flags & MAGIC_APPLE) {
1992 if (file_printf(ms, "%.8s", m->apple) == -1)
1993 return -1;
1994 return 1;
1996 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
1997 if (file_printf(ms, "%s", m->mimetype) == -1)
1998 return -1;
1999 return 1;
2001 return 0;
2004 private int
2005 print_sep(struct magic_set *ms, int firstline)
2007 if (ms->flags & MAGIC_MIME)
2008 return 0;
2009 if (firstline)
2010 return 0;
2012 * we found another match
2013 * put a newline and '-' to do some simple formatting
2015 return file_printf(ms, "\n- ");