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