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