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