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