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