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