softmagic.c revision 302555
1208963Srdivacky/*
2208963Srdivacky * Copyright (c) Ian F. Darwin 1986-1995.
3246259Sdim * Software written by Ian F. Darwin and others;
4246259Sdim * maintained 1995-present by Christos Zoulas and others.
5208963Srdivacky *
6208963Srdivacky * Redistribution and use in source and binary forms, with or without
7208963Srdivacky * modification, are permitted provided that the following conditions
8234353Sdim * are met:
9243830Sdim * 1. Redistributions of source code must retain the above copyright
10210299Sed *    notice immediately at the beginning of the file, without modification,
11219077Sdim *    this list of conditions, and the following disclaimer.
12212904Sdim * 2. Redistributions in binary form must reproduce the above copyright
13243830Sdim *    notice, this list of conditions and the following disclaimer in the
14218893Sdim *    documentation and/or other materials provided with the distribution.
15263508Sdim *
16234353Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17212904Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18210299Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19243830Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20234353Sdim * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21210299Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22226633Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23212904Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24210299Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25212904Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26226633Sdim * SUCH DAMAGE.
27221345Sdim */
28208963Srdivacky/*
29210299Sed * softmagic - interpret variable magic from MAGIC
30210299Sed */
31249423Sdim
32239462Sdim#include "file.h"
33210299Sed
34210299Sed#ifndef	lint
35210299SedFILE_RCSID("@(#)$File: softmagic.c,v 1.234 2016/06/13 12:02:06 christos Exp $")
36210299Sed#endif	/* lint */
37208963Srdivacky
38208963Srdivacky#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				*op = 0;
831				return 0;
832			}
833			break;
834		}
835
836	default:
837		o = 0;
838		break;
839	}
840
841	if ((size_t)o > nbytes) {
842#if 0
843		file_error(ms, 0, "Offset out of range %zu > %zu",
844		    (size_t)o, nbytes);
845#endif
846		return -1;
847	}
848	*op = o;
849	return 1;
850}
851
852private uint32_t
853cvt_id3(struct magic_set *ms, uint32_t v)
854{
855	v = ((((v >>  0) & 0x7f) <<  0) |
856	     (((v >>  8) & 0x7f) <<  7) |
857	     (((v >> 16) & 0x7f) << 14) |
858	     (((v >> 24) & 0x7f) << 21));
859	if ((ms->flags & MAGIC_DEBUG) != 0)
860		fprintf(stderr, "id3 offs=%u\n", v);
861	return v;
862}
863
864private int
865cvt_flip(int type, int flip)
866{
867	if (flip == 0)
868		return type;
869	switch (type) {
870	case FILE_BESHORT:
871		return FILE_LESHORT;
872	case FILE_BELONG:
873		return FILE_LELONG;
874	case FILE_BEDATE:
875		return FILE_LEDATE;
876	case FILE_BELDATE:
877		return FILE_LELDATE;
878	case FILE_BEQUAD:
879		return FILE_LEQUAD;
880	case FILE_BEQDATE:
881		return FILE_LEQDATE;
882	case FILE_BEQLDATE:
883		return FILE_LEQLDATE;
884	case FILE_BEQWDATE:
885		return FILE_LEQWDATE;
886	case FILE_LESHORT:
887		return FILE_BESHORT;
888	case FILE_LELONG:
889		return FILE_BELONG;
890	case FILE_LEDATE:
891		return FILE_BEDATE;
892	case FILE_LELDATE:
893		return FILE_BELDATE;
894	case FILE_LEQUAD:
895		return FILE_BEQUAD;
896	case FILE_LEQDATE:
897		return FILE_BEQDATE;
898	case FILE_LEQLDATE:
899		return FILE_BEQLDATE;
900	case FILE_LEQWDATE:
901		return FILE_BEQWDATE;
902	case FILE_BEFLOAT:
903		return FILE_LEFLOAT;
904	case FILE_LEFLOAT:
905		return FILE_BEFLOAT;
906	case FILE_BEDOUBLE:
907		return FILE_LEDOUBLE;
908	case FILE_LEDOUBLE:
909		return FILE_BEDOUBLE;
910	default:
911		return type;
912	}
913}
914#define DO_CVT(fld, cast) \
915	if (m->num_mask) \
916		switch (m->mask_op & FILE_OPS_MASK) { \
917		case FILE_OPAND: \
918			p->fld &= cast m->num_mask; \
919			break; \
920		case FILE_OPOR: \
921			p->fld |= cast m->num_mask; \
922			break; \
923		case FILE_OPXOR: \
924			p->fld ^= cast m->num_mask; \
925			break; \
926		case FILE_OPADD: \
927			p->fld += cast m->num_mask; \
928			break; \
929		case FILE_OPMINUS: \
930			p->fld -= cast m->num_mask; \
931			break; \
932		case FILE_OPMULTIPLY: \
933			p->fld *= cast m->num_mask; \
934			break; \
935		case FILE_OPDIVIDE: \
936			if (cast m->num_mask == 0) \
937				return -1; \
938			p->fld /= cast m->num_mask; \
939			break; \
940		case FILE_OPMODULO: \
941			if (cast m->num_mask == 0) \
942				return -1; \
943			p->fld %= cast m->num_mask; \
944			break; \
945		} \
946	if (m->mask_op & FILE_OPINVERSE) \
947		p->fld = ~p->fld \
948
949private int
950cvt_8(union VALUETYPE *p, const struct magic *m)
951{
952	DO_CVT(b, (uint8_t));
953	return 0;
954}
955
956private int
957cvt_16(union VALUETYPE *p, const struct magic *m)
958{
959	DO_CVT(h, (uint16_t));
960	return 0;
961}
962
963private int
964cvt_32(union VALUETYPE *p, const struct magic *m)
965{
966	DO_CVT(l, (uint32_t));
967	return 0;
968}
969
970private int
971cvt_64(union VALUETYPE *p, const struct magic *m)
972{
973	DO_CVT(q, (uint64_t));
974	return 0;
975}
976
977#define DO_CVT2(fld, cast) \
978	if (m->num_mask) \
979		switch (m->mask_op & FILE_OPS_MASK) { \
980		case FILE_OPADD: \
981			p->fld += cast m->num_mask; \
982			break; \
983		case FILE_OPMINUS: \
984			p->fld -= cast m->num_mask; \
985			break; \
986		case FILE_OPMULTIPLY: \
987			p->fld *= cast m->num_mask; \
988			break; \
989		case FILE_OPDIVIDE: \
990			if (cast m->num_mask == 0) \
991				return -1; \
992			p->fld /= cast m->num_mask; \
993			break; \
994		} \
995
996private int
997cvt_float(union VALUETYPE *p, const struct magic *m)
998{
999	DO_CVT2(f, (float));
1000	return 0;
1001}
1002
1003private int
1004cvt_double(union VALUETYPE *p, const struct magic *m)
1005{
1006	DO_CVT2(d, (double));
1007	return 0;
1008}
1009
1010/*
1011 * Convert the byte order of the data we are looking at
1012 * While we're here, let's apply the mask operation
1013 * (unless you have a better idea)
1014 */
1015private int
1016mconvert(struct magic_set *ms, struct magic *m, int flip)
1017{
1018	union VALUETYPE *p = &ms->ms_value;
1019	uint8_t type;
1020
1021	switch (type = cvt_flip(m->type, flip)) {
1022	case FILE_BYTE:
1023		if (cvt_8(p, m) == -1)
1024			goto out;
1025		return 1;
1026	case FILE_SHORT:
1027		if (cvt_16(p, m) == -1)
1028			goto out;
1029		return 1;
1030	case FILE_LONG:
1031	case FILE_DATE:
1032	case FILE_LDATE:
1033		if (cvt_32(p, m) == -1)
1034			goto out;
1035		return 1;
1036	case FILE_QUAD:
1037	case FILE_QDATE:
1038	case FILE_QLDATE:
1039	case FILE_QWDATE:
1040		if (cvt_64(p, m) == -1)
1041			goto out;
1042		return 1;
1043	case FILE_STRING:
1044	case FILE_BESTRING16:
1045	case FILE_LESTRING16: {
1046		/* Null terminate and eat *trailing* return */
1047		p->s[sizeof(p->s) - 1] = '\0';
1048		return 1;
1049	}
1050	case FILE_PSTRING: {
1051		size_t sz = file_pstring_length_size(m);
1052		char *ptr1 = p->s, *ptr2 = ptr1 + sz;
1053		size_t len = file_pstring_get_length(m, ptr1);
1054		sz = sizeof(p->s) - sz; /* maximum length of string */
1055		if (len >= sz) {
1056			/*
1057			 * The size of the pascal string length (sz)
1058			 * is 1, 2, or 4. We need at least 1 byte for NUL
1059			 * termination, but we've already truncated the
1060			 * string by p->s, so we need to deduct sz.
1061			 * Because we can use one of the bytes of the length
1062			 * after we shifted as NUL termination.
1063			 */
1064			len = sz;
1065		}
1066		while (len--)
1067			*ptr1++ = *ptr2++;
1068		*ptr1 = '\0';
1069		return 1;
1070	}
1071	case FILE_BESHORT:
1072		p->h = (short)BE16(p);
1073		if (cvt_16(p, m) == -1)
1074			goto out;
1075		return 1;
1076	case FILE_BELONG:
1077	case FILE_BEDATE:
1078	case FILE_BELDATE:
1079		p->l = (int32_t)BE32(p);
1080		if (cvt_32(p, m) == -1)
1081			goto out;
1082		return 1;
1083	case FILE_BEQUAD:
1084	case FILE_BEQDATE:
1085	case FILE_BEQLDATE:
1086	case FILE_BEQWDATE:
1087		p->q = (uint64_t)BE64(p);
1088		if (cvt_64(p, m) == -1)
1089			goto out;
1090		return 1;
1091	case FILE_LESHORT:
1092		p->h = (short)LE16(p);
1093		if (cvt_16(p, m) == -1)
1094			goto out;
1095		return 1;
1096	case FILE_LELONG:
1097	case FILE_LEDATE:
1098	case FILE_LELDATE:
1099		p->l = (int32_t)LE32(p);
1100		if (cvt_32(p, m) == -1)
1101			goto out;
1102		return 1;
1103	case FILE_LEQUAD:
1104	case FILE_LEQDATE:
1105	case FILE_LEQLDATE:
1106	case FILE_LEQWDATE:
1107		p->q = (uint64_t)LE64(p);
1108		if (cvt_64(p, m) == -1)
1109			goto out;
1110		return 1;
1111	case FILE_MELONG:
1112	case FILE_MEDATE:
1113	case FILE_MELDATE:
1114		p->l = (int32_t)ME32(p);
1115		if (cvt_32(p, m) == -1)
1116			goto out;
1117		return 1;
1118	case FILE_FLOAT:
1119		if (cvt_float(p, m) == -1)
1120			goto out;
1121		return 1;
1122	case FILE_BEFLOAT:
1123		p->l = BE32(p);
1124		if (cvt_float(p, m) == -1)
1125			goto out;
1126		return 1;
1127	case FILE_LEFLOAT:
1128		p->l = LE32(p);
1129		if (cvt_float(p, m) == -1)
1130			goto out;
1131		return 1;
1132	case FILE_DOUBLE:
1133		if (cvt_double(p, m) == -1)
1134			goto out;
1135		return 1;
1136	case FILE_BEDOUBLE:
1137		p->q = BE64(p);
1138		if (cvt_double(p, m) == -1)
1139			goto out;
1140		return 1;
1141	case FILE_LEDOUBLE:
1142		p->q = LE64(p);
1143		if (cvt_double(p, m) == -1)
1144			goto out;
1145		return 1;
1146	case FILE_REGEX:
1147	case FILE_SEARCH:
1148	case FILE_DEFAULT:
1149	case FILE_CLEAR:
1150	case FILE_NAME:
1151	case FILE_USE:
1152	case FILE_DER:
1153		return 1;
1154	default:
1155		file_magerror(ms, "invalid type %d in mconvert()", m->type);
1156		return 0;
1157	}
1158out:
1159	file_magerror(ms, "zerodivide in mconvert()");
1160	return 0;
1161}
1162
1163
1164private void
1165mdebug(uint32_t offset, const char *str, size_t len)
1166{
1167	(void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1168	file_showstr(stderr, str, len);
1169	(void) fputc('\n', stderr);
1170	(void) fputc('\n', stderr);
1171}
1172
1173private int
1174mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1175    const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1176{
1177	/*
1178	 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1179	 * anything, but setup pointers into the source
1180	 */
1181	if (indir == 0) {
1182		switch (type) {
1183		case FILE_DER:
1184		case FILE_SEARCH:
1185			if (offset > nbytes)
1186				offset = nbytes;
1187			ms->search.s = RCAST(const char *, s) + offset;
1188			ms->search.s_len = nbytes - offset;
1189			ms->search.offset = offset;
1190			return 0;
1191
1192		case FILE_REGEX: {
1193			const char *b;
1194			const char *c;
1195			const char *last;	/* end of search region */
1196			const char *buf;	/* start of search region */
1197			const char *end;
1198			size_t lines, linecnt, bytecnt;
1199
1200			if (s == NULL) {
1201				ms->search.s_len = 0;
1202				ms->search.s = NULL;
1203				return 0;
1204			}
1205
1206			if (m->str_flags & REGEX_LINE_COUNT) {
1207				linecnt = m->str_range;
1208				bytecnt = linecnt * 80;
1209			} else {
1210				linecnt = 0;
1211				bytecnt = m->str_range;
1212			}
1213
1214			if (bytecnt == 0 || bytecnt > nbytes - offset)
1215				bytecnt = nbytes - offset;
1216			if (bytecnt > ms->regex_max)
1217				bytecnt = ms->regex_max;
1218
1219			buf = RCAST(const char *, s) + offset;
1220			end = last = RCAST(const char *, s) + bytecnt + offset;
1221			/* mget() guarantees buf <= last */
1222			for (lines = linecnt, b = buf; lines && b < end &&
1223			     ((b = CAST(const char *,
1224				 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1225			     || (b = CAST(const char *,
1226				 memchr(c, '\r', CAST(size_t, (end - c))))));
1227			     lines--, b++) {
1228				last = b;
1229				if (b[0] == '\r' && b[1] == '\n')
1230					b++;
1231			}
1232			if (lines)
1233				last = RCAST(const char *, s) + bytecnt;
1234
1235			ms->search.s = buf;
1236			ms->search.s_len = last - buf;
1237			ms->search.offset = offset;
1238			ms->search.rm_len = 0;
1239			return 0;
1240		}
1241		case FILE_BESTRING16:
1242		case FILE_LESTRING16: {
1243			const unsigned char *src = s + offset;
1244			const unsigned char *esrc = s + nbytes;
1245			char *dst = p->s;
1246			char *edst = &p->s[sizeof(p->s) - 1];
1247
1248			if (type == FILE_BESTRING16)
1249				src++;
1250
1251			/* check that offset is within range */
1252			if (offset >= nbytes)
1253				break;
1254			for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1255				if (dst < edst)
1256					*dst = *src;
1257				else
1258					break;
1259				if (*dst == '\0') {
1260					if (type == FILE_BESTRING16 ?
1261					    *(src - 1) != '\0' :
1262					    *(src + 1) != '\0')
1263						*dst = ' ';
1264				}
1265			}
1266			*edst = '\0';
1267			return 0;
1268		}
1269		case FILE_STRING:	/* XXX - these two should not need */
1270		case FILE_PSTRING:	/* to copy anything, but do anyway. */
1271		default:
1272			break;
1273		}
1274	}
1275
1276	if (offset >= nbytes) {
1277		(void)memset(p, '\0', sizeof(*p));
1278		return 0;
1279	}
1280	if (nbytes - offset < sizeof(*p))
1281		nbytes = nbytes - offset;
1282	else
1283		nbytes = sizeof(*p);
1284
1285	(void)memcpy(p, s + offset, nbytes);
1286
1287	/*
1288	 * the usefulness of padding with zeroes eludes me, it
1289	 * might even cause problems
1290	 */
1291	if (nbytes < sizeof(*p))
1292		(void)memset(((char *)(void *)p) + nbytes, '\0',
1293		    sizeof(*p) - nbytes);
1294	return 0;
1295}
1296
1297private int
1298mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
1299    size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
1300    int flip, uint16_t *indir_count, uint16_t *name_count,
1301    int *printed_something, int *need_separator, int *returnval)
1302{
1303	uint32_t offset = ms->offset;
1304	uint32_t lhs;
1305	file_pushbuf_t *pb;
1306	int rv, oneed_separator, in_type;
1307	char *rbuf;
1308	union VALUETYPE *p = &ms->ms_value;
1309	struct mlist ml;
1310
1311	if (*indir_count >= ms->indir_max) {
1312		file_error(ms, 0, "indirect count (%hu) exceeded",
1313		    *indir_count);
1314		return -1;
1315	}
1316
1317	if (*name_count >= ms->name_max) {
1318		file_error(ms, 0, "name use count (%hu) exceeded",
1319		    *name_count);
1320		return -1;
1321	}
1322
1323	if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
1324	    (uint32_t)nbytes, m) == -1)
1325		return -1;
1326
1327	if ((ms->flags & MAGIC_DEBUG) != 0) {
1328		fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%"
1329		    SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1330		    "u, il=%hu, nc=%hu)\n",
1331		    m->type, m->flag, offset, o, nbytes,
1332		    *indir_count, *name_count);
1333		mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1334#ifndef COMPILE_ONLY
1335		file_mdump(m);
1336#endif
1337	}
1338
1339	if (m->flag & INDIR) {
1340		int off = m->in_offset;
1341		if (m->in_op & FILE_OPINDIRECT) {
1342			const union VALUETYPE *q = CAST(const union VALUETYPE *,
1343			    ((const void *)(s + offset + off)));
1344			if (OFFSET_OOB(nbytes, offset + off, sizeof(*q)))
1345				return 0;
1346			switch (cvt_flip(m->in_type, flip)) {
1347			case FILE_BYTE:
1348				off = q->b;
1349				break;
1350			case FILE_SHORT:
1351				off = q->h;
1352				break;
1353			case FILE_BESHORT:
1354				off = (short)BE16(q);
1355				break;
1356			case FILE_LESHORT:
1357				off = (short)LE16(q);
1358				break;
1359			case FILE_LONG:
1360				off = q->l;
1361				break;
1362			case FILE_BELONG:
1363			case FILE_BEID3:
1364				off = (int32_t)BE32(q);
1365				break;
1366			case FILE_LEID3:
1367			case FILE_LELONG:
1368				off = (int32_t)LE32(q);
1369				break;
1370			case FILE_MELONG:
1371				off = (int32_t)ME32(q);
1372				break;
1373			}
1374			if ((ms->flags & MAGIC_DEBUG) != 0)
1375				fprintf(stderr, "indirect offs=%u\n", off);
1376		}
1377		switch (in_type = cvt_flip(m->in_type, flip)) {
1378		case FILE_BYTE:
1379			if (OFFSET_OOB(nbytes, offset, 1))
1380				return 0;
1381			if (off) {
1382				switch (m->in_op & FILE_OPS_MASK) {
1383				case FILE_OPAND:
1384					offset = p->b & off;
1385					break;
1386				case FILE_OPOR:
1387					offset = p->b | off;
1388					break;
1389				case FILE_OPXOR:
1390					offset = p->b ^ off;
1391					break;
1392				case FILE_OPADD:
1393					offset = p->b + off;
1394					break;
1395				case FILE_OPMINUS:
1396					offset = p->b - off;
1397					break;
1398				case FILE_OPMULTIPLY:
1399					offset = p->b * off;
1400					break;
1401				case FILE_OPDIVIDE:
1402					offset = p->b / off;
1403					break;
1404				case FILE_OPMODULO:
1405					offset = p->b % off;
1406					break;
1407				}
1408			} else
1409				offset = p->b;
1410			if (m->in_op & FILE_OPINVERSE)
1411				offset = ~offset;
1412			break;
1413		case FILE_BESHORT:
1414			if (OFFSET_OOB(nbytes, offset, 2))
1415				return 0;
1416			lhs = (p->hs[0] << 8) | p->hs[1];
1417			if (off) {
1418				switch (m->in_op & FILE_OPS_MASK) {
1419				case FILE_OPAND:
1420					offset = lhs & off;
1421					break;
1422				case FILE_OPOR:
1423					offset = lhs | off;
1424					break;
1425				case FILE_OPXOR:
1426					offset = lhs ^ off;
1427					break;
1428				case FILE_OPADD:
1429					offset = lhs + off;
1430					break;
1431				case FILE_OPMINUS:
1432					offset = lhs - off;
1433					break;
1434				case FILE_OPMULTIPLY:
1435					offset = lhs * off;
1436					break;
1437				case FILE_OPDIVIDE:
1438					offset = lhs / off;
1439					break;
1440				case FILE_OPMODULO:
1441					offset = lhs % off;
1442					break;
1443				}
1444			} else
1445				offset = lhs;
1446			if (m->in_op & FILE_OPINVERSE)
1447				offset = ~offset;
1448			break;
1449		case FILE_LESHORT:
1450			if (OFFSET_OOB(nbytes, offset, 2))
1451				return 0;
1452			lhs = (p->hs[1] << 8) | p->hs[0];
1453			if (off) {
1454				switch (m->in_op & FILE_OPS_MASK) {
1455				case FILE_OPAND:
1456					offset = lhs & off;
1457					break;
1458				case FILE_OPOR:
1459					offset = lhs | off;
1460					break;
1461				case FILE_OPXOR:
1462					offset = lhs ^ off;
1463					break;
1464				case FILE_OPADD:
1465					offset = lhs + off;
1466					break;
1467				case FILE_OPMINUS:
1468					offset = lhs - off;
1469					break;
1470				case FILE_OPMULTIPLY:
1471					offset = lhs * off;
1472					break;
1473				case FILE_OPDIVIDE:
1474					offset = lhs / off;
1475					break;
1476				case FILE_OPMODULO:
1477					offset = lhs % off;
1478					break;
1479				}
1480			} else
1481				offset = lhs;
1482			if (m->in_op & FILE_OPINVERSE)
1483				offset = ~offset;
1484			break;
1485		case FILE_SHORT:
1486			if (OFFSET_OOB(nbytes, offset, 2))
1487				return 0;
1488			if (off) {
1489				switch (m->in_op & FILE_OPS_MASK) {
1490				case FILE_OPAND:
1491					offset = p->h & off;
1492					break;
1493				case FILE_OPOR:
1494					offset = p->h | off;
1495					break;
1496				case FILE_OPXOR:
1497					offset = p->h ^ off;
1498					break;
1499				case FILE_OPADD:
1500					offset = p->h + off;
1501					break;
1502				case FILE_OPMINUS:
1503					offset = p->h - off;
1504					break;
1505				case FILE_OPMULTIPLY:
1506					offset = p->h * off;
1507					break;
1508				case FILE_OPDIVIDE:
1509					offset = p->h / off;
1510					break;
1511				case FILE_OPMODULO:
1512					offset = p->h % off;
1513					break;
1514				}
1515			}
1516			else
1517				offset = p->h;
1518			if (m->in_op & FILE_OPINVERSE)
1519				offset = ~offset;
1520			break;
1521		case FILE_BELONG:
1522		case FILE_BEID3:
1523			if (OFFSET_OOB(nbytes, offset, 4))
1524				return 0;
1525			lhs = BE32(p);
1526			if (in_type == FILE_BEID3)
1527				lhs = cvt_id3(ms, lhs);
1528			if (off) {
1529				switch (m->in_op & FILE_OPS_MASK) {
1530				case FILE_OPAND:
1531					offset = lhs & off;
1532					break;
1533				case FILE_OPOR:
1534					offset = lhs | off;
1535					break;
1536				case FILE_OPXOR:
1537					offset = lhs ^ off;
1538					break;
1539				case FILE_OPADD:
1540					offset = lhs + off;
1541					break;
1542				case FILE_OPMINUS:
1543					offset = lhs - off;
1544					break;
1545				case FILE_OPMULTIPLY:
1546					offset = lhs * off;
1547					break;
1548				case FILE_OPDIVIDE:
1549					offset = lhs / off;
1550					break;
1551				case FILE_OPMODULO:
1552					offset = lhs % off;
1553					break;
1554				}
1555			} else
1556				offset = lhs;
1557			if (m->in_op & FILE_OPINVERSE)
1558				offset = ~offset;
1559			break;
1560		case FILE_LELONG:
1561		case FILE_LEID3:
1562			if (OFFSET_OOB(nbytes, offset, 4))
1563				return 0;
1564			lhs = LE32(p);
1565			if (in_type == FILE_LEID3)
1566				lhs = cvt_id3(ms, lhs);
1567			if (off) {
1568				switch (m->in_op & FILE_OPS_MASK) {
1569				case FILE_OPAND:
1570					offset = lhs & off;
1571					break;
1572				case FILE_OPOR:
1573					offset = lhs | off;
1574					break;
1575				case FILE_OPXOR:
1576					offset = lhs ^ off;
1577					break;
1578				case FILE_OPADD:
1579					offset = lhs + off;
1580					break;
1581				case FILE_OPMINUS:
1582					offset = lhs - off;
1583					break;
1584				case FILE_OPMULTIPLY:
1585					offset = lhs * off;
1586					break;
1587				case FILE_OPDIVIDE:
1588					offset = lhs / off;
1589					break;
1590				case FILE_OPMODULO:
1591					offset = lhs % off;
1592					break;
1593				}
1594			} else
1595				offset = lhs;
1596			if (m->in_op & FILE_OPINVERSE)
1597				offset = ~offset;
1598			break;
1599		case FILE_MELONG:
1600			if (OFFSET_OOB(nbytes, offset, 4))
1601				return 0;
1602			lhs = ME32(p);
1603			if (off) {
1604				switch (m->in_op & FILE_OPS_MASK) {
1605				case FILE_OPAND:
1606					offset = lhs & off;
1607					break;
1608				case FILE_OPOR:
1609					offset = lhs | off;
1610					break;
1611				case FILE_OPXOR:
1612					offset = lhs ^ off;
1613					break;
1614				case FILE_OPADD:
1615					offset = lhs + off;
1616					break;
1617				case FILE_OPMINUS:
1618					offset = lhs - off;
1619					break;
1620				case FILE_OPMULTIPLY:
1621					offset = lhs * off;
1622					break;
1623				case FILE_OPDIVIDE:
1624					offset = lhs / off;
1625					break;
1626				case FILE_OPMODULO:
1627					offset = lhs % off;
1628					break;
1629				}
1630			} else
1631				offset = lhs;
1632			if (m->in_op & FILE_OPINVERSE)
1633				offset = ~offset;
1634			break;
1635		case FILE_LONG:
1636			if (OFFSET_OOB(nbytes, offset, 4))
1637				return 0;
1638			if (off) {
1639				switch (m->in_op & FILE_OPS_MASK) {
1640				case FILE_OPAND:
1641					offset = p->l & off;
1642					break;
1643				case FILE_OPOR:
1644					offset = p->l | off;
1645					break;
1646				case FILE_OPXOR:
1647					offset = p->l ^ off;
1648					break;
1649				case FILE_OPADD:
1650					offset = p->l + off;
1651					break;
1652				case FILE_OPMINUS:
1653					offset = p->l - off;
1654					break;
1655				case FILE_OPMULTIPLY:
1656					offset = p->l * off;
1657					break;
1658				case FILE_OPDIVIDE:
1659					offset = p->l / off;
1660					break;
1661				case FILE_OPMODULO:
1662					offset = p->l % off;
1663					break;
1664				}
1665			} else
1666				offset = p->l;
1667			if (m->in_op & FILE_OPINVERSE)
1668				offset = ~offset;
1669			break;
1670		default:
1671			break;
1672		}
1673
1674		if (m->flag & INDIROFFADD) {
1675			offset += ms->c.li[cont_level-1].off;
1676			if (offset == 0) {
1677				if ((ms->flags & MAGIC_DEBUG) != 0)
1678					fprintf(stderr,
1679					    "indirect *zero* offset\n");
1680				return 0;
1681			}
1682			if ((ms->flags & MAGIC_DEBUG) != 0)
1683				fprintf(stderr, "indirect +offs=%u\n", offset);
1684		}
1685		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1686			return -1;
1687		ms->offset = offset;
1688
1689		if ((ms->flags & MAGIC_DEBUG) != 0) {
1690			mdebug(offset, (char *)(void *)p,
1691			    sizeof(union VALUETYPE));
1692#ifndef COMPILE_ONLY
1693			file_mdump(m);
1694#endif
1695		}
1696	}
1697
1698	/* Verify we have enough data to match magic type */
1699	switch (m->type) {
1700	case FILE_BYTE:
1701		if (OFFSET_OOB(nbytes, offset, 1))
1702			return 0;
1703		break;
1704
1705	case FILE_SHORT:
1706	case FILE_BESHORT:
1707	case FILE_LESHORT:
1708		if (OFFSET_OOB(nbytes, offset, 2))
1709			return 0;
1710		break;
1711
1712	case FILE_LONG:
1713	case FILE_BELONG:
1714	case FILE_LELONG:
1715	case FILE_MELONG:
1716	case FILE_DATE:
1717	case FILE_BEDATE:
1718	case FILE_LEDATE:
1719	case FILE_MEDATE:
1720	case FILE_LDATE:
1721	case FILE_BELDATE:
1722	case FILE_LELDATE:
1723	case FILE_MELDATE:
1724	case FILE_FLOAT:
1725	case FILE_BEFLOAT:
1726	case FILE_LEFLOAT:
1727		if (OFFSET_OOB(nbytes, offset, 4))
1728			return 0;
1729		break;
1730
1731	case FILE_DOUBLE:
1732	case FILE_BEDOUBLE:
1733	case FILE_LEDOUBLE:
1734		if (OFFSET_OOB(nbytes, offset, 8))
1735			return 0;
1736		break;
1737
1738	case FILE_STRING:
1739	case FILE_PSTRING:
1740	case FILE_SEARCH:
1741		if (OFFSET_OOB(nbytes, offset, m->vallen))
1742			return 0;
1743		break;
1744
1745	case FILE_REGEX:
1746		if (nbytes < offset)
1747			return 0;
1748		break;
1749
1750	case FILE_INDIRECT:
1751		if (m->str_flags & INDIRECT_RELATIVE)
1752			offset += CAST(uint32_t, o);
1753		if (offset == 0)
1754			return 0;
1755
1756		if (nbytes < offset)
1757			return 0;
1758
1759		if ((pb = file_push_buffer(ms)) == NULL)
1760			return -1;
1761
1762		(*indir_count)++;
1763		rv = file_softmagic(ms, s + offset, nbytes - offset,
1764		    indir_count, name_count, BINTEST, text);
1765
1766		if ((ms->flags & MAGIC_DEBUG) != 0)
1767			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1768
1769		rbuf = file_pop_buffer(ms, pb);
1770		if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1771			return -1;
1772
1773		if (rv == 1) {
1774			if ((ms->flags & MAGIC_NODESC) == 0 &&
1775			    file_printf(ms, F(ms, m, "%u"), offset) == -1) {
1776				free(rbuf);
1777				return -1;
1778			}
1779			if (file_printf(ms, "%s", rbuf) == -1) {
1780				free(rbuf);
1781				return -1;
1782			}
1783		}
1784		free(rbuf);
1785		return rv;
1786
1787	case FILE_USE:
1788		if (nbytes < offset)
1789			return 0;
1790		rbuf = m->value.s;
1791		if (*rbuf == '^') {
1792			rbuf++;
1793			flip = !flip;
1794		}
1795		if (file_magicfind(ms, rbuf, &ml) == -1) {
1796			file_error(ms, 0, "cannot find entry `%s'", rbuf);
1797			return -1;
1798		}
1799		(*name_count)++;
1800		oneed_separator = *need_separator;
1801		if (m->flag & NOSPACE)
1802			*need_separator = 0;
1803		rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
1804		    mode, text, flip, indir_count, name_count,
1805		    printed_something, need_separator, returnval);
1806		if (rv != 1)
1807		    *need_separator = oneed_separator;
1808		return 1;
1809
1810	case FILE_NAME:
1811		if (ms->flags & MAGIC_NODESC)
1812			return 1;
1813		if (file_printf(ms, "%s", m->desc) == -1)
1814			return -1;
1815		return 1;
1816	case FILE_DER:
1817	case FILE_DEFAULT:	/* nothing to check */
1818	case FILE_CLEAR:
1819	default:
1820		break;
1821	}
1822	if (!mconvert(ms, m, flip))
1823		return 0;
1824	return 1;
1825}
1826
1827private uint64_t
1828file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1829{
1830	/*
1831	 * Convert the source args to unsigned here so that (1) the
1832	 * compare will be unsigned as it is in strncmp() and (2) so
1833	 * the ctype functions will work correctly without extra
1834	 * casting.
1835	 */
1836	const unsigned char *a = (const unsigned char *)s1;
1837	const unsigned char *b = (const unsigned char *)s2;
1838	uint64_t v;
1839
1840	/*
1841	 * What we want here is v = strncmp(s1, s2, len),
1842	 * but ignoring any nulls.
1843	 */
1844	v = 0;
1845	if (0L == flags) { /* normal string: do it fast */
1846		while (len-- > 0)
1847			if ((v = *b++ - *a++) != '\0')
1848				break;
1849	}
1850	else { /* combine the others */
1851		while (len-- > 0) {
1852			if ((flags & STRING_IGNORE_LOWERCASE) &&
1853			    islower(*a)) {
1854				if ((v = tolower(*b++) - *a++) != '\0')
1855					break;
1856			}
1857			else if ((flags & STRING_IGNORE_UPPERCASE) &&
1858			    isupper(*a)) {
1859				if ((v = toupper(*b++) - *a++) != '\0')
1860					break;
1861			}
1862			else if ((flags & STRING_COMPACT_WHITESPACE) &&
1863			    isspace(*a)) {
1864				a++;
1865				if (isspace(*b++)) {
1866					if (!isspace(*a))
1867						while (isspace(*b))
1868							b++;
1869				}
1870				else {
1871					v = 1;
1872					break;
1873				}
1874			}
1875			else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1876			    isspace(*a)) {
1877				a++;
1878				while (isspace(*b))
1879					b++;
1880			}
1881			else {
1882				if ((v = *b++ - *a++) != '\0')
1883					break;
1884			}
1885		}
1886	}
1887	return v;
1888}
1889
1890private uint64_t
1891file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1892{
1893	/*
1894	 * XXX - The 16-bit string compare probably needs to be done
1895	 * differently, especially if the flags are to be supported.
1896	 * At the moment, I am unsure.
1897	 */
1898	flags = 0;
1899	return file_strncmp(a, b, len, flags);
1900}
1901
1902private int
1903magiccheck(struct magic_set *ms, struct magic *m)
1904{
1905	uint64_t l = m->value.q;
1906	uint64_t v;
1907	float fl, fv;
1908	double dl, dv;
1909	int matched;
1910	union VALUETYPE *p = &ms->ms_value;
1911
1912	switch (m->type) {
1913	case FILE_BYTE:
1914		v = p->b;
1915		break;
1916
1917	case FILE_SHORT:
1918	case FILE_BESHORT:
1919	case FILE_LESHORT:
1920		v = p->h;
1921		break;
1922
1923	case FILE_LONG:
1924	case FILE_BELONG:
1925	case FILE_LELONG:
1926	case FILE_MELONG:
1927	case FILE_DATE:
1928	case FILE_BEDATE:
1929	case FILE_LEDATE:
1930	case FILE_MEDATE:
1931	case FILE_LDATE:
1932	case FILE_BELDATE:
1933	case FILE_LELDATE:
1934	case FILE_MELDATE:
1935		v = p->l;
1936		break;
1937
1938	case FILE_QUAD:
1939	case FILE_LEQUAD:
1940	case FILE_BEQUAD:
1941	case FILE_QDATE:
1942	case FILE_BEQDATE:
1943	case FILE_LEQDATE:
1944	case FILE_QLDATE:
1945	case FILE_BEQLDATE:
1946	case FILE_LEQLDATE:
1947	case FILE_QWDATE:
1948	case FILE_BEQWDATE:
1949	case FILE_LEQWDATE:
1950		v = p->q;
1951		break;
1952
1953	case FILE_FLOAT:
1954	case FILE_BEFLOAT:
1955	case FILE_LEFLOAT:
1956		fl = m->value.f;
1957		fv = p->f;
1958		switch (m->reln) {
1959		case 'x':
1960			matched = 1;
1961			break;
1962
1963		case '!':
1964			matched = fv != fl;
1965			break;
1966
1967		case '=':
1968			matched = fv == fl;
1969			break;
1970
1971		case '>':
1972			matched = fv > fl;
1973			break;
1974
1975		case '<':
1976			matched = fv < fl;
1977			break;
1978
1979		default:
1980			file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1981			    m->reln);
1982			return -1;
1983		}
1984		return matched;
1985
1986	case FILE_DOUBLE:
1987	case FILE_BEDOUBLE:
1988	case FILE_LEDOUBLE:
1989		dl = m->value.d;
1990		dv = p->d;
1991		switch (m->reln) {
1992		case 'x':
1993			matched = 1;
1994			break;
1995
1996		case '!':
1997			matched = dv != dl;
1998			break;
1999
2000		case '=':
2001			matched = dv == dl;
2002			break;
2003
2004		case '>':
2005			matched = dv > dl;
2006			break;
2007
2008		case '<':
2009			matched = dv < dl;
2010			break;
2011
2012		default:
2013			file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
2014			return -1;
2015		}
2016		return matched;
2017
2018	case FILE_DEFAULT:
2019	case FILE_CLEAR:
2020		l = 0;
2021		v = 0;
2022		break;
2023
2024	case FILE_STRING:
2025	case FILE_PSTRING:
2026		l = 0;
2027		v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
2028		break;
2029
2030	case FILE_BESTRING16:
2031	case FILE_LESTRING16:
2032		l = 0;
2033		v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
2034		break;
2035
2036	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
2037		size_t slen;
2038		size_t idx;
2039
2040		if (ms->search.s == NULL)
2041			return 0;
2042
2043		slen = MIN(m->vallen, sizeof(m->value.s));
2044		l = 0;
2045		v = 0;
2046
2047		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
2048			if (slen + idx > ms->search.s_len)
2049				break;
2050
2051			v = file_strncmp(m->value.s, ms->search.s + idx, slen,
2052			    m->str_flags);
2053			if (v == 0) {	/* found match */
2054				ms->search.offset += idx;
2055				ms->search.rm_len = m->str_range - idx;
2056				break;
2057			}
2058		}
2059		break;
2060	}
2061	case FILE_REGEX: {
2062		int rc;
2063		file_regex_t rx;
2064		const char *search;
2065
2066		if (ms->search.s == NULL)
2067			return 0;
2068
2069		l = 0;
2070		rc = file_regcomp(&rx, m->value.s,
2071		    REG_EXTENDED|REG_NEWLINE|
2072		    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
2073		if (rc) {
2074			file_regerror(&rx, rc, ms);
2075			v = (uint64_t)-1;
2076		} else {
2077			regmatch_t pmatch;
2078			size_t slen = ms->search.s_len;
2079			char *copy;
2080			if (slen != 0) {
2081			    copy = malloc(slen);
2082			    if (copy == NULL)  {
2083				file_regfree(&rx);
2084				file_error(ms, errno,
2085				    "can't allocate %" SIZE_T_FORMAT "u bytes",
2086				    slen);
2087				return -1;
2088			    }
2089			    memcpy(copy, ms->search.s, slen);
2090			    copy[--slen] = '\0';
2091			    search = copy;
2092			} else {
2093			    search = ms->search.s;
2094			    copy = NULL;
2095			}
2096			rc = file_regexec(&rx, (const char *)search,
2097			    1, &pmatch, 0);
2098			free(copy);
2099			switch (rc) {
2100			case 0:
2101				ms->search.s += (int)pmatch.rm_so;
2102				ms->search.offset += (size_t)pmatch.rm_so;
2103				ms->search.rm_len =
2104				    (size_t)(pmatch.rm_eo - pmatch.rm_so);
2105				v = 0;
2106				break;
2107
2108			case REG_NOMATCH:
2109				v = 1;
2110				break;
2111
2112			default:
2113				file_regerror(&rx, rc, ms);
2114				v = (uint64_t)-1;
2115				break;
2116			}
2117		}
2118		file_regfree(&rx);
2119		if (v == (uint64_t)-1)
2120			return -1;
2121		break;
2122	}
2123	case FILE_INDIRECT:
2124	case FILE_USE:
2125	case FILE_NAME:
2126		return 1;
2127	case FILE_DER:
2128		matched = der_cmp(ms, m);
2129		if (matched == -1) {
2130			if ((ms->flags & MAGIC_DEBUG) != 0) {
2131				(void) fprintf(stderr,
2132				    "EOF comparing DER entries");
2133			}
2134			return 0;
2135		}
2136		return matched;
2137	default:
2138		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2139		return -1;
2140	}
2141
2142	v = file_signextend(ms, m, v);
2143
2144	switch (m->reln) {
2145	case 'x':
2146		if ((ms->flags & MAGIC_DEBUG) != 0)
2147			(void) fprintf(stderr, "%" INT64_T_FORMAT
2148			    "u == *any* = 1\n", (unsigned long long)v);
2149		matched = 1;
2150		break;
2151
2152	case '!':
2153		matched = v != l;
2154		if ((ms->flags & MAGIC_DEBUG) != 0)
2155			(void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2156			    INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2157			    (unsigned long long)l, matched);
2158		break;
2159
2160	case '=':
2161		matched = v == l;
2162		if ((ms->flags & MAGIC_DEBUG) != 0)
2163			(void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2164			    INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2165			    (unsigned long long)l, matched);
2166		break;
2167
2168	case '>':
2169		if (m->flag & UNSIGNED) {
2170			matched = v > l;
2171			if ((ms->flags & MAGIC_DEBUG) != 0)
2172				(void) fprintf(stderr, "%" INT64_T_FORMAT
2173				    "u > %" INT64_T_FORMAT "u = %d\n",
2174				    (unsigned long long)v,
2175				    (unsigned long long)l, matched);
2176		}
2177		else {
2178			matched = (int64_t) v > (int64_t) l;
2179			if ((ms->flags & MAGIC_DEBUG) != 0)
2180				(void) fprintf(stderr, "%" INT64_T_FORMAT
2181				    "d > %" INT64_T_FORMAT "d = %d\n",
2182				    (long long)v, (long long)l, matched);
2183		}
2184		break;
2185
2186	case '<':
2187		if (m->flag & UNSIGNED) {
2188			matched = v < l;
2189			if ((ms->flags & MAGIC_DEBUG) != 0)
2190				(void) fprintf(stderr, "%" INT64_T_FORMAT
2191				    "u < %" INT64_T_FORMAT "u = %d\n",
2192				    (unsigned long long)v,
2193				    (unsigned long long)l, matched);
2194		}
2195		else {
2196			matched = (int64_t) v < (int64_t) l;
2197			if ((ms->flags & MAGIC_DEBUG) != 0)
2198				(void) fprintf(stderr, "%" INT64_T_FORMAT
2199				    "d < %" INT64_T_FORMAT "d = %d\n",
2200				     (long long)v, (long long)l, matched);
2201		}
2202		break;
2203
2204	case '&':
2205		matched = (v & l) == l;
2206		if ((ms->flags & MAGIC_DEBUG) != 0)
2207			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2208			    INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2209			    "x) = %d\n", (unsigned long long)v,
2210			    (unsigned long long)l, (unsigned long long)l,
2211			    matched);
2212		break;
2213
2214	case '^':
2215		matched = (v & l) != l;
2216		if ((ms->flags & MAGIC_DEBUG) != 0)
2217			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2218			    INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2219			    "x) = %d\n", (unsigned long long)v,
2220			    (unsigned long long)l, (unsigned long long)l,
2221			    matched);
2222		break;
2223
2224	default:
2225		file_magerror(ms, "cannot happen: invalid relation `%c'",
2226		    m->reln);
2227		return -1;
2228	}
2229
2230	return matched;
2231}
2232
2233private int
2234handle_annotation(struct magic_set *ms, struct magic *m)
2235{
2236	if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
2237		if (file_printf(ms, "%.8s", m->apple) == -1)
2238			return -1;
2239		return 1;
2240	}
2241	if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
2242		if (file_printf(ms, "%s", m->ext) == -1)
2243			return -1;
2244		return 1;
2245	}
2246	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2247		if (file_printf(ms, "%s", m->mimetype) == -1)
2248			return -1;
2249		return 1;
2250	}
2251	return 0;
2252}
2253
2254private int
2255print_sep(struct magic_set *ms, int firstline)
2256{
2257	if (ms->flags & MAGIC_NODESC)
2258		return 0;
2259	if (firstline)
2260		return 0;
2261	/*
2262	 * we found another match
2263	 * put a newline and '-' to do some simple formatting
2264	 */
2265	return file_printf(ms, "\n- ");
2266}
2267