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