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