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