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