168349Sobrien/*
2133359Sobrien * Copyright (c) Ian F. Darwin 1986-1995.
3133359Sobrien * Software written by Ian F. Darwin and others;
4133359Sobrien * maintained 1995-present by Christos Zoulas and others.
5191736Sobrien *
6133359Sobrien * Redistribution and use in source and binary forms, with or without
7133359Sobrien * modification, are permitted provided that the following conditions
8133359Sobrien * are met:
9133359Sobrien * 1. Redistributions of source code must retain the above copyright
10133359Sobrien *    notice immediately at the beginning of the file, without modification,
11133359Sobrien *    this list of conditions, and the following disclaimer.
12133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright
13133359Sobrien *    notice, this list of conditions and the following disclaimer in the
14133359Sobrien *    documentation and/or other materials provided with the distribution.
15191736Sobrien *
16133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26133359Sobrien * SUCH DAMAGE.
27133359Sobrien */
28133359Sobrien/*
2975937Sobrien * softmagic - interpret variable magic from MAGIC
3068349Sobrien */
3168349Sobrien
32103373Sobrien#include "file.h"
33191736Sobrien
34191736Sobrien#ifndef	lint
35284193SdelphijFILE_RCSID("@(#)$File: softmagic.c,v 1.206 2015/01/01 17:07:34 christos Exp $")
36191736Sobrien#endif	/* lint */
37191736Sobrien
38133359Sobrien#include "magic.h"
39267843Sdelphij#include <assert.h>
4068349Sobrien#include <string.h>
4168349Sobrien#include <ctype.h>
4268349Sobrien#include <stdlib.h>
4368349Sobrien#include <time.h>
4468349Sobrien
45133359Sobrienprivate int match(struct magic_set *, struct magic *, uint32_t,
46284193Sdelphij    const unsigned char *, size_t, size_t, int, int, int, uint16_t,
47284193Sdelphij    uint16_t *, int *, int *, int *);
48169962Sobrienprivate int mget(struct magic_set *, const unsigned char *,
49284193Sdelphij    struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t,
50284193Sdelphij    uint16_t *, int *, int *, int *);
51169962Sobrienprivate int magiccheck(struct magic_set *, struct magic *);
52169962Sobrienprivate int32_t mprint(struct magic_set *, struct magic *);
53191736Sobrienprivate int32_t moffset(struct magic_set *, struct magic *);
54133359Sobrienprivate void mdebug(uint32_t, const char *, size_t);
55139368Sobrienprivate int mcopy(struct magic_set *, union VALUETYPE *, int, int,
56267843Sdelphij    const unsigned char *, uint32_t, size_t, struct magic *);
57267843Sdelphijprivate int mconvert(struct magic_set *, struct magic *, int);
58169942Sobrienprivate int print_sep(struct magic_set *, int);
59191736Sobrienprivate int handle_annotation(struct magic_set *, struct magic *);
60169942Sobrienprivate void cvt_8(union VALUETYPE *, const struct magic *);
61169942Sobrienprivate void cvt_16(union VALUETYPE *, const struct magic *);
62169942Sobrienprivate void cvt_32(union VALUETYPE *, const struct magic *);
63169942Sobrienprivate void cvt_64(union VALUETYPE *, const struct magic *);
6468349Sobrien
65267843Sdelphij#define OFFSET_OOB(n, o, i)	((n) < (o) || (i) > ((n) - (o)))
66275670Sdelphij
6768349Sobrien/*
68169942Sobrien * softmagic - lookup one file in parsed, in-memory copy of database
6968349Sobrien * Passed the name and FILE * of one file to be typed.
7068349Sobrien */
7168349Sobrien/*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
72133359Sobrienprotected int
73234250Sobrienfile_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
74284193Sdelphij    uint16_t indir_level, uint16_t *name_count, int mode, int text)
7568349Sobrien{
7674784Sobrien	struct mlist *ml;
77267843Sdelphij	int rv, printed_something = 0, need_separator = 0;
78284193Sdelphij	uint16_t nc;
79284193Sdelphij
80284193Sdelphij	if (name_count == NULL) {
81284193Sdelphij		nc = 0;
82284193Sdelphij		name_count = &nc;
83284193Sdelphij	}
84284193Sdelphij
85267843Sdelphij	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
86267843Sdelphij		if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
87284193Sdelphij		    text, 0, indir_level, name_count,
88284193Sdelphij		    &printed_something, &need_separator, NULL)) != 0)
89169942Sobrien			return rv;
9074784Sobrien
9168349Sobrien	return 0;
9268349Sobrien}
9368349Sobrien
94267843Sdelphij#define FILE_FMTDEBUG
95267843Sdelphij#ifdef FILE_FMTDEBUG
96267843Sdelphij#define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
97267843Sdelphij
98267843Sdelphijprivate const char * __attribute__((__format_arg__(3)))
99267843Sdelphijfile_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def,
100267843Sdelphij	const char *file, size_t line)
101267843Sdelphij{
102267843Sdelphij	const char *ptr = fmtcheck(m->desc, def);
103267843Sdelphij	if (ptr == def)
104267843Sdelphij		file_magerror(ms,
105284193Sdelphij		    "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
106284193Sdelphij		    " with `%s'", file, line, m->desc, def);
107267843Sdelphij	return ptr;
108267843Sdelphij}
109267843Sdelphij#else
110267843Sdelphij#define F(a, b, c) fmtcheck((b)->desc, (c))
111267843Sdelphij#endif
112267843Sdelphij
11368349Sobrien/*
11468349Sobrien * Go through the whole list, stopping if you find a match.  Process all
11568349Sobrien * the continuations of that match before returning.
11668349Sobrien *
11768349Sobrien * We support multi-level continuations:
11868349Sobrien *
11968349Sobrien *	At any time when processing a successful top-level match, there is a
12068349Sobrien *	current continuation level; it represents the level of the last
12168349Sobrien *	successfully matched continuation.
12268349Sobrien *
12368349Sobrien *	Continuations above that level are skipped as, if we see one, it
12468349Sobrien *	means that the continuation that controls them - i.e, the
12568349Sobrien *	lower-level continuation preceding them - failed to match.
12668349Sobrien *
12768349Sobrien *	Continuations below that level are processed as, if we see one,
12868349Sobrien *	it means we've finished processing or skipping higher-level
12968349Sobrien *	continuations under the control of a successful or unsuccessful
13068349Sobrien *	lower-level continuation, and are now seeing the next lower-level
13168349Sobrien *	continuation and should process it.  The current continuation
13268349Sobrien *	level reverts to the level of the one we're seeing.
13368349Sobrien *
13468349Sobrien *	Continuations at the current level are processed as, if we see
13568349Sobrien *	one, there's no lower-level continuation that may have failed.
13668349Sobrien *
13768349Sobrien *	If a continuation matches, we bump the current continuation level
13868349Sobrien *	so that higher-level continuations are processed.
13968349Sobrien */
140133359Sobrienprivate int
141133359Sobrienmatch(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
142267843Sdelphij    const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
143284193Sdelphij    int flip, uint16_t indir_level, uint16_t *name_count,
144284193Sdelphij    int *printed_something, int *need_separator, int *returnval)
14568349Sobrien{
146133359Sobrien	uint32_t magindex = 0;
147133359Sobrien	unsigned int cont_level = 0;
148267843Sdelphij	int returnvalv = 0, e; /* if a match is found it is set to 1*/
14968349Sobrien	int firstline = 1; /* a flag to print X\n  X\n- X */
150191736Sobrien	int print = (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0;
15168349Sobrien
152267843Sdelphij	if (returnval == NULL)
153267843Sdelphij		returnval = &returnvalv;
154267843Sdelphij
155169962Sobrien	if (file_check_mem(ms, cont_level) == -1)
156133359Sobrien		return -1;
15768349Sobrien
15868349Sobrien	for (magindex = 0; magindex < nmagic; magindex++) {
159191736Sobrien		int flush = 0;
160186690Sobrien		struct magic *m = &magic[magindex];
161169962Sobrien
162267843Sdelphij		if (m->type != FILE_NAME)
163234250Sobrien		if ((IS_STRING(m->type) &&
164267843Sdelphij#define FLT (STRING_BINTEST | STRING_TEXTTEST)
165267843Sdelphij		     ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
166267843Sdelphij		      (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
167234250Sobrien		    (m->flag & mode) != mode) {
168186690Sobrien			/* Skip sub-tests */
169267843Sdelphij			while (magindex + 1 < nmagic &&
170267843Sdelphij                               magic[magindex + 1].cont_level != 0 &&
171267843Sdelphij			       ++magindex)
172186690Sobrien				continue;
173186690Sobrien			continue; /* Skip to next top-level test*/
174186690Sobrien		}
175169962Sobrien
176186690Sobrien		ms->offset = m->offset;
177186690Sobrien		ms->line = m->lineno;
178186690Sobrien
17968349Sobrien		/* if main entry matches, print it... */
180267843Sdelphij		switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
181284193Sdelphij		    flip, indir_level, name_count,
182284193Sdelphij		    printed_something, need_separator, returnval)) {
183191736Sobrien		case -1:
184191736Sobrien			return -1;
185191736Sobrien		case 0:
186191736Sobrien			flush = m->reln != '!';
187191736Sobrien			break;
188191736Sobrien		default:
189191736Sobrien			if (m->type == FILE_INDIRECT)
190267843Sdelphij				*returnval = 1;
191226048Sobrien
192186690Sobrien			switch (magiccheck(ms, m)) {
193159764Sobrien			case -1:
194159764Sobrien				return -1;
195159764Sobrien			case 0:
196159764Sobrien				flush++;
197159764Sobrien				break;
198159764Sobrien			default:
199191736Sobrien				flush = 0;
200159764Sobrien				break;
201159764Sobrien			}
202191736Sobrien			break;
20368349Sobrien		}
204133359Sobrien		if (flush) {
205191736Sobrien			/*
206133359Sobrien			 * main entry didn't match,
207133359Sobrien			 * flush its continuations
208133359Sobrien			 */
209133359Sobrien			while (magindex < nmagic - 1 &&
210169962Sobrien			    magic[magindex + 1].cont_level != 0)
211169962Sobrien				magindex++;
212133359Sobrien			continue;
213133359Sobrien		}
21468349Sobrien
215267843Sdelphij		if ((e = handle_annotation(ms, m)) != 0) {
216267843Sdelphij			*need_separator = 1;
217267843Sdelphij			*printed_something = 1;
218267843Sdelphij			*returnval = 1;
219226048Sobrien			return e;
220267843Sdelphij		}
221169942Sobrien		/*
222169942Sobrien		 * If we are going to print something, we'll need to print
223169942Sobrien		 * a blank before we print something else.
224169942Sobrien		 */
225191736Sobrien		if (*m->desc) {
226267843Sdelphij			*need_separator = 1;
227267843Sdelphij			*printed_something = 1;
228169942Sobrien			if (print_sep(ms, firstline) == -1)
229133359Sobrien				return -1;
23068349Sobrien		}
23168349Sobrien
232191736Sobrien
233191736Sobrien		if (print && mprint(ms, m) == -1)
234133359Sobrien			return -1;
235169942Sobrien
236191736Sobrien		ms->c.li[cont_level].off = moffset(ms, m);
237191736Sobrien
23868349Sobrien		/* and any continuations that match */
239169962Sobrien		if (file_check_mem(ms, ++cont_level) == -1)
240133359Sobrien			return -1;
241133359Sobrien
242284193Sdelphij		while (magindex + 1 < nmagic &&
243284193Sdelphij		    magic[magindex + 1].cont_level != 0) {
244284193Sdelphij			m = &magic[++magindex];
245186690Sobrien			ms->line = m->lineno; /* for messages */
246169962Sobrien
247186690Sobrien			if (cont_level < m->cont_level)
248133359Sobrien				continue;
249186690Sobrien			if (cont_level > m->cont_level) {
250133359Sobrien				/*
251133359Sobrien				 * We're at the end of the level
252133359Sobrien				 * "cont_level" continuations.
253133359Sobrien				 */
254186690Sobrien				cont_level = m->cont_level;
255133359Sobrien			}
256186690Sobrien			ms->offset = m->offset;
257186690Sobrien			if (m->flag & OFFADD) {
258169942Sobrien				ms->offset +=
259169962Sobrien				    ms->c.li[cont_level - 1].off;
260133359Sobrien			}
261159764Sobrien
262169962Sobrien#ifdef ENABLE_CONDITIONALS
263186690Sobrien			if (m->cond == COND_ELSE ||
264186690Sobrien			    m->cond == COND_ELIF) {
265169962Sobrien				if (ms->c.li[cont_level].last_match == 1)
266169962Sobrien					continue;
267169962Sobrien			}
268169962Sobrien#endif
269267843Sdelphij			switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
270284193Sdelphij			    text, flip, indir_level, name_count,
271284193Sdelphij			    printed_something, need_separator, returnval)) {
272191736Sobrien			case -1:
273191736Sobrien				return -1;
274191736Sobrien			case 0:
275191736Sobrien				if (m->reln != '!')
276191736Sobrien					continue;
277191736Sobrien				flush = 1;
278191736Sobrien				break;
279191736Sobrien			default:
280191736Sobrien				if (m->type == FILE_INDIRECT)
281267843Sdelphij					*returnval = 1;
282191736Sobrien				flush = 0;
283191736Sobrien				break;
284191736Sobrien			}
285191736Sobrien
286186690Sobrien			switch (flush ? 1 : magiccheck(ms, m)) {
287133359Sobrien			case -1:
288133359Sobrien				return -1;
289133359Sobrien			case 0:
290169962Sobrien#ifdef ENABLE_CONDITIONALS
291169962Sobrien				ms->c.li[cont_level].last_match = 0;
292169962Sobrien#endif
293133359Sobrien				break;
294133359Sobrien			default:
295169962Sobrien#ifdef ENABLE_CONDITIONALS
296169962Sobrien				ms->c.li[cont_level].last_match = 1;
297169962Sobrien#endif
298267843Sdelphij				if (m->type == FILE_CLEAR)
299267843Sdelphij					ms->c.li[cont_level].got_match = 0;
300267843Sdelphij				else if (ms->c.li[cont_level].got_match) {
301267843Sdelphij					if (m->type == FILE_DEFAULT)
302267843Sdelphij						break;
303267843Sdelphij				} else
304169962Sobrien					ms->c.li[cont_level].got_match = 1;
305267843Sdelphij				if ((e = handle_annotation(ms, m)) != 0) {
306267843Sdelphij					*need_separator = 1;
307267843Sdelphij					*printed_something = 1;
308267843Sdelphij					*returnval = 1;
309267843Sdelphij					return e;
310169962Sobrien				}
311133359Sobrien				/*
312169942Sobrien				 * If we are going to print something,
313169942Sobrien				 * make sure that we have a separator first.
314169942Sobrien				 */
315191736Sobrien				if (*m->desc) {
316267843Sdelphij					if (!*printed_something) {
317267843Sdelphij						*printed_something = 1;
318192348Sdelphij						if (print_sep(ms, firstline)
319192348Sdelphij						    == -1)
320192348Sdelphij							return -1;
321192348Sdelphij					}
322169942Sobrien				}
323169942Sobrien				/*
324169962Sobrien				 * This continuation matched.  Print
325169962Sobrien				 * its message, with a blank before it
326169962Sobrien				 * if the previous item printed and
327169962Sobrien				 * this item isn't empty.
328133359Sobrien				 */
329133359Sobrien				/* space if previous printed */
330267843Sdelphij				if (*need_separator
331186690Sobrien				    && ((m->flag & NOSPACE) == 0)
332191736Sobrien				    && *m->desc) {
333191736Sobrien					if (print &&
334191736Sobrien					    file_printf(ms, " ") == -1)
335133359Sobrien						return -1;
336267843Sdelphij					*need_separator = 0;
33768349Sobrien				}
338191736Sobrien				if (print && mprint(ms, m) == -1)
339133359Sobrien					return -1;
340191736Sobrien
341191736Sobrien				ms->c.li[cont_level].off = moffset(ms, m);
342191736Sobrien
343191736Sobrien				if (*m->desc)
344267843Sdelphij					*need_separator = 1;
34568349Sobrien
346133359Sobrien				/*
347133359Sobrien				 * If we see any continuations
348133359Sobrien				 * at a higher level,
349133359Sobrien				 * process them.
350133359Sobrien				 */
351169962Sobrien				if (file_check_mem(ms, ++cont_level) == -1)
352133359Sobrien					return -1;
353169962Sobrien				break;
35468349Sobrien			}
35568349Sobrien		}
356267843Sdelphij		if (*printed_something) {
357175296Sobrien			firstline = 0;
358191736Sobrien			if (print)
359267843Sdelphij				*returnval = 1;
360175296Sobrien		}
361267843Sdelphij		if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) {
362267843Sdelphij			return *returnval; /* don't keep searching */
363191736Sobrien		}
36468349Sobrien	}
365267843Sdelphij	return *returnval;  /* This is hit if -k is set or there is no match */
36668349Sobrien}
36768349Sobrien
368133359Sobrienprivate int
369169942Sobriencheck_fmt(struct magic_set *ms, struct magic *m)
370169942Sobrien{
371267843Sdelphij	file_regex_t rx;
372267843Sdelphij	int rc, rv = -1;
373169942Sobrien
374191736Sobrien	if (strchr(m->desc, '%') == NULL)
375169942Sobrien		return 0;
376169942Sobrien
377267843Sdelphij	rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
378169942Sobrien	if (rc) {
379267843Sdelphij		file_regerror(&rx, rc, ms);
380169942Sobrien	} else {
381267843Sdelphij		rc = file_regexec(&rx, m->desc, 0, 0, 0);
382267843Sdelphij		rv = !rc;
383169942Sobrien	}
384267843Sdelphij	file_regfree(&rx);
385267843Sdelphij	return rv;
386169942Sobrien}
387169942Sobrien
388169962Sobrien#ifndef HAVE_STRNDUP
389169962Sobrienchar * strndup(const char *, size_t);
390169962Sobrien
391169962Sobrienchar *
392169962Sobrienstrndup(const char *str, size_t n)
393169962Sobrien{
394169962Sobrien	size_t len;
395169962Sobrien	char *copy;
396169962Sobrien
397192348Sdelphij	for (len = 0; len < n && str[len]; len++)
398192348Sdelphij		continue;
399192348Sdelphij	if ((copy = malloc(len + 1)) == NULL)
400192348Sdelphij		return NULL;
401192348Sdelphij	(void)memcpy(copy, str, len);
402169962Sobrien	copy[len] = '\0';
403192348Sdelphij	return copy;
404169962Sobrien}
405169962Sobrien#endif /* HAVE_STRNDUP */
406169962Sobrien
407133359Sobrienprivate int32_t
408169962Sobrienmprint(struct magic_set *ms, struct magic *m)
409133359Sobrien{
410169942Sobrien	uint64_t v;
411175296Sobrien	float vf;
412175296Sobrien	double vd;
413169962Sobrien	int64_t t = 0;
414284193Sdelphij 	char buf[128], tbuf[26], sbuf[512];
415169962Sobrien	union VALUETYPE *p = &ms->ms_value;
41668349Sobrien
41768349Sobrien  	switch (m->type) {
418133359Sobrien  	case FILE_BYTE:
419169942Sobrien		v = file_signextend(ms, m, (uint64_t)p->b);
420169942Sobrien		switch (check_fmt(ms, m)) {
421169942Sobrien		case -1:
422133359Sobrien			return -1;
423169942Sobrien		case 1:
424267843Sdelphij			(void)snprintf(buf, sizeof(buf), "%d",
425191736Sobrien			    (unsigned char)v);
426267843Sdelphij			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
427169942Sobrien				return -1;
428169942Sobrien			break;
429169942Sobrien		default:
430267843Sdelphij			if (file_printf(ms, F(ms, m, "%d"),
431267843Sdelphij			    (unsigned char) v) == -1)
432169942Sobrien				return -1;
433169942Sobrien			break;
434169942Sobrien		}
435169942Sobrien		t = ms->offset + sizeof(char);
43668349Sobrien		break;
43768349Sobrien
438133359Sobrien  	case FILE_SHORT:
439133359Sobrien  	case FILE_BESHORT:
440133359Sobrien  	case FILE_LESHORT:
441169942Sobrien		v = file_signextend(ms, m, (uint64_t)p->h);
442169942Sobrien		switch (check_fmt(ms, m)) {
443169942Sobrien		case -1:
444133359Sobrien			return -1;
445169942Sobrien		case 1:
446267843Sdelphij			(void)snprintf(buf, sizeof(buf), "%u",
447191736Sobrien			    (unsigned short)v);
448267843Sdelphij			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
449169942Sobrien				return -1;
450169942Sobrien			break;
451169942Sobrien		default:
452267843Sdelphij			if (file_printf(ms, F(ms, m, "%u"),
453267843Sdelphij			    (unsigned short) v) == -1)
454169942Sobrien				return -1;
455169942Sobrien			break;
456169942Sobrien		}
457169942Sobrien		t = ms->offset + sizeof(short);
45868349Sobrien		break;
45968349Sobrien
460133359Sobrien  	case FILE_LONG:
461133359Sobrien  	case FILE_BELONG:
462133359Sobrien  	case FILE_LELONG:
463159764Sobrien  	case FILE_MELONG:
464169942Sobrien		v = file_signextend(ms, m, (uint64_t)p->l);
465169942Sobrien		switch (check_fmt(ms, m)) {
466169942Sobrien		case -1:
467133359Sobrien			return -1;
468169942Sobrien		case 1:
469267843Sdelphij			(void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v);
470267843Sdelphij			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
471169942Sobrien				return -1;
472169942Sobrien			break;
473169942Sobrien		default:
474267843Sdelphij			if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1)
475169942Sobrien				return -1;
476169942Sobrien			break;
477169942Sobrien		}
478169942Sobrien		t = ms->offset + sizeof(int32_t);
47968349Sobrien  		break;
48068349Sobrien
481169942Sobrien  	case FILE_QUAD:
482169942Sobrien  	case FILE_BEQUAD:
483169942Sobrien  	case FILE_LEQUAD:
484169942Sobrien		v = file_signextend(ms, m, p->q);
485267843Sdelphij		switch (check_fmt(ms, m)) {
486267843Sdelphij		case -1:
487169942Sobrien			return -1;
488267843Sdelphij		case 1:
489267843Sdelphij			(void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
490267843Sdelphij			    (unsigned long long)v);
491267843Sdelphij			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
492267843Sdelphij				return -1;
493267843Sdelphij			break;
494267843Sdelphij		default:
495267843Sdelphij			if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"),
496267843Sdelphij			    (unsigned long long) v) == -1)
497267843Sdelphij				return -1;
498267843Sdelphij			break;
499267843Sdelphij		}
500169942Sobrien		t = ms->offset + sizeof(int64_t);
501169942Sobrien  		break;
502169962Sobrien
503133359Sobrien  	case FILE_STRING:
504133359Sobrien  	case FILE_PSTRING:
505139368Sobrien  	case FILE_BESTRING16:
506139368Sobrien  	case FILE_LESTRING16:
507159764Sobrien		if (m->reln == '=' || m->reln == '!') {
508284193Sdelphij			if (file_printf(ms, F(ms, m, "%s"),
509284193Sdelphij			    file_printable(sbuf, sizeof(sbuf), m->value.s))
510284193Sdelphij			    == -1)
511133359Sobrien				return -1;
512169942Sobrien			t = ms->offset + m->vallen;
51368349Sobrien		}
51468349Sobrien		else {
515267843Sdelphij			char *str = p->s;
516267843Sdelphij
517267843Sdelphij			/* compute t before we mangle the string? */
518267843Sdelphij			t = ms->offset + strlen(str);
519267843Sdelphij
520175296Sobrien			if (*m->value.s == '\0')
521267843Sdelphij				str[strcspn(str, "\n")] = '\0';
522267843Sdelphij
523267843Sdelphij			if (m->str_flags & STRING_TRIM) {
524267843Sdelphij				char *last;
525267843Sdelphij				while (isspace((unsigned char)*str))
526267843Sdelphij					str++;
527267843Sdelphij				last = str;
528267843Sdelphij				while (*last)
529267843Sdelphij					last++;
530267843Sdelphij				--last;
531267843Sdelphij				while (isspace((unsigned char)*last))
532267843Sdelphij					last--;
533267843Sdelphij				*++last = '\0';
534267843Sdelphij			}
535267843Sdelphij
536284193Sdelphij			if (file_printf(ms, F(ms, m, "%s"),
537284193Sdelphij			    file_printable(sbuf, sizeof(sbuf), str)) == -1)
538133359Sobrien				return -1;
539267843Sdelphij
540186690Sobrien			if (m->type == FILE_PSTRING)
541226048Sobrien				t += file_pstring_length_size(m);
54268349Sobrien		}
54368349Sobrien		break;
54468349Sobrien
545133359Sobrien	case FILE_DATE:
546133359Sobrien	case FILE_BEDATE:
547133359Sobrien	case FILE_LEDATE:
548159764Sobrien	case FILE_MEDATE:
549267843Sdelphij		if (file_printf(ms, F(ms, m, "%s"),
550267843Sdelphij		    file_fmttime(p->l + m->num_mask, FILE_T_LOCAL, tbuf)) == -1)
551133359Sobrien			return -1;
552267843Sdelphij		t = ms->offset + sizeof(uint32_t);
55368349Sobrien		break;
55468349Sobrien
555133359Sobrien	case FILE_LDATE:
556133359Sobrien	case FILE_BELDATE:
557133359Sobrien	case FILE_LELDATE:
558159764Sobrien	case FILE_MELDATE:
559267843Sdelphij		if (file_printf(ms, F(ms, m, "%s"),
560267843Sdelphij		    file_fmttime(p->l + m->num_mask, 0, tbuf)) == -1)
561133359Sobrien			return -1;
562267843Sdelphij		t = ms->offset + sizeof(uint32_t);
56380588Sobrien		break;
564169942Sobrien
565169942Sobrien	case FILE_QDATE:
566169942Sobrien	case FILE_BEQDATE:
567169942Sobrien	case FILE_LEQDATE:
568267843Sdelphij		if (file_printf(ms, F(ms, m, "%s"),
569267843Sdelphij		    file_fmttime(p->q + m->num_mask, FILE_T_LOCAL, tbuf)) == -1)
570169942Sobrien			return -1;
571169942Sobrien		t = ms->offset + sizeof(uint64_t);
572169942Sobrien		break;
573169942Sobrien
574169942Sobrien	case FILE_QLDATE:
575169942Sobrien	case FILE_BEQLDATE:
576169942Sobrien	case FILE_LEQLDATE:
577267843Sdelphij		if (file_printf(ms, F(ms, m, "%s"),
578267843Sdelphij		    file_fmttime(p->q + m->num_mask, 0, tbuf)) == -1)
579169942Sobrien			return -1;
580169942Sobrien		t = ms->offset + sizeof(uint64_t);
581169942Sobrien		break;
582169942Sobrien
583267843Sdelphij	case FILE_QWDATE:
584267843Sdelphij	case FILE_BEQWDATE:
585267843Sdelphij	case FILE_LEQWDATE:
586267843Sdelphij		if (file_printf(ms, F(ms, m, "%s"),
587267843Sdelphij		    file_fmttime(p->q + m->num_mask, FILE_T_WINDOWS, tbuf)) == -1)
588267843Sdelphij			return -1;
589267843Sdelphij		t = ms->offset + sizeof(uint64_t);
590267843Sdelphij		break;
591267843Sdelphij
592175296Sobrien  	case FILE_FLOAT:
593175296Sobrien  	case FILE_BEFLOAT:
594175296Sobrien  	case FILE_LEFLOAT:
595175296Sobrien		vf = p->f;
596175296Sobrien		switch (check_fmt(ms, m)) {
597175296Sobrien		case -1:
598175296Sobrien			return -1;
599175296Sobrien		case 1:
600191736Sobrien			(void)snprintf(buf, sizeof(buf), "%g", vf);
601267843Sdelphij			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
602175296Sobrien				return -1;
603175296Sobrien			break;
604175296Sobrien		default:
605267843Sdelphij			if (file_printf(ms, F(ms, m, "%g"), vf) == -1)
606175296Sobrien				return -1;
607175296Sobrien			break;
608175296Sobrien		}
609175296Sobrien		t = ms->offset + sizeof(float);
610175296Sobrien  		break;
611175296Sobrien
612175296Sobrien  	case FILE_DOUBLE:
613175296Sobrien  	case FILE_BEDOUBLE:
614175296Sobrien  	case FILE_LEDOUBLE:
615175296Sobrien		vd = p->d;
616175296Sobrien		switch (check_fmt(ms, m)) {
617175296Sobrien		case -1:
618175296Sobrien			return -1;
619175296Sobrien		case 1:
620191736Sobrien			(void)snprintf(buf, sizeof(buf), "%g", vd);
621267843Sdelphij			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
622175296Sobrien				return -1;
623175296Sobrien			break;
624175296Sobrien		default:
625267843Sdelphij			if (file_printf(ms, F(ms, m, "%g"), vd) == -1)
626175296Sobrien				return -1;
627175296Sobrien			break;
628175296Sobrien		}
629175296Sobrien		t = ms->offset + sizeof(double);
630175296Sobrien  		break;
631175296Sobrien
632169962Sobrien	case FILE_REGEX: {
633169962Sobrien		char *cp;
634169962Sobrien		int rval;
635169962Sobrien
636169962Sobrien		cp = strndup((const char *)ms->search.s, ms->search.rm_len);
637169962Sobrien		if (cp == NULL) {
638169962Sobrien			file_oomem(ms, ms->search.rm_len);
639133359Sobrien			return -1;
640169962Sobrien		}
641284193Sdelphij		rval = file_printf(ms, F(ms, m, "%s"),
642284193Sdelphij		    file_printable(sbuf, sizeof(sbuf), cp));
643169962Sobrien		free(cp);
644169962Sobrien
645169962Sobrien		if (rval == -1)
646169962Sobrien			return -1;
647169962Sobrien
648169962Sobrien		if ((m->str_flags & REGEX_OFFSET_START))
649169962Sobrien			t = ms->search.offset;
650169962Sobrien		else
651169962Sobrien			t = ms->search.offset + ms->search.rm_len;
652103373Sobrien		break;
653169962Sobrien	}
654169942Sobrien
655159764Sobrien	case FILE_SEARCH:
656284193Sdelphij	  	if (file_printf(ms, F(ms, m, "%s"),
657284193Sdelphij		    file_printable(sbuf, sizeof(sbuf), m->value.s)) == -1)
658159764Sobrien			return -1;
659169962Sobrien		if ((m->str_flags & REGEX_OFFSET_START))
660169962Sobrien			t = ms->search.offset;
661169962Sobrien		else
662169962Sobrien			t = ms->search.offset + m->vallen;
663159764Sobrien		break;
66480588Sobrien
665169962Sobrien	case FILE_DEFAULT:
666267843Sdelphij	case FILE_CLEAR:
667267843Sdelphij	  	if (file_printf(ms, "%s", m->desc) == -1)
668169962Sobrien			return -1;
669169962Sobrien		t = ms->offset;
670169962Sobrien		break;
671169962Sobrien
672191736Sobrien	case FILE_INDIRECT:
673267843Sdelphij	case FILE_USE:
674267843Sdelphij	case FILE_NAME:
675191736Sobrien		t = ms->offset;
676191736Sobrien		break;
677191736Sobrien
67868349Sobrien	default:
679169962Sobrien		file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
680133359Sobrien		return -1;
68168349Sobrien	}
682191736Sobrien	return (int32_t)t;
68368349Sobrien}
68468349Sobrien
685191736Sobrienprivate int32_t
686191736Sobrienmoffset(struct magic_set *ms, struct magic *m)
687191736Sobrien{
688191736Sobrien  	switch (m->type) {
689191736Sobrien  	case FILE_BYTE:
690226048Sobrien		return CAST(int32_t, (ms->offset + sizeof(char)));
691169942Sobrien
692191736Sobrien  	case FILE_SHORT:
693191736Sobrien  	case FILE_BESHORT:
694191736Sobrien  	case FILE_LESHORT:
695226048Sobrien		return CAST(int32_t, (ms->offset + sizeof(short)));
696191736Sobrien
697191736Sobrien  	case FILE_LONG:
698191736Sobrien  	case FILE_BELONG:
699191736Sobrien  	case FILE_LELONG:
700191736Sobrien  	case FILE_MELONG:
701226048Sobrien		return CAST(int32_t, (ms->offset + sizeof(int32_t)));
702191736Sobrien
703191736Sobrien  	case FILE_QUAD:
704191736Sobrien  	case FILE_BEQUAD:
705191736Sobrien  	case FILE_LEQUAD:
706226048Sobrien		return CAST(int32_t, (ms->offset + sizeof(int64_t)));
707191736Sobrien
708191736Sobrien  	case FILE_STRING:
709191736Sobrien  	case FILE_PSTRING:
710191736Sobrien  	case FILE_BESTRING16:
711191736Sobrien  	case FILE_LESTRING16:
712191736Sobrien		if (m->reln == '=' || m->reln == '!')
713191736Sobrien			return ms->offset + m->vallen;
714191736Sobrien		else {
715191736Sobrien			union VALUETYPE *p = &ms->ms_value;
716191736Sobrien			uint32_t t;
717191736Sobrien
718191736Sobrien			if (*m->value.s == '\0')
719191736Sobrien				p->s[strcspn(p->s, "\n")] = '\0';
720226048Sobrien			t = CAST(uint32_t, (ms->offset + strlen(p->s)));
721191736Sobrien			if (m->type == FILE_PSTRING)
722267843Sdelphij				t += (uint32_t)file_pstring_length_size(m);
723191736Sobrien			return t;
724191736Sobrien		}
725191736Sobrien
726191736Sobrien	case FILE_DATE:
727191736Sobrien	case FILE_BEDATE:
728191736Sobrien	case FILE_LEDATE:
729191736Sobrien	case FILE_MEDATE:
730267843Sdelphij		return CAST(int32_t, (ms->offset + sizeof(uint32_t)));
731191736Sobrien
732191736Sobrien	case FILE_LDATE:
733191736Sobrien	case FILE_BELDATE:
734191736Sobrien	case FILE_LELDATE:
735191736Sobrien	case FILE_MELDATE:
736267843Sdelphij		return CAST(int32_t, (ms->offset + sizeof(uint32_t)));
737191736Sobrien
738191736Sobrien	case FILE_QDATE:
739191736Sobrien	case FILE_BEQDATE:
740191736Sobrien	case FILE_LEQDATE:
741226048Sobrien		return CAST(int32_t, (ms->offset + sizeof(uint64_t)));
742191736Sobrien
743191736Sobrien	case FILE_QLDATE:
744191736Sobrien	case FILE_BEQLDATE:
745191736Sobrien	case FILE_LEQLDATE:
746226048Sobrien		return CAST(int32_t, (ms->offset + sizeof(uint64_t)));
747191736Sobrien
748191736Sobrien  	case FILE_FLOAT:
749191736Sobrien  	case FILE_BEFLOAT:
750191736Sobrien  	case FILE_LEFLOAT:
751226048Sobrien		return CAST(int32_t, (ms->offset + sizeof(float)));
752191736Sobrien
753191736Sobrien  	case FILE_DOUBLE:
754191736Sobrien  	case FILE_BEDOUBLE:
755191736Sobrien  	case FILE_LEDOUBLE:
756226048Sobrien		return CAST(int32_t, (ms->offset + sizeof(double)));
757191736Sobrien
758191736Sobrien	case FILE_REGEX:
759191736Sobrien		if ((m->str_flags & REGEX_OFFSET_START) != 0)
760226048Sobrien			return CAST(int32_t, ms->search.offset);
761191736Sobrien		else
762226048Sobrien			return CAST(int32_t, (ms->search.offset +
763226048Sobrien			    ms->search.rm_len));
764191736Sobrien
765191736Sobrien	case FILE_SEARCH:
766191736Sobrien		if ((m->str_flags & REGEX_OFFSET_START) != 0)
767226048Sobrien			return CAST(int32_t, ms->search.offset);
768191736Sobrien		else
769226048Sobrien			return CAST(int32_t, (ms->search.offset + m->vallen));
770191736Sobrien
771267843Sdelphij	case FILE_CLEAR:
772191736Sobrien	case FILE_DEFAULT:
773191736Sobrien	case FILE_INDIRECT:
774191736Sobrien		return ms->offset;
775191736Sobrien
776191736Sobrien	default:
777191736Sobrien		return 0;
778191736Sobrien	}
779191736Sobrien}
780191736Sobrien
781267843Sdelphijprivate int
782267843Sdelphijcvt_flip(int type, int flip)
783267843Sdelphij{
784267843Sdelphij	if (flip == 0)
785267843Sdelphij		return type;
786267843Sdelphij	switch (type) {
787267843Sdelphij	case FILE_BESHORT:
788267843Sdelphij		return FILE_LESHORT;
789267843Sdelphij	case FILE_BELONG:
790267843Sdelphij		return FILE_LELONG;
791267843Sdelphij	case FILE_BEDATE:
792267843Sdelphij		return FILE_LEDATE;
793267843Sdelphij	case FILE_BELDATE:
794267843Sdelphij		return FILE_LELDATE;
795267843Sdelphij	case FILE_BEQUAD:
796267843Sdelphij		return FILE_LEQUAD;
797267843Sdelphij	case FILE_BEQDATE:
798267843Sdelphij		return FILE_LEQDATE;
799267843Sdelphij	case FILE_BEQLDATE:
800267843Sdelphij		return FILE_LEQLDATE;
801267843Sdelphij	case FILE_BEQWDATE:
802267843Sdelphij		return FILE_LEQWDATE;
803267843Sdelphij	case FILE_LESHORT:
804267843Sdelphij		return FILE_BESHORT;
805267843Sdelphij	case FILE_LELONG:
806267843Sdelphij		return FILE_BELONG;
807267843Sdelphij	case FILE_LEDATE:
808267843Sdelphij		return FILE_BEDATE;
809267843Sdelphij	case FILE_LELDATE:
810267843Sdelphij		return FILE_BELDATE;
811267843Sdelphij	case FILE_LEQUAD:
812267843Sdelphij		return FILE_BEQUAD;
813267843Sdelphij	case FILE_LEQDATE:
814267843Sdelphij		return FILE_BEQDATE;
815267843Sdelphij	case FILE_LEQLDATE:
816267843Sdelphij		return FILE_BEQLDATE;
817267843Sdelphij	case FILE_LEQWDATE:
818267843Sdelphij		return FILE_BEQWDATE;
819267843Sdelphij	case FILE_BEFLOAT:
820267843Sdelphij		return FILE_LEFLOAT;
821267843Sdelphij	case FILE_LEFLOAT:
822267843Sdelphij		return FILE_BEFLOAT;
823267843Sdelphij	case FILE_BEDOUBLE:
824267843Sdelphij		return FILE_LEDOUBLE;
825267843Sdelphij	case FILE_LEDOUBLE:
826267843Sdelphij		return FILE_BEDOUBLE;
827267843Sdelphij	default:
828267843Sdelphij		return type;
829267843Sdelphij	}
830267843Sdelphij}
831169942Sobrien#define DO_CVT(fld, cast) \
832169962Sobrien	if (m->num_mask) \
833169962Sobrien		switch (m->mask_op & FILE_OPS_MASK) { \
834169942Sobrien		case FILE_OPAND: \
835169962Sobrien			p->fld &= cast m->num_mask; \
836169942Sobrien			break; \
837169942Sobrien		case FILE_OPOR: \
838169962Sobrien			p->fld |= cast m->num_mask; \
839169942Sobrien			break; \
840169942Sobrien		case FILE_OPXOR: \
841169962Sobrien			p->fld ^= cast m->num_mask; \
842169942Sobrien			break; \
843169942Sobrien		case FILE_OPADD: \
844169962Sobrien			p->fld += cast m->num_mask; \
845169942Sobrien			break; \
846169942Sobrien		case FILE_OPMINUS: \
847169962Sobrien			p->fld -= cast m->num_mask; \
848169942Sobrien			break; \
849169942Sobrien		case FILE_OPMULTIPLY: \
850169962Sobrien			p->fld *= cast m->num_mask; \
851169942Sobrien			break; \
852169942Sobrien		case FILE_OPDIVIDE: \
853169962Sobrien			p->fld /= cast m->num_mask; \
854169942Sobrien			break; \
855169942Sobrien		case FILE_OPMODULO: \
856169962Sobrien			p->fld %= cast m->num_mask; \
857169942Sobrien			break; \
858169942Sobrien		} \
859169942Sobrien	if (m->mask_op & FILE_OPINVERSE) \
860169942Sobrien		p->fld = ~p->fld \
861169942Sobrien
862169942Sobrienprivate void
863169942Sobriencvt_8(union VALUETYPE *p, const struct magic *m)
864169942Sobrien{
865169942Sobrien	DO_CVT(b, (uint8_t));
866169942Sobrien}
867169942Sobrien
868169942Sobrienprivate void
869169942Sobriencvt_16(union VALUETYPE *p, const struct magic *m)
870169942Sobrien{
871169942Sobrien	DO_CVT(h, (uint16_t));
872169942Sobrien}
873169942Sobrien
874169942Sobrienprivate void
875169942Sobriencvt_32(union VALUETYPE *p, const struct magic *m)
876169942Sobrien{
877169942Sobrien	DO_CVT(l, (uint32_t));
878169942Sobrien}
879169942Sobrien
880169942Sobrienprivate void
881169942Sobriencvt_64(union VALUETYPE *p, const struct magic *m)
882169942Sobrien{
883169942Sobrien	DO_CVT(q, (uint64_t));
884169942Sobrien}
885169942Sobrien
886175296Sobrien#define DO_CVT2(fld, cast) \
887175296Sobrien	if (m->num_mask) \
888175296Sobrien		switch (m->mask_op & FILE_OPS_MASK) { \
889175296Sobrien		case FILE_OPADD: \
890175296Sobrien			p->fld += cast m->num_mask; \
891175296Sobrien			break; \
892175296Sobrien		case FILE_OPMINUS: \
893175296Sobrien			p->fld -= cast m->num_mask; \
894175296Sobrien			break; \
895175296Sobrien		case FILE_OPMULTIPLY: \
896175296Sobrien			p->fld *= cast m->num_mask; \
897175296Sobrien			break; \
898175296Sobrien		case FILE_OPDIVIDE: \
899175296Sobrien			p->fld /= cast m->num_mask; \
900175296Sobrien			break; \
901175296Sobrien		} \
902175296Sobrien
903175296Sobrienprivate void
904175296Sobriencvt_float(union VALUETYPE *p, const struct magic *m)
905175296Sobrien{
906175296Sobrien	DO_CVT2(f, (float));
907175296Sobrien}
908175296Sobrien
909175296Sobrienprivate void
910175296Sobriencvt_double(union VALUETYPE *p, const struct magic *m)
911175296Sobrien{
912175296Sobrien	DO_CVT2(d, (double));
913175296Sobrien}
914175296Sobrien
91568349Sobrien/*
91668349Sobrien * Convert the byte order of the data we are looking at
91780588Sobrien * While we're here, let's apply the mask operation
91880588Sobrien * (unless you have a better idea)
91968349Sobrien */
920133359Sobrienprivate int
921267843Sdelphijmconvert(struct magic_set *ms, struct magic *m, int flip)
92268349Sobrien{
923169962Sobrien	union VALUETYPE *p = &ms->ms_value;
924267843Sdelphij	uint8_t type;
925169962Sobrien
926267843Sdelphij	switch (type = cvt_flip(m->type, flip)) {
927133359Sobrien	case FILE_BYTE:
928169942Sobrien		cvt_8(p, m);
92980588Sobrien		return 1;
930133359Sobrien	case FILE_SHORT:
931169942Sobrien		cvt_16(p, m);
93280588Sobrien		return 1;
933133359Sobrien	case FILE_LONG:
934133359Sobrien	case FILE_DATE:
935133359Sobrien	case FILE_LDATE:
936169942Sobrien		cvt_32(p, m);
93768349Sobrien		return 1;
938169942Sobrien	case FILE_QUAD:
939169942Sobrien	case FILE_QDATE:
940169942Sobrien	case FILE_QLDATE:
941267843Sdelphij	case FILE_QWDATE:
942169942Sobrien		cvt_64(p, m);
943169942Sobrien		return 1;
944133359Sobrien	case FILE_STRING:
945139368Sobrien	case FILE_BESTRING16:
946169962Sobrien	case FILE_LESTRING16: {
947169962Sobrien		/* Null terminate and eat *trailing* return */
948169962Sobrien		p->s[sizeof(p->s) - 1] = '\0';
949169962Sobrien		return 1;
950169962Sobrien	}
951169962Sobrien	case FILE_PSTRING: {
952267843Sdelphij		size_t sz = file_pstring_length_size(m);
953267843Sdelphij		char *ptr1 = p->s, *ptr2 = ptr1 + sz;
954226048Sobrien		size_t len = file_pstring_get_length(m, ptr1);
955284193Sdelphij		sz = sizeof(p->s) - sz; /* maximum length of string */
956284193Sdelphij		if (len >= sz) {
957267843Sdelphij			/*
958267843Sdelphij			 * The size of the pascal string length (sz)
959267843Sdelphij			 * is 1, 2, or 4. We need at least 1 byte for NUL
960267843Sdelphij			 * termination, but we've already truncated the
961267843Sdelphij			 * string by p->s, so we need to deduct sz.
962284193Sdelphij			 * Because we can use one of the bytes of the length
963284193Sdelphij			 * after we shifted as NUL termination.
964267843Sdelphij			 */
965284193Sdelphij			len = sz;
966267843Sdelphij		}
967169962Sobrien		while (len--)
968169962Sobrien			*ptr1++ = *ptr2++;
969169962Sobrien		*ptr1 = '\0';
970169962Sobrien		return 1;
971169962Sobrien	}
972133359Sobrien	case FILE_BESHORT:
97368349Sobrien		p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
974169942Sobrien		cvt_16(p, m);
97568349Sobrien		return 1;
976133359Sobrien	case FILE_BELONG:
977133359Sobrien	case FILE_BEDATE:
978133359Sobrien	case FILE_BELDATE:
979103373Sobrien		p->l = (int32_t)
98068349Sobrien		    ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
981267843Sdelphij		if (type == FILE_BELONG)
982267843Sdelphij			cvt_32(p, m);
98368349Sobrien		return 1;
984169942Sobrien	case FILE_BEQUAD:
985169942Sobrien	case FILE_BEQDATE:
986169942Sobrien	case FILE_BEQLDATE:
987267843Sdelphij	case FILE_BEQWDATE:
988186690Sobrien		p->q = (uint64_t)
989186690Sobrien		    (((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
990186690Sobrien		     ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
991186690Sobrien		     ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
992186690Sobrien		     ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7]));
993267843Sdelphij		if (type == FILE_BEQUAD)
994267843Sdelphij			cvt_64(p, m);
995169942Sobrien		return 1;
996133359Sobrien	case FILE_LESHORT:
99768349Sobrien		p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
998169942Sobrien		cvt_16(p, m);
99968349Sobrien		return 1;
1000133359Sobrien	case FILE_LELONG:
1001133359Sobrien	case FILE_LEDATE:
1002133359Sobrien	case FILE_LELDATE:
1003103373Sobrien		p->l = (int32_t)
100468349Sobrien		    ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
1005267843Sdelphij		if (type == FILE_LELONG)
1006267843Sdelphij			cvt_32(p, m);
100768349Sobrien		return 1;
1008169942Sobrien	case FILE_LEQUAD:
1009169942Sobrien	case FILE_LEQDATE:
1010169942Sobrien	case FILE_LEQLDATE:
1011267843Sdelphij	case FILE_LEQWDATE:
1012186690Sobrien		p->q = (uint64_t)
1013186690Sobrien		    (((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
1014186690Sobrien		     ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
1015186690Sobrien		     ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
1016186690Sobrien		     ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0]));
1017267843Sdelphij		if (type == FILE_LEQUAD)
1018267843Sdelphij			cvt_64(p, m);
1019169942Sobrien		return 1;
1020159764Sobrien	case FILE_MELONG:
1021159764Sobrien	case FILE_MEDATE:
1022159764Sobrien	case FILE_MELDATE:
1023159764Sobrien		p->l = (int32_t)
1024159764Sobrien		    ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2]));
1025267843Sdelphij		if (type == FILE_MELONG)
1026267843Sdelphij			cvt_32(p, m);
1027159764Sobrien		return 1;
1028175296Sobrien	case FILE_FLOAT:
1029175296Sobrien		cvt_float(p, m);
1030175296Sobrien		return 1;
1031175296Sobrien	case FILE_BEFLOAT:
1032175296Sobrien		p->l =  ((uint32_t)p->hl[0]<<24)|((uint32_t)p->hl[1]<<16)|
1033175296Sobrien			((uint32_t)p->hl[2]<<8) |((uint32_t)p->hl[3]);
1034175296Sobrien		cvt_float(p, m);
1035175296Sobrien		return 1;
1036175296Sobrien	case FILE_LEFLOAT:
1037175296Sobrien		p->l =  ((uint32_t)p->hl[3]<<24)|((uint32_t)p->hl[2]<<16)|
1038175296Sobrien			((uint32_t)p->hl[1]<<8) |((uint32_t)p->hl[0]);
1039175296Sobrien		cvt_float(p, m);
1040175296Sobrien		return 1;
1041175296Sobrien	case FILE_DOUBLE:
1042175296Sobrien		cvt_double(p, m);
1043175296Sobrien		return 1;
1044175296Sobrien	case FILE_BEDOUBLE:
1045175296Sobrien		p->q =  ((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
1046175296Sobrien			((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
1047175296Sobrien			((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
1048175296Sobrien			((uint64_t)p->hq[6]<<8) |((uint64_t)p->hq[7]);
1049175296Sobrien		cvt_double(p, m);
1050175296Sobrien		return 1;
1051175296Sobrien	case FILE_LEDOUBLE:
1052175296Sobrien		p->q =  ((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
1053175296Sobrien			((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
1054175296Sobrien			((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
1055175296Sobrien			((uint64_t)p->hq[1]<<8) |((uint64_t)p->hq[0]);
1056175296Sobrien		cvt_double(p, m);
1057175296Sobrien		return 1;
1058133359Sobrien	case FILE_REGEX:
1059159764Sobrien	case FILE_SEARCH:
1060169962Sobrien	case FILE_DEFAULT:
1061267843Sdelphij	case FILE_CLEAR:
1062267843Sdelphij	case FILE_NAME:
1063267843Sdelphij	case FILE_USE:
1064103373Sobrien		return 1;
106568349Sobrien	default:
1066169962Sobrien		file_magerror(ms, "invalid type %d in mconvert()", m->type);
106768349Sobrien		return 0;
106868349Sobrien	}
106968349Sobrien}
107068349Sobrien
107168349Sobrien
1072133359Sobrienprivate void
1073133359Sobrienmdebug(uint32_t offset, const char *str, size_t len)
107468349Sobrien{
1075284193Sdelphij	(void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1076133359Sobrien	file_showstr(stderr, str, len);
107768349Sobrien	(void) fputc('\n', stderr);
107868349Sobrien	(void) fputc('\n', stderr);
107968349Sobrien}
108068349Sobrien
1081133359Sobrienprivate int
1082139368Sobrienmcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1083267843Sdelphij    const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
108468349Sobrien{
1085169962Sobrien	/*
1086169962Sobrien	 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1087169962Sobrien	 * anything, but setup pointers into the source
1088169962Sobrien	 */
1089169962Sobrien	if (indir == 0) {
1090169962Sobrien		switch (type) {
1091169962Sobrien		case FILE_SEARCH:
1092226048Sobrien			ms->search.s = RCAST(const char *, s) + offset;
1093169962Sobrien			ms->search.s_len = nbytes - offset;
1094186690Sobrien			ms->search.offset = offset;
1095159764Sobrien			return 0;
109668349Sobrien
1097169962Sobrien		case FILE_REGEX: {
1098169962Sobrien			const char *b;
1099169962Sobrien			const char *c;
1100169962Sobrien			const char *last;	/* end of search region */
1101169962Sobrien			const char *buf;	/* start of search region */
1102191736Sobrien			const char *end;
1103267843Sdelphij			size_t lines, linecnt, bytecnt;
1104139368Sobrien
1105169962Sobrien			if (s == NULL) {
1106169962Sobrien				ms->search.s_len = 0;
1107169962Sobrien				ms->search.s = NULL;
1108169962Sobrien				return 0;
1109169962Sobrien			}
1110267843Sdelphij
1111267843Sdelphij			if (m->str_flags & REGEX_LINE_COUNT) {
1112267843Sdelphij				linecnt = m->str_range;
1113267843Sdelphij				bytecnt = linecnt * 80;
1114267843Sdelphij			} else {
1115267843Sdelphij				linecnt = 0;
1116267843Sdelphij				bytecnt = m->str_range;
1117267843Sdelphij			}
1118267843Sdelphij
1119267843Sdelphij			if (bytecnt == 0)
1120267843Sdelphij				bytecnt = 8192;
1121267843Sdelphij			if (bytecnt > nbytes)
1122267843Sdelphij				bytecnt = nbytes;
1123267843Sdelphij
1124226048Sobrien			buf = RCAST(const char *, s) + offset;
1125267843Sdelphij			end = last = RCAST(const char *, s) + bytecnt;
1126169962Sobrien			/* mget() guarantees buf <= last */
1127226048Sobrien			for (lines = linecnt, b = buf; lines && b < end &&
1128226048Sobrien			     ((b = CAST(const char *,
1129226048Sobrien				 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1130226048Sobrien			     || (b = CAST(const char *,
1131226048Sobrien				 memchr(c, '\r', CAST(size_t, (end - c))))));
1132169962Sobrien			     lines--, b++) {
1133169962Sobrien				last = b;
1134169962Sobrien				if (b[0] == '\r' && b[1] == '\n')
1135169962Sobrien					b++;
1136169962Sobrien			}
1137169962Sobrien			if (lines)
1138267843Sdelphij				last = RCAST(const char *, s) + bytecnt;
1139191736Sobrien
1140169962Sobrien			ms->search.s = buf;
1141169962Sobrien			ms->search.s_len = last - buf;
1142169962Sobrien			ms->search.offset = offset;
1143169962Sobrien			ms->search.rm_len = 0;
1144169962Sobrien			return 0;
1145169942Sobrien		}
1146169962Sobrien		case FILE_BESTRING16:
1147169962Sobrien		case FILE_LESTRING16: {
1148169962Sobrien			const unsigned char *src = s + offset;
1149169962Sobrien			const unsigned char *esrc = s + nbytes;
1150169962Sobrien			char *dst = p->s;
1151169962Sobrien			char *edst = &p->s[sizeof(p->s) - 1];
1152191736Sobrien
1153169962Sobrien			if (type == FILE_BESTRING16)
1154169962Sobrien				src++;
1155191736Sobrien
1156267843Sdelphij			/* check that offset is within range */
1157267843Sdelphij			if (offset >= nbytes)
1158267843Sdelphij				break;
1159175296Sobrien			for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1160169962Sobrien				if (dst < edst)
1161175296Sobrien					*dst = *src;
1162169962Sobrien				else
1163169962Sobrien					break;
1164175296Sobrien				if (*dst == '\0') {
1165175296Sobrien					if (type == FILE_BESTRING16 ?
1166175296Sobrien					    *(src - 1) != '\0' :
1167175296Sobrien					    *(src + 1) != '\0')
1168175296Sobrien						*dst = ' ';
1169175296Sobrien				}
1170169962Sobrien			}
1171169962Sobrien			*edst = '\0';
1172169962Sobrien			return 0;
1173139368Sobrien		}
1174169962Sobrien		case FILE_STRING:	/* XXX - these two should not need */
1175169962Sobrien		case FILE_PSTRING:	/* to copy anything, but do anyway. */
1176169962Sobrien		default:
1177169962Sobrien			break;
1178169962Sobrien		}
1179139368Sobrien	}
1180139368Sobrien
1181139368Sobrien	if (offset >= nbytes) {
1182139368Sobrien		(void)memset(p, '\0', sizeof(*p));
1183139368Sobrien		return 0;
1184139368Sobrien	}
1185139368Sobrien	if (nbytes - offset < sizeof(*p))
1186139368Sobrien		nbytes = nbytes - offset;
1187139368Sobrien	else
1188139368Sobrien		nbytes = sizeof(*p);
1189139368Sobrien
1190139368Sobrien	(void)memcpy(p, s + offset, nbytes);
1191139368Sobrien
1192139368Sobrien	/*
1193139368Sobrien	 * the usefulness of padding with zeroes eludes me, it
1194139368Sobrien	 * might even cause problems
1195139368Sobrien	 */
1196139368Sobrien	if (nbytes < sizeof(*p))
1197159764Sobrien		(void)memset(((char *)(void *)p) + nbytes, '\0',
1198159764Sobrien		    sizeof(*p) - nbytes);
1199139368Sobrien	return 0;
1200139368Sobrien}
1201139368Sobrien
1202139368Sobrienprivate int
1203267843Sdelphijmget(struct magic_set *ms, const unsigned char *s, struct magic *m,
1204267843Sdelphij    size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
1205284193Sdelphij    int flip, uint16_t indir_level, uint16_t *name_count,
1206284193Sdelphij    int *printed_something, int *need_separator, int *returnval)
1207139368Sobrien{
1208275670Sdelphij	uint32_t offset = ms->offset;
1209267843Sdelphij	uint32_t lhs;
1210275670Sdelphij	file_pushbuf_t *pb;
1211267843Sdelphij	int rv, oneed_separator, in_type;
1212275670Sdelphij	char *rbuf;
1213169962Sobrien	union VALUETYPE *p = &ms->ms_value;
1214267843Sdelphij	struct mlist ml;
1215139368Sobrien
1216284193Sdelphij	if (indir_level >= ms->indir_max) {
1217284193Sdelphij		file_error(ms, 0, "indirect recursion nesting (%hu) exceeded",
1218284193Sdelphij		    indir_level);
1219139368Sobrien		return -1;
1220267843Sdelphij	}
1221139368Sobrien
1222284193Sdelphij	if (*name_count >= ms->name_max) {
1223284193Sdelphij		file_error(ms, 0, "name use count (%hu) exceeded",
1224284193Sdelphij		    *name_count);
1225284193Sdelphij		return -1;
1226284193Sdelphij	}
1227284193Sdelphij
1228267843Sdelphij	if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
1229267843Sdelphij	    (uint32_t)nbytes, m) == -1)
1230267843Sdelphij		return -1;
1231267843Sdelphij
1232133359Sobrien	if ((ms->flags & MAGIC_DEBUG) != 0) {
1233284193Sdelphij		fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%"
1234284193Sdelphij		    SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1235284193Sdelphij		    "u, il=%hu, nc=%hu)\n",
1236284193Sdelphij		    m->type, m->flag, offset, o, nbytes,
1237284193Sdelphij		    indir_level, *name_count);
1238133359Sobrien		mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1239191736Sobrien#ifndef COMPILE_ONLY
1240133359Sobrien		file_mdump(m);
1241191736Sobrien#endif
1242133359Sobrien	}
1243133359Sobrien
124468349Sobrien	if (m->flag & INDIR) {
1245159764Sobrien		int off = m->in_offset;
1246159764Sobrien		if (m->in_op & FILE_OPINDIRECT) {
1247186690Sobrien			const union VALUETYPE *q = CAST(const union VALUETYPE *,
1248186690Sobrien			    ((const void *)(s + offset + off)));
1249267843Sdelphij			switch (cvt_flip(m->in_type, flip)) {
1250159764Sobrien			case FILE_BYTE:
1251159764Sobrien				off = q->b;
1252159764Sobrien				break;
1253159764Sobrien			case FILE_SHORT:
1254159764Sobrien				off = q->h;
1255159764Sobrien				break;
1256159764Sobrien			case FILE_BESHORT:
1257159764Sobrien				off = (short)((q->hs[0]<<8)|(q->hs[1]));
1258159764Sobrien				break;
1259159764Sobrien			case FILE_LESHORT:
1260159764Sobrien				off = (short)((q->hs[1]<<8)|(q->hs[0]));
1261159764Sobrien				break;
1262159764Sobrien			case FILE_LONG:
1263159764Sobrien				off = q->l;
1264159764Sobrien				break;
1265159764Sobrien			case FILE_BELONG:
1266191736Sobrien			case FILE_BEID3:
1267159764Sobrien				off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
1268159764Sobrien						 (q->hl[2]<<8)|(q->hl[3]));
1269159764Sobrien				break;
1270191736Sobrien			case FILE_LEID3:
1271159764Sobrien			case FILE_LELONG:
1272159764Sobrien				off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
1273159764Sobrien						 (q->hl[1]<<8)|(q->hl[0]));
1274159764Sobrien				break;
1275159764Sobrien			case FILE_MELONG:
1276159764Sobrien				off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
1277159764Sobrien						 (q->hl[3]<<8)|(q->hl[2]));
1278159764Sobrien				break;
1279159764Sobrien			}
1280267843Sdelphij			if ((ms->flags & MAGIC_DEBUG) != 0)
1281267843Sdelphij				fprintf(stderr, "indirect offs=%u\n", off);
1282159764Sobrien		}
1283267843Sdelphij		switch (in_type = cvt_flip(m->in_type, flip)) {
1284133359Sobrien		case FILE_BYTE:
1285267843Sdelphij			if (OFFSET_OOB(nbytes, offset, 1))
1286169962Sobrien				return 0;
1287159764Sobrien			if (off) {
1288169962Sobrien				switch (m->in_op & FILE_OPS_MASK) {
1289133359Sobrien				case FILE_OPAND:
1290159764Sobrien					offset = p->b & off;
129180588Sobrien					break;
1292133359Sobrien				case FILE_OPOR:
1293159764Sobrien					offset = p->b | off;
129480588Sobrien					break;
1295133359Sobrien				case FILE_OPXOR:
1296159764Sobrien					offset = p->b ^ off;
129780588Sobrien					break;
1298133359Sobrien				case FILE_OPADD:
1299159764Sobrien					offset = p->b + off;
130080588Sobrien					break;
1301133359Sobrien				case FILE_OPMINUS:
1302159764Sobrien					offset = p->b - off;
130380588Sobrien					break;
1304133359Sobrien				case FILE_OPMULTIPLY:
1305159764Sobrien					offset = p->b * off;
130680588Sobrien					break;
1307133359Sobrien				case FILE_OPDIVIDE:
1308159764Sobrien					offset = p->b / off;
130980588Sobrien					break;
1310133359Sobrien				case FILE_OPMODULO:
1311159764Sobrien					offset = p->b % off;
131280588Sobrien					break;
131380588Sobrien				}
1314133359Sobrien			} else
1315133359Sobrien				offset = p->b;
1316133359Sobrien			if (m->in_op & FILE_OPINVERSE)
131780588Sobrien				offset = ~offset;
131868349Sobrien			break;
1319133359Sobrien		case FILE_BESHORT:
1320267843Sdelphij			if (OFFSET_OOB(nbytes, offset, 2))
1321159764Sobrien				return 0;
1322267843Sdelphij			lhs = (p->hs[0] << 8) | p->hs[1];
1323159764Sobrien			if (off) {
1324169962Sobrien				switch (m->in_op & FILE_OPS_MASK) {
1325133359Sobrien				case FILE_OPAND:
1326267843Sdelphij					offset = lhs & off;
132780588Sobrien					break;
1328133359Sobrien				case FILE_OPOR:
1329267843Sdelphij					offset = lhs | off;
133080588Sobrien					break;
1331133359Sobrien				case FILE_OPXOR:
1332267843Sdelphij					offset = lhs ^ off;
133380588Sobrien					break;
1334133359Sobrien				case FILE_OPADD:
1335267843Sdelphij					offset = lhs + off;
133680588Sobrien					break;
1337133359Sobrien				case FILE_OPMINUS:
1338267843Sdelphij					offset = lhs - off;
133980588Sobrien					break;
1340133359Sobrien				case FILE_OPMULTIPLY:
1341267843Sdelphij					offset = lhs * off;
134280588Sobrien					break;
1343133359Sobrien				case FILE_OPDIVIDE:
1344267843Sdelphij					offset = lhs / off;
134580588Sobrien					break;
1346133359Sobrien				case FILE_OPMODULO:
1347267843Sdelphij					offset = lhs % off;
134880588Sobrien					break;
134980588Sobrien				}
1350133359Sobrien			} else
1351267843Sdelphij				offset = lhs;
1352133359Sobrien			if (m->in_op & FILE_OPINVERSE)
135380588Sobrien				offset = ~offset;
135468349Sobrien			break;
1355133359Sobrien		case FILE_LESHORT:
1356267843Sdelphij			if (OFFSET_OOB(nbytes, offset, 2))
1357159764Sobrien				return 0;
1358267843Sdelphij			lhs = (p->hs[1] << 8) | p->hs[0];
1359159764Sobrien			if (off) {
1360169962Sobrien				switch (m->in_op & FILE_OPS_MASK) {
1361133359Sobrien				case FILE_OPAND:
1362267843Sdelphij					offset = lhs & off;
136380588Sobrien					break;
1364133359Sobrien				case FILE_OPOR:
1365267843Sdelphij					offset = lhs | off;
136680588Sobrien					break;
1367133359Sobrien				case FILE_OPXOR:
1368267843Sdelphij					offset = lhs ^ off;
136980588Sobrien					break;
1370133359Sobrien				case FILE_OPADD:
1371267843Sdelphij					offset = lhs + off;
137280588Sobrien					break;
1373133359Sobrien				case FILE_OPMINUS:
1374267843Sdelphij					offset = lhs - off;
137580588Sobrien					break;
1376133359Sobrien				case FILE_OPMULTIPLY:
1377267843Sdelphij					offset = lhs * off;
137880588Sobrien					break;
1379133359Sobrien				case FILE_OPDIVIDE:
1380267843Sdelphij					offset = lhs / off;
138180588Sobrien					break;
1382133359Sobrien				case FILE_OPMODULO:
1383267843Sdelphij					offset = lhs % off;
138480588Sobrien					break;
138580588Sobrien				}
1386133359Sobrien			} else
1387267843Sdelphij				offset = lhs;
1388133359Sobrien			if (m->in_op & FILE_OPINVERSE)
138980588Sobrien				offset = ~offset;
139068349Sobrien			break;
1391133359Sobrien		case FILE_SHORT:
1392267843Sdelphij			if (OFFSET_OOB(nbytes, offset, 2))
1393159764Sobrien				return 0;
1394159764Sobrien			if (off) {
1395169962Sobrien				switch (m->in_op & FILE_OPS_MASK) {
1396133359Sobrien				case FILE_OPAND:
1397159764Sobrien					offset = p->h & off;
139880588Sobrien					break;
1399133359Sobrien				case FILE_OPOR:
1400159764Sobrien					offset = p->h | off;
140180588Sobrien					break;
1402133359Sobrien				case FILE_OPXOR:
1403159764Sobrien					offset = p->h ^ off;
140480588Sobrien					break;
1405133359Sobrien				case FILE_OPADD:
1406159764Sobrien					offset = p->h + off;
140780588Sobrien					break;
1408133359Sobrien				case FILE_OPMINUS:
1409159764Sobrien					offset = p->h - off;
141080588Sobrien					break;
1411133359Sobrien				case FILE_OPMULTIPLY:
1412159764Sobrien					offset = p->h * off;
141380588Sobrien					break;
1414133359Sobrien				case FILE_OPDIVIDE:
1415159764Sobrien					offset = p->h / off;
141680588Sobrien					break;
1417133359Sobrien				case FILE_OPMODULO:
1418159764Sobrien					offset = p->h % off;
141980588Sobrien					break;
142080588Sobrien				}
1421133359Sobrien			}
1422133359Sobrien			else
1423133359Sobrien				offset = p->h;
1424133359Sobrien			if (m->in_op & FILE_OPINVERSE)
142580588Sobrien				offset = ~offset;
142668349Sobrien			break;
1427133359Sobrien		case FILE_BELONG:
1428191736Sobrien		case FILE_BEID3:
1429267843Sdelphij			if (OFFSET_OOB(nbytes, offset, 4))
1430159764Sobrien				return 0;
1431267843Sdelphij			lhs = (p->hl[0] << 24) | (p->hl[1] << 16) |
1432267843Sdelphij			    (p->hl[2] << 8) | p->hl[3];
1433159764Sobrien			if (off) {
1434169962Sobrien				switch (m->in_op & FILE_OPS_MASK) {
1435133359Sobrien				case FILE_OPAND:
1436267843Sdelphij					offset = lhs & off;
143780588Sobrien					break;
1438133359Sobrien				case FILE_OPOR:
1439267843Sdelphij					offset = lhs | off;
144080588Sobrien					break;
1441133359Sobrien				case FILE_OPXOR:
1442267843Sdelphij					offset = lhs ^ off;
144380588Sobrien					break;
1444133359Sobrien				case FILE_OPADD:
1445267843Sdelphij					offset = lhs + off;
144680588Sobrien					break;
1447133359Sobrien				case FILE_OPMINUS:
1448267843Sdelphij					offset = lhs - off;
144980588Sobrien					break;
1450133359Sobrien				case FILE_OPMULTIPLY:
1451267843Sdelphij					offset = lhs * off;
145280588Sobrien					break;
1453133359Sobrien				case FILE_OPDIVIDE:
1454267843Sdelphij					offset = lhs / off;
145580588Sobrien					break;
1456133359Sobrien				case FILE_OPMODULO:
1457267843Sdelphij					offset = lhs % off;
145880588Sobrien					break;
145980588Sobrien				}
1460133359Sobrien			} else
1461267843Sdelphij				offset = lhs;
1462133359Sobrien			if (m->in_op & FILE_OPINVERSE)
146380588Sobrien				offset = ~offset;
146468349Sobrien			break;
1465133359Sobrien		case FILE_LELONG:
1466191736Sobrien		case FILE_LEID3:
1467267843Sdelphij			if (OFFSET_OOB(nbytes, offset, 4))
1468159764Sobrien				return 0;
1469267843Sdelphij			lhs = (p->hl[3] << 24) | (p->hl[2] << 16) |
1470267843Sdelphij			    (p->hl[1] << 8) | p->hl[0];
1471159764Sobrien			if (off) {
1472169962Sobrien				switch (m->in_op & FILE_OPS_MASK) {
1473133359Sobrien				case FILE_OPAND:
1474267843Sdelphij					offset = lhs & off;
147580588Sobrien					break;
1476133359Sobrien				case FILE_OPOR:
1477267843Sdelphij					offset = lhs | off;
147880588Sobrien					break;
1479133359Sobrien				case FILE_OPXOR:
1480267843Sdelphij					offset = lhs ^ off;
148180588Sobrien					break;
1482133359Sobrien				case FILE_OPADD:
1483267843Sdelphij					offset = lhs + off;
148480588Sobrien					break;
1485133359Sobrien				case FILE_OPMINUS:
1486267843Sdelphij					offset = lhs - off;
148780588Sobrien					break;
1488133359Sobrien				case FILE_OPMULTIPLY:
1489267843Sdelphij					offset = lhs * off;
149080588Sobrien					break;
1491133359Sobrien				case FILE_OPDIVIDE:
1492267843Sdelphij					offset = lhs / off;
149380588Sobrien					break;
1494133359Sobrien				case FILE_OPMODULO:
1495267843Sdelphij					offset = lhs % off;
149680588Sobrien					break;
149780588Sobrien				}
1498133359Sobrien			} else
1499267843Sdelphij				offset = lhs;
1500133359Sobrien			if (m->in_op & FILE_OPINVERSE)
150180588Sobrien				offset = ~offset;
150268349Sobrien			break;
1503159764Sobrien		case FILE_MELONG:
1504267843Sdelphij			if (OFFSET_OOB(nbytes, offset, 4))
1505159764Sobrien				return 0;
1506267843Sdelphij			lhs = (p->hl[1] << 24) | (p->hl[0] << 16) |
1507267843Sdelphij			    (p->hl[3] << 8) | p->hl[2];
1508159764Sobrien			if (off) {
1509169962Sobrien				switch (m->in_op & FILE_OPS_MASK) {
1510159764Sobrien				case FILE_OPAND:
1511267843Sdelphij					offset = lhs & off;
1512159764Sobrien					break;
1513159764Sobrien				case FILE_OPOR:
1514267843Sdelphij					offset = lhs | off;
1515159764Sobrien					break;
1516159764Sobrien				case FILE_OPXOR:
1517267843Sdelphij					offset = lhs ^ off;
1518159764Sobrien					break;
1519159764Sobrien				case FILE_OPADD:
1520267843Sdelphij					offset = lhs + off;
1521159764Sobrien					break;
1522159764Sobrien				case FILE_OPMINUS:
1523267843Sdelphij					offset = lhs - off;
1524159764Sobrien					break;
1525159764Sobrien				case FILE_OPMULTIPLY:
1526267843Sdelphij					offset = lhs * off;
1527159764Sobrien					break;
1528159764Sobrien				case FILE_OPDIVIDE:
1529267843Sdelphij					offset = lhs / off;
1530159764Sobrien					break;
1531159764Sobrien				case FILE_OPMODULO:
1532267843Sdelphij					offset = lhs % off;
1533159764Sobrien					break;
1534159764Sobrien				}
1535159764Sobrien			} else
1536267843Sdelphij				offset = lhs;
1537159764Sobrien			if (m->in_op & FILE_OPINVERSE)
1538159764Sobrien				offset = ~offset;
1539159764Sobrien			break;
1540133359Sobrien		case FILE_LONG:
1541267843Sdelphij			if (OFFSET_OOB(nbytes, offset, 4))
1542159764Sobrien				return 0;
1543159764Sobrien			if (off) {
1544169962Sobrien				switch (m->in_op & FILE_OPS_MASK) {
1545133359Sobrien				case FILE_OPAND:
1546159764Sobrien					offset = p->l & off;
154780588Sobrien					break;
1548133359Sobrien				case FILE_OPOR:
1549159764Sobrien					offset = p->l | off;
155080588Sobrien					break;
1551133359Sobrien				case FILE_OPXOR:
1552159764Sobrien					offset = p->l ^ off;
155380588Sobrien					break;
1554133359Sobrien				case FILE_OPADD:
1555159764Sobrien					offset = p->l + off;
155680588Sobrien					break;
1557133359Sobrien				case FILE_OPMINUS:
1558159764Sobrien					offset = p->l - off;
155980588Sobrien					break;
1560133359Sobrien				case FILE_OPMULTIPLY:
1561159764Sobrien					offset = p->l * off;
156280588Sobrien					break;
1563133359Sobrien				case FILE_OPDIVIDE:
1564159764Sobrien					offset = p->l / off;
156580588Sobrien					break;
1566133359Sobrien				case FILE_OPMODULO:
1567159764Sobrien					offset = p->l % off;
156880588Sobrien					break;
156980588Sobrien				}
1570133359Sobrien			} else
1571133359Sobrien				offset = p->l;
1572133359Sobrien			if (m->in_op & FILE_OPINVERSE)
157380588Sobrien				offset = ~offset;
157468349Sobrien			break;
1575267843Sdelphij		default:
1576267843Sdelphij			break;
157768349Sobrien		}
157868349Sobrien
1579267843Sdelphij		switch (in_type) {
1580191736Sobrien		case FILE_LEID3:
1581191736Sobrien		case FILE_BEID3:
1582191736Sobrien			offset = ((((offset >>  0) & 0x7f) <<  0) |
1583191736Sobrien				 (((offset >>  8) & 0x7f) <<  7) |
1584191736Sobrien				 (((offset >> 16) & 0x7f) << 14) |
1585191736Sobrien				 (((offset >> 24) & 0x7f) << 21)) + 10;
1586191736Sobrien			break;
1587191736Sobrien		default:
1588191736Sobrien			break;
1589191736Sobrien		}
1590191736Sobrien
1591191736Sobrien		if (m->flag & INDIROFFADD) {
1592169962Sobrien			offset += ms->c.li[cont_level-1].off;
1593267843Sdelphij			if (offset == 0) {
1594267843Sdelphij				if ((ms->flags & MAGIC_DEBUG) != 0)
1595267843Sdelphij					fprintf(stderr,
1596267843Sdelphij					    "indirect *zero* offset\n");
1597267843Sdelphij				return 0;
1598267843Sdelphij			}
1599267843Sdelphij			if ((ms->flags & MAGIC_DEBUG) != 0)
1600267843Sdelphij				fprintf(stderr, "indirect +offs=%u\n", offset);
1601191736Sobrien		}
1602267843Sdelphij		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1603139368Sobrien			return -1;
1604169942Sobrien		ms->offset = offset;
160568349Sobrien
1606133359Sobrien		if ((ms->flags & MAGIC_DEBUG) != 0) {
1607133359Sobrien			mdebug(offset, (char *)(void *)p,
1608133359Sobrien			    sizeof(union VALUETYPE));
1609191736Sobrien#ifndef COMPILE_ONLY
1610133359Sobrien			file_mdump(m);
1611191736Sobrien#endif
161268349Sobrien		}
161368349Sobrien	}
1614159764Sobrien
1615159764Sobrien	/* Verify we have enough data to match magic type */
1616159764Sobrien	switch (m->type) {
1617169962Sobrien	case FILE_BYTE:
1618267843Sdelphij		if (OFFSET_OOB(nbytes, offset, 1))
1619169962Sobrien			return 0;
1620169962Sobrien		break;
1621191736Sobrien
1622169962Sobrien	case FILE_SHORT:
1623169962Sobrien	case FILE_BESHORT:
1624169962Sobrien	case FILE_LESHORT:
1625267843Sdelphij		if (OFFSET_OOB(nbytes, offset, 2))
1626169962Sobrien			return 0;
1627169962Sobrien		break;
1628191736Sobrien
1629169962Sobrien	case FILE_LONG:
1630169962Sobrien	case FILE_BELONG:
1631169962Sobrien	case FILE_LELONG:
1632169962Sobrien	case FILE_MELONG:
1633169962Sobrien	case FILE_DATE:
1634169962Sobrien	case FILE_BEDATE:
1635169962Sobrien	case FILE_LEDATE:
1636169962Sobrien	case FILE_MEDATE:
1637169962Sobrien	case FILE_LDATE:
1638169962Sobrien	case FILE_BELDATE:
1639169962Sobrien	case FILE_LELDATE:
1640169962Sobrien	case FILE_MELDATE:
1641175296Sobrien	case FILE_FLOAT:
1642175296Sobrien	case FILE_BEFLOAT:
1643175296Sobrien	case FILE_LEFLOAT:
1644267843Sdelphij		if (OFFSET_OOB(nbytes, offset, 4))
1645169962Sobrien			return 0;
1646169962Sobrien		break;
1647191736Sobrien
1648175296Sobrien	case FILE_DOUBLE:
1649175296Sobrien	case FILE_BEDOUBLE:
1650175296Sobrien	case FILE_LEDOUBLE:
1651267843Sdelphij		if (OFFSET_OOB(nbytes, offset, 8))
1652175296Sobrien			return 0;
1653175296Sobrien		break;
1654175296Sobrien
1655169962Sobrien	case FILE_STRING:
1656169962Sobrien	case FILE_PSTRING:
1657169962Sobrien	case FILE_SEARCH:
1658267843Sdelphij		if (OFFSET_OOB(nbytes, offset, m->vallen))
1659169962Sobrien			return 0;
1660169962Sobrien		break;
1661159764Sobrien
1662169962Sobrien	case FILE_REGEX:
1663169962Sobrien		if (nbytes < offset)
1664169962Sobrien			return 0;
1665169962Sobrien		break;
1666159764Sobrien
1667191736Sobrien	case FILE_INDIRECT:
1668284193Sdelphij		if (m->str_flags & INDIRECT_RELATIVE)
1669284193Sdelphij			offset += o;
1670267843Sdelphij		if (offset == 0)
1671267843Sdelphij			return 0;
1672275670Sdelphij
1673191736Sobrien		if (nbytes < offset)
1674191736Sobrien			return 0;
1675275670Sdelphij
1676275670Sdelphij		if ((pb = file_push_buffer(ms)) == NULL)
1677275670Sdelphij			return -1;
1678275670Sdelphij
1679267843Sdelphij		rv = file_softmagic(ms, s + offset, nbytes - offset,
1680284193Sdelphij		    indir_level + 1, name_count, BINTEST, text);
1681275670Sdelphij
1682267843Sdelphij		if ((ms->flags & MAGIC_DEBUG) != 0)
1683267843Sdelphij			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1684275670Sdelphij
1685275670Sdelphij		rbuf = file_pop_buffer(ms, pb);
1686275670Sdelphij		if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1687275670Sdelphij			return -1;
1688275670Sdelphij
1689267843Sdelphij		if (rv == 1) {
1690267843Sdelphij			if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 &&
1691267843Sdelphij			    file_printf(ms, F(ms, m, "%u"), offset) == -1) {
1692267843Sdelphij				free(rbuf);
1693267843Sdelphij				return -1;
1694267843Sdelphij			}
1695267843Sdelphij			if (file_printf(ms, "%s", rbuf) == -1) {
1696267843Sdelphij				free(rbuf);
1697267843Sdelphij				return -1;
1698267843Sdelphij			}
1699267843Sdelphij		}
1700267843Sdelphij		free(rbuf);
1701267843Sdelphij		return rv;
1702191736Sobrien
1703267843Sdelphij	case FILE_USE:
1704267843Sdelphij		if (nbytes < offset)
1705267843Sdelphij			return 0;
1706275670Sdelphij		rbuf = m->value.s;
1707275670Sdelphij		if (*rbuf == '^') {
1708275670Sdelphij			rbuf++;
1709267843Sdelphij			flip = !flip;
1710267843Sdelphij		}
1711275670Sdelphij		if (file_magicfind(ms, rbuf, &ml) == -1) {
1712275670Sdelphij			file_error(ms, 0, "cannot find entry `%s'", rbuf);
1713267843Sdelphij			return -1;
1714267843Sdelphij		}
1715284193Sdelphij		(*name_count)++;
1716267843Sdelphij		oneed_separator = *need_separator;
1717267843Sdelphij		if (m->flag & NOSPACE)
1718267843Sdelphij			*need_separator = 0;
1719267843Sdelphij		rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
1720284193Sdelphij		    mode, text, flip, indir_level, name_count,
1721284193Sdelphij		    printed_something, need_separator, returnval);
1722267843Sdelphij		if (rv != 1)
1723267843Sdelphij		    *need_separator = oneed_separator;
1724267843Sdelphij		return rv;
1725267843Sdelphij
1726267843Sdelphij	case FILE_NAME:
1727267843Sdelphij		if (file_printf(ms, "%s", m->desc) == -1)
1728267843Sdelphij			return -1;
1729267843Sdelphij		return 1;
1730169962Sobrien	case FILE_DEFAULT:	/* nothing to check */
1731267843Sdelphij	case FILE_CLEAR:
1732169962Sobrien	default:
1733169962Sobrien		break;
1734169962Sobrien	}
1735267843Sdelphij	if (!mconvert(ms, m, flip))
1736169962Sobrien		return 0;
1737169962Sobrien	return 1;
1738169962Sobrien}
1739159764Sobrien
1740169962Sobrienprivate uint64_t
1741169962Sobrienfile_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1742169962Sobrien{
1743169962Sobrien	/*
1744169962Sobrien	 * Convert the source args to unsigned here so that (1) the
1745169962Sobrien	 * compare will be unsigned as it is in strncmp() and (2) so
1746169962Sobrien	 * the ctype functions will work correctly without extra
1747169962Sobrien	 * casting.
1748169962Sobrien	 */
1749169962Sobrien	const unsigned char *a = (const unsigned char *)s1;
1750169962Sobrien	const unsigned char *b = (const unsigned char *)s2;
1751169962Sobrien	uint64_t v;
1752169962Sobrien
1753169962Sobrien	/*
1754186690Sobrien	 * What we want here is v = strncmp(s1, s2, len),
1755186690Sobrien	 * but ignoring any nulls.
1756169962Sobrien	 */
1757169962Sobrien	v = 0;
1758169962Sobrien	if (0L == flags) { /* normal string: do it fast */
1759169962Sobrien		while (len-- > 0)
1760169962Sobrien			if ((v = *b++ - *a++) != '\0')
1761191736Sobrien				break;
1762159764Sobrien	}
1763169962Sobrien	else { /* combine the others */
1764169962Sobrien		while (len-- > 0) {
1765169962Sobrien			if ((flags & STRING_IGNORE_LOWERCASE) &&
1766169962Sobrien			    islower(*a)) {
1767169962Sobrien				if ((v = tolower(*b++) - *a++) != '\0')
1768169962Sobrien					break;
1769169962Sobrien			}
1770169962Sobrien			else if ((flags & STRING_IGNORE_UPPERCASE) &&
1771169962Sobrien			    isupper(*a)) {
1772169962Sobrien				if ((v = toupper(*b++) - *a++) != '\0')
1773169962Sobrien					break;
1774169962Sobrien			}
1775226048Sobrien			else if ((flags & STRING_COMPACT_WHITESPACE) &&
1776191736Sobrien			    isspace(*a)) {
1777169962Sobrien				a++;
1778169962Sobrien				if (isspace(*b++)) {
1779226048Sobrien					if (!isspace(*a))
1780226048Sobrien						while (isspace(*b))
1781226048Sobrien							b++;
1782169962Sobrien				}
1783169962Sobrien				else {
1784169962Sobrien					v = 1;
1785169962Sobrien					break;
1786169962Sobrien				}
1787169962Sobrien			}
1788226048Sobrien			else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1789169962Sobrien			    isspace(*a)) {
1790169962Sobrien				a++;
1791169962Sobrien				while (isspace(*b))
1792169962Sobrien					b++;
1793169962Sobrien			}
1794169962Sobrien			else {
1795169962Sobrien				if ((v = *b++ - *a++) != '\0')
1796169962Sobrien					break;
1797169962Sobrien			}
1798159764Sobrien		}
1799159764Sobrien	}
1800169962Sobrien	return v;
180168349Sobrien}
180268349Sobrien
1803169962Sobrienprivate uint64_t
1804169962Sobrienfile_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1805169962Sobrien{
1806169962Sobrien	/*
1807169962Sobrien	 * XXX - The 16-bit string compare probably needs to be done
1808169962Sobrien	 * differently, especially if the flags are to be supported.
1809169962Sobrien	 * At the moment, I am unsure.
1810169962Sobrien	 */
1811169962Sobrien	flags = 0;
1812169962Sobrien	return file_strncmp(a, b, len, flags);
1813169962Sobrien}
1814169962Sobrien
1815133359Sobrienprivate int
1816169962Sobrienmagiccheck(struct magic_set *ms, struct magic *m)
181768349Sobrien{
1818169942Sobrien	uint64_t l = m->value.q;
1819169942Sobrien	uint64_t v;
1820175296Sobrien	float fl, fv;
1821175296Sobrien	double dl, dv;
182268349Sobrien	int matched;
1823169962Sobrien	union VALUETYPE *p = &ms->ms_value;
182468349Sobrien
182568349Sobrien	switch (m->type) {
1826133359Sobrien	case FILE_BYTE:
182768349Sobrien		v = p->b;
182868349Sobrien		break;
182968349Sobrien
1830133359Sobrien	case FILE_SHORT:
1831133359Sobrien	case FILE_BESHORT:
1832133359Sobrien	case FILE_LESHORT:
183368349Sobrien		v = p->h;
183468349Sobrien		break;
183568349Sobrien
1836133359Sobrien	case FILE_LONG:
1837133359Sobrien	case FILE_BELONG:
1838133359Sobrien	case FILE_LELONG:
1839159764Sobrien	case FILE_MELONG:
1840133359Sobrien	case FILE_DATE:
1841133359Sobrien	case FILE_BEDATE:
1842133359Sobrien	case FILE_LEDATE:
1843159764Sobrien	case FILE_MEDATE:
1844133359Sobrien	case FILE_LDATE:
1845133359Sobrien	case FILE_BELDATE:
1846133359Sobrien	case FILE_LELDATE:
1847159764Sobrien	case FILE_MELDATE:
184868349Sobrien		v = p->l;
184968349Sobrien		break;
185068349Sobrien
1851169942Sobrien	case FILE_QUAD:
1852169942Sobrien	case FILE_LEQUAD:
1853169942Sobrien	case FILE_BEQUAD:
1854169942Sobrien	case FILE_QDATE:
1855169942Sobrien	case FILE_BEQDATE:
1856169942Sobrien	case FILE_LEQDATE:
1857169942Sobrien	case FILE_QLDATE:
1858169942Sobrien	case FILE_BEQLDATE:
1859169942Sobrien	case FILE_LEQLDATE:
1860267843Sdelphij	case FILE_QWDATE:
1861267843Sdelphij	case FILE_BEQWDATE:
1862267843Sdelphij	case FILE_LEQWDATE:
1863169942Sobrien		v = p->q;
1864169942Sobrien		break;
1865169942Sobrien
1866175296Sobrien	case FILE_FLOAT:
1867175296Sobrien	case FILE_BEFLOAT:
1868175296Sobrien	case FILE_LEFLOAT:
1869175296Sobrien		fl = m->value.f;
1870175296Sobrien		fv = p->f;
1871175296Sobrien		switch (m->reln) {
1872175296Sobrien		case 'x':
1873175296Sobrien			matched = 1;
1874175296Sobrien			break;
1875191736Sobrien
1876175296Sobrien		case '!':
1877175296Sobrien			matched = fv != fl;
1878175296Sobrien			break;
1879191736Sobrien
1880175296Sobrien		case '=':
1881175296Sobrien			matched = fv == fl;
1882175296Sobrien			break;
1883191736Sobrien
1884175296Sobrien		case '>':
1885175296Sobrien			matched = fv > fl;
1886175296Sobrien			break;
1887191736Sobrien
1888175296Sobrien		case '<':
1889175296Sobrien			matched = fv < fl;
1890175296Sobrien			break;
1891191736Sobrien
1892175296Sobrien		default:
1893191736Sobrien			file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1894191736Sobrien			    m->reln);
1895175296Sobrien			return -1;
1896175296Sobrien		}
1897175296Sobrien		return matched;
1898175296Sobrien
1899175296Sobrien	case FILE_DOUBLE:
1900175296Sobrien	case FILE_BEDOUBLE:
1901175296Sobrien	case FILE_LEDOUBLE:
1902175296Sobrien		dl = m->value.d;
1903175296Sobrien		dv = p->d;
1904175296Sobrien		switch (m->reln) {
1905175296Sobrien		case 'x':
1906175296Sobrien			matched = 1;
1907175296Sobrien			break;
1908191736Sobrien
1909175296Sobrien		case '!':
1910175296Sobrien			matched = dv != dl;
1911175296Sobrien			break;
1912191736Sobrien
1913175296Sobrien		case '=':
1914175296Sobrien			matched = dv == dl;
1915175296Sobrien			break;
1916191736Sobrien
1917175296Sobrien		case '>':
1918175296Sobrien			matched = dv > dl;
1919175296Sobrien			break;
1920191736Sobrien
1921175296Sobrien		case '<':
1922175296Sobrien			matched = dv < dl;
1923175296Sobrien			break;
1924191736Sobrien
1925175296Sobrien		default:
1926175296Sobrien			file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1927175296Sobrien			return -1;
1928175296Sobrien		}
1929175296Sobrien		return matched;
1930175296Sobrien
1931169962Sobrien	case FILE_DEFAULT:
1932267843Sdelphij	case FILE_CLEAR:
1933169962Sobrien		l = 0;
1934169962Sobrien		v = 0;
1935169962Sobrien		break;
1936169962Sobrien
1937133359Sobrien	case FILE_STRING:
1938169962Sobrien	case FILE_PSTRING:
1939169962Sobrien		l = 0;
1940169962Sobrien		v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1941169962Sobrien		break;
1942169962Sobrien
1943139368Sobrien	case FILE_BESTRING16:
1944139368Sobrien	case FILE_LESTRING16:
194568349Sobrien		l = 0;
1946169962Sobrien		v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1947169962Sobrien		break;
1948169962Sobrien
1949169962Sobrien	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1950169962Sobrien		size_t slen;
1951169962Sobrien		size_t idx;
1952169962Sobrien
1953169962Sobrien		if (ms->search.s == NULL)
1954169962Sobrien			return 0;
1955169962Sobrien
1956169962Sobrien		slen = MIN(m->vallen, sizeof(m->value.s));
1957169962Sobrien		l = 0;
195868349Sobrien		v = 0;
1959169962Sobrien
1960186690Sobrien		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1961169962Sobrien			if (slen + idx > ms->search.s_len)
1962169962Sobrien				break;
1963169962Sobrien
1964267843Sdelphij			v = file_strncmp(m->value.s, ms->search.s + idx, slen,
1965267843Sdelphij			    m->str_flags);
1966169962Sobrien			if (v == 0) {	/* found match */
1967186690Sobrien				ms->search.offset += idx;
1968169962Sobrien				break;
196968349Sobrien			}
197068349Sobrien		}
197168349Sobrien		break;
197268349Sobrien	}
1973169962Sobrien	case FILE_REGEX: {
1974103373Sobrien		int rc;
1975267843Sdelphij		file_regex_t rx;
1976284193Sdelphij		const char *search;
1977103373Sobrien
1978169962Sobrien		if (ms->search.s == NULL)
1979159764Sobrien			return 0;
1980159764Sobrien
1981169962Sobrien		l = 0;
1982267843Sdelphij		rc = file_regcomp(&rx, m->value.s,
1983169962Sobrien		    REG_EXTENDED|REG_NEWLINE|
1984169962Sobrien		    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
1985103373Sobrien		if (rc) {
1986267843Sdelphij			file_regerror(&rx, rc, ms);
1987169962Sobrien			v = (uint64_t)-1;
1988267843Sdelphij		} else {
1989169962Sobrien			regmatch_t pmatch[1];
1990267843Sdelphij			size_t slen = ms->search.s_len;
1991169962Sobrien#ifndef REG_STARTEND
1992169962Sobrien#define	REG_STARTEND	0
1993284193Sdelphij			char *copy;
1994284193Sdelphij			if (slen != 0) {
1995284193Sdelphij			    copy = malloc(slen);
1996284193Sdelphij			    if (copy == NULL)  {
1997284193Sdelphij				file_error(ms, errno,
1998284193Sdelphij				    "can't allocate %" SIZE_T_FORMAT "u bytes",
1999284193Sdelphij				    slen);
2000284193Sdelphij				return -1;
2001284193Sdelphij			    }
2002284193Sdelphij			    memcpy(copy, ms->search.s, slen);
2003284193Sdelphij			    copy[--slen] = '\0';
2004284193Sdelphij			    search = copy;
2005284193Sdelphij			} else {
2006284193Sdelphij			    search = ms->search.s;
2007284193Sdelphij			    copy = NULL;
2008284193Sdelphij			}
2009169962Sobrien#else
2010284193Sdelphij			search = ms->search.s;
2011169962Sobrien			pmatch[0].rm_so = 0;
2012267843Sdelphij			pmatch[0].rm_eo = slen;
2013169962Sobrien#endif
2014284193Sdelphij			rc = file_regexec(&rx, (const char *)search,
2015169962Sobrien			    1, pmatch, REG_STARTEND);
2016169962Sobrien#if REG_STARTEND == 0
2017284193Sdelphij			free(copy);
2018169962Sobrien#endif
2019169962Sobrien			switch (rc) {
2020169962Sobrien			case 0:
2021169962Sobrien				ms->search.s += (int)pmatch[0].rm_so;
2022169962Sobrien				ms->search.offset += (size_t)pmatch[0].rm_so;
2023169962Sobrien				ms->search.rm_len =
2024169962Sobrien				    (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so);
2025169962Sobrien				v = 0;
2026159764Sobrien				break;
2027169962Sobrien
2028169962Sobrien			case REG_NOMATCH:
2029169942Sobrien				v = 1;
2030159764Sobrien				break;
2031169962Sobrien
2032169962Sobrien			default:
2033267843Sdelphij				file_regerror(&rx, rc, ms);
2034169962Sobrien				v = (uint64_t)-1;
2035169962Sobrien				break;
2036169942Sobrien			}
2037159764Sobrien		}
2038267843Sdelphij		file_regfree(&rx);
2039169962Sobrien		if (v == (uint64_t)-1)
2040169962Sobrien			return -1;
2041159764Sobrien		break;
2042159764Sobrien	}
2043191736Sobrien	case FILE_INDIRECT:
2044267843Sdelphij	case FILE_USE:
2045267843Sdelphij	case FILE_NAME:
2046191736Sobrien		return 1;
204768349Sobrien	default:
2048169962Sobrien		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2049133359Sobrien		return -1;
205068349Sobrien	}
205168349Sobrien
2052169962Sobrien	v = file_signextend(ms, m, v);
205368349Sobrien
205468349Sobrien	switch (m->reln) {
205568349Sobrien	case 'x':
2056133359Sobrien		if ((ms->flags & MAGIC_DEBUG) != 0)
2057226048Sobrien			(void) fprintf(stderr, "%" INT64_T_FORMAT
2058226048Sobrien			    "u == *any* = 1\n", (unsigned long long)v);
205968349Sobrien		matched = 1;
206068349Sobrien		break;
206168349Sobrien
206268349Sobrien	case '!':
206368349Sobrien		matched = v != l;
2064133359Sobrien		if ((ms->flags & MAGIC_DEBUG) != 0)
2065226048Sobrien			(void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2066226048Sobrien			    INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2067226048Sobrien			    (unsigned long long)l, matched);
206868349Sobrien		break;
206968349Sobrien
207068349Sobrien	case '=':
207168349Sobrien		matched = v == l;
2072133359Sobrien		if ((ms->flags & MAGIC_DEBUG) != 0)
2073226048Sobrien			(void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2074226048Sobrien			    INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2075226048Sobrien			    (unsigned long long)l, matched);
207668349Sobrien		break;
207768349Sobrien
207868349Sobrien	case '>':
207968349Sobrien		if (m->flag & UNSIGNED) {
208068349Sobrien			matched = v > l;
2081133359Sobrien			if ((ms->flags & MAGIC_DEBUG) != 0)
2082226048Sobrien				(void) fprintf(stderr, "%" INT64_T_FORMAT
2083226048Sobrien				    "u > %" INT64_T_FORMAT "u = %d\n",
2084169942Sobrien				    (unsigned long long)v,
2085169942Sobrien				    (unsigned long long)l, matched);
208668349Sobrien		}
208768349Sobrien		else {
2088169962Sobrien			matched = (int64_t) v > (int64_t) l;
2089133359Sobrien			if ((ms->flags & MAGIC_DEBUG) != 0)
2090226048Sobrien				(void) fprintf(stderr, "%" INT64_T_FORMAT
2091226048Sobrien				    "d > %" INT64_T_FORMAT "d = %d\n",
2092169942Sobrien				    (long long)v, (long long)l, matched);
209368349Sobrien		}
209468349Sobrien		break;
209568349Sobrien
209668349Sobrien	case '<':
209768349Sobrien		if (m->flag & UNSIGNED) {
209868349Sobrien			matched = v < l;
2099133359Sobrien			if ((ms->flags & MAGIC_DEBUG) != 0)
2100226048Sobrien				(void) fprintf(stderr, "%" INT64_T_FORMAT
2101226048Sobrien				    "u < %" INT64_T_FORMAT "u = %d\n",
2102169942Sobrien				    (unsigned long long)v,
2103169942Sobrien				    (unsigned long long)l, matched);
210468349Sobrien		}
210568349Sobrien		else {
2106169962Sobrien			matched = (int64_t) v < (int64_t) l;
2107133359Sobrien			if ((ms->flags & MAGIC_DEBUG) != 0)
2108226048Sobrien				(void) fprintf(stderr, "%" INT64_T_FORMAT
2109226048Sobrien				    "d < %" INT64_T_FORMAT "d = %d\n",
2110226048Sobrien				     (long long)v, (long long)l, matched);
211168349Sobrien		}
211268349Sobrien		break;
211368349Sobrien
211468349Sobrien	case '&':
211568349Sobrien		matched = (v & l) == l;
2116133359Sobrien		if ((ms->flags & MAGIC_DEBUG) != 0)
2117226048Sobrien			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2118226048Sobrien			    INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2119226048Sobrien			    "x) = %d\n", (unsigned long long)v,
2120226048Sobrien			    (unsigned long long)l, (unsigned long long)l,
2121226048Sobrien			    matched);
212268349Sobrien		break;
212368349Sobrien
212468349Sobrien	case '^':
212568349Sobrien		matched = (v & l) != l;
2126133359Sobrien		if ((ms->flags & MAGIC_DEBUG) != 0)
2127226048Sobrien			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2128226048Sobrien			    INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2129226048Sobrien			    "x) = %d\n", (unsigned long long)v,
2130226048Sobrien			    (unsigned long long)l, (unsigned long long)l,
2131226048Sobrien			    matched);
213268349Sobrien		break;
213368349Sobrien
213468349Sobrien	default:
2135169962Sobrien		file_magerror(ms, "cannot happen: invalid relation `%c'",
2136133359Sobrien		    m->reln);
2137133359Sobrien		return -1;
213868349Sobrien	}
213968349Sobrien
214068349Sobrien	return matched;
214168349Sobrien}
2142169942Sobrien
2143169942Sobrienprivate int
2144191736Sobrienhandle_annotation(struct magic_set *ms, struct magic *m)
2145191736Sobrien{
2146191736Sobrien	if (ms->flags & MAGIC_APPLE) {
2147191736Sobrien		if (file_printf(ms, "%.8s", m->apple) == -1)
2148191736Sobrien			return -1;
2149191736Sobrien		return 1;
2150191736Sobrien	}
2151191736Sobrien	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2152191736Sobrien		if (file_printf(ms, "%s", m->mimetype) == -1)
2153191736Sobrien			return -1;
2154191736Sobrien		return 1;
2155191736Sobrien	}
2156191736Sobrien	return 0;
2157191736Sobrien}
2158191736Sobrien
2159191736Sobrienprivate int
2160169942Sobrienprint_sep(struct magic_set *ms, int firstline)
2161169942Sobrien{
2162191736Sobrien	if (ms->flags & MAGIC_MIME)
2163191736Sobrien		return 0;
2164169942Sobrien	if (firstline)
2165169942Sobrien		return 0;
2166169942Sobrien	/*
2167191736Sobrien	 * we found another match
2168169942Sobrien	 * put a newline and '-' to do some simple formatting
2169169942Sobrien	 */
2170169942Sobrien	return file_printf(ms, "\n- ");
2171169942Sobrien}
2172