ldconfig(8): clean up manual page
[dragonfly.git] / contrib / file / src / softmagic.c
blob9925219b70182d9b54f94b396b30a00cca961e8a
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.249 2017/06/19 18:30:25 christos Exp $")
36 #endif /* lint */
38 #include "magic.h"
39 #include <assert.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <time.h>
44 #include "der.h"
46 private int match(struct magic_set *, struct magic *, uint32_t,
47 const unsigned char *, size_t, size_t, int, int, int, uint16_t *,
48 uint16_t *, int *, int *, int *);
49 private int mget(struct magic_set *, const unsigned char *,
50 struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t *,
51 uint16_t *, int *, int *, int *);
52 private int magiccheck(struct magic_set *, struct magic *);
53 private int32_t mprint(struct magic_set *, struct magic *);
54 private int moffset(struct magic_set *, struct magic *, size_t, int32_t *);
55 private void mdebug(uint32_t, const char *, size_t);
56 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
57 const unsigned char *, uint32_t, size_t, struct magic *);
58 private int mconvert(struct magic_set *, struct magic *, int);
59 private int print_sep(struct magic_set *, int);
60 private int handle_annotation(struct magic_set *, struct magic *, int);
61 private int cvt_8(union VALUETYPE *, const struct magic *);
62 private int cvt_16(union VALUETYPE *, const struct magic *);
63 private int cvt_32(union VALUETYPE *, const struct magic *);
64 private int cvt_64(union VALUETYPE *, const struct magic *);
66 #define OFFSET_OOB(n, o, i) ((n) < (uint32_t)(o) || (i) > ((n) - (o)))
67 #define BE64(p) (((uint64_t)(p)->hq[0]<<56)|((uint64_t)(p)->hq[1]<<48)| \
68 ((uint64_t)(p)->hq[2]<<40)|((uint64_t)(p)->hq[3]<<32)| \
69 ((uint64_t)(p)->hq[4]<<24)|((uint64_t)(p)->hq[5]<<16)| \
70 ((uint64_t)(p)->hq[6]<<8)|((uint64_t)(p)->hq[7]))
71 #define LE64(p) (((uint64_t)(p)->hq[7]<<56)|((uint64_t)(p)->hq[6]<<48)| \
72 ((uint64_t)(p)->hq[5]<<40)|((uint64_t)(p)->hq[4]<<32)| \
73 ((uint64_t)(p)->hq[3]<<24)|((uint64_t)(p)->hq[2]<<16)| \
74 ((uint64_t)(p)->hq[1]<<8)|((uint64_t)(p)->hq[0]))
75 #define LE32(p) (((uint32_t)(p)->hl[3]<<24)|((uint32_t)(p)->hl[2]<<16)| \
76 ((uint32_t)(p)->hl[1]<<8)|((uint32_t)(p)->hl[0]))
77 #define BE32(p) (((uint32_t)(p)->hl[0]<<24)|((uint32_t)(p)->hl[1]<<16)| \
78 ((uint32_t)(p)->hl[2]<<8)|((uint32_t)(p)->hl[3]))
79 #define ME32(p) (((uint32_t)(p)->hl[1]<<24)|((uint32_t)(p)->hl[0]<<16)| \
80 ((uint32_t)(p)->hl[3]<<8)|((uint32_t)(p)->hl[2]))
81 #define BE16(p) (((uint16_t)(p)->hs[0]<<8)|((uint16_t)(p)->hs[1]))
82 #define LE16(p) (((uint16_t)(p)->hs[1]<<8)|((uint16_t)(p)->hs[0]))
83 #define SEXT(s,v,p) ((s)?(intmax_t)(int##v##_t)(p):(intmax_t)(uint##v##_t)(p))
86 * softmagic - lookup one file in parsed, in-memory copy of database
87 * Passed the name and FILE * of one file to be typed.
89 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
90 protected int
91 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
92 uint16_t *indir_count, uint16_t *name_count, int mode, int text)
94 struct mlist *ml;
95 int rv, printed_something = 0, need_separator = 0;
96 uint16_t nc, ic;
98 if (name_count == NULL) {
99 nc = 0;
100 name_count = &nc;
102 if (indir_count == NULL) {
103 ic = 0;
104 indir_count = &ic;
107 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
108 if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
109 text, 0, indir_count, name_count,
110 &printed_something, &need_separator, NULL)) != 0)
111 return rv;
113 return 0;
116 #define FILE_FMTDEBUG
117 #ifdef FILE_FMTDEBUG
118 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
120 private const char * __attribute__((__format_arg__(3)))
121 file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def,
122 const char *file, size_t line)
124 const char *ptr = fmtcheck(m->desc, def);
125 if (ptr == def)
126 file_magerror(ms,
127 "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
128 " with `%s'", file, line, m->desc, def);
129 return ptr;
131 #else
132 #define F(a, b, c) fmtcheck((b)->desc, (c))
133 #endif
136 * Go through the whole list, stopping if you find a match. Process all
137 * the continuations of that match before returning.
139 * We support multi-level continuations:
141 * At any time when processing a successful top-level match, there is a
142 * current continuation level; it represents the level of the last
143 * successfully matched continuation.
145 * Continuations above that level are skipped as, if we see one, it
146 * means that the continuation that controls them - i.e, the
147 * lower-level continuation preceding them - failed to match.
149 * Continuations below that level are processed as, if we see one,
150 * it means we've finished processing or skipping higher-level
151 * continuations under the control of a successful or unsuccessful
152 * lower-level continuation, and are now seeing the next lower-level
153 * continuation and should process it. The current continuation
154 * level reverts to the level of the one we're seeing.
156 * Continuations at the current level are processed as, if we see
157 * one, there's no lower-level continuation that may have failed.
159 * If a continuation matches, we bump the current continuation level
160 * so that higher-level continuations are processed.
162 private int
163 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
164 const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
165 int flip, uint16_t *indir_count, uint16_t *name_count,
166 int *printed_something, int *need_separator, int *returnval)
168 uint32_t magindex = 0;
169 unsigned int cont_level = 0;
170 int returnvalv = 0, e; /* if a match is found it is set to 1*/
171 int firstline = 1; /* a flag to print X\n X\n- X */
172 int print = (ms->flags & MAGIC_NODESC) == 0;
174 if (returnval == NULL)
175 returnval = &returnvalv;
177 if (file_check_mem(ms, cont_level) == -1)
178 return -1;
180 for (magindex = 0; magindex < nmagic; magindex++) {
181 int flush = 0;
182 struct magic *m = &magic[magindex];
184 if (m->type != FILE_NAME)
185 if ((IS_STRING(m->type) &&
186 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
187 ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
188 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
189 (m->flag & mode) != mode) {
190 flush:
191 /* Skip sub-tests */
192 while (magindex < nmagic - 1 &&
193 magic[magindex + 1].cont_level != 0)
194 magindex++;
195 cont_level = 0;
196 continue; /* Skip to next top-level test*/
199 ms->offset = m->offset;
200 ms->line = m->lineno;
202 /* if main entry matches, print it... */
203 switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
204 flip, indir_count, name_count,
205 printed_something, need_separator, returnval)) {
206 case -1:
207 return -1;
208 case 0:
209 flush = m->reln != '!';
210 break;
211 default:
212 if (m->type == FILE_INDIRECT)
213 *returnval = 1;
215 switch (magiccheck(ms, m)) {
216 case -1:
217 return -1;
218 case 0:
219 flush++;
220 break;
221 default:
222 flush = 0;
223 break;
225 break;
227 if (flush) {
229 * main entry didn't match,
230 * flush its continuations
232 goto flush;
235 if ((e = handle_annotation(ms, m, firstline)) != 0) {
236 *need_separator = 1;
237 *printed_something = 1;
238 *returnval = 1;
239 return e;
243 * If we are going to print something, we'll need to print
244 * a blank before we print something else.
246 if (*m->desc) {
247 *need_separator = 1;
248 *printed_something = 1;
249 if (print_sep(ms, firstline) == -1)
250 return -1;
254 if (print && mprint(ms, m) == -1)
255 return -1;
257 switch (moffset(ms, m, nbytes, &ms->c.li[cont_level].off)) {
258 case -1:
259 case 0:
260 goto flush;
261 default:
262 break;
265 /* and any continuations that match */
266 if (file_check_mem(ms, ++cont_level) == -1)
267 return -1;
269 while (magindex + 1 < nmagic &&
270 magic[magindex + 1].cont_level != 0) {
271 m = &magic[++magindex];
272 ms->line = m->lineno; /* for messages */
274 if (cont_level < m->cont_level)
275 continue;
276 if (cont_level > m->cont_level) {
278 * We're at the end of the level
279 * "cont_level" continuations.
281 cont_level = m->cont_level;
283 ms->offset = m->offset;
284 if (m->flag & OFFADD) {
285 ms->offset +=
286 ms->c.li[cont_level - 1].off;
289 #ifdef ENABLE_CONDITIONALS
290 if (m->cond == COND_ELSE ||
291 m->cond == COND_ELIF) {
292 if (ms->c.li[cont_level].last_match == 1)
293 continue;
295 #endif
296 switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
297 text, flip, indir_count, name_count,
298 printed_something, need_separator, returnval)) {
299 case -1:
300 return -1;
301 case 0:
302 if (m->reln != '!')
303 continue;
304 flush = 1;
305 break;
306 default:
307 if (m->type == FILE_INDIRECT)
308 *returnval = 1;
309 flush = 0;
310 break;
313 switch (flush ? 1 : magiccheck(ms, m)) {
314 case -1:
315 return -1;
316 case 0:
317 #ifdef ENABLE_CONDITIONALS
318 ms->c.li[cont_level].last_match = 0;
319 #endif
320 break;
321 default:
322 #ifdef ENABLE_CONDITIONALS
323 ms->c.li[cont_level].last_match = 1;
324 #endif
325 if (m->type == FILE_CLEAR)
326 ms->c.li[cont_level].got_match = 0;
327 else if (ms->c.li[cont_level].got_match) {
328 if (m->type == FILE_DEFAULT)
329 break;
330 } else
331 ms->c.li[cont_level].got_match = 1;
333 if ((e = handle_annotation(ms, m, firstline)) != 0) {
334 *need_separator = 1;
335 *printed_something = 1;
336 *returnval = 1;
337 return e;
340 * If we are going to print something,
341 * make sure that we have a separator first.
343 if (*m->desc) {
344 if (!*printed_something) {
345 *printed_something = 1;
346 if (print_sep(ms, firstline)
347 == -1)
348 return -1;
352 * This continuation matched. Print
353 * its message, with a blank before it
354 * if the previous item printed and
355 * this item isn't empty.
357 /* space if previous printed */
358 if (*need_separator
359 && ((m->flag & NOSPACE) == 0)
360 && *m->desc) {
361 if (print &&
362 file_printf(ms, " ") == -1)
363 return -1;
364 *need_separator = 0;
366 if (print && mprint(ms, m) == -1)
367 return -1;
369 switch (moffset(ms, m, nbytes,
370 &ms->c.li[cont_level].off)) {
371 case -1:
372 case 0:
373 flush = 1;
374 cont_level--;
375 break;
376 default:
377 break;
380 if (*m->desc)
381 *need_separator = 1;
384 * If we see any continuations
385 * at a higher level,
386 * process them.
388 if (file_check_mem(ms, ++cont_level) == -1)
389 return -1;
390 break;
393 if (*printed_something) {
394 firstline = 0;
395 if (print)
396 *returnval = 1;
398 if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) {
399 return *returnval; /* don't keep searching */
401 cont_level = 0;
403 return *returnval; /* This is hit if -k is set or there is no match */
406 private int
407 check_fmt(struct magic_set *ms, struct magic *m)
409 file_regex_t rx;
410 int rc, rv = -1;
412 if (strchr(m->desc, '%') == NULL)
413 return 0;
415 rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
416 if (rc) {
417 file_regerror(&rx, rc, ms);
418 } else {
419 rc = file_regexec(&rx, m->desc, 0, 0, 0);
420 rv = !rc;
422 file_regfree(&rx);
423 return rv;
426 #ifndef HAVE_STRNDUP
427 char * strndup(const char *, size_t);
429 char *
430 strndup(const char *str, size_t n)
432 size_t len;
433 char *copy;
435 for (len = 0; len < n && str[len]; len++)
436 continue;
437 if ((copy = malloc(len + 1)) == NULL)
438 return NULL;
439 (void)memcpy(copy, str, len);
440 copy[len] = '\0';
441 return copy;
443 #endif /* HAVE_STRNDUP */
445 private int32_t
446 mprint(struct magic_set *ms, struct magic *m)
448 uint64_t v;
449 float vf;
450 double vd;
451 int64_t t = 0;
452 char buf[128], tbuf[26], sbuf[512];
453 union VALUETYPE *p = &ms->ms_value;
455 switch (m->type) {
456 case FILE_BYTE:
457 v = file_signextend(ms, m, (uint64_t)p->b);
458 switch (check_fmt(ms, m)) {
459 case -1:
460 return -1;
461 case 1:
462 (void)snprintf(buf, sizeof(buf), "%d",
463 (unsigned char)v);
464 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
465 return -1;
466 break;
467 default:
468 if (file_printf(ms, F(ms, m, "%d"),
469 (unsigned char) v) == -1)
470 return -1;
471 break;
473 t = ms->offset + sizeof(char);
474 break;
476 case FILE_SHORT:
477 case FILE_BESHORT:
478 case FILE_LESHORT:
479 v = file_signextend(ms, m, (uint64_t)p->h);
480 switch (check_fmt(ms, m)) {
481 case -1:
482 return -1;
483 case 1:
484 (void)snprintf(buf, sizeof(buf), "%u",
485 (unsigned short)v);
486 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
487 return -1;
488 break;
489 default:
490 if (file_printf(ms, F(ms, m, "%u"),
491 (unsigned short) v) == -1)
492 return -1;
493 break;
495 t = ms->offset + sizeof(short);
496 break;
498 case FILE_LONG:
499 case FILE_BELONG:
500 case FILE_LELONG:
501 case FILE_MELONG:
502 v = file_signextend(ms, m, (uint64_t)p->l);
503 switch (check_fmt(ms, m)) {
504 case -1:
505 return -1;
506 case 1:
507 (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v);
508 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
509 return -1;
510 break;
511 default:
512 if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1)
513 return -1;
514 break;
516 t = ms->offset + sizeof(int32_t);
517 break;
519 case FILE_QUAD:
520 case FILE_BEQUAD:
521 case FILE_LEQUAD:
522 v = file_signextend(ms, m, p->q);
523 switch (check_fmt(ms, m)) {
524 case -1:
525 return -1;
526 case 1:
527 (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
528 (unsigned long long)v);
529 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
530 return -1;
531 break;
532 default:
533 if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"),
534 (unsigned long long) v) == -1)
535 return -1;
536 break;
538 t = ms->offset + sizeof(int64_t);
539 break;
541 case FILE_STRING:
542 case FILE_PSTRING:
543 case FILE_BESTRING16:
544 case FILE_LESTRING16:
545 if (m->reln == '=' || m->reln == '!') {
546 if (file_printf(ms, F(ms, m, "%s"),
547 file_printable(sbuf, sizeof(sbuf), m->value.s))
548 == -1)
549 return -1;
550 t = ms->offset + m->vallen;
552 else {
553 char *str = p->s;
555 /* compute t before we mangle the string? */
556 t = ms->offset + strlen(str);
558 if (*m->value.s == '\0')
559 str[strcspn(str, "\r\n")] = '\0';
561 if (m->str_flags & STRING_TRIM) {
562 char *last;
563 while (isspace((unsigned char)*str))
564 str++;
565 last = str;
566 while (*last)
567 last++;
568 --last;
569 while (isspace((unsigned char)*last))
570 last--;
571 *++last = '\0';
574 if (file_printf(ms, F(ms, m, "%s"),
575 file_printable(sbuf, sizeof(sbuf), str)) == -1)
576 return -1;
578 if (m->type == FILE_PSTRING)
579 t += file_pstring_length_size(m);
581 break;
583 case FILE_DATE:
584 case FILE_BEDATE:
585 case FILE_LEDATE:
586 case FILE_MEDATE:
587 if (file_printf(ms, F(ms, m, "%s"),
588 file_fmttime(p->l, 0, tbuf)) == -1)
589 return -1;
590 t = ms->offset + sizeof(uint32_t);
591 break;
593 case FILE_LDATE:
594 case FILE_BELDATE:
595 case FILE_LELDATE:
596 case FILE_MELDATE:
597 if (file_printf(ms, F(ms, m, "%s"),
598 file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1)
599 return -1;
600 t = ms->offset + sizeof(uint32_t);
601 break;
603 case FILE_QDATE:
604 case FILE_BEQDATE:
605 case FILE_LEQDATE:
606 if (file_printf(ms, F(ms, m, "%s"),
607 file_fmttime(p->q, 0, tbuf)) == -1)
608 return -1;
609 t = ms->offset + sizeof(uint64_t);
610 break;
612 case FILE_QLDATE:
613 case FILE_BEQLDATE:
614 case FILE_LEQLDATE:
615 if (file_printf(ms, F(ms, m, "%s"),
616 file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1)
617 return -1;
618 t = ms->offset + sizeof(uint64_t);
619 break;
621 case FILE_QWDATE:
622 case FILE_BEQWDATE:
623 case FILE_LEQWDATE:
624 if (file_printf(ms, F(ms, m, "%s"),
625 file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1)
626 return -1;
627 t = ms->offset + sizeof(uint64_t);
628 break;
630 case FILE_FLOAT:
631 case FILE_BEFLOAT:
632 case FILE_LEFLOAT:
633 vf = p->f;
634 switch (check_fmt(ms, m)) {
635 case -1:
636 return -1;
637 case 1:
638 (void)snprintf(buf, sizeof(buf), "%g", vf);
639 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
640 return -1;
641 break;
642 default:
643 if (file_printf(ms, F(ms, m, "%g"), vf) == -1)
644 return -1;
645 break;
647 t = ms->offset + sizeof(float);
648 break;
650 case FILE_DOUBLE:
651 case FILE_BEDOUBLE:
652 case FILE_LEDOUBLE:
653 vd = p->d;
654 switch (check_fmt(ms, m)) {
655 case -1:
656 return -1;
657 case 1:
658 (void)snprintf(buf, sizeof(buf), "%g", vd);
659 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
660 return -1;
661 break;
662 default:
663 if (file_printf(ms, F(ms, m, "%g"), vd) == -1)
664 return -1;
665 break;
667 t = ms->offset + sizeof(double);
668 break;
670 case FILE_SEARCH:
671 case FILE_REGEX: {
672 char *cp;
673 int rval;
675 cp = strndup((const char *)ms->search.s, ms->search.rm_len);
676 if (cp == NULL) {
677 file_oomem(ms, ms->search.rm_len);
678 return -1;
680 rval = file_printf(ms, F(ms, m, "%s"),
681 file_printable(sbuf, sizeof(sbuf), cp));
682 free(cp);
684 if (rval == -1)
685 return -1;
687 if ((m->str_flags & REGEX_OFFSET_START))
688 t = ms->search.offset;
689 else
690 t = ms->search.offset + ms->search.rm_len;
691 break;
694 case FILE_DEFAULT:
695 case FILE_CLEAR:
696 if (file_printf(ms, "%s", m->desc) == -1)
697 return -1;
698 t = ms->offset;
699 break;
701 case FILE_INDIRECT:
702 case FILE_USE:
703 case FILE_NAME:
704 t = ms->offset;
705 break;
706 case FILE_DER:
707 if (file_printf(ms, F(ms, m, "%s"),
708 file_printable(sbuf, sizeof(sbuf), ms->ms_value.s)) == -1)
709 return -1;
710 t = ms->offset;
711 break;
712 default:
713 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
714 return -1;
716 return (int32_t)t;
719 private int
720 moffset(struct magic_set *ms, struct magic *m, size_t nbytes, int32_t *op)
722 int32_t o;
724 switch (m->type) {
725 case FILE_BYTE:
726 o = CAST(int32_t, (ms->offset + sizeof(char)));
727 break;
729 case FILE_SHORT:
730 case FILE_BESHORT:
731 case FILE_LESHORT:
732 o = CAST(int32_t, (ms->offset + sizeof(short)));
733 break;
735 case FILE_LONG:
736 case FILE_BELONG:
737 case FILE_LELONG:
738 case FILE_MELONG:
739 o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
740 break;
742 case FILE_QUAD:
743 case FILE_BEQUAD:
744 case FILE_LEQUAD:
745 o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
746 break;
748 case FILE_STRING:
749 case FILE_PSTRING:
750 case FILE_BESTRING16:
751 case FILE_LESTRING16:
752 if (m->reln == '=' || m->reln == '!') {
753 o = ms->offset + m->vallen;
754 } else {
755 union VALUETYPE *p = &ms->ms_value;
757 if (*m->value.s == '\0')
758 p->s[strcspn(p->s, "\r\n")] = '\0';
759 o = CAST(uint32_t, (ms->offset + strlen(p->s)));
760 if (m->type == FILE_PSTRING)
761 o += (uint32_t)file_pstring_length_size(m);
763 break;
765 case FILE_DATE:
766 case FILE_BEDATE:
767 case FILE_LEDATE:
768 case FILE_MEDATE:
769 o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
770 break;
772 case FILE_LDATE:
773 case FILE_BELDATE:
774 case FILE_LELDATE:
775 case FILE_MELDATE:
776 o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
777 break;
779 case FILE_QDATE:
780 case FILE_BEQDATE:
781 case FILE_LEQDATE:
782 o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
783 break;
785 case FILE_QLDATE:
786 case FILE_BEQLDATE:
787 case FILE_LEQLDATE:
788 o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
789 break;
791 case FILE_FLOAT:
792 case FILE_BEFLOAT:
793 case FILE_LEFLOAT:
794 o = CAST(int32_t, (ms->offset + sizeof(float)));
795 break;
797 case FILE_DOUBLE:
798 case FILE_BEDOUBLE:
799 case FILE_LEDOUBLE:
800 o = CAST(int32_t, (ms->offset + sizeof(double)));
801 break;
803 case FILE_REGEX:
804 if ((m->str_flags & REGEX_OFFSET_START) != 0)
805 o = CAST(int32_t, ms->search.offset);
806 else
807 o = CAST(int32_t,
808 (ms->search.offset + ms->search.rm_len));
809 break;
811 case FILE_SEARCH:
812 if ((m->str_flags & REGEX_OFFSET_START) != 0)
813 o = CAST(int32_t, ms->search.offset);
814 else
815 o = CAST(int32_t, (ms->search.offset + m->vallen));
816 break;
818 case FILE_CLEAR:
819 case FILE_DEFAULT:
820 case FILE_INDIRECT:
821 o = ms->offset;
822 break;
824 case FILE_DER:
826 o = der_offs(ms, m, nbytes);
827 if (o == -1 || (size_t)o > nbytes) {
828 if ((ms->flags & MAGIC_DEBUG) != 0) {
829 (void)fprintf(stderr,
830 "Bad DER offset %d nbytes=%zu",
831 o, nbytes);
833 *op = 0;
834 return 0;
836 break;
839 default:
840 o = 0;
841 break;
844 if ((size_t)o > nbytes) {
845 #if 0
846 file_error(ms, 0, "Offset out of range %zu > %zu",
847 (size_t)o, nbytes);
848 #endif
849 return -1;
851 *op = o;
852 return 1;
855 private uint32_t
856 cvt_id3(struct magic_set *ms, uint32_t v)
858 v = ((((v >> 0) & 0x7f) << 0) |
859 (((v >> 8) & 0x7f) << 7) |
860 (((v >> 16) & 0x7f) << 14) |
861 (((v >> 24) & 0x7f) << 21));
862 if ((ms->flags & MAGIC_DEBUG) != 0)
863 fprintf(stderr, "id3 offs=%u\n", v);
864 return v;
867 private int
868 cvt_flip(int type, int flip)
870 if (flip == 0)
871 return type;
872 switch (type) {
873 case FILE_BESHORT:
874 return FILE_LESHORT;
875 case FILE_BELONG:
876 return FILE_LELONG;
877 case FILE_BEDATE:
878 return FILE_LEDATE;
879 case FILE_BELDATE:
880 return FILE_LELDATE;
881 case FILE_BEQUAD:
882 return FILE_LEQUAD;
883 case FILE_BEQDATE:
884 return FILE_LEQDATE;
885 case FILE_BEQLDATE:
886 return FILE_LEQLDATE;
887 case FILE_BEQWDATE:
888 return FILE_LEQWDATE;
889 case FILE_LESHORT:
890 return FILE_BESHORT;
891 case FILE_LELONG:
892 return FILE_BELONG;
893 case FILE_LEDATE:
894 return FILE_BEDATE;
895 case FILE_LELDATE:
896 return FILE_BELDATE;
897 case FILE_LEQUAD:
898 return FILE_BEQUAD;
899 case FILE_LEQDATE:
900 return FILE_BEQDATE;
901 case FILE_LEQLDATE:
902 return FILE_BEQLDATE;
903 case FILE_LEQWDATE:
904 return FILE_BEQWDATE;
905 case FILE_BEFLOAT:
906 return FILE_LEFLOAT;
907 case FILE_LEFLOAT:
908 return FILE_BEFLOAT;
909 case FILE_BEDOUBLE:
910 return FILE_LEDOUBLE;
911 case FILE_LEDOUBLE:
912 return FILE_BEDOUBLE;
913 default:
914 return type;
917 #define DO_CVT(fld, cast) \
918 if (m->num_mask) \
919 switch (m->mask_op & FILE_OPS_MASK) { \
920 case FILE_OPAND: \
921 p->fld &= cast m->num_mask; \
922 break; \
923 case FILE_OPOR: \
924 p->fld |= cast m->num_mask; \
925 break; \
926 case FILE_OPXOR: \
927 p->fld ^= cast m->num_mask; \
928 break; \
929 case FILE_OPADD: \
930 p->fld += cast m->num_mask; \
931 break; \
932 case FILE_OPMINUS: \
933 p->fld -= cast m->num_mask; \
934 break; \
935 case FILE_OPMULTIPLY: \
936 p->fld *= cast m->num_mask; \
937 break; \
938 case FILE_OPDIVIDE: \
939 if (cast m->num_mask == 0) \
940 return -1; \
941 p->fld /= cast m->num_mask; \
942 break; \
943 case FILE_OPMODULO: \
944 if (cast m->num_mask == 0) \
945 return -1; \
946 p->fld %= cast m->num_mask; \
947 break; \
949 if (m->mask_op & FILE_OPINVERSE) \
950 p->fld = ~p->fld \
952 private int
953 cvt_8(union VALUETYPE *p, const struct magic *m)
955 DO_CVT(b, (uint8_t));
956 return 0;
959 private int
960 cvt_16(union VALUETYPE *p, const struct magic *m)
962 DO_CVT(h, (uint16_t));
963 return 0;
966 private int
967 cvt_32(union VALUETYPE *p, const struct magic *m)
969 DO_CVT(l, (uint32_t));
970 return 0;
973 private int
974 cvt_64(union VALUETYPE *p, const struct magic *m)
976 DO_CVT(q, (uint64_t));
977 return 0;
980 #define DO_CVT2(fld, cast) \
981 if (m->num_mask) \
982 switch (m->mask_op & FILE_OPS_MASK) { \
983 case FILE_OPADD: \
984 p->fld += cast m->num_mask; \
985 break; \
986 case FILE_OPMINUS: \
987 p->fld -= cast m->num_mask; \
988 break; \
989 case FILE_OPMULTIPLY: \
990 p->fld *= cast m->num_mask; \
991 break; \
992 case FILE_OPDIVIDE: \
993 if (cast m->num_mask == 0) \
994 return -1; \
995 p->fld /= cast m->num_mask; \
996 break; \
999 private int
1000 cvt_float(union VALUETYPE *p, const struct magic *m)
1002 DO_CVT2(f, (float));
1003 return 0;
1006 private int
1007 cvt_double(union VALUETYPE *p, const struct magic *m)
1009 DO_CVT2(d, (double));
1010 return 0;
1014 * Convert the byte order of the data we are looking at
1015 * While we're here, let's apply the mask operation
1016 * (unless you have a better idea)
1018 private int
1019 mconvert(struct magic_set *ms, struct magic *m, int flip)
1021 union VALUETYPE *p = &ms->ms_value;
1023 switch (cvt_flip(m->type, flip)) {
1024 case FILE_BYTE:
1025 if (cvt_8(p, m) == -1)
1026 goto out;
1027 return 1;
1028 case FILE_SHORT:
1029 if (cvt_16(p, m) == -1)
1030 goto out;
1031 return 1;
1032 case FILE_LONG:
1033 case FILE_DATE:
1034 case FILE_LDATE:
1035 if (cvt_32(p, m) == -1)
1036 goto out;
1037 return 1;
1038 case FILE_QUAD:
1039 case FILE_QDATE:
1040 case FILE_QLDATE:
1041 case FILE_QWDATE:
1042 if (cvt_64(p, m) == -1)
1043 goto out;
1044 return 1;
1045 case FILE_STRING:
1046 case FILE_BESTRING16:
1047 case FILE_LESTRING16: {
1048 /* Null terminate and eat *trailing* return */
1049 p->s[sizeof(p->s) - 1] = '\0';
1050 return 1;
1052 case FILE_PSTRING: {
1053 size_t sz = file_pstring_length_size(m);
1054 char *ptr1 = p->s, *ptr2 = ptr1 + sz;
1055 size_t len = file_pstring_get_length(m, ptr1);
1056 sz = sizeof(p->s) - sz; /* maximum length of string */
1057 if (len >= sz) {
1059 * The size of the pascal string length (sz)
1060 * is 1, 2, or 4. We need at least 1 byte for NUL
1061 * termination, but we've already truncated the
1062 * string by p->s, so we need to deduct sz.
1063 * Because we can use one of the bytes of the length
1064 * after we shifted as NUL termination.
1066 len = sz;
1068 while (len--)
1069 *ptr1++ = *ptr2++;
1070 *ptr1 = '\0';
1071 return 1;
1073 case FILE_BESHORT:
1074 p->h = (short)BE16(p);
1075 if (cvt_16(p, m) == -1)
1076 goto out;
1077 return 1;
1078 case FILE_BELONG:
1079 case FILE_BEDATE:
1080 case FILE_BELDATE:
1081 p->l = (int32_t)BE32(p);
1082 if (cvt_32(p, m) == -1)
1083 goto out;
1084 return 1;
1085 case FILE_BEQUAD:
1086 case FILE_BEQDATE:
1087 case FILE_BEQLDATE:
1088 case FILE_BEQWDATE:
1089 p->q = (uint64_t)BE64(p);
1090 if (cvt_64(p, m) == -1)
1091 goto out;
1092 return 1;
1093 case FILE_LESHORT:
1094 p->h = (short)LE16(p);
1095 if (cvt_16(p, m) == -1)
1096 goto out;
1097 return 1;
1098 case FILE_LELONG:
1099 case FILE_LEDATE:
1100 case FILE_LELDATE:
1101 p->l = (int32_t)LE32(p);
1102 if (cvt_32(p, m) == -1)
1103 goto out;
1104 return 1;
1105 case FILE_LEQUAD:
1106 case FILE_LEQDATE:
1107 case FILE_LEQLDATE:
1108 case FILE_LEQWDATE:
1109 p->q = (uint64_t)LE64(p);
1110 if (cvt_64(p, m) == -1)
1111 goto out;
1112 return 1;
1113 case FILE_MELONG:
1114 case FILE_MEDATE:
1115 case FILE_MELDATE:
1116 p->l = (int32_t)ME32(p);
1117 if (cvt_32(p, m) == -1)
1118 goto out;
1119 return 1;
1120 case FILE_FLOAT:
1121 if (cvt_float(p, m) == -1)
1122 goto out;
1123 return 1;
1124 case FILE_BEFLOAT:
1125 p->l = BE32(p);
1126 if (cvt_float(p, m) == -1)
1127 goto out;
1128 return 1;
1129 case FILE_LEFLOAT:
1130 p->l = LE32(p);
1131 if (cvt_float(p, m) == -1)
1132 goto out;
1133 return 1;
1134 case FILE_DOUBLE:
1135 if (cvt_double(p, m) == -1)
1136 goto out;
1137 return 1;
1138 case FILE_BEDOUBLE:
1139 p->q = BE64(p);
1140 if (cvt_double(p, m) == -1)
1141 goto out;
1142 return 1;
1143 case FILE_LEDOUBLE:
1144 p->q = LE64(p);
1145 if (cvt_double(p, m) == -1)
1146 goto out;
1147 return 1;
1148 case FILE_REGEX:
1149 case FILE_SEARCH:
1150 case FILE_DEFAULT:
1151 case FILE_CLEAR:
1152 case FILE_NAME:
1153 case FILE_USE:
1154 case FILE_DER:
1155 return 1;
1156 default:
1157 file_magerror(ms, "invalid type %d in mconvert()", m->type);
1158 return 0;
1160 out:
1161 file_magerror(ms, "zerodivide in mconvert()");
1162 return 0;
1166 private void
1167 mdebug(uint32_t offset, const char *str, size_t len)
1169 (void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1170 file_showstr(stderr, str, len);
1171 (void) fputc('\n', stderr);
1172 (void) fputc('\n', stderr);
1175 private int
1176 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1177 const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1180 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1181 * anything, but setup pointers into the source
1183 if (indir == 0) {
1184 switch (type) {
1185 case FILE_DER:
1186 case FILE_SEARCH:
1187 if (offset > nbytes)
1188 offset = CAST(uint32_t, nbytes);
1189 ms->search.s = RCAST(const char *, s) + offset;
1190 ms->search.s_len = nbytes - offset;
1191 ms->search.offset = offset;
1192 return 0;
1194 case FILE_REGEX: {
1195 const char *b;
1196 const char *c;
1197 const char *last; /* end of search region */
1198 const char *buf; /* start of search region */
1199 const char *end;
1200 size_t lines, linecnt, bytecnt;
1202 if (s == NULL || nbytes < offset) {
1203 ms->search.s_len = 0;
1204 ms->search.s = NULL;
1205 return 0;
1208 if (m->str_flags & REGEX_LINE_COUNT) {
1209 linecnt = m->str_range;
1210 bytecnt = linecnt * 80;
1211 } else {
1212 linecnt = 0;
1213 bytecnt = m->str_range;
1216 if (bytecnt == 0 || bytecnt > nbytes - offset)
1217 bytecnt = nbytes - offset;
1218 if (bytecnt > ms->regex_max)
1219 bytecnt = ms->regex_max;
1221 buf = RCAST(const char *, s) + offset;
1222 end = last = RCAST(const char *, s) + bytecnt + offset;
1223 /* mget() guarantees buf <= last */
1224 for (lines = linecnt, b = buf; lines && b < end &&
1225 ((b = CAST(const char *,
1226 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1227 || (b = CAST(const char *,
1228 memchr(c, '\r', CAST(size_t, (end - c))))));
1229 lines--, b++) {
1230 last = b;
1231 if (b < end - 1 && b[0] == '\r' && b[1] == '\n')
1232 b++;
1234 if (lines)
1235 last = RCAST(const char *, s) + bytecnt;
1237 ms->search.s = buf;
1238 ms->search.s_len = last - buf;
1239 ms->search.offset = offset;
1240 ms->search.rm_len = 0;
1241 return 0;
1243 case FILE_BESTRING16:
1244 case FILE_LESTRING16: {
1245 const unsigned char *src = s + offset;
1246 const unsigned char *esrc = s + nbytes;
1247 char *dst = p->s;
1248 char *edst = &p->s[sizeof(p->s) - 1];
1250 if (type == FILE_BESTRING16)
1251 src++;
1253 /* check that offset is within range */
1254 if (offset >= nbytes)
1255 break;
1256 for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1257 if (dst < edst)
1258 *dst = *src;
1259 else
1260 break;
1261 if (*dst == '\0') {
1262 if (type == FILE_BESTRING16 ?
1263 *(src - 1) != '\0' :
1264 ((src + 1 < esrc) &&
1265 *(src + 1) != '\0'))
1266 *dst = ' ';
1269 *edst = '\0';
1270 return 0;
1272 case FILE_STRING: /* XXX - these two should not need */
1273 case FILE_PSTRING: /* to copy anything, but do anyway. */
1274 default:
1275 break;
1279 if (offset >= nbytes) {
1280 (void)memset(p, '\0', sizeof(*p));
1281 return 0;
1283 if (nbytes - offset < sizeof(*p))
1284 nbytes = nbytes - offset;
1285 else
1286 nbytes = sizeof(*p);
1288 (void)memcpy(p, s + offset, nbytes);
1291 * the usefulness of padding with zeroes eludes me, it
1292 * might even cause problems
1294 if (nbytes < sizeof(*p))
1295 (void)memset(((char *)(void *)p) + nbytes, '\0',
1296 sizeof(*p) - nbytes);
1297 return 0;
1300 private uint32_t
1301 do_ops(struct magic *m, intmax_t lhs, intmax_t off)
1303 intmax_t offset = 0;
1304 if (off) {
1305 switch (m->in_op & FILE_OPS_MASK) {
1306 case FILE_OPAND:
1307 offset = lhs & off;
1308 break;
1309 case FILE_OPOR:
1310 offset = lhs | off;
1311 break;
1312 case FILE_OPXOR:
1313 offset = lhs ^ off;
1314 break;
1315 case FILE_OPADD:
1316 offset = lhs + off;
1317 break;
1318 case FILE_OPMINUS:
1319 offset = lhs - off;
1320 break;
1321 case FILE_OPMULTIPLY:
1322 offset = lhs * off;
1323 break;
1324 case FILE_OPDIVIDE:
1325 offset = lhs / off;
1326 break;
1327 case FILE_OPMODULO:
1328 offset = lhs % off;
1329 break;
1331 } else
1332 offset = lhs;
1333 if (m->in_op & FILE_OPINVERSE)
1334 offset = ~offset;
1336 return (uint32_t)offset;
1339 private int
1340 mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
1341 size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
1342 int flip, uint16_t *indir_count, uint16_t *name_count,
1343 int *printed_something, int *need_separator, int *returnval)
1345 uint32_t offset = ms->offset;
1346 intmax_t lhs;
1347 file_pushbuf_t *pb;
1348 int rv, oneed_separator, in_type;
1349 char *rbuf;
1350 union VALUETYPE *p = &ms->ms_value;
1351 struct mlist ml;
1353 if (*indir_count >= ms->indir_max) {
1354 file_error(ms, 0, "indirect count (%hu) exceeded",
1355 *indir_count);
1356 return -1;
1359 if (*name_count >= ms->name_max) {
1360 file_error(ms, 0, "name use count (%hu) exceeded",
1361 *name_count);
1362 return -1;
1365 if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
1366 (uint32_t)nbytes, m) == -1)
1367 return -1;
1369 if ((ms->flags & MAGIC_DEBUG) != 0) {
1370 fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%"
1371 SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1372 "u, il=%hu, nc=%hu)\n",
1373 m->type, m->flag, offset, o, nbytes,
1374 *indir_count, *name_count);
1375 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1376 #ifndef COMPILE_ONLY
1377 file_mdump(m);
1378 #endif
1381 if (m->flag & INDIR) {
1382 intmax_t off = m->in_offset;
1383 const int sgn = m->in_op & FILE_OPSIGNED;
1384 if (m->in_op & FILE_OPINDIRECT) {
1385 const union VALUETYPE *q = CAST(const union VALUETYPE *,
1386 ((const void *)(s + offset + off)));
1387 if (OFFSET_OOB(nbytes, offset + off, sizeof(*q)))
1388 return 0;
1389 switch (cvt_flip(m->in_type, flip)) {
1390 case FILE_BYTE:
1391 off = SEXT(sgn,8,q->b);
1392 break;
1393 case FILE_SHORT:
1394 off = SEXT(sgn,16,q->h);
1395 break;
1396 case FILE_BESHORT:
1397 off = SEXT(sgn,16,BE16(q));
1398 break;
1399 case FILE_LESHORT:
1400 off = SEXT(sgn,16,LE16(q));
1401 break;
1402 case FILE_LONG:
1403 off = SEXT(sgn,32,q->l);
1404 break;
1405 case FILE_BELONG:
1406 case FILE_BEID3:
1407 off = SEXT(sgn,32,BE32(q));
1408 break;
1409 case FILE_LEID3:
1410 case FILE_LELONG:
1411 off = SEXT(sgn,32,LE32(q));
1412 break;
1413 case FILE_MELONG:
1414 off = SEXT(sgn,32,ME32(q));
1415 break;
1417 if ((ms->flags & MAGIC_DEBUG) != 0)
1418 fprintf(stderr, "indirect offs=%jd\n", off);
1420 switch (in_type = cvt_flip(m->in_type, flip)) {
1421 case FILE_BYTE:
1422 if (OFFSET_OOB(nbytes, offset, 1))
1423 return 0;
1424 offset = do_ops(m, SEXT(sgn,8,p->b), off);
1425 break;
1426 case FILE_BESHORT:
1427 if (OFFSET_OOB(nbytes, offset, 2))
1428 return 0;
1429 offset = do_ops(m, SEXT(sgn,16,BE16(p)), off);
1430 break;
1431 case FILE_LESHORT:
1432 if (OFFSET_OOB(nbytes, offset, 2))
1433 return 0;
1434 offset = do_ops(m, SEXT(sgn,16,LE16(p)), off);
1435 break;
1436 case FILE_SHORT:
1437 if (OFFSET_OOB(nbytes, offset, 2))
1438 return 0;
1439 offset = do_ops(m, SEXT(sgn,16,p->h), off);
1440 break;
1441 case FILE_BELONG:
1442 case FILE_BEID3:
1443 if (OFFSET_OOB(nbytes, offset, 4))
1444 return 0;
1445 lhs = BE32(p);
1446 if (in_type == FILE_BEID3)
1447 lhs = cvt_id3(ms, (uint32_t)lhs);
1448 offset = do_ops(m, SEXT(sgn,32,lhs), off);
1449 break;
1450 case FILE_LELONG:
1451 case FILE_LEID3:
1452 if (OFFSET_OOB(nbytes, offset, 4))
1453 return 0;
1454 lhs = LE32(p);
1455 if (in_type == FILE_LEID3)
1456 lhs = cvt_id3(ms, (uint32_t)lhs);
1457 offset = do_ops(m, SEXT(sgn,32,lhs), off);
1458 break;
1459 case FILE_MELONG:
1460 if (OFFSET_OOB(nbytes, offset, 4))
1461 return 0;
1462 offset = do_ops(m, SEXT(sgn,32,ME32(p)), off);
1463 break;
1464 case FILE_LONG:
1465 if (OFFSET_OOB(nbytes, offset, 4))
1466 return 0;
1467 offset = do_ops(m, SEXT(sgn,32,p->l), off);
1468 break;
1469 default:
1470 break;
1473 if (m->flag & INDIROFFADD) {
1474 offset += ms->c.li[cont_level-1].off;
1475 if (offset == 0) {
1476 if ((ms->flags & MAGIC_DEBUG) != 0)
1477 fprintf(stderr,
1478 "indirect *zero* offset\n");
1479 return 0;
1481 if ((ms->flags & MAGIC_DEBUG) != 0)
1482 fprintf(stderr, "indirect +offs=%u\n", offset);
1484 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1485 return -1;
1486 ms->offset = offset;
1488 if ((ms->flags & MAGIC_DEBUG) != 0) {
1489 mdebug(offset, (char *)(void *)p,
1490 sizeof(union VALUETYPE));
1491 #ifndef COMPILE_ONLY
1492 file_mdump(m);
1493 #endif
1497 /* Verify we have enough data to match magic type */
1498 switch (m->type) {
1499 case FILE_BYTE:
1500 if (OFFSET_OOB(nbytes, offset, 1))
1501 return 0;
1502 break;
1504 case FILE_SHORT:
1505 case FILE_BESHORT:
1506 case FILE_LESHORT:
1507 if (OFFSET_OOB(nbytes, offset, 2))
1508 return 0;
1509 break;
1511 case FILE_LONG:
1512 case FILE_BELONG:
1513 case FILE_LELONG:
1514 case FILE_MELONG:
1515 case FILE_DATE:
1516 case FILE_BEDATE:
1517 case FILE_LEDATE:
1518 case FILE_MEDATE:
1519 case FILE_LDATE:
1520 case FILE_BELDATE:
1521 case FILE_LELDATE:
1522 case FILE_MELDATE:
1523 case FILE_FLOAT:
1524 case FILE_BEFLOAT:
1525 case FILE_LEFLOAT:
1526 if (OFFSET_OOB(nbytes, offset, 4))
1527 return 0;
1528 break;
1530 case FILE_DOUBLE:
1531 case FILE_BEDOUBLE:
1532 case FILE_LEDOUBLE:
1533 if (OFFSET_OOB(nbytes, offset, 8))
1534 return 0;
1535 break;
1537 case FILE_STRING:
1538 case FILE_PSTRING:
1539 case FILE_SEARCH:
1540 if (OFFSET_OOB(nbytes, offset, m->vallen))
1541 return 0;
1542 break;
1544 case FILE_REGEX:
1545 if (nbytes < offset)
1546 return 0;
1547 break;
1549 case FILE_INDIRECT:
1550 if (m->str_flags & INDIRECT_RELATIVE)
1551 offset += CAST(uint32_t, o);
1552 if (offset == 0)
1553 return 0;
1555 if (nbytes < offset)
1556 return 0;
1558 if ((pb = file_push_buffer(ms)) == NULL)
1559 return -1;
1561 (*indir_count)++;
1562 rv = file_softmagic(ms, s + offset, nbytes - offset,
1563 indir_count, name_count, BINTEST, text);
1565 if ((ms->flags & MAGIC_DEBUG) != 0)
1566 fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1568 rbuf = file_pop_buffer(ms, pb);
1569 if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1570 return -1;
1572 if (rv == 1) {
1573 if ((ms->flags & MAGIC_NODESC) == 0 &&
1574 file_printf(ms, F(ms, m, "%u"), offset) == -1) {
1575 free(rbuf);
1576 return -1;
1578 if (file_printf(ms, "%s", rbuf) == -1) {
1579 free(rbuf);
1580 return -1;
1583 free(rbuf);
1584 return rv;
1586 case FILE_USE:
1587 if (nbytes < offset)
1588 return 0;
1589 rbuf = m->value.s;
1590 if (*rbuf == '^') {
1591 rbuf++;
1592 flip = !flip;
1594 if (file_magicfind(ms, rbuf, &ml) == -1) {
1595 file_error(ms, 0, "cannot find entry `%s'", rbuf);
1596 return -1;
1598 (*name_count)++;
1599 oneed_separator = *need_separator;
1600 if (m->flag & NOSPACE)
1601 *need_separator = 0;
1602 rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
1603 mode, text, flip, indir_count, name_count,
1604 printed_something, need_separator, returnval);
1605 if (rv != 1)
1606 *need_separator = oneed_separator;
1607 return 1;
1609 case FILE_NAME:
1610 if (ms->flags & MAGIC_NODESC)
1611 return 1;
1612 if (file_printf(ms, "%s", m->desc) == -1)
1613 return -1;
1614 return 1;
1615 case FILE_DER:
1616 case FILE_DEFAULT: /* nothing to check */
1617 case FILE_CLEAR:
1618 default:
1619 break;
1621 if (!mconvert(ms, m, flip))
1622 return 0;
1623 return 1;
1626 private uint64_t
1627 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1630 * Convert the source args to unsigned here so that (1) the
1631 * compare will be unsigned as it is in strncmp() and (2) so
1632 * the ctype functions will work correctly without extra
1633 * casting.
1635 const unsigned char *a = (const unsigned char *)s1;
1636 const unsigned char *b = (const unsigned char *)s2;
1637 const unsigned char *eb = b + len;
1638 uint64_t v;
1641 * What we want here is v = strncmp(s1, s2, len),
1642 * but ignoring any nulls.
1644 v = 0;
1645 if (0L == flags) { /* normal string: do it fast */
1646 while (len-- > 0)
1647 if ((v = *b++ - *a++) != '\0')
1648 break;
1650 else { /* combine the others */
1651 while (len-- > 0) {
1652 if (b >= eb) {
1653 v = 1;
1654 break;
1656 if ((flags & STRING_IGNORE_LOWERCASE) &&
1657 islower(*a)) {
1658 if ((v = tolower(*b++) - *a++) != '\0')
1659 break;
1661 else if ((flags & STRING_IGNORE_UPPERCASE) &&
1662 isupper(*a)) {
1663 if ((v = toupper(*b++) - *a++) != '\0')
1664 break;
1666 else if ((flags & STRING_COMPACT_WHITESPACE) &&
1667 isspace(*a)) {
1668 a++;
1669 if (isspace(*b++)) {
1670 if (!isspace(*a))
1671 while (b < eb && isspace(*b))
1672 b++;
1674 else {
1675 v = 1;
1676 break;
1679 else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1680 isspace(*a)) {
1681 a++;
1682 while (b < eb && isspace(*b))
1683 b++;
1685 else {
1686 if ((v = *b++ - *a++) != '\0')
1687 break;
1691 return v;
1694 private uint64_t
1695 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1698 * XXX - The 16-bit string compare probably needs to be done
1699 * differently, especially if the flags are to be supported.
1700 * At the moment, I am unsure.
1702 flags = 0;
1703 return file_strncmp(a, b, len, flags);
1706 private int
1707 magiccheck(struct magic_set *ms, struct magic *m)
1709 uint64_t l = m->value.q;
1710 uint64_t v;
1711 float fl, fv;
1712 double dl, dv;
1713 int matched;
1714 union VALUETYPE *p = &ms->ms_value;
1716 switch (m->type) {
1717 case FILE_BYTE:
1718 v = p->b;
1719 break;
1721 case FILE_SHORT:
1722 case FILE_BESHORT:
1723 case FILE_LESHORT:
1724 v = p->h;
1725 break;
1727 case FILE_LONG:
1728 case FILE_BELONG:
1729 case FILE_LELONG:
1730 case FILE_MELONG:
1731 case FILE_DATE:
1732 case FILE_BEDATE:
1733 case FILE_LEDATE:
1734 case FILE_MEDATE:
1735 case FILE_LDATE:
1736 case FILE_BELDATE:
1737 case FILE_LELDATE:
1738 case FILE_MELDATE:
1739 v = p->l;
1740 break;
1742 case FILE_QUAD:
1743 case FILE_LEQUAD:
1744 case FILE_BEQUAD:
1745 case FILE_QDATE:
1746 case FILE_BEQDATE:
1747 case FILE_LEQDATE:
1748 case FILE_QLDATE:
1749 case FILE_BEQLDATE:
1750 case FILE_LEQLDATE:
1751 case FILE_QWDATE:
1752 case FILE_BEQWDATE:
1753 case FILE_LEQWDATE:
1754 v = p->q;
1755 break;
1757 case FILE_FLOAT:
1758 case FILE_BEFLOAT:
1759 case FILE_LEFLOAT:
1760 fl = m->value.f;
1761 fv = p->f;
1762 switch (m->reln) {
1763 case 'x':
1764 matched = 1;
1765 break;
1767 case '!':
1768 matched = fv != fl;
1769 break;
1771 case '=':
1772 matched = fv == fl;
1773 break;
1775 case '>':
1776 matched = fv > fl;
1777 break;
1779 case '<':
1780 matched = fv < fl;
1781 break;
1783 default:
1784 file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1785 m->reln);
1786 return -1;
1788 return matched;
1790 case FILE_DOUBLE:
1791 case FILE_BEDOUBLE:
1792 case FILE_LEDOUBLE:
1793 dl = m->value.d;
1794 dv = p->d;
1795 switch (m->reln) {
1796 case 'x':
1797 matched = 1;
1798 break;
1800 case '!':
1801 matched = dv != dl;
1802 break;
1804 case '=':
1805 matched = dv == dl;
1806 break;
1808 case '>':
1809 matched = dv > dl;
1810 break;
1812 case '<':
1813 matched = dv < dl;
1814 break;
1816 default:
1817 file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1818 return -1;
1820 return matched;
1822 case FILE_DEFAULT:
1823 case FILE_CLEAR:
1824 l = 0;
1825 v = 0;
1826 break;
1828 case FILE_STRING:
1829 case FILE_PSTRING:
1830 l = 0;
1831 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1832 break;
1834 case FILE_BESTRING16:
1835 case FILE_LESTRING16:
1836 l = 0;
1837 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1838 break;
1840 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1841 size_t slen;
1842 size_t idx;
1844 if (ms->search.s == NULL)
1845 return 0;
1847 slen = MIN(m->vallen, sizeof(m->value.s));
1848 l = 0;
1849 v = 0;
1851 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1852 if (slen + idx > ms->search.s_len)
1853 return 0;
1855 v = file_strncmp(m->value.s, ms->search.s + idx, slen,
1856 m->str_flags);
1857 if (v == 0) { /* found match */
1858 ms->search.offset += idx;
1859 ms->search.rm_len = ms->search.s_len - idx;
1860 break;
1863 break;
1865 case FILE_REGEX: {
1866 int rc;
1867 file_regex_t rx;
1868 const char *search;
1870 if (ms->search.s == NULL)
1871 return 0;
1873 l = 0;
1874 rc = file_regcomp(&rx, m->value.s,
1875 REG_EXTENDED|REG_NEWLINE|
1876 ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
1877 if (rc) {
1878 file_regerror(&rx, rc, ms);
1879 v = (uint64_t)-1;
1880 } else {
1881 regmatch_t pmatch;
1882 size_t slen = ms->search.s_len;
1883 char *copy;
1884 if (slen != 0) {
1885 copy = CAST(char *, malloc(slen));
1886 if (copy == NULL) {
1887 file_regfree(&rx);
1888 file_error(ms, errno,
1889 "can't allocate %" SIZE_T_FORMAT "u bytes",
1890 slen);
1891 return -1;
1893 memcpy(copy, ms->search.s, slen);
1894 copy[--slen] = '\0';
1895 search = copy;
1896 } else {
1897 search = CCAST(char *, "");
1898 copy = NULL;
1900 rc = file_regexec(&rx, (const char *)search,
1901 1, &pmatch, 0);
1902 free(copy);
1903 switch (rc) {
1904 case 0:
1905 ms->search.s += (int)pmatch.rm_so;
1906 ms->search.offset += (size_t)pmatch.rm_so;
1907 ms->search.rm_len =
1908 (size_t)(pmatch.rm_eo - pmatch.rm_so);
1909 v = 0;
1910 break;
1912 case REG_NOMATCH:
1913 v = 1;
1914 break;
1916 default:
1917 file_regerror(&rx, rc, ms);
1918 v = (uint64_t)-1;
1919 break;
1922 file_regfree(&rx);
1923 if (v == (uint64_t)-1)
1924 return -1;
1925 break;
1927 case FILE_INDIRECT:
1928 case FILE_USE:
1929 case FILE_NAME:
1930 return 1;
1931 case FILE_DER:
1932 matched = der_cmp(ms, m);
1933 if (matched == -1) {
1934 if ((ms->flags & MAGIC_DEBUG) != 0) {
1935 (void) fprintf(stderr,
1936 "EOF comparing DER entries");
1938 return 0;
1940 return matched;
1941 default:
1942 file_magerror(ms, "invalid type %d in magiccheck()", m->type);
1943 return -1;
1946 v = file_signextend(ms, m, v);
1948 switch (m->reln) {
1949 case 'x':
1950 if ((ms->flags & MAGIC_DEBUG) != 0)
1951 (void) fprintf(stderr, "%" INT64_T_FORMAT
1952 "u == *any* = 1\n", (unsigned long long)v);
1953 matched = 1;
1954 break;
1956 case '!':
1957 matched = v != l;
1958 if ((ms->flags & MAGIC_DEBUG) != 0)
1959 (void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
1960 INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
1961 (unsigned long long)l, matched);
1962 break;
1964 case '=':
1965 matched = v == l;
1966 if ((ms->flags & MAGIC_DEBUG) != 0)
1967 (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
1968 INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
1969 (unsigned long long)l, matched);
1970 break;
1972 case '>':
1973 if (m->flag & UNSIGNED) {
1974 matched = v > l;
1975 if ((ms->flags & MAGIC_DEBUG) != 0)
1976 (void) fprintf(stderr, "%" INT64_T_FORMAT
1977 "u > %" INT64_T_FORMAT "u = %d\n",
1978 (unsigned long long)v,
1979 (unsigned long long)l, matched);
1981 else {
1982 matched = (int64_t) v > (int64_t) l;
1983 if ((ms->flags & MAGIC_DEBUG) != 0)
1984 (void) fprintf(stderr, "%" INT64_T_FORMAT
1985 "d > %" INT64_T_FORMAT "d = %d\n",
1986 (long long)v, (long long)l, matched);
1988 break;
1990 case '<':
1991 if (m->flag & UNSIGNED) {
1992 matched = v < l;
1993 if ((ms->flags & MAGIC_DEBUG) != 0)
1994 (void) fprintf(stderr, "%" INT64_T_FORMAT
1995 "u < %" INT64_T_FORMAT "u = %d\n",
1996 (unsigned long long)v,
1997 (unsigned long long)l, matched);
1999 else {
2000 matched = (int64_t) v < (int64_t) l;
2001 if ((ms->flags & MAGIC_DEBUG) != 0)
2002 (void) fprintf(stderr, "%" INT64_T_FORMAT
2003 "d < %" INT64_T_FORMAT "d = %d\n",
2004 (long long)v, (long long)l, matched);
2006 break;
2008 case '&':
2009 matched = (v & l) == l;
2010 if ((ms->flags & MAGIC_DEBUG) != 0)
2011 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2012 INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2013 "x) = %d\n", (unsigned long long)v,
2014 (unsigned long long)l, (unsigned long long)l,
2015 matched);
2016 break;
2018 case '^':
2019 matched = (v & l) != l;
2020 if ((ms->flags & MAGIC_DEBUG) != 0)
2021 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2022 INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2023 "x) = %d\n", (unsigned long long)v,
2024 (unsigned long long)l, (unsigned long long)l,
2025 matched);
2026 break;
2028 default:
2029 file_magerror(ms, "cannot happen: invalid relation `%c'",
2030 m->reln);
2031 return -1;
2034 return matched;
2037 private int
2038 handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
2040 if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
2041 if (!firstline && file_printf(ms, "\n- ") == -1)
2042 return -1;
2043 if (file_printf(ms, "%.8s", m->apple) == -1)
2044 return -1;
2045 return 1;
2047 if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
2048 if (!firstline && file_printf(ms, "\n- ") == -1)
2049 return -1;
2050 if (file_printf(ms, "%s", m->ext) == -1)
2051 return -1;
2052 return 1;
2054 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2055 if (!firstline && file_printf(ms, "\n- ") == -1)
2056 return -1;
2057 if (file_printf(ms, "%s", m->mimetype) == -1)
2058 return -1;
2059 return 1;
2061 return 0;
2064 private int
2065 print_sep(struct magic_set *ms, int firstline)
2067 // if (ms->flags & MAGIC_NODESC)
2068 // return 0;
2069 if (firstline)
2070 return 0;
2072 * we found another match
2073 * put a newline and '-' to do some simple formatting
2075 return file_printf(ms, "\n- ");