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