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