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