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