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