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