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