xref: /freebsd/contrib/file/src/softmagic.c (revision 7453645f2a9411a3f9d982b768bcc323f41cf906)
1 /*
2  * Copyright (c) Ian F. Darwin 1986-1995.
3  * Software written by Ian F. Darwin and others;
4  * maintained 1995-present by Christos Zoulas and others.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice immediately at the beginning of the file, without modification,
11  *    this list of conditions, and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 /*
29  * softmagic - interpret variable magic from MAGIC
30  */
31 
32 #include "file.h"
33 
34 #ifndef	lint
35 FILE_RCSID("@(#)$File: softmagic.c,v 1.234 2016/06/13 12:02:06 christos Exp $")
36 #endif	/* lint */
37 
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"
45 
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 *);
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 *);
65 
66 #define OFFSET_OOB(n, o, i)	((n) < (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 
84 /*
85  * softmagic - lookup one file in parsed, in-memory copy of database
86  * Passed the name and FILE * of one file to be typed.
87  */
88 /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
89 protected int
90 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
91     uint16_t *indir_count, uint16_t *name_count, int mode, int text)
92 {
93 	struct mlist *ml;
94 	int rv, printed_something = 0, need_separator = 0;
95 	uint16_t nc, ic;
96 
97 	if (name_count == NULL) {
98 		nc = 0;
99 		name_count = &nc;
100 	}
101 	if (indir_count == NULL) {
102 		ic = 0;
103 		indir_count = &ic;
104 	}
105 
106 	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
107 		if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
108 		    text, 0, indir_count, name_count,
109 		    &printed_something, &need_separator, NULL)) != 0)
110 			return rv;
111 
112 	return 0;
113 }
114 
115 #define FILE_FMTDEBUG
116 #ifdef FILE_FMTDEBUG
117 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
118 
119 private const char * __attribute__((__format_arg__(3)))
120 file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def,
121 	const char *file, size_t line)
122 {
123 	const char *ptr = fmtcheck(m->desc, def);
124 	if (ptr == def)
125 		file_magerror(ms,
126 		    "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
127 		    " with `%s'", file, line, m->desc, def);
128 	return ptr;
129 }
130 #else
131 #define F(a, b, c) fmtcheck((b)->desc, (c))
132 #endif
133 
134 /*
135  * Go through the whole list, stopping if you find a match.  Process all
136  * the continuations of that match before returning.
137  *
138  * We support multi-level continuations:
139  *
140  *	At any time when processing a successful top-level match, there is a
141  *	current continuation level; it represents the level of the last
142  *	successfully matched continuation.
143  *
144  *	Continuations above that level are skipped as, if we see one, it
145  *	means that the continuation that controls them - i.e, the
146  *	lower-level continuation preceding them - failed to match.
147  *
148  *	Continuations below that level are processed as, if we see one,
149  *	it means we've finished processing or skipping higher-level
150  *	continuations under the control of a successful or unsuccessful
151  *	lower-level continuation, and are now seeing the next lower-level
152  *	continuation and should process it.  The current continuation
153  *	level reverts to the level of the one we're seeing.
154  *
155  *	Continuations at the current level are processed as, if we see
156  *	one, there's no lower-level continuation that may have failed.
157  *
158  *	If a continuation matches, we bump the current continuation level
159  *	so that higher-level continuations are processed.
160  */
161 private int
162 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
163     const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
164     int flip, uint16_t *indir_count, uint16_t *name_count,
165     int *printed_something, int *need_separator, int *returnval)
166 {
167 	uint32_t magindex = 0;
168 	unsigned int cont_level = 0;
169 	int returnvalv = 0, e; /* if a match is found it is set to 1*/
170 	int firstline = 1; /* a flag to print X\n  X\n- X */
171 	int print = (ms->flags & MAGIC_NODESC) == 0;
172 
173 	if (returnval == NULL)
174 		returnval = &returnvalv;
175 
176 	if (file_check_mem(ms, cont_level) == -1)
177 		return -1;
178 
179 	for (magindex = 0; magindex < nmagic; magindex++) {
180 		int flush = 0;
181 		struct magic *m = &magic[magindex];
182 
183 		if (m->type != FILE_NAME)
184 		if ((IS_STRING(m->type) &&
185 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
186 		     ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
187 		      (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
188 		    (m->flag & mode) != mode) {
189 flush:
190 			/* Skip sub-tests */
191 			while (magindex < nmagic - 1 &&
192 			    magic[magindex + 1].cont_level != 0)
193 				magindex++;
194 			continue; /* Skip to next top-level test*/
195 		}
196 
197 		ms->offset = m->offset;
198 		ms->line = m->lineno;
199 
200 		/* if main entry matches, print it... */
201 		switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
202 		    flip, indir_count, name_count,
203 		    printed_something, need_separator, returnval)) {
204 		case -1:
205 			return -1;
206 		case 0:
207 			flush = m->reln != '!';
208 			break;
209 		default:
210 			if (m->type == FILE_INDIRECT)
211 				*returnval = 1;
212 
213 			switch (magiccheck(ms, m)) {
214 			case -1:
215 				return -1;
216 			case 0:
217 				flush++;
218 				break;
219 			default:
220 				flush = 0;
221 				break;
222 			}
223 			break;
224 		}
225 		if (flush) {
226 			/*
227 			 * main entry didn't match,
228 			 * flush its continuations
229 			 */
230 			goto flush;
231 		}
232 
233 		if ((e = handle_annotation(ms, m)) != 0) {
234 			*need_separator = 1;
235 			*printed_something = 1;
236 			*returnval = 1;
237 			return e;
238 		}
239 
240 		/*
241 		 * If we are going to print something, we'll need to print
242 		 * a blank before we print something else.
243 		 */
244 		if (*m->desc) {
245 			*need_separator = 1;
246 			*printed_something = 1;
247 			if (print_sep(ms, firstline) == -1)
248 				return -1;
249 		}
250 
251 
252 		if (print && mprint(ms, m) == -1)
253 			return -1;
254 
255 		switch (moffset(ms, m, nbytes, &ms->c.li[cont_level].off)) {
256 		case -1:
257 		case 0:
258 			goto flush;
259 		default:
260 			break;
261 		}
262 
263 		/* and any continuations that match */
264 		if (file_check_mem(ms, ++cont_level) == -1)
265 			return -1;
266 
267 		while (magindex + 1 < nmagic &&
268 		    magic[magindex + 1].cont_level != 0) {
269 			m = &magic[++magindex];
270 			ms->line = m->lineno; /* for messages */
271 
272 			if (cont_level < m->cont_level)
273 				continue;
274 			if (cont_level > m->cont_level) {
275 				/*
276 				 * We're at the end of the level
277 				 * "cont_level" continuations.
278 				 */
279 				cont_level = m->cont_level;
280 			}
281 			ms->offset = m->offset;
282 			if (m->flag & OFFADD) {
283 				ms->offset +=
284 				    ms->c.li[cont_level - 1].off;
285 			}
286 
287 #ifdef ENABLE_CONDITIONALS
288 			if (m->cond == COND_ELSE ||
289 			    m->cond == COND_ELIF) {
290 				if (ms->c.li[cont_level].last_match == 1)
291 					continue;
292 			}
293 #endif
294 			switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
295 			    text, flip, indir_count, name_count,
296 			    printed_something, need_separator, returnval)) {
297 			case -1:
298 				return -1;
299 			case 0:
300 				if (m->reln != '!')
301 					continue;
302 				flush = 1;
303 				break;
304 			default:
305 				if (m->type == FILE_INDIRECT)
306 					*returnval = 1;
307 				flush = 0;
308 				break;
309 			}
310 
311 			switch (flush ? 1 : magiccheck(ms, m)) {
312 			case -1:
313 				return -1;
314 			case 0:
315 #ifdef ENABLE_CONDITIONALS
316 				ms->c.li[cont_level].last_match = 0;
317 #endif
318 				break;
319 			default:
320 #ifdef ENABLE_CONDITIONALS
321 				ms->c.li[cont_level].last_match = 1;
322 #endif
323 				if (m->type == FILE_CLEAR)
324 					ms->c.li[cont_level].got_match = 0;
325 				else if (ms->c.li[cont_level].got_match) {
326 					if (m->type == FILE_DEFAULT)
327 						break;
328 				} else
329 					ms->c.li[cont_level].got_match = 1;
330 
331 				if ((e = handle_annotation(ms, m)) != 0) {
332 					*need_separator = 1;
333 					*printed_something = 1;
334 					*returnval = 1;
335 					return e;
336 				}
337 				/*
338 				 * If we are going to print something,
339 				 * make sure that we have a separator first.
340 				 */
341 				if (*m->desc) {
342 					if (!*printed_something) {
343 						*printed_something = 1;
344 						if (print_sep(ms, firstline)
345 						    == -1)
346 							return -1;
347 					}
348 				}
349 				/*
350 				 * This continuation matched.  Print
351 				 * its message, with a blank before it
352 				 * if the previous item printed and
353 				 * this item isn't empty.
354 				 */
355 				/* space if previous printed */
356 				if (*need_separator
357 				    && ((m->flag & NOSPACE) == 0)
358 				    && *m->desc) {
359 					if (print &&
360 					    file_printf(ms, " ") == -1)
361 						return -1;
362 					*need_separator = 0;
363 				}
364 				if (print && mprint(ms, m) == -1)
365 					return -1;
366 
367 				switch (moffset(ms, m, nbytes,
368 				    &ms->c.li[cont_level].off)) {
369 				case -1:
370 				case 0:
371 					flush = 1;
372 					break;
373 				default:
374 					break;
375 				}
376 
377 				if (*m->desc)
378 					*need_separator = 1;
379 
380 				/*
381 				 * If we see any continuations
382 				 * at a higher level,
383 				 * process them.
384 				 */
385 				if (file_check_mem(ms, ++cont_level) == -1)
386 					return -1;
387 				break;
388 			}
389 		}
390 		if (*printed_something) {
391 			firstline = 0;
392 			if (print)
393 				*returnval = 1;
394 		}
395 		if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) {
396 			return *returnval; /* don't keep searching */
397 		}
398 		cont_level = 0;
399 	}
400 	return *returnval;  /* This is hit if -k is set or there is no match */
401 }
402 
403 private int
404 check_fmt(struct magic_set *ms, struct magic *m)
405 {
406 	file_regex_t rx;
407 	int rc, rv = -1;
408 
409 	if (strchr(m->desc, '%') == NULL)
410 		return 0;
411 
412 	rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
413 	if (rc) {
414 		file_regerror(&rx, rc, ms);
415 	} else {
416 		rc = file_regexec(&rx, m->desc, 0, 0, 0);
417 		rv = !rc;
418 	}
419 	file_regfree(&rx);
420 	return rv;
421 }
422 
423 #ifndef HAVE_STRNDUP
424 char * strndup(const char *, size_t);
425 
426 char *
427 strndup(const char *str, size_t n)
428 {
429 	size_t len;
430 	char *copy;
431 
432 	for (len = 0; len < n && str[len]; len++)
433 		continue;
434 	if ((copy = malloc(len + 1)) == NULL)
435 		return NULL;
436 	(void)memcpy(copy, str, len);
437 	copy[len] = '\0';
438 	return copy;
439 }
440 #endif /* HAVE_STRNDUP */
441 
442 private int32_t
443 mprint(struct magic_set *ms, struct magic *m)
444 {
445 	uint64_t v;
446 	float vf;
447 	double vd;
448 	int64_t t = 0;
449  	char buf[128], tbuf[26], sbuf[512];
450 	union VALUETYPE *p = &ms->ms_value;
451 
452   	switch (m->type) {
453   	case FILE_BYTE:
454 		v = file_signextend(ms, m, (uint64_t)p->b);
455 		switch (check_fmt(ms, m)) {
456 		case -1:
457 			return -1;
458 		case 1:
459 			(void)snprintf(buf, sizeof(buf), "%d",
460 			    (unsigned char)v);
461 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
462 				return -1;
463 			break;
464 		default:
465 			if (file_printf(ms, F(ms, m, "%d"),
466 			    (unsigned char) v) == -1)
467 				return -1;
468 			break;
469 		}
470 		t = ms->offset + sizeof(char);
471 		break;
472 
473   	case FILE_SHORT:
474   	case FILE_BESHORT:
475   	case FILE_LESHORT:
476 		v = file_signextend(ms, m, (uint64_t)p->h);
477 		switch (check_fmt(ms, m)) {
478 		case -1:
479 			return -1;
480 		case 1:
481 			(void)snprintf(buf, sizeof(buf), "%u",
482 			    (unsigned short)v);
483 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
484 				return -1;
485 			break;
486 		default:
487 			if (file_printf(ms, F(ms, m, "%u"),
488 			    (unsigned short) v) == -1)
489 				return -1;
490 			break;
491 		}
492 		t = ms->offset + sizeof(short);
493 		break;
494 
495   	case FILE_LONG:
496   	case FILE_BELONG:
497   	case FILE_LELONG:
498   	case FILE_MELONG:
499 		v = file_signextend(ms, m, (uint64_t)p->l);
500 		switch (check_fmt(ms, m)) {
501 		case -1:
502 			return -1;
503 		case 1:
504 			(void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v);
505 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
506 				return -1;
507 			break;
508 		default:
509 			if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1)
510 				return -1;
511 			break;
512 		}
513 		t = ms->offset + sizeof(int32_t);
514   		break;
515 
516   	case FILE_QUAD:
517   	case FILE_BEQUAD:
518   	case FILE_LEQUAD:
519 		v = file_signextend(ms, m, p->q);
520 		switch (check_fmt(ms, m)) {
521 		case -1:
522 			return -1;
523 		case 1:
524 			(void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
525 			    (unsigned long long)v);
526 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
527 				return -1;
528 			break;
529 		default:
530 			if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"),
531 			    (unsigned long long) v) == -1)
532 				return -1;
533 			break;
534 		}
535 		t = ms->offset + sizeof(int64_t);
536   		break;
537 
538   	case FILE_STRING:
539   	case FILE_PSTRING:
540   	case FILE_BESTRING16:
541   	case FILE_LESTRING16:
542 		if (m->reln == '=' || m->reln == '!') {
543 			if (file_printf(ms, F(ms, m, "%s"),
544 			    file_printable(sbuf, sizeof(sbuf), m->value.s))
545 			    == -1)
546 				return -1;
547 			t = ms->offset + m->vallen;
548 		}
549 		else {
550 			char *str = p->s;
551 
552 			/* compute t before we mangle the string? */
553 			t = ms->offset + strlen(str);
554 
555 			if (*m->value.s == '\0')
556 				str[strcspn(str, "\r\n")] = '\0';
557 
558 			if (m->str_flags & STRING_TRIM) {
559 				char *last;
560 				while (isspace((unsigned char)*str))
561 					str++;
562 				last = str;
563 				while (*last)
564 					last++;
565 				--last;
566 				while (isspace((unsigned char)*last))
567 					last--;
568 				*++last = '\0';
569 			}
570 
571 			if (file_printf(ms, F(ms, m, "%s"),
572 			    file_printable(sbuf, sizeof(sbuf), str)) == -1)
573 				return -1;
574 
575 			if (m->type == FILE_PSTRING)
576 				t += file_pstring_length_size(m);
577 		}
578 		break;
579 
580 	case FILE_DATE:
581 	case FILE_BEDATE:
582 	case FILE_LEDATE:
583 	case FILE_MEDATE:
584 		if (file_printf(ms, F(ms, m, "%s"),
585 		    file_fmttime(p->l, 0, tbuf)) == -1)
586 			return -1;
587 		t = ms->offset + sizeof(uint32_t);
588 		break;
589 
590 	case FILE_LDATE:
591 	case FILE_BELDATE:
592 	case FILE_LELDATE:
593 	case FILE_MELDATE:
594 		if (file_printf(ms, F(ms, m, "%s"),
595 		    file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1)
596 			return -1;
597 		t = ms->offset + sizeof(uint32_t);
598 		break;
599 
600 	case FILE_QDATE:
601 	case FILE_BEQDATE:
602 	case FILE_LEQDATE:
603 		if (file_printf(ms, F(ms, m, "%s"),
604 		    file_fmttime(p->q, 0, tbuf)) == -1)
605 			return -1;
606 		t = ms->offset + sizeof(uint64_t);
607 		break;
608 
609 	case FILE_QLDATE:
610 	case FILE_BEQLDATE:
611 	case FILE_LEQLDATE:
612 		if (file_printf(ms, F(ms, m, "%s"),
613 		    file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1)
614 			return -1;
615 		t = ms->offset + sizeof(uint64_t);
616 		break;
617 
618 	case FILE_QWDATE:
619 	case FILE_BEQWDATE:
620 	case FILE_LEQWDATE:
621 		if (file_printf(ms, F(ms, m, "%s"),
622 		    file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1)
623 			return -1;
624 		t = ms->offset + sizeof(uint64_t);
625 		break;
626 
627 	case FILE_FLOAT:
628 	case FILE_BEFLOAT:
629 	case FILE_LEFLOAT:
630 		vf = p->f;
631 		switch (check_fmt(ms, m)) {
632 		case -1:
633 			return -1;
634 		case 1:
635 			(void)snprintf(buf, sizeof(buf), "%g", vf);
636 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
637 				return -1;
638 			break;
639 		default:
640 			if (file_printf(ms, F(ms, m, "%g"), vf) == -1)
641 				return -1;
642 			break;
643 		}
644 		t = ms->offset + sizeof(float);
645   		break;
646 
647 	case FILE_DOUBLE:
648 	case FILE_BEDOUBLE:
649 	case FILE_LEDOUBLE:
650 		vd = p->d;
651 		switch (check_fmt(ms, m)) {
652 		case -1:
653 			return -1;
654 		case 1:
655 			(void)snprintf(buf, sizeof(buf), "%g", vd);
656 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
657 				return -1;
658 			break;
659 		default:
660 			if (file_printf(ms, F(ms, m, "%g"), vd) == -1)
661 				return -1;
662 			break;
663 		}
664 		t = ms->offset + sizeof(double);
665   		break;
666 
667 	case FILE_SEARCH:
668 	case FILE_REGEX: {
669 		char *cp;
670 		int rval;
671 
672 		cp = strndup((const char *)ms->search.s, ms->search.rm_len);
673 		if (cp == NULL) {
674 			file_oomem(ms, ms->search.rm_len);
675 			return -1;
676 		}
677 		rval = file_printf(ms, F(ms, m, "%s"),
678 		    file_printable(sbuf, sizeof(sbuf), cp));
679 		free(cp);
680 
681 		if (rval == -1)
682 			return -1;
683 
684 		if ((m->str_flags & REGEX_OFFSET_START))
685 			t = ms->search.offset;
686 		else
687 			t = ms->search.offset + ms->search.rm_len;
688 		break;
689 	}
690 
691 	case FILE_DEFAULT:
692 	case FILE_CLEAR:
693 	  	if (file_printf(ms, "%s", m->desc) == -1)
694 			return -1;
695 		t = ms->offset;
696 		break;
697 
698 	case FILE_INDIRECT:
699 	case FILE_USE:
700 	case FILE_NAME:
701 		t = ms->offset;
702 		break;
703 	case FILE_DER:
704 		if (file_printf(ms, F(ms, m, "%s"),
705 		    file_printable(sbuf, sizeof(sbuf), ms->ms_value.s)) == -1)
706 			return -1;
707 		t = ms->offset;
708 		break;
709 	default:
710 		file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
711 		return -1;
712 	}
713 	return (int32_t)t;
714 }
715 
716 private int
717 moffset(struct magic_set *ms, struct magic *m, size_t nbytes, int32_t *op)
718 {
719 	int32_t o;
720 
721   	switch (m->type) {
722   	case FILE_BYTE:
723 		o = CAST(int32_t, (ms->offset + sizeof(char)));
724 		break;
725 
726   	case FILE_SHORT:
727   	case FILE_BESHORT:
728   	case FILE_LESHORT:
729 		o = CAST(int32_t, (ms->offset + sizeof(short)));
730 		break;
731 
732   	case FILE_LONG:
733   	case FILE_BELONG:
734   	case FILE_LELONG:
735   	case FILE_MELONG:
736 		o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
737 		break;
738 
739   	case FILE_QUAD:
740   	case FILE_BEQUAD:
741   	case FILE_LEQUAD:
742 		o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
743 		break;
744 
745   	case FILE_STRING:
746   	case FILE_PSTRING:
747   	case FILE_BESTRING16:
748   	case FILE_LESTRING16:
749 		if (m->reln == '=' || m->reln == '!') {
750 			o = ms->offset + m->vallen;
751 		} else {
752 			union VALUETYPE *p = &ms->ms_value;
753 
754 			if (*m->value.s == '\0')
755 				p->s[strcspn(p->s, "\r\n")] = '\0';
756 			o = CAST(uint32_t, (ms->offset + strlen(p->s)));
757 			if (m->type == FILE_PSTRING)
758 				o += (uint32_t)file_pstring_length_size(m);
759 		}
760 		break;
761 
762 	case FILE_DATE:
763 	case FILE_BEDATE:
764 	case FILE_LEDATE:
765 	case FILE_MEDATE:
766 		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
767 		break;
768 
769 	case FILE_LDATE:
770 	case FILE_BELDATE:
771 	case FILE_LELDATE:
772 	case FILE_MELDATE:
773 		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
774 		break;
775 
776 	case FILE_QDATE:
777 	case FILE_BEQDATE:
778 	case FILE_LEQDATE:
779 		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
780 		break;
781 
782 	case FILE_QLDATE:
783 	case FILE_BEQLDATE:
784 	case FILE_LEQLDATE:
785 		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
786 		break;
787 
788   	case FILE_FLOAT:
789   	case FILE_BEFLOAT:
790   	case FILE_LEFLOAT:
791 		o = CAST(int32_t, (ms->offset + sizeof(float)));
792 		break;
793 
794   	case FILE_DOUBLE:
795   	case FILE_BEDOUBLE:
796   	case FILE_LEDOUBLE:
797 		o = CAST(int32_t, (ms->offset + sizeof(double)));
798 		break;
799 
800 	case FILE_REGEX:
801 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
802 			o = CAST(int32_t, ms->search.offset);
803 		else
804 			o = CAST(int32_t,
805 			    (ms->search.offset + ms->search.rm_len));
806 		break;
807 
808 	case FILE_SEARCH:
809 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
810 			o = CAST(int32_t, ms->search.offset);
811 		else
812 			o = CAST(int32_t, (ms->search.offset + m->vallen));
813 		break;
814 
815 	case FILE_CLEAR:
816 	case FILE_DEFAULT:
817 	case FILE_INDIRECT:
818 		o = ms->offset;
819 		break;
820 
821 	case FILE_DER:
822 		{
823 			o = der_offs(ms, m, nbytes);
824 			if (o == -1 || (size_t)o > nbytes) {
825 				if ((ms->flags & MAGIC_DEBUG) != 0) {
826 					(void)fprintf(stderr,
827 					    "Bad DER offset %d nbytes=%zu",
828 					    o, nbytes);
829 				}
830 				*op = 0;
831 				return 0;
832 			}
833 			break;
834 		}
835 
836 	default:
837 		o = 0;
838 		break;
839 	}
840 
841 	if ((size_t)o > nbytes) {
842 #if 0
843 		file_error(ms, 0, "Offset out of range %zu > %zu",
844 		    (size_t)o, nbytes);
845 #endif
846 		return -1;
847 	}
848 	*op = o;
849 	return 1;
850 }
851 
852 private uint32_t
853 cvt_id3(struct magic_set *ms, uint32_t v)
854 {
855 	v = ((((v >>  0) & 0x7f) <<  0) |
856 	     (((v >>  8) & 0x7f) <<  7) |
857 	     (((v >> 16) & 0x7f) << 14) |
858 	     (((v >> 24) & 0x7f) << 21));
859 	if ((ms->flags & MAGIC_DEBUG) != 0)
860 		fprintf(stderr, "id3 offs=%u\n", v);
861 	return v;
862 }
863 
864 private int
865 cvt_flip(int type, int flip)
866 {
867 	if (flip == 0)
868 		return type;
869 	switch (type) {
870 	case FILE_BESHORT:
871 		return FILE_LESHORT;
872 	case FILE_BELONG:
873 		return FILE_LELONG;
874 	case FILE_BEDATE:
875 		return FILE_LEDATE;
876 	case FILE_BELDATE:
877 		return FILE_LELDATE;
878 	case FILE_BEQUAD:
879 		return FILE_LEQUAD;
880 	case FILE_BEQDATE:
881 		return FILE_LEQDATE;
882 	case FILE_BEQLDATE:
883 		return FILE_LEQLDATE;
884 	case FILE_BEQWDATE:
885 		return FILE_LEQWDATE;
886 	case FILE_LESHORT:
887 		return FILE_BESHORT;
888 	case FILE_LELONG:
889 		return FILE_BELONG;
890 	case FILE_LEDATE:
891 		return FILE_BEDATE;
892 	case FILE_LELDATE:
893 		return FILE_BELDATE;
894 	case FILE_LEQUAD:
895 		return FILE_BEQUAD;
896 	case FILE_LEQDATE:
897 		return FILE_BEQDATE;
898 	case FILE_LEQLDATE:
899 		return FILE_BEQLDATE;
900 	case FILE_LEQWDATE:
901 		return FILE_BEQWDATE;
902 	case FILE_BEFLOAT:
903 		return FILE_LEFLOAT;
904 	case FILE_LEFLOAT:
905 		return FILE_BEFLOAT;
906 	case FILE_BEDOUBLE:
907 		return FILE_LEDOUBLE;
908 	case FILE_LEDOUBLE:
909 		return FILE_BEDOUBLE;
910 	default:
911 		return type;
912 	}
913 }
914 #define DO_CVT(fld, cast) \
915 	if (m->num_mask) \
916 		switch (m->mask_op & FILE_OPS_MASK) { \
917 		case FILE_OPAND: \
918 			p->fld &= cast m->num_mask; \
919 			break; \
920 		case FILE_OPOR: \
921 			p->fld |= cast m->num_mask; \
922 			break; \
923 		case FILE_OPXOR: \
924 			p->fld ^= cast m->num_mask; \
925 			break; \
926 		case FILE_OPADD: \
927 			p->fld += cast m->num_mask; \
928 			break; \
929 		case FILE_OPMINUS: \
930 			p->fld -= cast m->num_mask; \
931 			break; \
932 		case FILE_OPMULTIPLY: \
933 			p->fld *= cast m->num_mask; \
934 			break; \
935 		case FILE_OPDIVIDE: \
936 			if (cast m->num_mask == 0) \
937 				return -1; \
938 			p->fld /= cast m->num_mask; \
939 			break; \
940 		case FILE_OPMODULO: \
941 			if (cast m->num_mask == 0) \
942 				return -1; \
943 			p->fld %= cast m->num_mask; \
944 			break; \
945 		} \
946 	if (m->mask_op & FILE_OPINVERSE) \
947 		p->fld = ~p->fld \
948 
949 private int
950 cvt_8(union VALUETYPE *p, const struct magic *m)
951 {
952 	DO_CVT(b, (uint8_t));
953 	return 0;
954 }
955 
956 private int
957 cvt_16(union VALUETYPE *p, const struct magic *m)
958 {
959 	DO_CVT(h, (uint16_t));
960 	return 0;
961 }
962 
963 private int
964 cvt_32(union VALUETYPE *p, const struct magic *m)
965 {
966 	DO_CVT(l, (uint32_t));
967 	return 0;
968 }
969 
970 private int
971 cvt_64(union VALUETYPE *p, const struct magic *m)
972 {
973 	DO_CVT(q, (uint64_t));
974 	return 0;
975 }
976 
977 #define DO_CVT2(fld, cast) \
978 	if (m->num_mask) \
979 		switch (m->mask_op & FILE_OPS_MASK) { \
980 		case FILE_OPADD: \
981 			p->fld += cast m->num_mask; \
982 			break; \
983 		case FILE_OPMINUS: \
984 			p->fld -= cast m->num_mask; \
985 			break; \
986 		case FILE_OPMULTIPLY: \
987 			p->fld *= cast m->num_mask; \
988 			break; \
989 		case FILE_OPDIVIDE: \
990 			if (cast m->num_mask == 0) \
991 				return -1; \
992 			p->fld /= cast m->num_mask; \
993 			break; \
994 		} \
995 
996 private int
997 cvt_float(union VALUETYPE *p, const struct magic *m)
998 {
999 	DO_CVT2(f, (float));
1000 	return 0;
1001 }
1002 
1003 private int
1004 cvt_double(union VALUETYPE *p, const struct magic *m)
1005 {
1006 	DO_CVT2(d, (double));
1007 	return 0;
1008 }
1009 
1010 /*
1011  * Convert the byte order of the data we are looking at
1012  * While we're here, let's apply the mask operation
1013  * (unless you have a better idea)
1014  */
1015 private int
1016 mconvert(struct magic_set *ms, struct magic *m, int flip)
1017 {
1018 	union VALUETYPE *p = &ms->ms_value;
1019 	uint8_t type;
1020 
1021 	switch (type = cvt_flip(m->type, flip)) {
1022 	case FILE_BYTE:
1023 		if (cvt_8(p, m) == -1)
1024 			goto out;
1025 		return 1;
1026 	case FILE_SHORT:
1027 		if (cvt_16(p, m) == -1)
1028 			goto out;
1029 		return 1;
1030 	case FILE_LONG:
1031 	case FILE_DATE:
1032 	case FILE_LDATE:
1033 		if (cvt_32(p, m) == -1)
1034 			goto out;
1035 		return 1;
1036 	case FILE_QUAD:
1037 	case FILE_QDATE:
1038 	case FILE_QLDATE:
1039 	case FILE_QWDATE:
1040 		if (cvt_64(p, m) == -1)
1041 			goto out;
1042 		return 1;
1043 	case FILE_STRING:
1044 	case FILE_BESTRING16:
1045 	case FILE_LESTRING16: {
1046 		/* Null terminate and eat *trailing* return */
1047 		p->s[sizeof(p->s) - 1] = '\0';
1048 		return 1;
1049 	}
1050 	case FILE_PSTRING: {
1051 		size_t sz = file_pstring_length_size(m);
1052 		char *ptr1 = p->s, *ptr2 = ptr1 + sz;
1053 		size_t len = file_pstring_get_length(m, ptr1);
1054 		sz = sizeof(p->s) - sz; /* maximum length of string */
1055 		if (len >= sz) {
1056 			/*
1057 			 * The size of the pascal string length (sz)
1058 			 * is 1, 2, or 4. We need at least 1 byte for NUL
1059 			 * termination, but we've already truncated the
1060 			 * string by p->s, so we need to deduct sz.
1061 			 * Because we can use one of the bytes of the length
1062 			 * after we shifted as NUL termination.
1063 			 */
1064 			len = sz;
1065 		}
1066 		while (len--)
1067 			*ptr1++ = *ptr2++;
1068 		*ptr1 = '\0';
1069 		return 1;
1070 	}
1071 	case FILE_BESHORT:
1072 		p->h = (short)BE16(p);
1073 		if (cvt_16(p, m) == -1)
1074 			goto out;
1075 		return 1;
1076 	case FILE_BELONG:
1077 	case FILE_BEDATE:
1078 	case FILE_BELDATE:
1079 		p->l = (int32_t)BE32(p);
1080 		if (cvt_32(p, m) == -1)
1081 			goto out;
1082 		return 1;
1083 	case FILE_BEQUAD:
1084 	case FILE_BEQDATE:
1085 	case FILE_BEQLDATE:
1086 	case FILE_BEQWDATE:
1087 		p->q = (uint64_t)BE64(p);
1088 		if (cvt_64(p, m) == -1)
1089 			goto out;
1090 		return 1;
1091 	case FILE_LESHORT:
1092 		p->h = (short)LE16(p);
1093 		if (cvt_16(p, m) == -1)
1094 			goto out;
1095 		return 1;
1096 	case FILE_LELONG:
1097 	case FILE_LEDATE:
1098 	case FILE_LELDATE:
1099 		p->l = (int32_t)LE32(p);
1100 		if (cvt_32(p, m) == -1)
1101 			goto out;
1102 		return 1;
1103 	case FILE_LEQUAD:
1104 	case FILE_LEQDATE:
1105 	case FILE_LEQLDATE:
1106 	case FILE_LEQWDATE:
1107 		p->q = (uint64_t)LE64(p);
1108 		if (cvt_64(p, m) == -1)
1109 			goto out;
1110 		return 1;
1111 	case FILE_MELONG:
1112 	case FILE_MEDATE:
1113 	case FILE_MELDATE:
1114 		p->l = (int32_t)ME32(p);
1115 		if (cvt_32(p, m) == -1)
1116 			goto out;
1117 		return 1;
1118 	case FILE_FLOAT:
1119 		if (cvt_float(p, m) == -1)
1120 			goto out;
1121 		return 1;
1122 	case FILE_BEFLOAT:
1123 		p->l = BE32(p);
1124 		if (cvt_float(p, m) == -1)
1125 			goto out;
1126 		return 1;
1127 	case FILE_LEFLOAT:
1128 		p->l = LE32(p);
1129 		if (cvt_float(p, m) == -1)
1130 			goto out;
1131 		return 1;
1132 	case FILE_DOUBLE:
1133 		if (cvt_double(p, m) == -1)
1134 			goto out;
1135 		return 1;
1136 	case FILE_BEDOUBLE:
1137 		p->q = BE64(p);
1138 		if (cvt_double(p, m) == -1)
1139 			goto out;
1140 		return 1;
1141 	case FILE_LEDOUBLE:
1142 		p->q = LE64(p);
1143 		if (cvt_double(p, m) == -1)
1144 			goto out;
1145 		return 1;
1146 	case FILE_REGEX:
1147 	case FILE_SEARCH:
1148 	case FILE_DEFAULT:
1149 	case FILE_CLEAR:
1150 	case FILE_NAME:
1151 	case FILE_USE:
1152 	case FILE_DER:
1153 		return 1;
1154 	default:
1155 		file_magerror(ms, "invalid type %d in mconvert()", m->type);
1156 		return 0;
1157 	}
1158 out:
1159 	file_magerror(ms, "zerodivide in mconvert()");
1160 	return 0;
1161 }
1162 
1163 
1164 private void
1165 mdebug(uint32_t offset, const char *str, size_t len)
1166 {
1167 	(void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1168 	file_showstr(stderr, str, len);
1169 	(void) fputc('\n', stderr);
1170 	(void) fputc('\n', stderr);
1171 }
1172 
1173 private int
1174 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1175     const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1176 {
1177 	/*
1178 	 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1179 	 * anything, but setup pointers into the source
1180 	 */
1181 	if (indir == 0) {
1182 		switch (type) {
1183 		case FILE_DER:
1184 		case FILE_SEARCH:
1185 			if (offset > nbytes)
1186 				offset = nbytes;
1187 			ms->search.s = RCAST(const char *, s) + offset;
1188 			ms->search.s_len = nbytes - offset;
1189 			ms->search.offset = offset;
1190 			return 0;
1191 
1192 		case FILE_REGEX: {
1193 			const char *b;
1194 			const char *c;
1195 			const char *last;	/* end of search region */
1196 			const char *buf;	/* start of search region */
1197 			const char *end;
1198 			size_t lines, linecnt, bytecnt;
1199 
1200 			if (s == NULL) {
1201 				ms->search.s_len = 0;
1202 				ms->search.s = NULL;
1203 				return 0;
1204 			}
1205 
1206 			if (m->str_flags & REGEX_LINE_COUNT) {
1207 				linecnt = m->str_range;
1208 				bytecnt = linecnt * 80;
1209 			} else {
1210 				linecnt = 0;
1211 				bytecnt = m->str_range;
1212 			}
1213 
1214 			if (bytecnt == 0 || bytecnt > nbytes - offset)
1215 				bytecnt = nbytes - offset;
1216 			if (bytecnt > ms->regex_max)
1217 				bytecnt = ms->regex_max;
1218 
1219 			buf = RCAST(const char *, s) + offset;
1220 			end = last = RCAST(const char *, s) + bytecnt + offset;
1221 			/* mget() guarantees buf <= last */
1222 			for (lines = linecnt, b = buf; lines && b < end &&
1223 			     ((b = CAST(const char *,
1224 				 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1225 			     || (b = CAST(const char *,
1226 				 memchr(c, '\r', CAST(size_t, (end - c))))));
1227 			     lines--, b++) {
1228 				last = b;
1229 				if (b[0] == '\r' && b[1] == '\n')
1230 					b++;
1231 			}
1232 			if (lines)
1233 				last = RCAST(const char *, s) + bytecnt;
1234 
1235 			ms->search.s = buf;
1236 			ms->search.s_len = last - buf;
1237 			ms->search.offset = offset;
1238 			ms->search.rm_len = 0;
1239 			return 0;
1240 		}
1241 		case FILE_BESTRING16:
1242 		case FILE_LESTRING16: {
1243 			const unsigned char *src = s + offset;
1244 			const unsigned char *esrc = s + nbytes;
1245 			char *dst = p->s;
1246 			char *edst = &p->s[sizeof(p->s) - 1];
1247 
1248 			if (type == FILE_BESTRING16)
1249 				src++;
1250 
1251 			/* check that offset is within range */
1252 			if (offset >= nbytes)
1253 				break;
1254 			for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1255 				if (dst < edst)
1256 					*dst = *src;
1257 				else
1258 					break;
1259 				if (*dst == '\0') {
1260 					if (type == FILE_BESTRING16 ?
1261 					    *(src - 1) != '\0' :
1262 					    *(src + 1) != '\0')
1263 						*dst = ' ';
1264 				}
1265 			}
1266 			*edst = '\0';
1267 			return 0;
1268 		}
1269 		case FILE_STRING:	/* XXX - these two should not need */
1270 		case FILE_PSTRING:	/* to copy anything, but do anyway. */
1271 		default:
1272 			break;
1273 		}
1274 	}
1275 
1276 	if (offset >= nbytes) {
1277 		(void)memset(p, '\0', sizeof(*p));
1278 		return 0;
1279 	}
1280 	if (nbytes - offset < sizeof(*p))
1281 		nbytes = nbytes - offset;
1282 	else
1283 		nbytes = sizeof(*p);
1284 
1285 	(void)memcpy(p, s + offset, nbytes);
1286 
1287 	/*
1288 	 * the usefulness of padding with zeroes eludes me, it
1289 	 * might even cause problems
1290 	 */
1291 	if (nbytes < sizeof(*p))
1292 		(void)memset(((char *)(void *)p) + nbytes, '\0',
1293 		    sizeof(*p) - nbytes);
1294 	return 0;
1295 }
1296 
1297 private int
1298 mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
1299     size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
1300     int flip, uint16_t *indir_count, uint16_t *name_count,
1301     int *printed_something, int *need_separator, int *returnval)
1302 {
1303 	uint32_t offset = ms->offset;
1304 	uint32_t lhs;
1305 	file_pushbuf_t *pb;
1306 	int rv, oneed_separator, in_type;
1307 	char *rbuf;
1308 	union VALUETYPE *p = &ms->ms_value;
1309 	struct mlist ml;
1310 
1311 	if (*indir_count >= ms->indir_max) {
1312 		file_error(ms, 0, "indirect count (%hu) exceeded",
1313 		    *indir_count);
1314 		return -1;
1315 	}
1316 
1317 	if (*name_count >= ms->name_max) {
1318 		file_error(ms, 0, "name use count (%hu) exceeded",
1319 		    *name_count);
1320 		return -1;
1321 	}
1322 
1323 	if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
1324 	    (uint32_t)nbytes, m) == -1)
1325 		return -1;
1326 
1327 	if ((ms->flags & MAGIC_DEBUG) != 0) {
1328 		fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%"
1329 		    SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1330 		    "u, il=%hu, nc=%hu)\n",
1331 		    m->type, m->flag, offset, o, nbytes,
1332 		    *indir_count, *name_count);
1333 		mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1334 #ifndef COMPILE_ONLY
1335 		file_mdump(m);
1336 #endif
1337 	}
1338 
1339 	if (m->flag & INDIR) {
1340 		int off = m->in_offset;
1341 		if (m->in_op & FILE_OPINDIRECT) {
1342 			const union VALUETYPE *q = CAST(const union VALUETYPE *,
1343 			    ((const void *)(s + offset + off)));
1344 			if (OFFSET_OOB(nbytes, offset + off, sizeof(*q)))
1345 				return 0;
1346 			switch (cvt_flip(m->in_type, flip)) {
1347 			case FILE_BYTE:
1348 				off = q->b;
1349 				break;
1350 			case FILE_SHORT:
1351 				off = q->h;
1352 				break;
1353 			case FILE_BESHORT:
1354 				off = (short)BE16(q);
1355 				break;
1356 			case FILE_LESHORT:
1357 				off = (short)LE16(q);
1358 				break;
1359 			case FILE_LONG:
1360 				off = q->l;
1361 				break;
1362 			case FILE_BELONG:
1363 			case FILE_BEID3:
1364 				off = (int32_t)BE32(q);
1365 				break;
1366 			case FILE_LEID3:
1367 			case FILE_LELONG:
1368 				off = (int32_t)LE32(q);
1369 				break;
1370 			case FILE_MELONG:
1371 				off = (int32_t)ME32(q);
1372 				break;
1373 			}
1374 			if ((ms->flags & MAGIC_DEBUG) != 0)
1375 				fprintf(stderr, "indirect offs=%u\n", off);
1376 		}
1377 		switch (in_type = cvt_flip(m->in_type, flip)) {
1378 		case FILE_BYTE:
1379 			if (OFFSET_OOB(nbytes, offset, 1))
1380 				return 0;
1381 			if (off) {
1382 				switch (m->in_op & FILE_OPS_MASK) {
1383 				case FILE_OPAND:
1384 					offset = p->b & off;
1385 					break;
1386 				case FILE_OPOR:
1387 					offset = p->b | off;
1388 					break;
1389 				case FILE_OPXOR:
1390 					offset = p->b ^ off;
1391 					break;
1392 				case FILE_OPADD:
1393 					offset = p->b + off;
1394 					break;
1395 				case FILE_OPMINUS:
1396 					offset = p->b - off;
1397 					break;
1398 				case FILE_OPMULTIPLY:
1399 					offset = p->b * off;
1400 					break;
1401 				case FILE_OPDIVIDE:
1402 					offset = p->b / off;
1403 					break;
1404 				case FILE_OPMODULO:
1405 					offset = p->b % off;
1406 					break;
1407 				}
1408 			} else
1409 				offset = p->b;
1410 			if (m->in_op & FILE_OPINVERSE)
1411 				offset = ~offset;
1412 			break;
1413 		case FILE_BESHORT:
1414 			if (OFFSET_OOB(nbytes, offset, 2))
1415 				return 0;
1416 			lhs = (p->hs[0] << 8) | p->hs[1];
1417 			if (off) {
1418 				switch (m->in_op & FILE_OPS_MASK) {
1419 				case FILE_OPAND:
1420 					offset = lhs & off;
1421 					break;
1422 				case FILE_OPOR:
1423 					offset = lhs | off;
1424 					break;
1425 				case FILE_OPXOR:
1426 					offset = lhs ^ off;
1427 					break;
1428 				case FILE_OPADD:
1429 					offset = lhs + off;
1430 					break;
1431 				case FILE_OPMINUS:
1432 					offset = lhs - off;
1433 					break;
1434 				case FILE_OPMULTIPLY:
1435 					offset = lhs * off;
1436 					break;
1437 				case FILE_OPDIVIDE:
1438 					offset = lhs / off;
1439 					break;
1440 				case FILE_OPMODULO:
1441 					offset = lhs % off;
1442 					break;
1443 				}
1444 			} else
1445 				offset = lhs;
1446 			if (m->in_op & FILE_OPINVERSE)
1447 				offset = ~offset;
1448 			break;
1449 		case FILE_LESHORT:
1450 			if (OFFSET_OOB(nbytes, offset, 2))
1451 				return 0;
1452 			lhs = (p->hs[1] << 8) | p->hs[0];
1453 			if (off) {
1454 				switch (m->in_op & FILE_OPS_MASK) {
1455 				case FILE_OPAND:
1456 					offset = lhs & off;
1457 					break;
1458 				case FILE_OPOR:
1459 					offset = lhs | off;
1460 					break;
1461 				case FILE_OPXOR:
1462 					offset = lhs ^ off;
1463 					break;
1464 				case FILE_OPADD:
1465 					offset = lhs + off;
1466 					break;
1467 				case FILE_OPMINUS:
1468 					offset = lhs - off;
1469 					break;
1470 				case FILE_OPMULTIPLY:
1471 					offset = lhs * off;
1472 					break;
1473 				case FILE_OPDIVIDE:
1474 					offset = lhs / off;
1475 					break;
1476 				case FILE_OPMODULO:
1477 					offset = lhs % off;
1478 					break;
1479 				}
1480 			} else
1481 				offset = lhs;
1482 			if (m->in_op & FILE_OPINVERSE)
1483 				offset = ~offset;
1484 			break;
1485 		case FILE_SHORT:
1486 			if (OFFSET_OOB(nbytes, offset, 2))
1487 				return 0;
1488 			if (off) {
1489 				switch (m->in_op & FILE_OPS_MASK) {
1490 				case FILE_OPAND:
1491 					offset = p->h & off;
1492 					break;
1493 				case FILE_OPOR:
1494 					offset = p->h | off;
1495 					break;
1496 				case FILE_OPXOR:
1497 					offset = p->h ^ off;
1498 					break;
1499 				case FILE_OPADD:
1500 					offset = p->h + off;
1501 					break;
1502 				case FILE_OPMINUS:
1503 					offset = p->h - off;
1504 					break;
1505 				case FILE_OPMULTIPLY:
1506 					offset = p->h * off;
1507 					break;
1508 				case FILE_OPDIVIDE:
1509 					offset = p->h / off;
1510 					break;
1511 				case FILE_OPMODULO:
1512 					offset = p->h % off;
1513 					break;
1514 				}
1515 			}
1516 			else
1517 				offset = p->h;
1518 			if (m->in_op & FILE_OPINVERSE)
1519 				offset = ~offset;
1520 			break;
1521 		case FILE_BELONG:
1522 		case FILE_BEID3:
1523 			if (OFFSET_OOB(nbytes, offset, 4))
1524 				return 0;
1525 			lhs = BE32(p);
1526 			if (in_type == FILE_BEID3)
1527 				lhs = cvt_id3(ms, lhs);
1528 			if (off) {
1529 				switch (m->in_op & FILE_OPS_MASK) {
1530 				case FILE_OPAND:
1531 					offset = lhs & off;
1532 					break;
1533 				case FILE_OPOR:
1534 					offset = lhs | off;
1535 					break;
1536 				case FILE_OPXOR:
1537 					offset = lhs ^ off;
1538 					break;
1539 				case FILE_OPADD:
1540 					offset = lhs + off;
1541 					break;
1542 				case FILE_OPMINUS:
1543 					offset = lhs - off;
1544 					break;
1545 				case FILE_OPMULTIPLY:
1546 					offset = lhs * off;
1547 					break;
1548 				case FILE_OPDIVIDE:
1549 					offset = lhs / off;
1550 					break;
1551 				case FILE_OPMODULO:
1552 					offset = lhs % off;
1553 					break;
1554 				}
1555 			} else
1556 				offset = lhs;
1557 			if (m->in_op & FILE_OPINVERSE)
1558 				offset = ~offset;
1559 			break;
1560 		case FILE_LELONG:
1561 		case FILE_LEID3:
1562 			if (OFFSET_OOB(nbytes, offset, 4))
1563 				return 0;
1564 			lhs = LE32(p);
1565 			if (in_type == FILE_LEID3)
1566 				lhs = cvt_id3(ms, lhs);
1567 			if (off) {
1568 				switch (m->in_op & FILE_OPS_MASK) {
1569 				case FILE_OPAND:
1570 					offset = lhs & off;
1571 					break;
1572 				case FILE_OPOR:
1573 					offset = lhs | off;
1574 					break;
1575 				case FILE_OPXOR:
1576 					offset = lhs ^ off;
1577 					break;
1578 				case FILE_OPADD:
1579 					offset = lhs + off;
1580 					break;
1581 				case FILE_OPMINUS:
1582 					offset = lhs - off;
1583 					break;
1584 				case FILE_OPMULTIPLY:
1585 					offset = lhs * off;
1586 					break;
1587 				case FILE_OPDIVIDE:
1588 					offset = lhs / off;
1589 					break;
1590 				case FILE_OPMODULO:
1591 					offset = lhs % off;
1592 					break;
1593 				}
1594 			} else
1595 				offset = lhs;
1596 			if (m->in_op & FILE_OPINVERSE)
1597 				offset = ~offset;
1598 			break;
1599 		case FILE_MELONG:
1600 			if (OFFSET_OOB(nbytes, offset, 4))
1601 				return 0;
1602 			lhs = ME32(p);
1603 			if (off) {
1604 				switch (m->in_op & FILE_OPS_MASK) {
1605 				case FILE_OPAND:
1606 					offset = lhs & off;
1607 					break;
1608 				case FILE_OPOR:
1609 					offset = lhs | off;
1610 					break;
1611 				case FILE_OPXOR:
1612 					offset = lhs ^ off;
1613 					break;
1614 				case FILE_OPADD:
1615 					offset = lhs + off;
1616 					break;
1617 				case FILE_OPMINUS:
1618 					offset = lhs - off;
1619 					break;
1620 				case FILE_OPMULTIPLY:
1621 					offset = lhs * off;
1622 					break;
1623 				case FILE_OPDIVIDE:
1624 					offset = lhs / off;
1625 					break;
1626 				case FILE_OPMODULO:
1627 					offset = lhs % off;
1628 					break;
1629 				}
1630 			} else
1631 				offset = lhs;
1632 			if (m->in_op & FILE_OPINVERSE)
1633 				offset = ~offset;
1634 			break;
1635 		case FILE_LONG:
1636 			if (OFFSET_OOB(nbytes, offset, 4))
1637 				return 0;
1638 			if (off) {
1639 				switch (m->in_op & FILE_OPS_MASK) {
1640 				case FILE_OPAND:
1641 					offset = p->l & off;
1642 					break;
1643 				case FILE_OPOR:
1644 					offset = p->l | off;
1645 					break;
1646 				case FILE_OPXOR:
1647 					offset = p->l ^ off;
1648 					break;
1649 				case FILE_OPADD:
1650 					offset = p->l + off;
1651 					break;
1652 				case FILE_OPMINUS:
1653 					offset = p->l - off;
1654 					break;
1655 				case FILE_OPMULTIPLY:
1656 					offset = p->l * off;
1657 					break;
1658 				case FILE_OPDIVIDE:
1659 					offset = p->l / off;
1660 					break;
1661 				case FILE_OPMODULO:
1662 					offset = p->l % off;
1663 					break;
1664 				}
1665 			} else
1666 				offset = p->l;
1667 			if (m->in_op & FILE_OPINVERSE)
1668 				offset = ~offset;
1669 			break;
1670 		default:
1671 			break;
1672 		}
1673 
1674 		if (m->flag & INDIROFFADD) {
1675 			offset += ms->c.li[cont_level-1].off;
1676 			if (offset == 0) {
1677 				if ((ms->flags & MAGIC_DEBUG) != 0)
1678 					fprintf(stderr,
1679 					    "indirect *zero* offset\n");
1680 				return 0;
1681 			}
1682 			if ((ms->flags & MAGIC_DEBUG) != 0)
1683 				fprintf(stderr, "indirect +offs=%u\n", offset);
1684 		}
1685 		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1686 			return -1;
1687 		ms->offset = offset;
1688 
1689 		if ((ms->flags & MAGIC_DEBUG) != 0) {
1690 			mdebug(offset, (char *)(void *)p,
1691 			    sizeof(union VALUETYPE));
1692 #ifndef COMPILE_ONLY
1693 			file_mdump(m);
1694 #endif
1695 		}
1696 	}
1697 
1698 	/* Verify we have enough data to match magic type */
1699 	switch (m->type) {
1700 	case FILE_BYTE:
1701 		if (OFFSET_OOB(nbytes, offset, 1))
1702 			return 0;
1703 		break;
1704 
1705 	case FILE_SHORT:
1706 	case FILE_BESHORT:
1707 	case FILE_LESHORT:
1708 		if (OFFSET_OOB(nbytes, offset, 2))
1709 			return 0;
1710 		break;
1711 
1712 	case FILE_LONG:
1713 	case FILE_BELONG:
1714 	case FILE_LELONG:
1715 	case FILE_MELONG:
1716 	case FILE_DATE:
1717 	case FILE_BEDATE:
1718 	case FILE_LEDATE:
1719 	case FILE_MEDATE:
1720 	case FILE_LDATE:
1721 	case FILE_BELDATE:
1722 	case FILE_LELDATE:
1723 	case FILE_MELDATE:
1724 	case FILE_FLOAT:
1725 	case FILE_BEFLOAT:
1726 	case FILE_LEFLOAT:
1727 		if (OFFSET_OOB(nbytes, offset, 4))
1728 			return 0;
1729 		break;
1730 
1731 	case FILE_DOUBLE:
1732 	case FILE_BEDOUBLE:
1733 	case FILE_LEDOUBLE:
1734 		if (OFFSET_OOB(nbytes, offset, 8))
1735 			return 0;
1736 		break;
1737 
1738 	case FILE_STRING:
1739 	case FILE_PSTRING:
1740 	case FILE_SEARCH:
1741 		if (OFFSET_OOB(nbytes, offset, m->vallen))
1742 			return 0;
1743 		break;
1744 
1745 	case FILE_REGEX:
1746 		if (nbytes < offset)
1747 			return 0;
1748 		break;
1749 
1750 	case FILE_INDIRECT:
1751 		if (m->str_flags & INDIRECT_RELATIVE)
1752 			offset += CAST(uint32_t, o);
1753 		if (offset == 0)
1754 			return 0;
1755 
1756 		if (nbytes < offset)
1757 			return 0;
1758 
1759 		if ((pb = file_push_buffer(ms)) == NULL)
1760 			return -1;
1761 
1762 		(*indir_count)++;
1763 		rv = file_softmagic(ms, s + offset, nbytes - offset,
1764 		    indir_count, name_count, BINTEST, text);
1765 
1766 		if ((ms->flags & MAGIC_DEBUG) != 0)
1767 			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1768 
1769 		rbuf = file_pop_buffer(ms, pb);
1770 		if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1771 			return -1;
1772 
1773 		if (rv == 1) {
1774 			if ((ms->flags & MAGIC_NODESC) == 0 &&
1775 			    file_printf(ms, F(ms, m, "%u"), offset) == -1) {
1776 				free(rbuf);
1777 				return -1;
1778 			}
1779 			if (file_printf(ms, "%s", rbuf) == -1) {
1780 				free(rbuf);
1781 				return -1;
1782 			}
1783 		}
1784 		free(rbuf);
1785 		return rv;
1786 
1787 	case FILE_USE:
1788 		if (nbytes < offset)
1789 			return 0;
1790 		rbuf = m->value.s;
1791 		if (*rbuf == '^') {
1792 			rbuf++;
1793 			flip = !flip;
1794 		}
1795 		if (file_magicfind(ms, rbuf, &ml) == -1) {
1796 			file_error(ms, 0, "cannot find entry `%s'", rbuf);
1797 			return -1;
1798 		}
1799 		(*name_count)++;
1800 		oneed_separator = *need_separator;
1801 		if (m->flag & NOSPACE)
1802 			*need_separator = 0;
1803 		rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
1804 		    mode, text, flip, indir_count, name_count,
1805 		    printed_something, need_separator, returnval);
1806 		if (rv != 1)
1807 		    *need_separator = oneed_separator;
1808 		return 1;
1809 
1810 	case FILE_NAME:
1811 		if (ms->flags & MAGIC_NODESC)
1812 			return 1;
1813 		if (file_printf(ms, "%s", m->desc) == -1)
1814 			return -1;
1815 		return 1;
1816 	case FILE_DER:
1817 	case FILE_DEFAULT:	/* nothing to check */
1818 	case FILE_CLEAR:
1819 	default:
1820 		break;
1821 	}
1822 	if (!mconvert(ms, m, flip))
1823 		return 0;
1824 	return 1;
1825 }
1826 
1827 private uint64_t
1828 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1829 {
1830 	/*
1831 	 * Convert the source args to unsigned here so that (1) the
1832 	 * compare will be unsigned as it is in strncmp() and (2) so
1833 	 * the ctype functions will work correctly without extra
1834 	 * casting.
1835 	 */
1836 	const unsigned char *a = (const unsigned char *)s1;
1837 	const unsigned char *b = (const unsigned char *)s2;
1838 	uint64_t v;
1839 
1840 	/*
1841 	 * What we want here is v = strncmp(s1, s2, len),
1842 	 * but ignoring any nulls.
1843 	 */
1844 	v = 0;
1845 	if (0L == flags) { /* normal string: do it fast */
1846 		while (len-- > 0)
1847 			if ((v = *b++ - *a++) != '\0')
1848 				break;
1849 	}
1850 	else { /* combine the others */
1851 		while (len-- > 0) {
1852 			if ((flags & STRING_IGNORE_LOWERCASE) &&
1853 			    islower(*a)) {
1854 				if ((v = tolower(*b++) - *a++) != '\0')
1855 					break;
1856 			}
1857 			else if ((flags & STRING_IGNORE_UPPERCASE) &&
1858 			    isupper(*a)) {
1859 				if ((v = toupper(*b++) - *a++) != '\0')
1860 					break;
1861 			}
1862 			else if ((flags & STRING_COMPACT_WHITESPACE) &&
1863 			    isspace(*a)) {
1864 				a++;
1865 				if (isspace(*b++)) {
1866 					if (!isspace(*a))
1867 						while (isspace(*b))
1868 							b++;
1869 				}
1870 				else {
1871 					v = 1;
1872 					break;
1873 				}
1874 			}
1875 			else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1876 			    isspace(*a)) {
1877 				a++;
1878 				while (isspace(*b))
1879 					b++;
1880 			}
1881 			else {
1882 				if ((v = *b++ - *a++) != '\0')
1883 					break;
1884 			}
1885 		}
1886 	}
1887 	return v;
1888 }
1889 
1890 private uint64_t
1891 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1892 {
1893 	/*
1894 	 * XXX - The 16-bit string compare probably needs to be done
1895 	 * differently, especially if the flags are to be supported.
1896 	 * At the moment, I am unsure.
1897 	 */
1898 	flags = 0;
1899 	return file_strncmp(a, b, len, flags);
1900 }
1901 
1902 private int
1903 magiccheck(struct magic_set *ms, struct magic *m)
1904 {
1905 	uint64_t l = m->value.q;
1906 	uint64_t v;
1907 	float fl, fv;
1908 	double dl, dv;
1909 	int matched;
1910 	union VALUETYPE *p = &ms->ms_value;
1911 
1912 	switch (m->type) {
1913 	case FILE_BYTE:
1914 		v = p->b;
1915 		break;
1916 
1917 	case FILE_SHORT:
1918 	case FILE_BESHORT:
1919 	case FILE_LESHORT:
1920 		v = p->h;
1921 		break;
1922 
1923 	case FILE_LONG:
1924 	case FILE_BELONG:
1925 	case FILE_LELONG:
1926 	case FILE_MELONG:
1927 	case FILE_DATE:
1928 	case FILE_BEDATE:
1929 	case FILE_LEDATE:
1930 	case FILE_MEDATE:
1931 	case FILE_LDATE:
1932 	case FILE_BELDATE:
1933 	case FILE_LELDATE:
1934 	case FILE_MELDATE:
1935 		v = p->l;
1936 		break;
1937 
1938 	case FILE_QUAD:
1939 	case FILE_LEQUAD:
1940 	case FILE_BEQUAD:
1941 	case FILE_QDATE:
1942 	case FILE_BEQDATE:
1943 	case FILE_LEQDATE:
1944 	case FILE_QLDATE:
1945 	case FILE_BEQLDATE:
1946 	case FILE_LEQLDATE:
1947 	case FILE_QWDATE:
1948 	case FILE_BEQWDATE:
1949 	case FILE_LEQWDATE:
1950 		v = p->q;
1951 		break;
1952 
1953 	case FILE_FLOAT:
1954 	case FILE_BEFLOAT:
1955 	case FILE_LEFLOAT:
1956 		fl = m->value.f;
1957 		fv = p->f;
1958 		switch (m->reln) {
1959 		case 'x':
1960 			matched = 1;
1961 			break;
1962 
1963 		case '!':
1964 			matched = fv != fl;
1965 			break;
1966 
1967 		case '=':
1968 			matched = fv == fl;
1969 			break;
1970 
1971 		case '>':
1972 			matched = fv > fl;
1973 			break;
1974 
1975 		case '<':
1976 			matched = fv < fl;
1977 			break;
1978 
1979 		default:
1980 			file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1981 			    m->reln);
1982 			return -1;
1983 		}
1984 		return matched;
1985 
1986 	case FILE_DOUBLE:
1987 	case FILE_BEDOUBLE:
1988 	case FILE_LEDOUBLE:
1989 		dl = m->value.d;
1990 		dv = p->d;
1991 		switch (m->reln) {
1992 		case 'x':
1993 			matched = 1;
1994 			break;
1995 
1996 		case '!':
1997 			matched = dv != dl;
1998 			break;
1999 
2000 		case '=':
2001 			matched = dv == dl;
2002 			break;
2003 
2004 		case '>':
2005 			matched = dv > dl;
2006 			break;
2007 
2008 		case '<':
2009 			matched = dv < dl;
2010 			break;
2011 
2012 		default:
2013 			file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
2014 			return -1;
2015 		}
2016 		return matched;
2017 
2018 	case FILE_DEFAULT:
2019 	case FILE_CLEAR:
2020 		l = 0;
2021 		v = 0;
2022 		break;
2023 
2024 	case FILE_STRING:
2025 	case FILE_PSTRING:
2026 		l = 0;
2027 		v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
2028 		break;
2029 
2030 	case FILE_BESTRING16:
2031 	case FILE_LESTRING16:
2032 		l = 0;
2033 		v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
2034 		break;
2035 
2036 	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
2037 		size_t slen;
2038 		size_t idx;
2039 
2040 		if (ms->search.s == NULL)
2041 			return 0;
2042 
2043 		slen = MIN(m->vallen, sizeof(m->value.s));
2044 		l = 0;
2045 		v = 0;
2046 
2047 		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
2048 			if (slen + idx > ms->search.s_len)
2049 				break;
2050 
2051 			v = file_strncmp(m->value.s, ms->search.s + idx, slen,
2052 			    m->str_flags);
2053 			if (v == 0) {	/* found match */
2054 				ms->search.offset += idx;
2055 				ms->search.rm_len = m->str_range - idx;
2056 				break;
2057 			}
2058 		}
2059 		break;
2060 	}
2061 	case FILE_REGEX: {
2062 		int rc;
2063 		file_regex_t rx;
2064 		const char *search;
2065 
2066 		if (ms->search.s == NULL)
2067 			return 0;
2068 
2069 		l = 0;
2070 		rc = file_regcomp(&rx, m->value.s,
2071 		    REG_EXTENDED|REG_NEWLINE|
2072 		    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
2073 		if (rc) {
2074 			file_regerror(&rx, rc, ms);
2075 			v = (uint64_t)-1;
2076 		} else {
2077 			regmatch_t pmatch;
2078 			size_t slen = ms->search.s_len;
2079 			char *copy;
2080 			if (slen != 0) {
2081 			    copy = malloc(slen);
2082 			    if (copy == NULL)  {
2083 				file_regfree(&rx);
2084 				file_error(ms, errno,
2085 				    "can't allocate %" SIZE_T_FORMAT "u bytes",
2086 				    slen);
2087 				return -1;
2088 			    }
2089 			    memcpy(copy, ms->search.s, slen);
2090 			    copy[--slen] = '\0';
2091 			    search = copy;
2092 			} else {
2093 			    search = ms->search.s;
2094 			    copy = NULL;
2095 			}
2096 			rc = file_regexec(&rx, (const char *)search,
2097 			    1, &pmatch, 0);
2098 			free(copy);
2099 			switch (rc) {
2100 			case 0:
2101 				ms->search.s += (int)pmatch.rm_so;
2102 				ms->search.offset += (size_t)pmatch.rm_so;
2103 				ms->search.rm_len =
2104 				    (size_t)(pmatch.rm_eo - pmatch.rm_so);
2105 				v = 0;
2106 				break;
2107 
2108 			case REG_NOMATCH:
2109 				v = 1;
2110 				break;
2111 
2112 			default:
2113 				file_regerror(&rx, rc, ms);
2114 				v = (uint64_t)-1;
2115 				break;
2116 			}
2117 		}
2118 		file_regfree(&rx);
2119 		if (v == (uint64_t)-1)
2120 			return -1;
2121 		break;
2122 	}
2123 	case FILE_INDIRECT:
2124 	case FILE_USE:
2125 	case FILE_NAME:
2126 		return 1;
2127 	case FILE_DER:
2128 		matched = der_cmp(ms, m);
2129 		if (matched == -1) {
2130 			if ((ms->flags & MAGIC_DEBUG) != 0) {
2131 				(void) fprintf(stderr,
2132 				    "EOF comparing DER entries");
2133 			}
2134 			return 0;
2135 		}
2136 		return matched;
2137 	default:
2138 		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2139 		return -1;
2140 	}
2141 
2142 	v = file_signextend(ms, m, v);
2143 
2144 	switch (m->reln) {
2145 	case 'x':
2146 		if ((ms->flags & MAGIC_DEBUG) != 0)
2147 			(void) fprintf(stderr, "%" INT64_T_FORMAT
2148 			    "u == *any* = 1\n", (unsigned long long)v);
2149 		matched = 1;
2150 		break;
2151 
2152 	case '!':
2153 		matched = v != l;
2154 		if ((ms->flags & MAGIC_DEBUG) != 0)
2155 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2156 			    INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2157 			    (unsigned long long)l, matched);
2158 		break;
2159 
2160 	case '=':
2161 		matched = v == l;
2162 		if ((ms->flags & MAGIC_DEBUG) != 0)
2163 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2164 			    INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2165 			    (unsigned long long)l, matched);
2166 		break;
2167 
2168 	case '>':
2169 		if (m->flag & UNSIGNED) {
2170 			matched = v > l;
2171 			if ((ms->flags & MAGIC_DEBUG) != 0)
2172 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2173 				    "u > %" INT64_T_FORMAT "u = %d\n",
2174 				    (unsigned long long)v,
2175 				    (unsigned long long)l, matched);
2176 		}
2177 		else {
2178 			matched = (int64_t) v > (int64_t) l;
2179 			if ((ms->flags & MAGIC_DEBUG) != 0)
2180 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2181 				    "d > %" INT64_T_FORMAT "d = %d\n",
2182 				    (long long)v, (long long)l, matched);
2183 		}
2184 		break;
2185 
2186 	case '<':
2187 		if (m->flag & UNSIGNED) {
2188 			matched = v < l;
2189 			if ((ms->flags & MAGIC_DEBUG) != 0)
2190 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2191 				    "u < %" INT64_T_FORMAT "u = %d\n",
2192 				    (unsigned long long)v,
2193 				    (unsigned long long)l, matched);
2194 		}
2195 		else {
2196 			matched = (int64_t) v < (int64_t) l;
2197 			if ((ms->flags & MAGIC_DEBUG) != 0)
2198 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2199 				    "d < %" INT64_T_FORMAT "d = %d\n",
2200 				     (long long)v, (long long)l, matched);
2201 		}
2202 		break;
2203 
2204 	case '&':
2205 		matched = (v & l) == l;
2206 		if ((ms->flags & MAGIC_DEBUG) != 0)
2207 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2208 			    INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2209 			    "x) = %d\n", (unsigned long long)v,
2210 			    (unsigned long long)l, (unsigned long long)l,
2211 			    matched);
2212 		break;
2213 
2214 	case '^':
2215 		matched = (v & l) != l;
2216 		if ((ms->flags & MAGIC_DEBUG) != 0)
2217 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2218 			    INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2219 			    "x) = %d\n", (unsigned long long)v,
2220 			    (unsigned long long)l, (unsigned long long)l,
2221 			    matched);
2222 		break;
2223 
2224 	default:
2225 		file_magerror(ms, "cannot happen: invalid relation `%c'",
2226 		    m->reln);
2227 		return -1;
2228 	}
2229 
2230 	return matched;
2231 }
2232 
2233 private int
2234 handle_annotation(struct magic_set *ms, struct magic *m)
2235 {
2236 	if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
2237 		if (file_printf(ms, "%.8s", m->apple) == -1)
2238 			return -1;
2239 		return 1;
2240 	}
2241 	if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
2242 		if (file_printf(ms, "%s", m->ext) == -1)
2243 			return -1;
2244 		return 1;
2245 	}
2246 	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2247 		if (file_printf(ms, "%s", m->mimetype) == -1)
2248 			return -1;
2249 		return 1;
2250 	}
2251 	return 0;
2252 }
2253 
2254 private int
2255 print_sep(struct magic_set *ms, int firstline)
2256 {
2257 	if (ms->flags & MAGIC_NODESC)
2258 		return 0;
2259 	if (firstline)
2260 		return 0;
2261 	/*
2262 	 * we found another match
2263 	 * put a newline and '-' to do some simple formatting
2264 	 */
2265 	return file_printf(ms, "\n- ");
2266 }
2267