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