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
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
29 * softmagic - interpret variable magic from MAGIC
35 FILE_RCSID("@(#)$File: softmagic.c,v 1.191 2014/06/04 17:36:34 christos Exp $")
44 #if defined(HAVE_LOCALE_H)
49 private int match(struct magic_set *, struct magic *, uint32_t,
50 const unsigned char *, size_t, size_t, int, int, int, int, int *, int *,
52 private int mget(struct magic_set *, const unsigned char *,
53 struct magic *, size_t, size_t, unsigned int, int, int, int, int, 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, struct magic *);
61 private int mconvert(struct magic_set *, struct magic *, int);
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 *);
69 #define OFFSET_OOB(n, o, i) ((n) < (o) || (i) > ((n) - (o)))
71 * softmagic - lookup one file in parsed, in-memory copy of database
72 * Passed the name and FILE * of one file to be typed.
74 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
76 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
77 size_t level, int mode, int text)
80 int rv, printed_something = 0, need_separator = 0;
81 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
82 if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
83 text, 0, level, &printed_something, &need_separator,
92 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
94 private const char * __attribute__((__format_arg__(3)))
95 file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def,
96 const char *file, size_t line)
98 const char *ptr = fmtcheck(m->desc, def);
101 "%s, %zu: format `%s' does not match with `%s'",
102 file, line, m->desc, def);
106 #define F(a, b, c) fmtcheck((b)->desc, (c))
110 * Go through the whole list, stopping if you find a match. Process all
111 * the continuations of that match before returning.
113 * We support multi-level continuations:
115 * At any time when processing a successful top-level match, there is a
116 * current continuation level; it represents the level of the last
117 * successfully matched continuation.
119 * Continuations above that level are skipped as, if we see one, it
120 * means that the continuation that controls them - i.e, the
121 * lower-level continuation preceding them - failed to match.
123 * Continuations below that level are processed as, if we see one,
124 * it means we've finished processing or skipping higher-level
125 * continuations under the control of a successful or unsuccessful
126 * lower-level continuation, and are now seeing the next lower-level
127 * continuation and should process it. The current continuation
128 * level reverts to the level of the one we're seeing.
130 * Continuations at the current level are processed as, if we see
131 * one, there's no lower-level continuation that may have failed.
133 * If a continuation matches, we bump the current continuation level
134 * so that higher-level continuations are processed.
137 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
138 const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
139 int flip, int recursion_level, int *printed_something, int *need_separator,
142 uint32_t magindex = 0;
143 unsigned int cont_level = 0;
144 int returnvalv = 0, e; /* if a match is found it is set to 1*/
145 int firstline = 1; /* a flag to print X\n X\n- X */
146 int print = (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0;
148 if (returnval == NULL)
149 returnval = &returnvalv;
151 if (file_check_mem(ms, cont_level) == -1)
154 for (magindex = 0; magindex < nmagic; magindex++) {
156 struct magic *m = &magic[magindex];
158 if (m->type != FILE_NAME)
159 if ((IS_STRING(m->type) &&
160 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
161 ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
162 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
163 (m->flag & mode) != mode) {
165 while (magindex + 1 < nmagic &&
166 magic[magindex + 1].cont_level != 0 &&
169 continue; /* Skip to next top-level test*/
172 ms->offset = m->offset;
173 ms->line = m->lineno;
175 /* if main entry matches, print it... */
176 switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
177 flip, recursion_level + 1, printed_something,
178 need_separator, returnval)) {
182 flush = m->reln != '!';
185 if (m->type == FILE_INDIRECT)
188 switch (magiccheck(ms, m)) {
202 * main entry didn't match,
203 * flush its continuations
205 while (magindex < nmagic - 1 &&
206 magic[magindex + 1].cont_level != 0)
211 if ((e = handle_annotation(ms, m)) != 0) {
213 *printed_something = 1;
218 * If we are going to print something, we'll need to print
219 * a blank before we print something else.
223 *printed_something = 1;
224 if (print_sep(ms, firstline) == -1)
229 if (print && mprint(ms, m) == -1)
232 ms->c.li[cont_level].off = moffset(ms, m);
234 /* and any continuations that match */
235 if (file_check_mem(ms, ++cont_level) == -1)
238 while (++magindex < nmagic &&
239 magic[magindex].cont_level != 0) {
240 m = &magic[magindex];
241 ms->line = m->lineno; /* for messages */
243 if (cont_level < m->cont_level)
245 if (cont_level > m->cont_level) {
247 * We're at the end of the level
248 * "cont_level" continuations.
250 cont_level = m->cont_level;
252 ms->offset = m->offset;
253 if (m->flag & OFFADD) {
255 ms->c.li[cont_level - 1].off;
258 #ifdef ENABLE_CONDITIONALS
259 if (m->cond == COND_ELSE ||
260 m->cond == COND_ELIF) {
261 if (ms->c.li[cont_level].last_match == 1)
265 switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
266 text, flip, recursion_level + 1, printed_something,
267 need_separator, returnval)) {
276 if (m->type == FILE_INDIRECT)
282 switch (flush ? 1 : magiccheck(ms, m)) {
286 #ifdef ENABLE_CONDITIONALS
287 ms->c.li[cont_level].last_match = 0;
291 #ifdef ENABLE_CONDITIONALS
292 ms->c.li[cont_level].last_match = 1;
294 if (m->type == FILE_CLEAR)
295 ms->c.li[cont_level].got_match = 0;
296 else if (ms->c.li[cont_level].got_match) {
297 if (m->type == FILE_DEFAULT)
300 ms->c.li[cont_level].got_match = 1;
301 if ((e = handle_annotation(ms, m)) != 0) {
303 *printed_something = 1;
308 * If we are going to print something,
309 * make sure that we have a separator first.
312 if (!*printed_something) {
313 *printed_something = 1;
314 if (print_sep(ms, firstline)
320 * This continuation matched. Print
321 * its message, with a blank before it
322 * if the previous item printed and
323 * this item isn't empty.
325 /* space if previous printed */
327 && ((m->flag & NOSPACE) == 0)
330 file_printf(ms, " ") == -1)
334 if (print && mprint(ms, m) == -1)
337 ms->c.li[cont_level].off = moffset(ms, m);
343 * If we see any continuations
347 if (file_check_mem(ms, ++cont_level) == -1)
352 if (*printed_something) {
357 if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) {
358 return *returnval; /* don't keep searching */
361 return *returnval; /* This is hit if -k is set or there is no match */
365 check_fmt(struct magic_set *ms, struct magic *m)
370 if (strchr(m->desc, '%') == NULL)
373 rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
375 file_regerror(&rx, rc, ms);
377 rc = file_regexec(&rx, m->desc, 0, 0, 0);
385 char * strndup(const char *, size_t);
388 strndup(const char *str, size_t n)
393 for (len = 0; len < n && str[len]; len++)
395 if ((copy = malloc(len + 1)) == NULL)
397 (void)memcpy(copy, str, len);
401 #endif /* HAVE_STRNDUP */
404 mprint(struct magic_set *ms, struct magic *m)
410 char buf[128], tbuf[26];
411 union VALUETYPE *p = &ms->ms_value;
415 v = file_signextend(ms, m, (uint64_t)p->b);
416 switch (check_fmt(ms, m)) {
420 (void)snprintf(buf, sizeof(buf), "%d",
422 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
426 if (file_printf(ms, F(ms, m, "%d"),
427 (unsigned char) v) == -1)
431 t = ms->offset + sizeof(char);
437 v = file_signextend(ms, m, (uint64_t)p->h);
438 switch (check_fmt(ms, m)) {
442 (void)snprintf(buf, sizeof(buf), "%u",
444 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
448 if (file_printf(ms, F(ms, m, "%u"),
449 (unsigned short) v) == -1)
453 t = ms->offset + sizeof(short);
460 v = file_signextend(ms, m, (uint64_t)p->l);
461 switch (check_fmt(ms, m)) {
465 (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v);
466 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
470 if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1)
474 t = ms->offset + sizeof(int32_t);
480 v = file_signextend(ms, m, p->q);
481 switch (check_fmt(ms, m)) {
485 (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
486 (unsigned long long)v);
487 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
491 if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"),
492 (unsigned long long) v) == -1)
496 t = ms->offset + sizeof(int64_t);
501 case FILE_BESTRING16:
502 case FILE_LESTRING16:
503 if (m->reln == '=' || m->reln == '!') {
504 if (file_printf(ms, F(ms, m, "%s"), m->value.s) == -1)
506 t = ms->offset + m->vallen;
511 /* compute t before we mangle the string? */
512 t = ms->offset + strlen(str);
514 if (*m->value.s == '\0')
515 str[strcspn(str, "\n")] = '\0';
517 if (m->str_flags & STRING_TRIM) {
519 while (isspace((unsigned char)*str))
525 while (isspace((unsigned char)*last))
530 if (file_printf(ms, F(ms, m, "%s"), str) == -1)
533 if (m->type == FILE_PSTRING)
534 t += file_pstring_length_size(m);
542 if (file_printf(ms, F(ms, m, "%s"),
543 file_fmttime(p->l + m->num_mask, FILE_T_LOCAL, tbuf)) == -1)
545 t = ms->offset + sizeof(uint32_t);
552 if (file_printf(ms, F(ms, m, "%s"),
553 file_fmttime(p->l + m->num_mask, 0, tbuf)) == -1)
555 t = ms->offset + sizeof(uint32_t);
561 if (file_printf(ms, F(ms, m, "%s"),
562 file_fmttime(p->q + m->num_mask, FILE_T_LOCAL, tbuf)) == -1)
564 t = ms->offset + sizeof(uint64_t);
570 if (file_printf(ms, F(ms, m, "%s"),
571 file_fmttime(p->q + m->num_mask, 0, tbuf)) == -1)
573 t = ms->offset + sizeof(uint64_t);
579 if (file_printf(ms, F(ms, m, "%s"),
580 file_fmttime(p->q + m->num_mask, FILE_T_WINDOWS, tbuf)) == -1)
582 t = ms->offset + sizeof(uint64_t);
589 switch (check_fmt(ms, m)) {
593 (void)snprintf(buf, sizeof(buf), "%g", vf);
594 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
598 if (file_printf(ms, F(ms, m, "%g"), vf) == -1)
602 t = ms->offset + sizeof(float);
609 switch (check_fmt(ms, m)) {
613 (void)snprintf(buf, sizeof(buf), "%g", vd);
614 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
618 if (file_printf(ms, F(ms, m, "%g"), vd) == -1)
622 t = ms->offset + sizeof(double);
629 cp = strndup((const char *)ms->search.s, ms->search.rm_len);
631 file_oomem(ms, ms->search.rm_len);
634 rval = file_printf(ms, F(ms, m, "%s"), cp);
640 if ((m->str_flags & REGEX_OFFSET_START))
641 t = ms->search.offset;
643 t = ms->search.offset + ms->search.rm_len;
648 if (file_printf(ms, F(ms, m, "%s"), m->value.s) == -1)
650 if ((m->str_flags & REGEX_OFFSET_START))
651 t = ms->search.offset;
653 t = ms->search.offset + m->vallen;
658 if (file_printf(ms, "%s", m->desc) == -1)
670 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
677 moffset(struct magic_set *ms, struct magic *m)
681 return CAST(int32_t, (ms->offset + sizeof(char)));
686 return CAST(int32_t, (ms->offset + sizeof(short)));
692 return CAST(int32_t, (ms->offset + sizeof(int32_t)));
697 return CAST(int32_t, (ms->offset + sizeof(int64_t)));
701 case FILE_BESTRING16:
702 case FILE_LESTRING16:
703 if (m->reln == '=' || m->reln == '!')
704 return ms->offset + m->vallen;
706 union VALUETYPE *p = &ms->ms_value;
709 if (*m->value.s == '\0')
710 p->s[strcspn(p->s, "\n")] = '\0';
711 t = CAST(uint32_t, (ms->offset + strlen(p->s)));
712 if (m->type == FILE_PSTRING)
713 t += (uint32_t)file_pstring_length_size(m);
721 return CAST(int32_t, (ms->offset + sizeof(uint32_t)));
727 return CAST(int32_t, (ms->offset + sizeof(uint32_t)));
732 return CAST(int32_t, (ms->offset + sizeof(uint64_t)));
737 return CAST(int32_t, (ms->offset + sizeof(uint64_t)));
742 return CAST(int32_t, (ms->offset + sizeof(float)));
747 return CAST(int32_t, (ms->offset + sizeof(double)));
750 if ((m->str_flags & REGEX_OFFSET_START) != 0)
751 return CAST(int32_t, ms->search.offset);
753 return CAST(int32_t, (ms->search.offset +
757 if ((m->str_flags & REGEX_OFFSET_START) != 0)
758 return CAST(int32_t, ms->search.offset);
760 return CAST(int32_t, (ms->search.offset + m->vallen));
773 cvt_flip(int type, int flip)
791 return FILE_LEQLDATE;
793 return FILE_LEQWDATE;
807 return FILE_BEQLDATE;
809 return FILE_BEQWDATE;
815 return FILE_LEDOUBLE;
817 return FILE_BEDOUBLE;
822 #define DO_CVT(fld, cast) \
824 switch (m->mask_op & FILE_OPS_MASK) { \
826 p->fld &= cast m->num_mask; \
829 p->fld |= cast m->num_mask; \
832 p->fld ^= cast m->num_mask; \
835 p->fld += cast m->num_mask; \
838 p->fld -= cast m->num_mask; \
840 case FILE_OPMULTIPLY: \
841 p->fld *= cast m->num_mask; \
843 case FILE_OPDIVIDE: \
844 p->fld /= cast m->num_mask; \
846 case FILE_OPMODULO: \
847 p->fld %= cast m->num_mask; \
850 if (m->mask_op & FILE_OPINVERSE) \
854 cvt_8(union VALUETYPE *p, const struct magic *m)
856 DO_CVT(b, (uint8_t));
860 cvt_16(union VALUETYPE *p, const struct magic *m)
862 DO_CVT(h, (uint16_t));
866 cvt_32(union VALUETYPE *p, const struct magic *m)
868 DO_CVT(l, (uint32_t));
872 cvt_64(union VALUETYPE *p, const struct magic *m)
874 DO_CVT(q, (uint64_t));
877 #define DO_CVT2(fld, cast) \
879 switch (m->mask_op & FILE_OPS_MASK) { \
881 p->fld += cast m->num_mask; \
884 p->fld -= cast m->num_mask; \
886 case FILE_OPMULTIPLY: \
887 p->fld *= cast m->num_mask; \
889 case FILE_OPDIVIDE: \
890 p->fld /= cast m->num_mask; \
895 cvt_float(union VALUETYPE *p, const struct magic *m)
901 cvt_double(union VALUETYPE *p, const struct magic *m)
903 DO_CVT2(d, (double));
907 * Convert the byte order of the data we are looking at
908 * While we're here, let's apply the mask operation
909 * (unless you have a better idea)
912 mconvert(struct magic_set *ms, struct magic *m, int flip)
914 union VALUETYPE *p = &ms->ms_value;
917 switch (type = cvt_flip(m->type, flip)) {
936 case FILE_BESTRING16:
937 case FILE_LESTRING16: {
938 /* Null terminate and eat *trailing* return */
939 p->s[sizeof(p->s) - 1] = '\0';
943 size_t sz = file_pstring_length_size(m);
944 char *ptr1 = p->s, *ptr2 = ptr1 + sz;
945 size_t len = file_pstring_get_length(m, ptr1);
946 if (len >= sizeof(p->s)) {
948 * The size of the pascal string length (sz)
949 * is 1, 2, or 4. We need at least 1 byte for NUL
950 * termination, but we've already truncated the
951 * string by p->s, so we need to deduct sz.
953 len = sizeof(p->s) - sz;
961 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
968 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
969 if (type == FILE_BELONG)
977 (((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
978 ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
979 ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
980 ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7]));
981 if (type == FILE_BEQUAD)
985 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
992 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
993 if (type == FILE_LELONG)
1001 (((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
1002 ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
1003 ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
1004 ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0]));
1005 if (type == FILE_LEQUAD)
1012 ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2]));
1013 if (type == FILE_MELONG)
1020 p->l = ((uint32_t)p->hl[0]<<24)|((uint32_t)p->hl[1]<<16)|
1021 ((uint32_t)p->hl[2]<<8) |((uint32_t)p->hl[3]);
1025 p->l = ((uint32_t)p->hl[3]<<24)|((uint32_t)p->hl[2]<<16)|
1026 ((uint32_t)p->hl[1]<<8) |((uint32_t)p->hl[0]);
1033 p->q = ((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
1034 ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
1035 ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
1036 ((uint64_t)p->hq[6]<<8) |((uint64_t)p->hq[7]);
1040 p->q = ((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
1041 ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
1042 ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
1043 ((uint64_t)p->hq[1]<<8) |((uint64_t)p->hq[0]);
1054 file_magerror(ms, "invalid type %d in mconvert()", m->type);
1061 mdebug(uint32_t offset, const char *str, size_t len)
1063 (void) fprintf(stderr, "mget/%zu @%d: ", len, offset);
1064 file_showstr(stderr, str, len);
1065 (void) fputc('\n', stderr);
1066 (void) fputc('\n', stderr);
1070 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1071 const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1074 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1075 * anything, but setup pointers into the source
1080 ms->search.s = RCAST(const char *, s) + offset;
1081 ms->search.s_len = nbytes - offset;
1082 ms->search.offset = offset;
1088 const char *last; /* end of search region */
1089 const char *buf; /* start of search region */
1091 size_t lines, linecnt, bytecnt;
1094 ms->search.s_len = 0;
1095 ms->search.s = NULL;
1099 if (m->str_flags & REGEX_LINE_COUNT) {
1100 linecnt = m->str_range;
1101 bytecnt = linecnt * 80;
1104 bytecnt = m->str_range;
1109 if (bytecnt > nbytes)
1112 buf = RCAST(const char *, s) + offset;
1113 end = last = RCAST(const char *, s) + bytecnt;
1114 /* mget() guarantees buf <= last */
1115 for (lines = linecnt, b = buf; lines && b < end &&
1116 ((b = CAST(const char *,
1117 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1118 || (b = CAST(const char *,
1119 memchr(c, '\r', CAST(size_t, (end - c))))));
1122 if (b[0] == '\r' && b[1] == '\n')
1126 last = RCAST(const char *, s) + bytecnt;
1129 ms->search.s_len = last - buf;
1130 ms->search.offset = offset;
1131 ms->search.rm_len = 0;
1134 case FILE_BESTRING16:
1135 case FILE_LESTRING16: {
1136 const unsigned char *src = s + offset;
1137 const unsigned char *esrc = s + nbytes;
1139 char *edst = &p->s[sizeof(p->s) - 1];
1141 if (type == FILE_BESTRING16)
1144 /* check that offset is within range */
1145 if (offset >= nbytes)
1147 for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1153 if (type == FILE_BESTRING16 ?
1154 *(src - 1) != '\0' :
1162 case FILE_STRING: /* XXX - these two should not need */
1163 case FILE_PSTRING: /* to copy anything, but do anyway. */
1169 if (offset >= nbytes) {
1170 (void)memset(p, '\0', sizeof(*p));
1173 if (nbytes - offset < sizeof(*p))
1174 nbytes = nbytes - offset;
1176 nbytes = sizeof(*p);
1178 (void)memcpy(p, s + offset, nbytes);
1181 * the usefulness of padding with zeroes eludes me, it
1182 * might even cause problems
1184 if (nbytes < sizeof(*p))
1185 (void)memset(((char *)(void *)p) + nbytes, '\0',
1186 sizeof(*p) - nbytes);
1191 mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
1192 size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
1193 int flip, int recursion_level, int *printed_something,
1194 int *need_separator, int *returnval)
1196 uint32_t soffset, offset = ms->offset;
1198 int rv, oneed_separator, in_type;
1200 union VALUETYPE *p = &ms->ms_value;
1203 if (recursion_level >= 20) {
1204 file_error(ms, 0, "recursion nesting exceeded");
1208 if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
1209 (uint32_t)nbytes, m) == -1)
1212 if ((ms->flags & MAGIC_DEBUG) != 0) {
1213 fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, "
1214 "nbytes=%zu)\n", m->type, m->flag, offset, o, nbytes);
1215 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1216 #ifndef COMPILE_ONLY
1221 if (m->flag & INDIR) {
1222 int off = m->in_offset;
1223 if (m->in_op & FILE_OPINDIRECT) {
1224 const union VALUETYPE *q = CAST(const union VALUETYPE *,
1225 ((const void *)(s + offset + off)));
1226 switch (cvt_flip(m->in_type, flip)) {
1234 off = (short)((q->hs[0]<<8)|(q->hs[1]));
1237 off = (short)((q->hs[1]<<8)|(q->hs[0]));
1244 off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
1245 (q->hl[2]<<8)|(q->hl[3]));
1249 off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
1250 (q->hl[1]<<8)|(q->hl[0]));
1253 off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
1254 (q->hl[3]<<8)|(q->hl[2]));
1257 if ((ms->flags & MAGIC_DEBUG) != 0)
1258 fprintf(stderr, "indirect offs=%u\n", off);
1260 switch (in_type = cvt_flip(m->in_type, flip)) {
1262 if (OFFSET_OOB(nbytes, offset, 1))
1265 switch (m->in_op & FILE_OPS_MASK) {
1267 offset = p->b & off;
1270 offset = p->b | off;
1273 offset = p->b ^ off;
1276 offset = p->b + off;
1279 offset = p->b - off;
1281 case FILE_OPMULTIPLY:
1282 offset = p->b * off;
1285 offset = p->b / off;
1288 offset = p->b % off;
1293 if (m->in_op & FILE_OPINVERSE)
1297 if (OFFSET_OOB(nbytes, offset, 2))
1299 lhs = (p->hs[0] << 8) | p->hs[1];
1301 switch (m->in_op & FILE_OPS_MASK) {
1317 case FILE_OPMULTIPLY:
1329 if (m->in_op & FILE_OPINVERSE)
1333 if (OFFSET_OOB(nbytes, offset, 2))
1335 lhs = (p->hs[1] << 8) | p->hs[0];
1337 switch (m->in_op & FILE_OPS_MASK) {
1353 case FILE_OPMULTIPLY:
1365 if (m->in_op & FILE_OPINVERSE)
1369 if (OFFSET_OOB(nbytes, offset, 2))
1372 switch (m->in_op & FILE_OPS_MASK) {
1374 offset = p->h & off;
1377 offset = p->h | off;
1380 offset = p->h ^ off;
1383 offset = p->h + off;
1386 offset = p->h - off;
1388 case FILE_OPMULTIPLY:
1389 offset = p->h * off;
1392 offset = p->h / off;
1395 offset = p->h % off;
1401 if (m->in_op & FILE_OPINVERSE)
1406 if (OFFSET_OOB(nbytes, offset, 4))
1408 lhs = (p->hl[0] << 24) | (p->hl[1] << 16) |
1409 (p->hl[2] << 8) | p->hl[3];
1411 switch (m->in_op & FILE_OPS_MASK) {
1427 case FILE_OPMULTIPLY:
1439 if (m->in_op & FILE_OPINVERSE)
1444 if (OFFSET_OOB(nbytes, offset, 4))
1446 lhs = (p->hl[3] << 24) | (p->hl[2] << 16) |
1447 (p->hl[1] << 8) | p->hl[0];
1449 switch (m->in_op & FILE_OPS_MASK) {
1465 case FILE_OPMULTIPLY:
1477 if (m->in_op & FILE_OPINVERSE)
1481 if (OFFSET_OOB(nbytes, offset, 4))
1483 lhs = (p->hl[1] << 24) | (p->hl[0] << 16) |
1484 (p->hl[3] << 8) | p->hl[2];
1486 switch (m->in_op & FILE_OPS_MASK) {
1502 case FILE_OPMULTIPLY:
1514 if (m->in_op & FILE_OPINVERSE)
1518 if (OFFSET_OOB(nbytes, offset, 4))
1521 switch (m->in_op & FILE_OPS_MASK) {
1523 offset = p->l & off;
1526 offset = p->l | off;
1529 offset = p->l ^ off;
1532 offset = p->l + off;
1535 offset = p->l - off;
1537 case FILE_OPMULTIPLY:
1538 offset = p->l * off;
1541 offset = p->l / off;
1544 offset = p->l % off;
1549 if (m->in_op & FILE_OPINVERSE)
1559 offset = ((((offset >> 0) & 0x7f) << 0) |
1560 (((offset >> 8) & 0x7f) << 7) |
1561 (((offset >> 16) & 0x7f) << 14) |
1562 (((offset >> 24) & 0x7f) << 21)) + 10;
1568 if (m->flag & INDIROFFADD) {
1569 offset += ms->c.li[cont_level-1].off;
1571 if ((ms->flags & MAGIC_DEBUG) != 0)
1573 "indirect *zero* offset\n");
1576 if ((ms->flags & MAGIC_DEBUG) != 0)
1577 fprintf(stderr, "indirect +offs=%u\n", offset);
1579 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1581 ms->offset = offset;
1583 if ((ms->flags & MAGIC_DEBUG) != 0) {
1584 mdebug(offset, (char *)(void *)p,
1585 sizeof(union VALUETYPE));
1586 #ifndef COMPILE_ONLY
1592 /* Verify we have enough data to match magic type */
1595 if (OFFSET_OOB(nbytes, offset, 1))
1602 if (OFFSET_OOB(nbytes, offset, 2))
1621 if (OFFSET_OOB(nbytes, offset, 4))
1628 if (OFFSET_OOB(nbytes, offset, 8))
1635 if (OFFSET_OOB(nbytes, offset, m->vallen))
1640 if (nbytes < offset)
1647 if (nbytes < offset)
1650 soffset = ms->offset;
1653 rv = file_softmagic(ms, s + offset, nbytes - offset,
1654 recursion_level, BINTEST, text);
1655 if ((ms->flags & MAGIC_DEBUG) != 0)
1656 fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1659 ms->offset = soffset;
1661 if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 &&
1662 file_printf(ms, F(ms, m, "%u"), offset) == -1) {
1666 if (file_printf(ms, "%s", rbuf) == -1) {
1675 if (nbytes < offset)
1682 if (file_magicfind(ms, sbuf, &ml) == -1) {
1683 file_error(ms, 0, "cannot find entry `%s'", sbuf);
1687 oneed_separator = *need_separator;
1688 if (m->flag & NOSPACE)
1689 *need_separator = 0;
1690 rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
1691 mode, text, flip, recursion_level, printed_something,
1692 need_separator, returnval);
1694 *need_separator = oneed_separator;
1698 if (file_printf(ms, "%s", m->desc) == -1)
1701 case FILE_DEFAULT: /* nothing to check */
1706 if (!mconvert(ms, m, flip))
1712 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1715 * Convert the source args to unsigned here so that (1) the
1716 * compare will be unsigned as it is in strncmp() and (2) so
1717 * the ctype functions will work correctly without extra
1720 const unsigned char *a = (const unsigned char *)s1;
1721 const unsigned char *b = (const unsigned char *)s2;
1725 * What we want here is v = strncmp(s1, s2, len),
1726 * but ignoring any nulls.
1729 if (0L == flags) { /* normal string: do it fast */
1731 if ((v = *b++ - *a++) != '\0')
1734 else { /* combine the others */
1736 if ((flags & STRING_IGNORE_LOWERCASE) &&
1738 if ((v = tolower(*b++) - *a++) != '\0')
1741 else if ((flags & STRING_IGNORE_UPPERCASE) &&
1743 if ((v = toupper(*b++) - *a++) != '\0')
1746 else if ((flags & STRING_COMPACT_WHITESPACE) &&
1749 if (isspace(*b++)) {
1759 else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1766 if ((v = *b++ - *a++) != '\0')
1775 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1778 * XXX - The 16-bit string compare probably needs to be done
1779 * differently, especially if the flags are to be supported.
1780 * At the moment, I am unsure.
1783 return file_strncmp(a, b, len, flags);
1787 magiccheck(struct magic_set *ms, struct magic *m)
1789 uint64_t l = m->value.q;
1794 union VALUETYPE *p = &ms->ms_value;
1864 file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1897 file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1911 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1914 case FILE_BESTRING16:
1915 case FILE_LESTRING16:
1917 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1920 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1924 if (ms->search.s == NULL)
1927 slen = MIN(m->vallen, sizeof(m->value.s));
1931 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1932 if (slen + idx > ms->search.s_len)
1935 v = file_strncmp(m->value.s, ms->search.s + idx, slen,
1937 if (v == 0) { /* found match */
1938 ms->search.offset += idx;
1948 if (ms->search.s == NULL)
1952 rc = file_regcomp(&rx, m->value.s,
1953 REG_EXTENDED|REG_NEWLINE|
1954 ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
1956 file_regerror(&rx, rc, ms);
1959 regmatch_t pmatch[1];
1960 size_t slen = ms->search.s_len;
1961 #ifndef REG_STARTEND
1962 #define REG_STARTEND 0
1966 c = ms->search.s[slen];
1967 ((char *)(intptr_t)ms->search.s)[slen] = '\0';
1969 pmatch[0].rm_so = 0;
1970 pmatch[0].rm_eo = slen;
1972 rc = file_regexec(&rx, (const char *)ms->search.s,
1973 1, pmatch, REG_STARTEND);
1974 #if REG_STARTEND == 0
1975 ((char *)(intptr_t)ms->search.s)[l] = c;
1979 ms->search.s += (int)pmatch[0].rm_so;
1980 ms->search.offset += (size_t)pmatch[0].rm_so;
1982 (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so);
1991 file_regerror(&rx, rc, ms);
1997 if (v == (uint64_t)-1)
2006 file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2010 v = file_signextend(ms, m, v);
2014 if ((ms->flags & MAGIC_DEBUG) != 0)
2015 (void) fprintf(stderr, "%" INT64_T_FORMAT
2016 "u == *any* = 1\n", (unsigned long long)v);
2022 if ((ms->flags & MAGIC_DEBUG) != 0)
2023 (void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2024 INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2025 (unsigned long long)l, matched);
2030 if ((ms->flags & MAGIC_DEBUG) != 0)
2031 (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2032 INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2033 (unsigned long long)l, matched);
2037 if (m->flag & UNSIGNED) {
2039 if ((ms->flags & MAGIC_DEBUG) != 0)
2040 (void) fprintf(stderr, "%" INT64_T_FORMAT
2041 "u > %" INT64_T_FORMAT "u = %d\n",
2042 (unsigned long long)v,
2043 (unsigned long long)l, matched);
2046 matched = (int64_t) v > (int64_t) l;
2047 if ((ms->flags & MAGIC_DEBUG) != 0)
2048 (void) fprintf(stderr, "%" INT64_T_FORMAT
2049 "d > %" INT64_T_FORMAT "d = %d\n",
2050 (long long)v, (long long)l, matched);
2055 if (m->flag & UNSIGNED) {
2057 if ((ms->flags & MAGIC_DEBUG) != 0)
2058 (void) fprintf(stderr, "%" INT64_T_FORMAT
2059 "u < %" INT64_T_FORMAT "u = %d\n",
2060 (unsigned long long)v,
2061 (unsigned long long)l, matched);
2064 matched = (int64_t) v < (int64_t) l;
2065 if ((ms->flags & MAGIC_DEBUG) != 0)
2066 (void) fprintf(stderr, "%" INT64_T_FORMAT
2067 "d < %" INT64_T_FORMAT "d = %d\n",
2068 (long long)v, (long long)l, matched);
2073 matched = (v & l) == l;
2074 if ((ms->flags & MAGIC_DEBUG) != 0)
2075 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2076 INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2077 "x) = %d\n", (unsigned long long)v,
2078 (unsigned long long)l, (unsigned long long)l,
2083 matched = (v & l) != l;
2084 if ((ms->flags & MAGIC_DEBUG) != 0)
2085 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2086 INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2087 "x) = %d\n", (unsigned long long)v,
2088 (unsigned long long)l, (unsigned long long)l,
2093 file_magerror(ms, "cannot happen: invalid relation `%c'",
2102 handle_annotation(struct magic_set *ms, struct magic *m)
2104 if (ms->flags & MAGIC_APPLE) {
2105 if (file_printf(ms, "%.8s", m->apple) == -1)
2109 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2110 if (file_printf(ms, "%s", m->mimetype) == -1)
2118 print_sep(struct magic_set *ms, int firstline)
2120 if (ms->flags & MAGIC_MIME)
2125 * we found another match
2126 * put a newline and '-' to do some simple formatting
2128 return file_printf(ms, "\n- ");