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