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