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