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