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