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