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