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