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