xref: /freebsd/contrib/file/src/softmagic.c (revision ae316d1d1cffd71ab7751f94e10118777a88e027)
1b6cee71dSXin LI /*
2b6cee71dSXin LI  * Copyright (c) Ian F. Darwin 1986-1995.
3b6cee71dSXin LI  * Software written by Ian F. Darwin and others;
4b6cee71dSXin LI  * maintained 1995-present by Christos Zoulas and others.
5b6cee71dSXin LI  *
6b6cee71dSXin LI  * Redistribution and use in source and binary forms, with or without
7b6cee71dSXin LI  * modification, are permitted provided that the following conditions
8b6cee71dSXin LI  * are met:
9b6cee71dSXin LI  * 1. Redistributions of source code must retain the above copyright
10b6cee71dSXin LI  *    notice immediately at the beginning of the file, without modification,
11b6cee71dSXin LI  *    this list of conditions, and the following disclaimer.
12b6cee71dSXin LI  * 2. Redistributions in binary form must reproduce the above copyright
13b6cee71dSXin LI  *    notice, this list of conditions and the following disclaimer in the
14b6cee71dSXin LI  *    documentation and/or other materials provided with the distribution.
15b6cee71dSXin LI  *
16b6cee71dSXin LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17b6cee71dSXin LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18b6cee71dSXin LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19b6cee71dSXin LI  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20b6cee71dSXin LI  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21b6cee71dSXin LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22b6cee71dSXin LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23b6cee71dSXin LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24b6cee71dSXin LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25b6cee71dSXin LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26b6cee71dSXin LI  * SUCH DAMAGE.
27b6cee71dSXin LI  */
28b6cee71dSXin LI /*
29b6cee71dSXin LI  * softmagic - interpret variable magic from MAGIC
30b6cee71dSXin LI  */
31b6cee71dSXin LI 
32b6cee71dSXin LI #include "file.h"
33b6cee71dSXin LI 
34b6cee71dSXin LI #ifndef	lint
35*ae316d1dSXin LI FILE_RCSID("@(#)$File: softmagic.c,v 1.350 2024/11/27 15:37:00 christos Exp $")
36b6cee71dSXin LI #endif	/* lint */
37b6cee71dSXin LI 
38b6cee71dSXin LI #include "magic.h"
39b6cee71dSXin LI #include <assert.h>
40898496eeSXin LI #include <math.h>
41b6cee71dSXin LI #include <string.h>
42b6cee71dSXin LI #include <ctype.h>
43b6cee71dSXin LI #include <stdlib.h>
44898496eeSXin LI #include <limits.h>
45b6cee71dSXin LI #include <time.h>
463e41d09dSXin LI #include "der.h"
47b6cee71dSXin LI 
48898496eeSXin LI file_private int match(struct magic_set *, struct magic *, file_regex_t **, size_t,
4958a0f0d0SEitan Adler     const struct buffer *, size_t, int, int, int, uint16_t *,
50898496eeSXin LI     uint16_t *, int *, int *, int *, int *, int *);
51898496eeSXin LI file_private int mget(struct magic_set *, struct magic *, const struct buffer *,
5258a0f0d0SEitan Adler     const unsigned char *, size_t,
5358a0f0d0SEitan Adler     size_t, unsigned int, int, int, int, uint16_t *,
54898496eeSXin LI     uint16_t *, int *, int *, int *, int *, int *);
55898496eeSXin LI file_private int msetoffset(struct magic_set *, struct magic *, struct buffer *,
5658a0f0d0SEitan Adler     const struct buffer *, size_t, unsigned int);
57898496eeSXin LI file_private int magiccheck(struct magic_set *, struct magic *, file_regex_t **);
58898496eeSXin LI file_private int mprint(struct magic_set *, struct magic *);
59*ae316d1dSXin LI file_private int moffset(struct magic_set *, struct magic *,
60*ae316d1dSXin LI     const struct buffer *, size_t, int32_t *);
61898496eeSXin LI file_private void mdebug(uint32_t, const char *, size_t);
62898496eeSXin LI file_private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
63b6cee71dSXin LI     const unsigned char *, uint32_t, size_t, struct magic *);
64898496eeSXin LI file_private int mconvert(struct magic_set *, struct magic *, int);
65898496eeSXin LI file_private int print_sep(struct magic_set *, int);
66898496eeSXin LI file_private int handle_annotation(struct magic_set *, struct magic *, int);
67898496eeSXin LI file_private int cvt_8(union VALUETYPE *, const struct magic *);
68898496eeSXin LI file_private int cvt_16(union VALUETYPE *, const struct magic *);
69898496eeSXin LI file_private int cvt_32(union VALUETYPE *, const struct magic *);
70898496eeSXin LI file_private int cvt_64(union VALUETYPE *, const struct magic *);
71b6cee71dSXin LI 
7248c779cdSXin LI #define OFFSET_OOB(n, o, i)	((n) < CAST(uint32_t, (o)) || (i) > ((n) - (o)))
7348c779cdSXin LI #define BE64(p) ( \
74*ae316d1dSXin LI     (CAST(uint64_t, (p)[0])<<56)| \
75*ae316d1dSXin LI     (CAST(uint64_t, (p)[1])<<48)| \
76*ae316d1dSXin LI     (CAST(uint64_t, (p)[2])<<40)| \
77*ae316d1dSXin LI     (CAST(uint64_t, (p)[3])<<32)| \
78*ae316d1dSXin LI     (CAST(uint64_t, (p)[4])<<24)| \
79*ae316d1dSXin LI     (CAST(uint64_t, (p)[5])<<16)| \
80*ae316d1dSXin LI     (CAST(uint64_t, (p)[6])<<8)| \
81*ae316d1dSXin LI     (CAST(uint64_t, (p)[7])))
8248c779cdSXin LI #define LE64(p) ( \
83*ae316d1dSXin LI     (CAST(uint64_t, (p)[7])<<56)| \
84*ae316d1dSXin LI     (CAST(uint64_t, (p)[6])<<48)| \
85*ae316d1dSXin LI     (CAST(uint64_t, (p)[5])<<40)| \
86*ae316d1dSXin LI     (CAST(uint64_t, (p)[4])<<32)| \
87*ae316d1dSXin LI     (CAST(uint64_t, (p)[3])<<24)| \
88*ae316d1dSXin LI     (CAST(uint64_t, (p)[2])<<16)| \
89*ae316d1dSXin LI     (CAST(uint64_t, (p)[1])<<8)| \
90*ae316d1dSXin LI     (CAST(uint64_t, (p)[0])))
9148c779cdSXin LI #define LE32(p) ( \
92*ae316d1dSXin LI     (CAST(uint32_t, (p)[3])<<24)| \
93*ae316d1dSXin LI     (CAST(uint32_t, (p)[2])<<16)| \
94*ae316d1dSXin LI     (CAST(uint32_t, (p)[1])<<8)| \
95*ae316d1dSXin LI     (CAST(uint32_t, (p)[0])))
9648c779cdSXin LI #define BE32(p) ( \
97*ae316d1dSXin LI     (CAST(uint32_t, (p)[0])<<24)| \
98*ae316d1dSXin LI     (CAST(uint32_t, (p)[1])<<16)| \
99*ae316d1dSXin LI     (CAST(uint32_t, (p)[2])<<8)| \
100*ae316d1dSXin LI     (CAST(uint32_t, (p)[3])))
10148c779cdSXin LI #define ME32(p) ( \
102*ae316d1dSXin LI     (CAST(uint32_t, (p)[1])<<24)| \
103*ae316d1dSXin LI     (CAST(uint32_t, (p)[0])<<16)| \
104*ae316d1dSXin LI     (CAST(uint32_t, (p)[3])<<8)| \
105*ae316d1dSXin LI     (CAST(uint32_t, (p)[2])))
10648c779cdSXin LI 
107*ae316d1dSXin LI #define BE16(p) ((CAST(uint16_t, (p)[0])<<8)|(CAST(uint16_t, (p)[1])))
108*ae316d1dSXin LI #define LE16(p) ((CAST(uint16_t, (p)[1])<<8)|(CAST(uint16_t, (p)[0])))
10948c779cdSXin LI #define SEXT(s,v,p) ((s) ? \
11048c779cdSXin LI 	CAST(intmax_t, CAST(int##v##_t, p)) : \
11148c779cdSXin LI 	CAST(intmax_t, CAST(uint##v##_t, p)))
1122c4f1647SXin LI 
113b6cee71dSXin LI /*
114b6cee71dSXin LI  * softmagic - lookup one file in parsed, in-memory copy of database
115b6cee71dSXin LI  * Passed the name and FILE * of one file to be typed.
116b6cee71dSXin LI  */
117b6cee71dSXin LI /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
118898496eeSXin LI file_protected int
file_softmagic(struct magic_set * ms,const struct buffer * b,uint16_t * indir_count,uint16_t * name_count,int mode,int text)11958a0f0d0SEitan Adler file_softmagic(struct magic_set *ms, const struct buffer *b,
1203e41d09dSXin LI     uint16_t *indir_count, uint16_t *name_count, int mode, int text)
121b6cee71dSXin LI {
122b6cee71dSXin LI 	struct mlist *ml;
123898496eeSXin LI 	int rv = 0, printed_something = 0, need_separator = 0, firstline = 1;
1243e41d09dSXin LI 	uint16_t nc, ic;
125c2931133SXin LI 
126c2931133SXin LI 	if (name_count == NULL) {
127c2931133SXin LI 		nc = 0;
128c2931133SXin LI 		name_count = &nc;
129c2931133SXin LI 	}
1303e41d09dSXin LI 	if (indir_count == NULL) {
1313e41d09dSXin LI 		ic = 0;
1323e41d09dSXin LI 		indir_count = &ic;
1333e41d09dSXin LI 	}
134c2931133SXin LI 
135a2dfb722SXin LI 	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) {
136a2dfb722SXin LI 		int ret = match(ms, ml->magic, ml->magic_rxcomp, ml->nmagic, b,
137a4d6d3b8SXin LI 		    0, mode, text, 0, indir_count, name_count,
138898496eeSXin LI 		    &printed_something, &need_separator, &firstline,
139898496eeSXin LI 		    NULL, NULL);
140a2dfb722SXin LI 		switch (ret) {
141a2dfb722SXin LI 		case -1:
142a2dfb722SXin LI 			return ret;
143a2dfb722SXin LI 		case 0:
144a2dfb722SXin LI 			continue;
145a2dfb722SXin LI 		default:
146a2dfb722SXin LI 			if ((ms->flags & MAGIC_CONTINUE) == 0)
147a2dfb722SXin LI 				return ret;
148a2dfb722SXin LI 			rv = ret;
149a2dfb722SXin LI 			break;
150a2dfb722SXin LI 		}
151a2dfb722SXin LI 	}
152b6cee71dSXin LI 
153a2dfb722SXin LI 	return rv;
154b6cee71dSXin LI }
155b6cee71dSXin LI 
156b6cee71dSXin LI #define FILE_FMTDEBUG
157b6cee71dSXin LI #ifdef FILE_FMTDEBUG
158b6cee71dSXin LI #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
159b6cee71dSXin LI 
160898496eeSXin LI file_private const char * __attribute__((__format_arg__(3)))
file_fmtcheck(struct magic_set * ms,const char * desc,const char * def,const char * file,size_t line)16158a0f0d0SEitan Adler file_fmtcheck(struct magic_set *ms, const char *desc, const char *def,
162b6cee71dSXin LI 	const char *file, size_t line)
163b6cee71dSXin LI {
16448c779cdSXin LI 	const char *ptr;
16548c779cdSXin LI 
16648c779cdSXin LI 	if (strchr(desc, '%') == NULL)
16748c779cdSXin LI 		return desc;
16848c779cdSXin LI 
16948c779cdSXin LI 	ptr = fmtcheck(desc, def);
170b6cee71dSXin LI 	if (ptr == def)
171b6cee71dSXin LI 		file_magerror(ms,
172c2931133SXin LI 		    "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
17358a0f0d0SEitan Adler 		    " with `%s'", file, line, desc, def);
174b6cee71dSXin LI 	return ptr;
175b6cee71dSXin LI }
176b6cee71dSXin LI #else
17758a0f0d0SEitan Adler #define F(a, b, c) fmtcheck((b), (c))
178b6cee71dSXin LI #endif
179b6cee71dSXin LI 
180b6cee71dSXin LI /*
181b6cee71dSXin LI  * Go through the whole list, stopping if you find a match.  Process all
182b6cee71dSXin LI  * the continuations of that match before returning.
183b6cee71dSXin LI  *
184b6cee71dSXin LI  * We support multi-level continuations:
185b6cee71dSXin LI  *
186b6cee71dSXin LI  *	At any time when processing a successful top-level match, there is a
187b6cee71dSXin LI  *	current continuation level; it represents the level of the last
188b6cee71dSXin LI  *	successfully matched continuation.
189b6cee71dSXin LI  *
190b6cee71dSXin LI  *	Continuations above that level are skipped as, if we see one, it
191b6cee71dSXin LI  *	means that the continuation that controls them - i.e, the
192b6cee71dSXin LI  *	lower-level continuation preceding them - failed to match.
193b6cee71dSXin LI  *
194b6cee71dSXin LI  *	Continuations below that level are processed as, if we see one,
195b6cee71dSXin LI  *	it means we've finished processing or skipping higher-level
196b6cee71dSXin LI  *	continuations under the control of a successful or unsuccessful
197b6cee71dSXin LI  *	lower-level continuation, and are now seeing the next lower-level
198b6cee71dSXin LI  *	continuation and should process it.  The current continuation
199b6cee71dSXin LI  *	level reverts to the level of the one we're seeing.
200b6cee71dSXin LI  *
201b6cee71dSXin LI  *	Continuations at the current level are processed as, if we see
202b6cee71dSXin LI  *	one, there's no lower-level continuation that may have failed.
203b6cee71dSXin LI  *
204b6cee71dSXin LI  *	If a continuation matches, we bump the current continuation level
205b6cee71dSXin LI  *	so that higher-level continuations are processed.
206b6cee71dSXin LI  */
207898496eeSXin LI file_private int
match(struct magic_set * ms,struct magic * magic,file_regex_t ** magic_rxcomp,size_t nmagic,const struct buffer * b,size_t offset,int mode,int text,int flip,uint16_t * indir_count,uint16_t * name_count,int * printed_something,int * need_separator,int * firstline,int * returnval,int * found_match)208a4d6d3b8SXin LI match(struct magic_set *ms, struct magic *magic, file_regex_t **magic_rxcomp,
209a2dfb722SXin LI     size_t nmagic, const struct buffer *b, size_t offset, int mode, int text,
2103e41d09dSXin LI     int flip, uint16_t *indir_count, uint16_t *name_count,
211898496eeSXin LI     int *printed_something, int *need_separator, int *firstline,
212898496eeSXin LI     int *returnval, int *found_match)
213b6cee71dSXin LI {
214b6cee71dSXin LI 	uint32_t magindex = 0;
215b6cee71dSXin LI 	unsigned int cont_level = 0;
21648c779cdSXin LI 	int found_matchv = 0; /* if a match is found it is set to 1*/
21748c779cdSXin LI 	int returnvalv = 0, e;
21858a0f0d0SEitan Adler 	struct buffer bb;
2195f0216bdSXin LI 	int print = (ms->flags & MAGIC_NODESC) == 0;
220b6cee71dSXin LI 
22148c779cdSXin LI 	/*
22248c779cdSXin LI 	 * returnval can be 0 if a match is found, but there was no
22348c779cdSXin LI 	 * annotation to be printed.
22448c779cdSXin LI 	 */
225b6cee71dSXin LI 	if (returnval == NULL)
226b6cee71dSXin LI 		returnval = &returnvalv;
22748c779cdSXin LI 	if (found_match == NULL)
22848c779cdSXin LI 		found_match = &found_matchv;
229b6cee71dSXin LI 
230b6cee71dSXin LI 	if (file_check_mem(ms, cont_level) == -1)
231b6cee71dSXin LI 		return -1;
232b6cee71dSXin LI 
233b6cee71dSXin LI 	for (magindex = 0; magindex < nmagic; magindex++) {
234b6cee71dSXin LI 		int flush = 0;
235b6cee71dSXin LI 		struct magic *m = &magic[magindex];
236a4d6d3b8SXin LI 		file_regex_t **m_rxcomp = &magic_rxcomp[magindex];
237b6cee71dSXin LI 
238b6cee71dSXin LI 		if (m->type != FILE_NAME)
239b6cee71dSXin LI 		if ((IS_STRING(m->type) &&
240b6cee71dSXin LI #define FLT (STRING_BINTEST | STRING_TEXTTEST)
241b6cee71dSXin LI 		     ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
242b6cee71dSXin LI 		      (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
243b6cee71dSXin LI 		    (m->flag & mode) != mode) {
24453021c7eSXin LI flush:
245b6cee71dSXin LI 			/* Skip sub-tests */
24653021c7eSXin LI 			while (magindex < nmagic - 1 &&
24753021c7eSXin LI 			    magic[magindex + 1].cont_level != 0)
24853021c7eSXin LI 				magindex++;
24940427ccaSGordon Tetlow 			cont_level = 0;
250b6cee71dSXin LI 			continue; /* Skip to next top-level test*/
251b6cee71dSXin LI 		}
252b6cee71dSXin LI 
25358a0f0d0SEitan Adler 		if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
25458a0f0d0SEitan Adler 			goto flush;
255b6cee71dSXin LI 		ms->line = m->lineno;
256b6cee71dSXin LI 
257b6cee71dSXin LI 		/* if main entry matches, print it... */
25848c779cdSXin LI 		switch (mget(ms, m, b, CAST(const unsigned char *, bb.fbuf),
25948c779cdSXin LI 		    bb.flen, offset, cont_level,
26058a0f0d0SEitan Adler 		    mode, text, flip, indir_count, name_count,
261898496eeSXin LI 		    printed_something, need_separator, firstline, returnval,
262898496eeSXin LI 		    found_match))
26348c779cdSXin LI 		{
264b6cee71dSXin LI 		case -1:
265b6cee71dSXin LI 			return -1;
266b6cee71dSXin LI 		case 0:
267b6cee71dSXin LI 			flush = m->reln != '!';
268b6cee71dSXin LI 			break;
269b6cee71dSXin LI 		default:
27048c779cdSXin LI 			if (m->type == FILE_INDIRECT) {
27148c779cdSXin LI 				*found_match = 1;
272b6cee71dSXin LI 				*returnval = 1;
27348c779cdSXin LI 			}
274b6cee71dSXin LI 
275a4d6d3b8SXin LI 			switch (magiccheck(ms, m, m_rxcomp)) {
276b6cee71dSXin LI 			case -1:
277b6cee71dSXin LI 				return -1;
278b6cee71dSXin LI 			case 0:
279b6cee71dSXin LI 				flush++;
280b6cee71dSXin LI 				break;
281b6cee71dSXin LI 			default:
282b6cee71dSXin LI 				flush = 0;
283b6cee71dSXin LI 				break;
284b6cee71dSXin LI 			}
285b6cee71dSXin LI 			break;
286b6cee71dSXin LI 		}
287b6cee71dSXin LI 		if (flush) {
288b6cee71dSXin LI 			/*
289b6cee71dSXin LI 			 * main entry didn't match,
290b6cee71dSXin LI 			 * flush its continuations
291b6cee71dSXin LI 			 */
29253021c7eSXin LI 			goto flush;
293b6cee71dSXin LI 		}
294b6cee71dSXin LI 
295898496eeSXin LI 		if ((e = handle_annotation(ms, m, *firstline)) != 0)
29648c779cdSXin LI 		{
29743a5ec4eSXin LI 			*found_match = 1;
298b6cee71dSXin LI 			*need_separator = 1;
299b6cee71dSXin LI 			*printed_something = 1;
300b6cee71dSXin LI 			*returnval = 1;
301898496eeSXin LI 			*firstline = 0;
302b6cee71dSXin LI 			return e;
303b6cee71dSXin LI 		}
3043e41d09dSXin LI 
305b6cee71dSXin LI 		/*
306b6cee71dSXin LI 		 * If we are going to print something, we'll need to print
307b6cee71dSXin LI 		 * a blank before we print something else.
308b6cee71dSXin LI 		 */
30943a5ec4eSXin LI 		if (*m->desc) {
31043a5ec4eSXin LI 			*found_match = 1;
31143a5ec4eSXin LI 			if (print) {
31243a5ec4eSXin LI 				*returnval = 1;
313b6cee71dSXin LI 				*need_separator = 1;
314b6cee71dSXin LI 				*printed_something = 1;
315898496eeSXin LI 				if (print_sep(ms, *firstline) == -1)
316b6cee71dSXin LI 					return -1;
31748c779cdSXin LI 				if (mprint(ms, m) == -1)
318b6cee71dSXin LI 					return -1;
31948c779cdSXin LI 			}
32043a5ec4eSXin LI 		}
321b6cee71dSXin LI 
322*ae316d1dSXin LI 		switch (moffset(ms, m, &bb, offset, &ms->c.li[cont_level].off)) {
32353021c7eSXin LI 		case -1:
32453021c7eSXin LI 		case 0:
32553021c7eSXin LI 			goto flush;
32653021c7eSXin LI 		default:
32753021c7eSXin LI 			break;
32853021c7eSXin LI 		}
329b6cee71dSXin LI 
330b6cee71dSXin LI 		/* and any continuations that match */
331b6cee71dSXin LI 		if (file_check_mem(ms, ++cont_level) == -1)
332b6cee71dSXin LI 			return -1;
333b6cee71dSXin LI 
334c2931133SXin LI 		while (magindex + 1 < nmagic &&
335c2931133SXin LI 		    magic[magindex + 1].cont_level != 0) {
336c2931133SXin LI 			m = &magic[++magindex];
337a4d6d3b8SXin LI 			m_rxcomp = &magic_rxcomp[magindex];
338b6cee71dSXin LI 			ms->line = m->lineno; /* for messages */
339b6cee71dSXin LI 
340b6cee71dSXin LI 			if (cont_level < m->cont_level)
341b6cee71dSXin LI 				continue;
342b6cee71dSXin LI 			if (cont_level > m->cont_level) {
343b6cee71dSXin LI 				/*
344b6cee71dSXin LI 				 * We're at the end of the level
345b6cee71dSXin LI 				 * "cont_level" continuations.
346b6cee71dSXin LI 				 */
347b6cee71dSXin LI 				cont_level = m->cont_level;
348b6cee71dSXin LI 			}
34958a0f0d0SEitan Adler 			if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
35058a0f0d0SEitan Adler 				goto flush;
351b6cee71dSXin LI 			if (m->flag & OFFADD) {
3522726a701SXin LI 				if (cont_level == 0) {
3532726a701SXin LI 					if ((ms->flags & MAGIC_DEBUG) != 0)
3542726a701SXin LI 						fprintf(stderr,
3552726a701SXin LI 						    "direct *zero*"
3562726a701SXin LI 						    " cont_level\n");
3572726a701SXin LI 					return 0;
3582726a701SXin LI 				}
359b6cee71dSXin LI 				ms->offset +=
360b6cee71dSXin LI 				    ms->c.li[cont_level - 1].off;
361b6cee71dSXin LI 			}
362b6cee71dSXin LI 
363b6cee71dSXin LI #ifdef ENABLE_CONDITIONALS
364b6cee71dSXin LI 			if (m->cond == COND_ELSE ||
365b6cee71dSXin LI 			    m->cond == COND_ELIF) {
366b6cee71dSXin LI 				if (ms->c.li[cont_level].last_match == 1)
367b6cee71dSXin LI 					continue;
368b6cee71dSXin LI 			}
369b6cee71dSXin LI #endif
37048c779cdSXin LI 			switch (mget(ms, m, b, CAST(const unsigned char *,
37148c779cdSXin LI 			    bb.fbuf), bb.flen, offset,
37258a0f0d0SEitan Adler 			    cont_level, mode, text, flip, indir_count,
37358a0f0d0SEitan Adler 			    name_count, printed_something, need_separator,
374898496eeSXin LI 			    firstline, returnval, found_match)) {
375b6cee71dSXin LI 			case -1:
376b6cee71dSXin LI 				return -1;
377b6cee71dSXin LI 			case 0:
378b6cee71dSXin LI 				if (m->reln != '!')
379b6cee71dSXin LI 					continue;
380b6cee71dSXin LI 				flush = 1;
381b6cee71dSXin LI 				break;
382b6cee71dSXin LI 			default:
38348c779cdSXin LI 				if (m->type == FILE_INDIRECT) {
38448c779cdSXin LI 					*found_match = 1;
385b6cee71dSXin LI 					*returnval = 1;
38648c779cdSXin LI 				}
387b6cee71dSXin LI 				flush = 0;
388b6cee71dSXin LI 				break;
389b6cee71dSXin LI 			}
390b6cee71dSXin LI 
391a4d6d3b8SXin LI 			switch (flush ? 1 : magiccheck(ms, m, m_rxcomp)) {
392b6cee71dSXin LI 			case -1:
393b6cee71dSXin LI 				return -1;
394b6cee71dSXin LI 			case 0:
395b6cee71dSXin LI #ifdef ENABLE_CONDITIONALS
396b6cee71dSXin LI 				ms->c.li[cont_level].last_match = 0;
397b6cee71dSXin LI #endif
398b6cee71dSXin LI 				break;
399b6cee71dSXin LI 			default:
400b6cee71dSXin LI #ifdef ENABLE_CONDITIONALS
401b6cee71dSXin LI 				ms->c.li[cont_level].last_match = 1;
402b6cee71dSXin LI #endif
403b6cee71dSXin LI 				if (m->type == FILE_CLEAR)
404b6cee71dSXin LI 					ms->c.li[cont_level].got_match = 0;
405b6cee71dSXin LI 				else if (ms->c.li[cont_level].got_match) {
406b6cee71dSXin LI 					if (m->type == FILE_DEFAULT)
407b6cee71dSXin LI 						break;
408b6cee71dSXin LI 				} else
409b6cee71dSXin LI 					ms->c.li[cont_level].got_match = 1;
4103e41d09dSXin LI 
411898496eeSXin LI 				if ((e = handle_annotation(ms, m, *firstline))
41258a0f0d0SEitan Adler 				    != 0) {
41343a5ec4eSXin LI 					*found_match = 1;
414b6cee71dSXin LI 					*need_separator = 1;
415b6cee71dSXin LI 					*printed_something = 1;
416b6cee71dSXin LI 					*returnval = 1;
417b6cee71dSXin LI 					return e;
418b6cee71dSXin LI 				}
41943a5ec4eSXin LI 				if (*m->desc) {
42043a5ec4eSXin LI 					*found_match = 1;
42143a5ec4eSXin LI 				}
42248c779cdSXin LI 				if (print && *m->desc) {
42343a5ec4eSXin LI 					*returnval = 1;
424b6cee71dSXin LI 					/*
425b6cee71dSXin LI 					 * This continuation matched.  Print
426b6cee71dSXin LI 					 * its message, with a blank before it
427b6cee71dSXin LI 					 * if the previous item printed and
428b6cee71dSXin LI 					 * this item isn't empty.
429b6cee71dSXin LI 					 */
43048c779cdSXin LI 					/*
43148c779cdSXin LI 					 * If we are going to print something,
43248c779cdSXin LI 					 * make sure that we have a separator
43348c779cdSXin LI 					 * first.
43448c779cdSXin LI 					 */
43548c779cdSXin LI 					if (!*printed_something) {
43648c779cdSXin LI 						*printed_something = 1;
437898496eeSXin LI 						if (print_sep(ms, *firstline)
43848c779cdSXin LI 						    == -1)
43948c779cdSXin LI 							return -1;
44048c779cdSXin LI 					}
441b6cee71dSXin LI 					/* space if previous printed */
442b6cee71dSXin LI 					if (*need_separator
44348c779cdSXin LI 					    && (m->flag & NOSPACE) == 0) {
44448c779cdSXin LI 						if (file_printf(ms, " ") == -1)
445b6cee71dSXin LI 							return -1;
446b6cee71dSXin LI 					}
44748c779cdSXin LI 					if (mprint(ms, m) == -1)
448b6cee71dSXin LI 						return -1;
44948c779cdSXin LI 					*need_separator = 1;
45048c779cdSXin LI 				}
451b6cee71dSXin LI 
452*ae316d1dSXin LI 				switch (moffset(ms, m, &bb, offset,
45353021c7eSXin LI 				    &ms->c.li[cont_level].off)) {
45453021c7eSXin LI 				case -1:
45553021c7eSXin LI 				case 0:
45640427ccaSGordon Tetlow 					cont_level--;
45753021c7eSXin LI 					break;
45853021c7eSXin LI 				default:
45953021c7eSXin LI 					break;
46053021c7eSXin LI 				}
461b6cee71dSXin LI 
462b6cee71dSXin LI 				/*
463b6cee71dSXin LI 				 * If we see any continuations
464b6cee71dSXin LI 				 * at a higher level,
465b6cee71dSXin LI 				 * process them.
466b6cee71dSXin LI 				 */
467b6cee71dSXin LI 				if (file_check_mem(ms, ++cont_level) == -1)
468b6cee71dSXin LI 					return -1;
469b6cee71dSXin LI 				break;
470b6cee71dSXin LI 			}
471b6cee71dSXin LI 		}
472b6cee71dSXin LI 		if (*printed_something) {
473898496eeSXin LI 			*firstline = 0;
474b6cee71dSXin LI 		}
47548c779cdSXin LI 		if (*found_match) {
47648c779cdSXin LI 			if ((ms->flags & MAGIC_CONTINUE) == 0)
47743a5ec4eSXin LI 				return *returnval;
47848c779cdSXin LI 			// So that we print a separator
47948c779cdSXin LI 			*printed_something = 0;
480898496eeSXin LI 			*firstline = 0;
481b6cee71dSXin LI 		}
4825f0216bdSXin LI 		cont_level = 0;
483b6cee71dSXin LI 	}
48443a5ec4eSXin LI 	return *returnval;
485b6cee71dSXin LI }
486b6cee71dSXin LI 
487898496eeSXin LI file_private int
check_fmt(struct magic_set * ms,const char * fmt)48858a0f0d0SEitan Adler check_fmt(struct magic_set *ms, const char *fmt)
489b6cee71dSXin LI {
490b6cee71dSXin LI 	file_regex_t rx;
491b6cee71dSXin LI 	int rc, rv = -1;
492a4d6d3b8SXin LI         const char* pat = "%[-0-9\\.]*s";
493b6cee71dSXin LI 
49458a0f0d0SEitan Adler 	if (strchr(fmt, '%') == NULL)
495b6cee71dSXin LI 		return 0;
496b6cee71dSXin LI 
497a4d6d3b8SXin LI 	rc = file_regcomp(ms, &rx, pat, REG_EXTENDED|REG_NOSUB);
498a4d6d3b8SXin LI 	if (rc == 0) {
499a4d6d3b8SXin LI 		rc = file_regexec(ms, &rx, fmt, 0, 0, 0);
500b6cee71dSXin LI 		rv = !rc;
501b6cee71dSXin LI 	}
502b6cee71dSXin LI 	file_regfree(&rx);
503b6cee71dSXin LI 	return rv;
504b6cee71dSXin LI }
505b6cee71dSXin LI 
50643a5ec4eSXin LI #if !defined(HAVE_STRNDUP) || defined(__aiws__) || defined(_AIX)
50743a5ec4eSXin LI # if defined(__aiws__) || defined(_AIX)
5082dc4dbb9SEitan Adler #  define strndup aix_strndup	/* aix is broken */
5092dc4dbb9SEitan Adler # endif
510b6cee71dSXin LI char *strndup(const char *, size_t);
511b6cee71dSXin LI 
512b6cee71dSXin LI char *
strndup(const char * str,size_t n)513b6cee71dSXin LI strndup(const char *str, size_t n)
514b6cee71dSXin LI {
515b6cee71dSXin LI 	size_t len;
516b6cee71dSXin LI 	char *copy;
517b6cee71dSXin LI 
518b6cee71dSXin LI 	for (len = 0; len < n && str[len]; len++)
519b6cee71dSXin LI 		continue;
520a4d6d3b8SXin LI 	if ((copy = CAST(char *, malloc(len + 1))) == NULL)
521b6cee71dSXin LI 		return NULL;
522b6cee71dSXin LI 	(void)memcpy(copy, str, len);
523b6cee71dSXin LI 	copy[len] = '\0';
524b6cee71dSXin LI 	return copy;
525b6cee71dSXin LI }
526b6cee71dSXin LI #endif /* HAVE_STRNDUP */
527b6cee71dSXin LI 
52858a0f0d0SEitan Adler static int
varexpand(struct magic_set * ms,char * buf,size_t len,const char * str)5292dc4dbb9SEitan Adler varexpand(struct magic_set *ms, char *buf, size_t len, const char *str)
53058a0f0d0SEitan Adler {
53158a0f0d0SEitan Adler 	const char *ptr, *sptr, *e, *t, *ee, *et;
53258a0f0d0SEitan Adler 	size_t l;
53358a0f0d0SEitan Adler 
53458a0f0d0SEitan Adler 	for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) {
53548c779cdSXin LI 		l = CAST(size_t, ptr - sptr);
53658a0f0d0SEitan Adler 		if (l >= len)
53758a0f0d0SEitan Adler 			return -1;
53858a0f0d0SEitan Adler 		memcpy(buf, sptr, l);
53958a0f0d0SEitan Adler 		buf += l;
54058a0f0d0SEitan Adler 		len -= l;
54158a0f0d0SEitan Adler 		ptr += 2;
54258a0f0d0SEitan Adler 		if (!*ptr || ptr[1] != '?')
54358a0f0d0SEitan Adler 			return -1;
54458a0f0d0SEitan Adler 		for (et = t = ptr + 2; *et && *et != ':'; et++)
54558a0f0d0SEitan Adler 			continue;
54658a0f0d0SEitan Adler 		if (*et != ':')
54758a0f0d0SEitan Adler 			return -1;
54858a0f0d0SEitan Adler 		for (ee = e = et + 1; *ee && *ee != '}'; ee++)
54958a0f0d0SEitan Adler 			continue;
55058a0f0d0SEitan Adler 		if (*ee != '}')
55158a0f0d0SEitan Adler 			return -1;
55258a0f0d0SEitan Adler 		switch (*ptr) {
55358a0f0d0SEitan Adler 		case 'x':
5542dc4dbb9SEitan Adler 			if (ms->mode & 0111) {
55558a0f0d0SEitan Adler 				ptr = t;
55658a0f0d0SEitan Adler 				l = et - t;
55758a0f0d0SEitan Adler 			} else {
55858a0f0d0SEitan Adler 				ptr = e;
55958a0f0d0SEitan Adler 				l = ee - e;
56058a0f0d0SEitan Adler 			}
56158a0f0d0SEitan Adler 			break;
56258a0f0d0SEitan Adler 		default:
56358a0f0d0SEitan Adler 			return -1;
56458a0f0d0SEitan Adler 		}
56558a0f0d0SEitan Adler 		if (l >= len)
56658a0f0d0SEitan Adler 			return -1;
56758a0f0d0SEitan Adler 		memcpy(buf, ptr, l);
56858a0f0d0SEitan Adler 		buf += l;
56958a0f0d0SEitan Adler 		len -= l;
57058a0f0d0SEitan Adler 		sptr = ee + 1;
57158a0f0d0SEitan Adler 	}
57258a0f0d0SEitan Adler 
57358a0f0d0SEitan Adler 	l = strlen(sptr);
57458a0f0d0SEitan Adler 	if (l >= len)
57558a0f0d0SEitan Adler 		return -1;
57658a0f0d0SEitan Adler 
57758a0f0d0SEitan Adler 	memcpy(buf, sptr, l);
57858a0f0d0SEitan Adler 	buf[l] = '\0';
57958a0f0d0SEitan Adler 	return 0;
58058a0f0d0SEitan Adler }
58158a0f0d0SEitan Adler 
58258a0f0d0SEitan Adler 
583898496eeSXin LI file_private int
mprint(struct magic_set * ms,struct magic * m)5842dc4dbb9SEitan Adler mprint(struct magic_set *ms, struct magic *m)
585b6cee71dSXin LI {
586b6cee71dSXin LI 	uint64_t v;
587b6cee71dSXin LI 	float vf;
588b6cee71dSXin LI 	double vd;
58958a0f0d0SEitan Adler  	char buf[128], tbuf[26], sbuf[512], ebuf[512];
59058a0f0d0SEitan Adler 	const char *desc;
591b6cee71dSXin LI 	union VALUETYPE *p = &ms->ms_value;
592b6cee71dSXin LI 
5932dc4dbb9SEitan Adler 	if (varexpand(ms, ebuf, sizeof(ebuf), m->desc) == -1)
59458a0f0d0SEitan Adler 		desc = m->desc;
59558a0f0d0SEitan Adler 	else
59658a0f0d0SEitan Adler 		desc = ebuf;
59758a0f0d0SEitan Adler 
59843a5ec4eSXin LI #define	PRINTER(value, format, stype, utype)	\
59943a5ec4eSXin LI 	v = file_signextend(ms, m, CAST(uint64_t, value)); \
60043a5ec4eSXin LI 	switch (check_fmt(ms, desc)) { \
60143a5ec4eSXin LI 	case -1: \
60243a5ec4eSXin LI 		return -1; \
60343a5ec4eSXin LI 	case 1: \
60443a5ec4eSXin LI 		if (m->flag & UNSIGNED) { \
60543a5ec4eSXin LI 			(void)snprintf(buf, sizeof(buf), "%" format "u", \
60643a5ec4eSXin LI 			    CAST(utype, v)); \
60743a5ec4eSXin LI 		} else { \
60843a5ec4eSXin LI 			(void)snprintf(buf, sizeof(buf), "%" format "d", \
60943a5ec4eSXin LI 			    CAST(stype, v)); \
61043a5ec4eSXin LI 		} \
61143a5ec4eSXin LI 		if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) \
61243a5ec4eSXin LI 			return -1; \
61343a5ec4eSXin LI 		break; \
61443a5ec4eSXin LI 	default: \
61543a5ec4eSXin LI 		if (m->flag & UNSIGNED) { \
61643a5ec4eSXin LI 		       if (file_printf(ms, F(ms, desc, "%" format "u"), \
61743a5ec4eSXin LI 			   CAST(utype, v)) == -1) \
61843a5ec4eSXin LI 			   return -1; \
61943a5ec4eSXin LI 		} else { \
62043a5ec4eSXin LI 		       if (file_printf(ms, F(ms, desc, "%" format "d"), \
62143a5ec4eSXin LI 			   CAST(stype, v)) == -1) \
62243a5ec4eSXin LI 			   return -1; \
62343a5ec4eSXin LI 		} \
62443a5ec4eSXin LI 		break; \
62543a5ec4eSXin LI 	} \
62643a5ec4eSXin LI 	break
62743a5ec4eSXin LI 
628b6cee71dSXin LI   	switch (m->type) {
629b6cee71dSXin LI   	case FILE_BYTE:
63043a5ec4eSXin LI 		PRINTER(p->b, "", int8_t, uint8_t);
631b6cee71dSXin LI 
632b6cee71dSXin LI   	case FILE_SHORT:
633b6cee71dSXin LI   	case FILE_BESHORT:
634b6cee71dSXin LI   	case FILE_LESHORT:
63543a5ec4eSXin LI 		PRINTER(p->h, "", int16_t, uint16_t);
636b6cee71dSXin LI 
637b6cee71dSXin LI   	case FILE_LONG:
638b6cee71dSXin LI   	case FILE_BELONG:
639b6cee71dSXin LI   	case FILE_LELONG:
640b6cee71dSXin LI   	case FILE_MELONG:
64143a5ec4eSXin LI 		PRINTER(p->l, "", int32_t, uint32_t);
642b6cee71dSXin LI 
643b6cee71dSXin LI   	case FILE_QUAD:
644b6cee71dSXin LI   	case FILE_BEQUAD:
645b6cee71dSXin LI   	case FILE_LEQUAD:
6462726a701SXin LI 	case FILE_OFFSET:
64743a5ec4eSXin LI 		PRINTER(p->q, INT64_T_FORMAT, long long, unsigned long long);
648b6cee71dSXin LI 
649b6cee71dSXin LI   	case FILE_STRING:
650b6cee71dSXin LI   	case FILE_PSTRING:
651b6cee71dSXin LI   	case FILE_BESTRING16:
652b6cee71dSXin LI   	case FILE_LESTRING16:
653b6cee71dSXin LI 		if (m->reln == '=' || m->reln == '!') {
65458a0f0d0SEitan Adler 			if (file_printf(ms, F(ms, desc, "%s"),
65543a5ec4eSXin LI 			    file_printable(ms, sbuf, sizeof(sbuf), m->value.s,
65648c779cdSXin LI 			    sizeof(m->value.s))) == -1)
657b6cee71dSXin LI 				return -1;
658b6cee71dSXin LI 		}
659b6cee71dSXin LI 		else {
660b6cee71dSXin LI 			char *str = p->s;
661b6cee71dSXin LI 
662b6cee71dSXin LI 			/* compute t before we mangle the string? */
663b6cee71dSXin LI 
664b6cee71dSXin LI 			if (*m->value.s == '\0')
6655f0216bdSXin LI 				str[strcspn(str, "\r\n")] = '\0';
666b6cee71dSXin LI 
66743a5ec4eSXin LI 			if (m->str_flags & STRING_TRIM)
66843a5ec4eSXin LI 				str = file_strtrim(str);
669b6cee71dSXin LI 
67058a0f0d0SEitan Adler 			if (file_printf(ms, F(ms, desc, "%s"),
67143a5ec4eSXin LI 			    file_printable(ms, sbuf, sizeof(sbuf), str,
67248c779cdSXin LI 				sizeof(p->s) - (str - p->s))) == -1)
673b6cee71dSXin LI 				return -1;
674b6cee71dSXin LI 
6752726a701SXin LI 			if (m->type == FILE_PSTRING) {
6762726a701SXin LI 				size_t l = file_pstring_length_size(ms, m);
6772726a701SXin LI 				if (l == FILE_BADSIZE)
6782726a701SXin LI 					return -1;
6792726a701SXin LI 			}
680b6cee71dSXin LI 		}
681b6cee71dSXin LI 		break;
682b6cee71dSXin LI 
683b6cee71dSXin LI 	case FILE_DATE:
684b6cee71dSXin LI 	case FILE_BEDATE:
685b6cee71dSXin LI 	case FILE_LEDATE:
686b6cee71dSXin LI 	case FILE_MEDATE:
68758a0f0d0SEitan Adler 		if (file_printf(ms, F(ms, desc, "%s"),
688a4d6d3b8SXin LI 		    file_fmtdatetime(tbuf, sizeof(tbuf), p->l, 0)) == -1)
689b6cee71dSXin LI 			return -1;
690b6cee71dSXin LI 		break;
691b6cee71dSXin LI 
692b6cee71dSXin LI 	case FILE_LDATE:
693b6cee71dSXin LI 	case FILE_BELDATE:
694b6cee71dSXin LI 	case FILE_LELDATE:
695b6cee71dSXin LI 	case FILE_MELDATE:
69658a0f0d0SEitan Adler 		if (file_printf(ms, F(ms, desc, "%s"),
697a4d6d3b8SXin LI 		    file_fmtdatetime(tbuf, sizeof(tbuf), p->l, FILE_T_LOCAL))
698a4d6d3b8SXin LI 			== -1)
699b6cee71dSXin LI 			return -1;
700b6cee71dSXin LI 		break;
701b6cee71dSXin LI 
702b6cee71dSXin LI 	case FILE_QDATE:
703b6cee71dSXin LI 	case FILE_BEQDATE:
704b6cee71dSXin LI 	case FILE_LEQDATE:
70558a0f0d0SEitan Adler 		if (file_printf(ms, F(ms, desc, "%s"),
706a4d6d3b8SXin LI 		    file_fmtdatetime(tbuf, sizeof(tbuf), p->q, 0)) == -1)
707b6cee71dSXin LI 			return -1;
708b6cee71dSXin LI 		break;
709b6cee71dSXin LI 
710b6cee71dSXin LI 	case FILE_QLDATE:
711b6cee71dSXin LI 	case FILE_BEQLDATE:
712b6cee71dSXin LI 	case FILE_LEQLDATE:
71358a0f0d0SEitan Adler 		if (file_printf(ms, F(ms, desc, "%s"),
714a4d6d3b8SXin LI 		    file_fmtdatetime(tbuf, sizeof(tbuf), p->q, FILE_T_LOCAL)) == -1)
715b6cee71dSXin LI 			return -1;
716b6cee71dSXin LI 		break;
717b6cee71dSXin LI 
718b6cee71dSXin LI 	case FILE_QWDATE:
719b6cee71dSXin LI 	case FILE_BEQWDATE:
720b6cee71dSXin LI 	case FILE_LEQWDATE:
72158a0f0d0SEitan Adler 		if (file_printf(ms, F(ms, desc, "%s"),
722a4d6d3b8SXin LI 		    file_fmtdatetime(tbuf, sizeof(tbuf), p->q, FILE_T_WINDOWS))
7232726a701SXin LI 		    == -1)
724b6cee71dSXin LI 			return -1;
725b6cee71dSXin LI 		break;
726b6cee71dSXin LI 
727b6cee71dSXin LI 	case FILE_FLOAT:
728b6cee71dSXin LI 	case FILE_BEFLOAT:
729b6cee71dSXin LI 	case FILE_LEFLOAT:
730b6cee71dSXin LI 		vf = p->f;
73158a0f0d0SEitan Adler 		switch (check_fmt(ms, desc)) {
732b6cee71dSXin LI 		case -1:
733b6cee71dSXin LI 			return -1;
734b6cee71dSXin LI 		case 1:
735b6cee71dSXin LI 			(void)snprintf(buf, sizeof(buf), "%g", vf);
73658a0f0d0SEitan Adler 			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
737b6cee71dSXin LI 				return -1;
738b6cee71dSXin LI 			break;
739b6cee71dSXin LI 		default:
74058a0f0d0SEitan Adler 			if (file_printf(ms, F(ms, desc, "%g"), vf) == -1)
741b6cee71dSXin LI 				return -1;
742b6cee71dSXin LI 			break;
743b6cee71dSXin LI 		}
744b6cee71dSXin LI   		break;
745b6cee71dSXin LI 
746b6cee71dSXin LI 	case FILE_DOUBLE:
747b6cee71dSXin LI 	case FILE_BEDOUBLE:
748b6cee71dSXin LI 	case FILE_LEDOUBLE:
749b6cee71dSXin LI 		vd = p->d;
75058a0f0d0SEitan Adler 		switch (check_fmt(ms, desc)) {
751b6cee71dSXin LI 		case -1:
752b6cee71dSXin LI 			return -1;
753b6cee71dSXin LI 		case 1:
754b6cee71dSXin LI 			(void)snprintf(buf, sizeof(buf), "%g", vd);
75558a0f0d0SEitan Adler 			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
756b6cee71dSXin LI 				return -1;
757b6cee71dSXin LI 			break;
758b6cee71dSXin LI 		default:
75958a0f0d0SEitan Adler 			if (file_printf(ms, F(ms, desc, "%g"), vd) == -1)
760b6cee71dSXin LI 				return -1;
761b6cee71dSXin LI 			break;
762b6cee71dSXin LI 		}
763b6cee71dSXin LI   		break;
764b6cee71dSXin LI 
7655f0216bdSXin LI 	case FILE_SEARCH:
766b6cee71dSXin LI 	case FILE_REGEX: {
76743a5ec4eSXin LI 		char *cp, *scp;
768b6cee71dSXin LI 		int rval;
769b6cee71dSXin LI 
77048c779cdSXin LI 		cp = strndup(RCAST(const char *, ms->search.s),
77148c779cdSXin LI 		    ms->search.rm_len);
772b6cee71dSXin LI 		if (cp == NULL) {
773b6cee71dSXin LI 			file_oomem(ms, ms->search.rm_len);
774b6cee71dSXin LI 			return -1;
775b6cee71dSXin LI 		}
77643a5ec4eSXin LI 		scp = (m->str_flags & STRING_TRIM) ? file_strtrim(cp) : cp;
77743a5ec4eSXin LI 
77843a5ec4eSXin LI 		rval = file_printf(ms, F(ms, desc, "%s"), file_printable(ms,
77943a5ec4eSXin LI 		    sbuf, sizeof(sbuf), scp, ms->search.rm_len));
780b6cee71dSXin LI 		free(cp);
781b6cee71dSXin LI 
782b6cee71dSXin LI 		if (rval == -1)
783b6cee71dSXin LI 			return -1;
784b6cee71dSXin LI 		break;
785b6cee71dSXin LI 	}
786b6cee71dSXin LI 
787b6cee71dSXin LI 	case FILE_DEFAULT:
788b6cee71dSXin LI 	case FILE_CLEAR:
789b6cee71dSXin LI 	  	if (file_printf(ms, "%s", m->desc) == -1)
790b6cee71dSXin LI 			return -1;
791b6cee71dSXin LI 		break;
792b6cee71dSXin LI 
793b6cee71dSXin LI 	case FILE_INDIRECT:
794b6cee71dSXin LI 	case FILE_USE:
795b6cee71dSXin LI 	case FILE_NAME:
796b6cee71dSXin LI 		break;
7973e41d09dSXin LI 	case FILE_DER:
79858a0f0d0SEitan Adler 		if (file_printf(ms, F(ms, desc, "%s"),
79943a5ec4eSXin LI 		    file_printable(ms, sbuf, sizeof(sbuf), ms->ms_value.s,
80048c779cdSXin LI 			sizeof(ms->ms_value.s))) == -1)
8013e41d09dSXin LI 			return -1;
8023e41d09dSXin LI 		break;
8032726a701SXin LI 	case FILE_GUID:
8042726a701SXin LI 		(void) file_print_guid(buf, sizeof(buf), ms->ms_value.guid);
8052726a701SXin LI 		if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
8062726a701SXin LI 			return -1;
807a4d6d3b8SXin LI 		break;
808a4d6d3b8SXin LI 	case FILE_MSDOSDATE:
809a4d6d3b8SXin LI 	case FILE_BEMSDOSDATE:
810a4d6d3b8SXin LI 	case FILE_LEMSDOSDATE:
811a4d6d3b8SXin LI 		if (file_printf(ms, F(ms, desc, "%s"),
812a4d6d3b8SXin LI 		    file_fmtdate(tbuf, sizeof(tbuf), p->h)) == -1)
813a4d6d3b8SXin LI 			return -1;
814a4d6d3b8SXin LI 		break;
815a4d6d3b8SXin LI 	case FILE_MSDOSTIME:
816a4d6d3b8SXin LI 	case FILE_BEMSDOSTIME:
817a4d6d3b8SXin LI 	case FILE_LEMSDOSTIME:
818a4d6d3b8SXin LI 		if (file_printf(ms, F(ms, desc, "%s"),
819a4d6d3b8SXin LI 		    file_fmttime(tbuf, sizeof(tbuf), p->h)) == -1)
820a4d6d3b8SXin LI 			return -1;
8212726a701SXin LI 		break;
822a2dfb722SXin LI 	case FILE_OCTAL:
823a2dfb722SXin LI 		file_fmtnum(buf, sizeof(buf), m->value.s, 8);
824a2dfb722SXin LI 		if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
825a2dfb722SXin LI 			return -1;
826a2dfb722SXin LI 		break;
827b6cee71dSXin LI 	default:
828b6cee71dSXin LI 		file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
829b6cee71dSXin LI 		return -1;
830b6cee71dSXin LI 	}
831a4d6d3b8SXin LI 	return 0;
832b6cee71dSXin LI }
833b6cee71dSXin LI 
834898496eeSXin LI file_private int
moffset(struct magic_set * ms,struct magic * m,const struct buffer * b,size_t offset,int32_t * op)83558a0f0d0SEitan Adler moffset(struct magic_set *ms, struct magic *m, const struct buffer *b,
836*ae316d1dSXin LI     size_t offset, int32_t *op)
837b6cee71dSXin LI {
83858a0f0d0SEitan Adler 	size_t nbytes = b->flen;
8393e41d09dSXin LI 	int32_t o;
8403e41d09dSXin LI 
841b6cee71dSXin LI   	switch (m->type) {
842b6cee71dSXin LI   	case FILE_BYTE:
8433e41d09dSXin LI 		o = CAST(int32_t, (ms->offset + sizeof(char)));
8443e41d09dSXin LI 		break;
845b6cee71dSXin LI 
846b6cee71dSXin LI   	case FILE_SHORT:
847b6cee71dSXin LI   	case FILE_BESHORT:
848b6cee71dSXin LI   	case FILE_LESHORT:
849a4d6d3b8SXin LI 	case FILE_MSDOSDATE:
850a4d6d3b8SXin LI 	case FILE_LEMSDOSDATE:
851a4d6d3b8SXin LI 	case FILE_BEMSDOSDATE:
852a4d6d3b8SXin LI 	case FILE_MSDOSTIME:
853a4d6d3b8SXin LI 	case FILE_LEMSDOSTIME:
854a4d6d3b8SXin LI 	case FILE_BEMSDOSTIME:
8553e41d09dSXin LI 		o = CAST(int32_t, (ms->offset + sizeof(short)));
8563e41d09dSXin LI 		break;
857b6cee71dSXin LI 
858b6cee71dSXin LI   	case FILE_LONG:
859b6cee71dSXin LI   	case FILE_BELONG:
860b6cee71dSXin LI   	case FILE_LELONG:
861b6cee71dSXin LI   	case FILE_MELONG:
8623e41d09dSXin LI 		o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
8633e41d09dSXin LI 		break;
864b6cee71dSXin LI 
865b6cee71dSXin LI   	case FILE_QUAD:
866b6cee71dSXin LI   	case FILE_BEQUAD:
867b6cee71dSXin LI   	case FILE_LEQUAD:
8683e41d09dSXin LI 		o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
8693e41d09dSXin LI 		break;
870b6cee71dSXin LI 
871b6cee71dSXin LI   	case FILE_STRING:
872b6cee71dSXin LI   	case FILE_PSTRING:
873b6cee71dSXin LI   	case FILE_BESTRING16:
874b6cee71dSXin LI   	case FILE_LESTRING16:
875a2dfb722SXin LI 	case FILE_OCTAL:
8763e41d09dSXin LI 		if (m->reln == '=' || m->reln == '!') {
8773e41d09dSXin LI 			o = ms->offset + m->vallen;
8783e41d09dSXin LI 		} else {
879b6cee71dSXin LI 			union VALUETYPE *p = &ms->ms_value;
880b6cee71dSXin LI 
881b6cee71dSXin LI 			if (*m->value.s == '\0')
8825f0216bdSXin LI 				p->s[strcspn(p->s, "\r\n")] = '\0';
8833e41d09dSXin LI 			o = CAST(uint32_t, (ms->offset + strlen(p->s)));
8842726a701SXin LI 			if (m->type == FILE_PSTRING) {
8852726a701SXin LI 				size_t l = file_pstring_length_size(ms, m);
8862726a701SXin LI 				if (l == FILE_BADSIZE)
8872726a701SXin LI 					return -1;
8882726a701SXin LI 				o += CAST(uint32_t, l);
8892726a701SXin LI 			}
890b6cee71dSXin LI 		}
8913e41d09dSXin LI 		break;
892b6cee71dSXin LI 
893b6cee71dSXin LI 	case FILE_DATE:
894b6cee71dSXin LI 	case FILE_BEDATE:
895b6cee71dSXin LI 	case FILE_LEDATE:
896b6cee71dSXin LI 	case FILE_MEDATE:
8973e41d09dSXin LI 		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
8983e41d09dSXin LI 		break;
899b6cee71dSXin LI 
900b6cee71dSXin LI 	case FILE_LDATE:
901b6cee71dSXin LI 	case FILE_BELDATE:
902b6cee71dSXin LI 	case FILE_LELDATE:
903b6cee71dSXin LI 	case FILE_MELDATE:
9043e41d09dSXin LI 		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
9053e41d09dSXin LI 		break;
906b6cee71dSXin LI 
907b6cee71dSXin LI 	case FILE_QDATE:
908b6cee71dSXin LI 	case FILE_BEQDATE:
909b6cee71dSXin LI 	case FILE_LEQDATE:
9103e41d09dSXin LI 		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
9113e41d09dSXin LI 		break;
912b6cee71dSXin LI 
913b6cee71dSXin LI 	case FILE_QLDATE:
914b6cee71dSXin LI 	case FILE_BEQLDATE:
915b6cee71dSXin LI 	case FILE_LEQLDATE:
9163e41d09dSXin LI 		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
9173e41d09dSXin LI 		break;
918b6cee71dSXin LI 
919b6cee71dSXin LI   	case FILE_FLOAT:
920b6cee71dSXin LI   	case FILE_BEFLOAT:
921b6cee71dSXin LI   	case FILE_LEFLOAT:
9223e41d09dSXin LI 		o = CAST(int32_t, (ms->offset + sizeof(float)));
9233e41d09dSXin LI 		break;
924b6cee71dSXin LI 
925b6cee71dSXin LI   	case FILE_DOUBLE:
926b6cee71dSXin LI   	case FILE_BEDOUBLE:
927b6cee71dSXin LI   	case FILE_LEDOUBLE:
9283e41d09dSXin LI 		o = CAST(int32_t, (ms->offset + sizeof(double)));
9293e41d09dSXin LI 		break;
930b6cee71dSXin LI 
931b6cee71dSXin LI 	case FILE_REGEX:
932b6cee71dSXin LI 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
933*ae316d1dSXin LI 			o = CAST(int32_t, ms->search.offset - offset);
934b6cee71dSXin LI 		else
9353e41d09dSXin LI 			o = CAST(int32_t,
936*ae316d1dSXin LI 			    (ms->search.offset + ms->search.rm_len - offset));
9373e41d09dSXin LI 		break;
938b6cee71dSXin LI 
939b6cee71dSXin LI 	case FILE_SEARCH:
940b6cee71dSXin LI 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
941*ae316d1dSXin LI 			o = CAST(int32_t, ms->search.offset - offset);
942b6cee71dSXin LI 		else
943*ae316d1dSXin LI 			o = CAST(int32_t, (ms->search.offset + m->vallen - offset));
9443e41d09dSXin LI 		break;
945b6cee71dSXin LI 
946b6cee71dSXin LI 	case FILE_CLEAR:
947b6cee71dSXin LI 	case FILE_DEFAULT:
948b6cee71dSXin LI 	case FILE_INDIRECT:
9492726a701SXin LI 	case FILE_OFFSET:
95043a5ec4eSXin LI 	case FILE_USE:
9513e41d09dSXin LI 		o = ms->offset;
9523e41d09dSXin LI 		break;
9533e41d09dSXin LI 
9543e41d09dSXin LI 	case FILE_DER:
9553e41d09dSXin LI 		o = der_offs(ms, m, nbytes);
95648c779cdSXin LI 		if (o == -1 || CAST(size_t, o) > nbytes) {
95753021c7eSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0) {
95853021c7eSXin LI 				(void)fprintf(stderr,
95948c779cdSXin LI 				    "Bad DER offset %d nbytes=%"
96048c779cdSXin LI 				    SIZE_T_FORMAT "u", o, nbytes);
96153021c7eSXin LI 			}
962282e23f0SXin LI 			*op = 0;
96353021c7eSXin LI 			return 0;
9643e41d09dSXin LI 		}
9653e41d09dSXin LI 		break;
9662726a701SXin LI 
9672726a701SXin LI 	case FILE_GUID:
9682726a701SXin LI 		o = CAST(int32_t, (ms->offset + 2 * sizeof(uint64_t)));
9692726a701SXin LI 		break;
970b6cee71dSXin LI 
971b6cee71dSXin LI 	default:
9723e41d09dSXin LI 		o = 0;
9733e41d09dSXin LI 		break;
9743e41d09dSXin LI 	}
9753e41d09dSXin LI 
97648c779cdSXin LI 	if (CAST(size_t, o) > nbytes) {
97753021c7eSXin LI #if 0
97848c779cdSXin LI 		file_error(ms, 0, "Offset out of range %" SIZE_T_FORMAT
97948c779cdSXin LI 		    "u > %" SIZE_T_FORMAT "u", (size_t)o, nbytes);
98053021c7eSXin LI #endif
9813e41d09dSXin LI 		return -1;
9823e41d09dSXin LI 	}
9833e41d09dSXin LI 	*op = o;
98453021c7eSXin LI 	return 1;
985b6cee71dSXin LI }
9863e41d09dSXin LI 
987898496eeSXin LI file_private uint32_t
cvt_id3(struct magic_set * ms,uint32_t v)9883e41d09dSXin LI cvt_id3(struct magic_set *ms, uint32_t v)
9893e41d09dSXin LI {
9903e41d09dSXin LI 	v = ((((v >>  0) & 0x7f) <<  0) |
9913e41d09dSXin LI 	     (((v >>  8) & 0x7f) <<  7) |
9923e41d09dSXin LI 	     (((v >> 16) & 0x7f) << 14) |
9933e41d09dSXin LI 	     (((v >> 24) & 0x7f) << 21));
9943e41d09dSXin LI 	if ((ms->flags & MAGIC_DEBUG) != 0)
9953e41d09dSXin LI 		fprintf(stderr, "id3 offs=%u\n", v);
9963e41d09dSXin LI 	return v;
997b6cee71dSXin LI }
998b6cee71dSXin LI 
999898496eeSXin LI file_private int
cvt_flip(int type,int flip)1000b6cee71dSXin LI cvt_flip(int type, int flip)
1001b6cee71dSXin LI {
1002b6cee71dSXin LI 	if (flip == 0)
1003b6cee71dSXin LI 		return type;
1004b6cee71dSXin LI 	switch (type) {
1005b6cee71dSXin LI 	case FILE_BESHORT:
1006b6cee71dSXin LI 		return FILE_LESHORT;
1007b6cee71dSXin LI 	case FILE_BELONG:
1008b6cee71dSXin LI 		return FILE_LELONG;
1009b6cee71dSXin LI 	case FILE_BEDATE:
1010b6cee71dSXin LI 		return FILE_LEDATE;
1011b6cee71dSXin LI 	case FILE_BELDATE:
1012b6cee71dSXin LI 		return FILE_LELDATE;
1013b6cee71dSXin LI 	case FILE_BEQUAD:
1014b6cee71dSXin LI 		return FILE_LEQUAD;
1015b6cee71dSXin LI 	case FILE_BEQDATE:
1016b6cee71dSXin LI 		return FILE_LEQDATE;
1017b6cee71dSXin LI 	case FILE_BEQLDATE:
1018b6cee71dSXin LI 		return FILE_LEQLDATE;
1019b6cee71dSXin LI 	case FILE_BEQWDATE:
1020b6cee71dSXin LI 		return FILE_LEQWDATE;
1021b6cee71dSXin LI 	case FILE_LESHORT:
1022b6cee71dSXin LI 		return FILE_BESHORT;
1023b6cee71dSXin LI 	case FILE_LELONG:
1024b6cee71dSXin LI 		return FILE_BELONG;
1025b6cee71dSXin LI 	case FILE_LEDATE:
1026b6cee71dSXin LI 		return FILE_BEDATE;
1027b6cee71dSXin LI 	case FILE_LELDATE:
1028b6cee71dSXin LI 		return FILE_BELDATE;
1029b6cee71dSXin LI 	case FILE_LEQUAD:
1030b6cee71dSXin LI 		return FILE_BEQUAD;
1031b6cee71dSXin LI 	case FILE_LEQDATE:
1032b6cee71dSXin LI 		return FILE_BEQDATE;
1033b6cee71dSXin LI 	case FILE_LEQLDATE:
1034b6cee71dSXin LI 		return FILE_BEQLDATE;
1035b6cee71dSXin LI 	case FILE_LEQWDATE:
1036b6cee71dSXin LI 		return FILE_BEQWDATE;
1037b6cee71dSXin LI 	case FILE_BEFLOAT:
1038b6cee71dSXin LI 		return FILE_LEFLOAT;
1039b6cee71dSXin LI 	case FILE_LEFLOAT:
1040b6cee71dSXin LI 		return FILE_BEFLOAT;
1041b6cee71dSXin LI 	case FILE_BEDOUBLE:
1042b6cee71dSXin LI 		return FILE_LEDOUBLE;
1043b6cee71dSXin LI 	case FILE_LEDOUBLE:
1044b6cee71dSXin LI 		return FILE_BEDOUBLE;
1045b6cee71dSXin LI 	default:
1046b6cee71dSXin LI 		return type;
1047b6cee71dSXin LI 	}
1048b6cee71dSXin LI }
104948c779cdSXin LI #define DO_CVT(fld, type) \
1050b6cee71dSXin LI 	if (m->num_mask) \
1051b6cee71dSXin LI 		switch (m->mask_op & FILE_OPS_MASK) { \
1052b6cee71dSXin LI 		case FILE_OPAND: \
105348c779cdSXin LI 			p->fld &= CAST(type, m->num_mask); \
1054b6cee71dSXin LI 			break; \
1055b6cee71dSXin LI 		case FILE_OPOR: \
105648c779cdSXin LI 			p->fld |= CAST(type, m->num_mask); \
1057b6cee71dSXin LI 			break; \
1058b6cee71dSXin LI 		case FILE_OPXOR: \
105948c779cdSXin LI 			p->fld ^= CAST(type, m->num_mask); \
1060b6cee71dSXin LI 			break; \
1061b6cee71dSXin LI 		case FILE_OPADD: \
106248c779cdSXin LI 			p->fld += CAST(type, m->num_mask); \
1063b6cee71dSXin LI 			break; \
1064b6cee71dSXin LI 		case FILE_OPMINUS: \
106548c779cdSXin LI 			p->fld -= CAST(type, m->num_mask); \
1066b6cee71dSXin LI 			break; \
1067b6cee71dSXin LI 		case FILE_OPMULTIPLY: \
106848c779cdSXin LI 			p->fld *= CAST(type, m->num_mask); \
1069b6cee71dSXin LI 			break; \
1070b6cee71dSXin LI 		case FILE_OPDIVIDE: \
107148c779cdSXin LI 			if (CAST(type, m->num_mask) == 0) \
10723e41d09dSXin LI 				return -1; \
107348c779cdSXin LI 			p->fld /= CAST(type, m->num_mask); \
1074b6cee71dSXin LI 			break; \
1075b6cee71dSXin LI 		case FILE_OPMODULO: \
107648c779cdSXin LI 			if (CAST(type, m->num_mask) == 0) \
10773e41d09dSXin LI 				return -1; \
107848c779cdSXin LI 			p->fld %= CAST(type, m->num_mask); \
1079b6cee71dSXin LI 			break; \
1080b6cee71dSXin LI 		} \
1081b6cee71dSXin LI 	if (m->mask_op & FILE_OPINVERSE) \
1082b6cee71dSXin LI 		p->fld = ~p->fld \
1083b6cee71dSXin LI 
1084898496eeSXin LI file_private int
cvt_8(union VALUETYPE * p,const struct magic * m)1085b6cee71dSXin LI cvt_8(union VALUETYPE *p, const struct magic *m)
1086b6cee71dSXin LI {
108748c779cdSXin LI 	DO_CVT(b, uint8_t);
10883e41d09dSXin LI 	return 0;
1089b6cee71dSXin LI }
1090b6cee71dSXin LI 
1091898496eeSXin LI file_private int
cvt_16(union VALUETYPE * p,const struct magic * m)1092b6cee71dSXin LI cvt_16(union VALUETYPE *p, const struct magic *m)
1093b6cee71dSXin LI {
109448c779cdSXin LI 	DO_CVT(h, uint16_t);
10953e41d09dSXin LI 	return 0;
1096b6cee71dSXin LI }
1097b6cee71dSXin LI 
1098898496eeSXin LI file_private int
cvt_32(union VALUETYPE * p,const struct magic * m)1099b6cee71dSXin LI cvt_32(union VALUETYPE *p, const struct magic *m)
1100b6cee71dSXin LI {
110148c779cdSXin LI 	DO_CVT(l, uint32_t);
11023e41d09dSXin LI 	return 0;
1103b6cee71dSXin LI }
1104b6cee71dSXin LI 
1105898496eeSXin LI file_private int
cvt_64(union VALUETYPE * p,const struct magic * m)1106b6cee71dSXin LI cvt_64(union VALUETYPE *p, const struct magic *m)
1107b6cee71dSXin LI {
110848c779cdSXin LI 	DO_CVT(q, uint64_t);
11093e41d09dSXin LI 	return 0;
1110b6cee71dSXin LI }
1111b6cee71dSXin LI 
111248c779cdSXin LI #define DO_CVT2(fld, type) \
1113b6cee71dSXin LI 	if (m->num_mask) \
1114b6cee71dSXin LI 		switch (m->mask_op & FILE_OPS_MASK) { \
1115b6cee71dSXin LI 		case FILE_OPADD: \
111648c779cdSXin LI 			p->fld += CAST(type, m->num_mask); \
1117b6cee71dSXin LI 			break; \
1118b6cee71dSXin LI 		case FILE_OPMINUS: \
111948c779cdSXin LI 			p->fld -= CAST(type, m->num_mask); \
1120b6cee71dSXin LI 			break; \
1121b6cee71dSXin LI 		case FILE_OPMULTIPLY: \
112248c779cdSXin LI 			p->fld *= CAST(type, m->num_mask); \
1123b6cee71dSXin LI 			break; \
1124b6cee71dSXin LI 		case FILE_OPDIVIDE: \
112548c779cdSXin LI 			if (CAST(type, m->num_mask) == 0) \
11263e41d09dSXin LI 				return -1; \
112748c779cdSXin LI 			p->fld /= CAST(type, m->num_mask); \
1128b6cee71dSXin LI 			break; \
1129b6cee71dSXin LI 		} \
1130b6cee71dSXin LI 
1131898496eeSXin LI file_private int
cvt_float(union VALUETYPE * p,const struct magic * m)1132b6cee71dSXin LI cvt_float(union VALUETYPE *p, const struct magic *m)
1133b6cee71dSXin LI {
113448c779cdSXin LI 	DO_CVT2(f, float);
11353e41d09dSXin LI 	return 0;
1136b6cee71dSXin LI }
1137b6cee71dSXin LI 
1138898496eeSXin LI file_private int
cvt_double(union VALUETYPE * p,const struct magic * m)1139b6cee71dSXin LI cvt_double(union VALUETYPE *p, const struct magic *m)
1140b6cee71dSXin LI {
114148c779cdSXin LI 	DO_CVT2(d, double);
11423e41d09dSXin LI 	return 0;
1143b6cee71dSXin LI }
1144b6cee71dSXin LI 
1145b6cee71dSXin LI /*
1146b6cee71dSXin LI  * Convert the byte order of the data we are looking at
1147b6cee71dSXin LI  * While we're here, let's apply the mask operation
1148b6cee71dSXin LI  * (unless you have a better idea)
1149b6cee71dSXin LI  */
1150898496eeSXin LI file_private int
mconvert(struct magic_set * ms,struct magic * m,int flip)1151b6cee71dSXin LI mconvert(struct magic_set *ms, struct magic *m, int flip)
1152b6cee71dSXin LI {
1153b6cee71dSXin LI 	union VALUETYPE *p = &ms->ms_value;
1154b6cee71dSXin LI 
115540427ccaSGordon Tetlow 	switch (cvt_flip(m->type, flip)) {
1156b6cee71dSXin LI 	case FILE_BYTE:
11573e41d09dSXin LI 		if (cvt_8(p, m) == -1)
11583e41d09dSXin LI 			goto out;
1159b6cee71dSXin LI 		return 1;
1160b6cee71dSXin LI 	case FILE_SHORT:
1161a4d6d3b8SXin LI 	case FILE_MSDOSDATE:
1162a4d6d3b8SXin LI 	case FILE_LEMSDOSDATE:
1163a4d6d3b8SXin LI 	case FILE_BEMSDOSDATE:
1164a4d6d3b8SXin LI 	case FILE_MSDOSTIME:
1165a4d6d3b8SXin LI 	case FILE_LEMSDOSTIME:
1166a4d6d3b8SXin LI 	case FILE_BEMSDOSTIME:
11673e41d09dSXin LI 		if (cvt_16(p, m) == -1)
11683e41d09dSXin LI 			goto out;
1169b6cee71dSXin LI 		return 1;
1170b6cee71dSXin LI 	case FILE_LONG:
1171b6cee71dSXin LI 	case FILE_DATE:
1172b6cee71dSXin LI 	case FILE_LDATE:
11733e41d09dSXin LI 		if (cvt_32(p, m) == -1)
11743e41d09dSXin LI 			goto out;
1175b6cee71dSXin LI 		return 1;
1176b6cee71dSXin LI 	case FILE_QUAD:
1177b6cee71dSXin LI 	case FILE_QDATE:
1178b6cee71dSXin LI 	case FILE_QLDATE:
1179b6cee71dSXin LI 	case FILE_QWDATE:
11802726a701SXin LI 	case FILE_OFFSET:
11813e41d09dSXin LI 		if (cvt_64(p, m) == -1)
11823e41d09dSXin LI 			goto out;
1183b6cee71dSXin LI 		return 1;
1184b6cee71dSXin LI 	case FILE_STRING:
1185b6cee71dSXin LI 	case FILE_BESTRING16:
1186a2dfb722SXin LI 	case FILE_LESTRING16:
1187a2dfb722SXin LI 	case FILE_OCTAL: {
1188b6cee71dSXin LI 		/* Null terminate and eat *trailing* return */
1189b6cee71dSXin LI 		p->s[sizeof(p->s) - 1] = '\0';
1190b6cee71dSXin LI 		return 1;
1191b6cee71dSXin LI 	}
1192b6cee71dSXin LI 	case FILE_PSTRING: {
11932726a701SXin LI 		char *ptr1, *ptr2;
11942726a701SXin LI 		size_t len, sz = file_pstring_length_size(ms, m);
11952726a701SXin LI 		if (sz == FILE_BADSIZE)
11962726a701SXin LI 			return 0;
11972726a701SXin LI 		ptr1 = p->s;
11982726a701SXin LI 		ptr2 = ptr1 + sz;
11992726a701SXin LI 		len = file_pstring_get_length(ms, m, ptr1);
12002726a701SXin LI 		if (len == FILE_BADSIZE)
12012726a701SXin LI 			return 0;
1202c2931133SXin LI 		sz = sizeof(p->s) - sz; /* maximum length of string */
1203c2931133SXin LI 		if (len >= sz) {
1204b6cee71dSXin LI 			/*
1205b6cee71dSXin LI 			 * The size of the pascal string length (sz)
1206b6cee71dSXin LI 			 * is 1, 2, or 4. We need at least 1 byte for NUL
1207b6cee71dSXin LI 			 * termination, but we've already truncated the
1208b6cee71dSXin LI 			 * string by p->s, so we need to deduct sz.
1209c2931133SXin LI 			 * Because we can use one of the bytes of the length
1210c2931133SXin LI 			 * after we shifted as NUL termination.
1211b6cee71dSXin LI 			 */
1212c2931133SXin LI 			len = sz;
1213b6cee71dSXin LI 		}
1214b6cee71dSXin LI 		while (len--)
1215b6cee71dSXin LI 			*ptr1++ = *ptr2++;
1216b6cee71dSXin LI 		*ptr1 = '\0';
1217b6cee71dSXin LI 		return 1;
1218b6cee71dSXin LI 	}
1219b6cee71dSXin LI 	case FILE_BESHORT:
1220*ae316d1dSXin LI 		p->h = CAST(short, BE16(p->hs));
12213e41d09dSXin LI 		if (cvt_16(p, m) == -1)
12223e41d09dSXin LI 			goto out;
1223b6cee71dSXin LI 		return 1;
1224b6cee71dSXin LI 	case FILE_BELONG:
1225b6cee71dSXin LI 	case FILE_BEDATE:
1226b6cee71dSXin LI 	case FILE_BELDATE:
1227*ae316d1dSXin LI 		p->l = CAST(int32_t, BE32(p->hl));
12283e41d09dSXin LI 		if (cvt_32(p, m) == -1)
12293e41d09dSXin LI 			goto out;
1230b6cee71dSXin LI 		return 1;
1231b6cee71dSXin LI 	case FILE_BEQUAD:
1232b6cee71dSXin LI 	case FILE_BEQDATE:
1233b6cee71dSXin LI 	case FILE_BEQLDATE:
1234b6cee71dSXin LI 	case FILE_BEQWDATE:
1235*ae316d1dSXin LI 		p->q = CAST(uint64_t, BE64(p->hq));
12363e41d09dSXin LI 		if (cvt_64(p, m) == -1)
12373e41d09dSXin LI 			goto out;
1238b6cee71dSXin LI 		return 1;
1239b6cee71dSXin LI 	case FILE_LESHORT:
1240*ae316d1dSXin LI 		p->h = CAST(short, LE16(p->hs));
12413e41d09dSXin LI 		if (cvt_16(p, m) == -1)
12423e41d09dSXin LI 			goto out;
1243b6cee71dSXin LI 		return 1;
1244b6cee71dSXin LI 	case FILE_LELONG:
1245b6cee71dSXin LI 	case FILE_LEDATE:
1246b6cee71dSXin LI 	case FILE_LELDATE:
1247*ae316d1dSXin LI 		p->l = CAST(int32_t, LE32(p->hl));
12483e41d09dSXin LI 		if (cvt_32(p, m) == -1)
12493e41d09dSXin LI 			goto out;
1250b6cee71dSXin LI 		return 1;
1251b6cee71dSXin LI 	case FILE_LEQUAD:
1252b6cee71dSXin LI 	case FILE_LEQDATE:
1253b6cee71dSXin LI 	case FILE_LEQLDATE:
1254b6cee71dSXin LI 	case FILE_LEQWDATE:
1255*ae316d1dSXin LI 		p->q = CAST(uint64_t, LE64(p->hq));
12563e41d09dSXin LI 		if (cvt_64(p, m) == -1)
12573e41d09dSXin LI 			goto out;
1258b6cee71dSXin LI 		return 1;
1259b6cee71dSXin LI 	case FILE_MELONG:
1260b6cee71dSXin LI 	case FILE_MEDATE:
1261b6cee71dSXin LI 	case FILE_MELDATE:
1262*ae316d1dSXin LI 		p->l = CAST(int32_t, ME32(p->hl));
12633e41d09dSXin LI 		if (cvt_32(p, m) == -1)
12643e41d09dSXin LI 			goto out;
1265b6cee71dSXin LI 		return 1;
1266b6cee71dSXin LI 	case FILE_FLOAT:
12673e41d09dSXin LI 		if (cvt_float(p, m) == -1)
12683e41d09dSXin LI 			goto out;
1269b6cee71dSXin LI 		return 1;
1270b6cee71dSXin LI 	case FILE_BEFLOAT:
1271*ae316d1dSXin LI 		p->l = BE32(p->hl);
12723e41d09dSXin LI 		if (cvt_float(p, m) == -1)
12733e41d09dSXin LI 			goto out;
1274b6cee71dSXin LI 		return 1;
1275b6cee71dSXin LI 	case FILE_LEFLOAT:
1276*ae316d1dSXin LI 		p->l = LE32(p->hl);
12773e41d09dSXin LI 		if (cvt_float(p, m) == -1)
12783e41d09dSXin LI 			goto out;
1279b6cee71dSXin LI 		return 1;
1280b6cee71dSXin LI 	case FILE_DOUBLE:
12813e41d09dSXin LI 		if (cvt_double(p, m) == -1)
12823e41d09dSXin LI 			goto out;
1283b6cee71dSXin LI 		return 1;
1284b6cee71dSXin LI 	case FILE_BEDOUBLE:
1285*ae316d1dSXin LI 		p->q = BE64(p->hq);
12863e41d09dSXin LI 		if (cvt_double(p, m) == -1)
12873e41d09dSXin LI 			goto out;
1288b6cee71dSXin LI 		return 1;
1289b6cee71dSXin LI 	case FILE_LEDOUBLE:
1290*ae316d1dSXin LI 		p->q = LE64(p->hq);
12913e41d09dSXin LI 		if (cvt_double(p, m) == -1)
12923e41d09dSXin LI 			goto out;
1293b6cee71dSXin LI 		return 1;
1294b6cee71dSXin LI 	case FILE_REGEX:
1295b6cee71dSXin LI 	case FILE_SEARCH:
1296b6cee71dSXin LI 	case FILE_DEFAULT:
1297b6cee71dSXin LI 	case FILE_CLEAR:
1298b6cee71dSXin LI 	case FILE_NAME:
1299b6cee71dSXin LI 	case FILE_USE:
13003e41d09dSXin LI 	case FILE_DER:
13012726a701SXin LI 	case FILE_GUID:
1302b6cee71dSXin LI 		return 1;
1303b6cee71dSXin LI 	default:
1304b6cee71dSXin LI 		file_magerror(ms, "invalid type %d in mconvert()", m->type);
1305b6cee71dSXin LI 		return 0;
1306b6cee71dSXin LI 	}
13073e41d09dSXin LI out:
13083e41d09dSXin LI 	file_magerror(ms, "zerodivide in mconvert()");
13093e41d09dSXin LI 	return 0;
1310b6cee71dSXin LI }
1311b6cee71dSXin LI 
1312b6cee71dSXin LI 
1313898496eeSXin LI file_private void
mdebug(uint32_t offset,const char * str,size_t len)1314b6cee71dSXin LI mdebug(uint32_t offset, const char *str, size_t len)
1315b6cee71dSXin LI {
1316c2931133SXin LI 	(void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1317b6cee71dSXin LI 	file_showstr(stderr, str, len);
1318b6cee71dSXin LI 	(void) fputc('\n', stderr);
1319b6cee71dSXin LI 	(void) fputc('\n', stderr);
1320b6cee71dSXin LI }
1321b6cee71dSXin LI 
1322898496eeSXin LI file_private int
mcopy(struct magic_set * ms,union VALUETYPE * p,int type,int indir,const unsigned char * s,uint32_t offset,size_t nbytes,struct magic * m)1323b6cee71dSXin LI mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1324b6cee71dSXin LI     const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1325b6cee71dSXin LI {
1326898496eeSXin LI 	size_t size = sizeof(*p);
1327b6cee71dSXin LI 	/*
1328b6cee71dSXin LI 	 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1329b6cee71dSXin LI 	 * anything, but setup pointers into the source
1330b6cee71dSXin LI 	 */
1331b6cee71dSXin LI 	if (indir == 0) {
1332b6cee71dSXin LI 		switch (type) {
13333e41d09dSXin LI 		case FILE_DER:
1334b6cee71dSXin LI 		case FILE_SEARCH:
1335282e23f0SXin LI 			if (offset > nbytes)
133640427ccaSGordon Tetlow 				offset = CAST(uint32_t, nbytes);
1337b6cee71dSXin LI 			ms->search.s = RCAST(const char *, s) + offset;
1338b6cee71dSXin LI 			ms->search.s_len = nbytes - offset;
1339b6cee71dSXin LI 			ms->search.offset = offset;
1340b6cee71dSXin LI 			return 0;
1341b6cee71dSXin LI 
1342b6cee71dSXin LI 		case FILE_REGEX: {
1343b6cee71dSXin LI 			const char *b;
1344b6cee71dSXin LI 			const char *c;
1345b6cee71dSXin LI 			const char *last;	/* end of search region */
1346b6cee71dSXin LI 			const char *buf;	/* start of search region */
1347b6cee71dSXin LI 			const char *end;
1348b6cee71dSXin LI 			size_t lines, linecnt, bytecnt;
1349b6cee71dSXin LI 
135040427ccaSGordon Tetlow 			if (s == NULL || nbytes < offset) {
1351b6cee71dSXin LI 				ms->search.s_len = 0;
1352b6cee71dSXin LI 				ms->search.s = NULL;
1353b6cee71dSXin LI 				return 0;
1354b6cee71dSXin LI 			}
1355b6cee71dSXin LI 
1356b6cee71dSXin LI 			if (m->str_flags & REGEX_LINE_COUNT) {
1357b6cee71dSXin LI 				linecnt = m->str_range;
1358b6cee71dSXin LI 				bytecnt = linecnt * 80;
1359b6cee71dSXin LI 			} else {
1360b6cee71dSXin LI 				linecnt = 0;
1361b6cee71dSXin LI 				bytecnt = m->str_range;
1362b6cee71dSXin LI 			}
1363b6cee71dSXin LI 
13645f0216bdSXin LI 			if (bytecnt == 0 || bytecnt > nbytes - offset)
13655f0216bdSXin LI 				bytecnt = nbytes - offset;
13669ce06829SXin LI 			if (bytecnt > ms->regex_max)
13679ce06829SXin LI 				bytecnt = ms->regex_max;
1368b6cee71dSXin LI 
1369b6cee71dSXin LI 			buf = RCAST(const char *, s) + offset;
13705f0216bdSXin LI 			end = last = RCAST(const char *, s) + bytecnt + offset;
1371b6cee71dSXin LI 			/* mget() guarantees buf <= last */
1372b6cee71dSXin LI 			for (lines = linecnt, b = buf; lines && b < end &&
1373b6cee71dSXin LI 			     ((b = CAST(const char *,
1374b6cee71dSXin LI 				 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1375b6cee71dSXin LI 			     || (b = CAST(const char *,
1376b6cee71dSXin LI 				 memchr(c, '\r', CAST(size_t, (end - c))))));
1377b6cee71dSXin LI 			     lines--, b++) {
1378a5d223e6SXin LI 				if (b < end - 1 && b[0] == '\r' && b[1] == '\n')
1379b6cee71dSXin LI 					b++;
138048c779cdSXin LI 				if (b < end - 1 && b[0] == '\n')
138148c779cdSXin LI 					b++;
138248c779cdSXin LI 				last = b;
1383b6cee71dSXin LI 			}
1384b6cee71dSXin LI 			if (lines)
138558a0f0d0SEitan Adler 				last = end;
1386b6cee71dSXin LI 
1387b6cee71dSXin LI 			ms->search.s = buf;
1388b6cee71dSXin LI 			ms->search.s_len = last - buf;
1389b6cee71dSXin LI 			ms->search.offset = offset;
1390b6cee71dSXin LI 			ms->search.rm_len = 0;
1391b6cee71dSXin LI 			return 0;
1392b6cee71dSXin LI 		}
1393b6cee71dSXin LI 		case FILE_BESTRING16:
1394b6cee71dSXin LI 		case FILE_LESTRING16: {
1395b6cee71dSXin LI 			const unsigned char *src = s + offset;
1396b6cee71dSXin LI 			const unsigned char *esrc = s + nbytes;
1397b6cee71dSXin LI 			char *dst = p->s;
1398b6cee71dSXin LI 			char *edst = &p->s[sizeof(p->s) - 1];
1399b6cee71dSXin LI 
1400b6cee71dSXin LI 			if (type == FILE_BESTRING16)
1401b6cee71dSXin LI 				src++;
1402b6cee71dSXin LI 
1403b6cee71dSXin LI 			/* check that offset is within range */
1404b6cee71dSXin LI 			if (offset >= nbytes)
1405b6cee71dSXin LI 				break;
1406b6cee71dSXin LI 			for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1407b6cee71dSXin LI 				if (dst < edst)
1408b6cee71dSXin LI 					*dst = *src;
1409b6cee71dSXin LI 				else
1410b6cee71dSXin LI 					break;
1411b6cee71dSXin LI 				if (*dst == '\0') {
1412b6cee71dSXin LI 					if (type == FILE_BESTRING16 ?
1413b6cee71dSXin LI 					    *(src - 1) != '\0' :
141440427ccaSGordon Tetlow 					    ((src + 1 < esrc) &&
141540427ccaSGordon Tetlow 					    *(src + 1) != '\0'))
1416b6cee71dSXin LI 						*dst = ' ';
1417b6cee71dSXin LI 				}
1418b6cee71dSXin LI 			}
1419b6cee71dSXin LI 			*edst = '\0';
1420*ae316d1dSXin LI 			*dst = '\0';
1421b6cee71dSXin LI 			return 0;
1422b6cee71dSXin LI 		}
1423b6cee71dSXin LI 		case FILE_STRING:	/* XXX - these two should not need */
1424b6cee71dSXin LI 		case FILE_PSTRING:	/* to copy anything, but do anyway. */
1425898496eeSXin LI 			if (m->str_range != 0 && m->str_range < sizeof(*p))
1426898496eeSXin LI 				size = m->str_range;
1427898496eeSXin LI 			break;
1428b6cee71dSXin LI 		default:
1429b6cee71dSXin LI 			break;
1430b6cee71dSXin LI 		}
1431b6cee71dSXin LI 	}
1432b6cee71dSXin LI 
14332726a701SXin LI 	if (type == FILE_OFFSET) {
14342726a701SXin LI 		(void)memset(p, '\0', sizeof(*p));
14352726a701SXin LI 		p->q = offset;
14362726a701SXin LI 		return 0;
14372726a701SXin LI 	}
14382726a701SXin LI 
1439b6cee71dSXin LI 	if (offset >= nbytes) {
1440b6cee71dSXin LI 		(void)memset(p, '\0', sizeof(*p));
1441b6cee71dSXin LI 		return 0;
1442b6cee71dSXin LI 	}
1443898496eeSXin LI 	if (nbytes - offset < size)
1444b6cee71dSXin LI 		nbytes = nbytes - offset;
1445b6cee71dSXin LI 	else
1446898496eeSXin LI 		nbytes = size;
1447b6cee71dSXin LI 
1448b6cee71dSXin LI 	(void)memcpy(p, s + offset, nbytes);
1449b6cee71dSXin LI 
1450b6cee71dSXin LI 	/*
1451b6cee71dSXin LI 	 * the usefulness of padding with zeroes eludes me, it
1452b6cee71dSXin LI 	 * might even cause problems
1453b6cee71dSXin LI 	 */
1454b6cee71dSXin LI 	if (nbytes < sizeof(*p))
145548c779cdSXin LI 		(void)memset(RCAST(char *, RCAST(void *, p)) + nbytes, '\0',
1456b6cee71dSXin LI 		    sizeof(*p) - nbytes);
1457b6cee71dSXin LI 	return 0;
1458b6cee71dSXin LI }
1459b6cee71dSXin LI 
1460898496eeSXin LI file_private int
do_ops(struct magic_set * ms,struct magic * m,uint32_t * rv,intmax_t lhs,intmax_t off)1461898496eeSXin LI do_ops(struct magic_set *ms, struct magic *m, uint32_t *rv, intmax_t lhs,
1462898496eeSXin LI     intmax_t off)
1463a5d223e6SXin LI {
1464a5d223e6SXin LI 	intmax_t offset;
1465898496eeSXin LI 	// On purpose not INTMAX_MAX
1466898496eeSXin LI 	if (lhs >= UINT_MAX || lhs <= INT_MIN ||
1467898496eeSXin LI 	    off >= UINT_MAX || off <= INT_MIN) {
1468898496eeSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
1469898496eeSXin LI 			fprintf(stderr, "lhs/off overflow %jd %jd\n", lhs, off);
1470898496eeSXin LI 		return 1;
1471898496eeSXin LI 	}
1472898496eeSXin LI 
1473a5d223e6SXin LI 	if (off) {
1474a5d223e6SXin LI 		switch (m->in_op & FILE_OPS_MASK) {
1475a5d223e6SXin LI 		case FILE_OPAND:
1476a5d223e6SXin LI 			offset = lhs & off;
1477a5d223e6SXin LI 			break;
1478a5d223e6SXin LI 		case FILE_OPOR:
1479a5d223e6SXin LI 			offset = lhs | off;
1480a5d223e6SXin LI 			break;
1481a5d223e6SXin LI 		case FILE_OPXOR:
1482a5d223e6SXin LI 			offset = lhs ^ off;
1483a5d223e6SXin LI 			break;
1484a5d223e6SXin LI 		case FILE_OPADD:
1485a5d223e6SXin LI 			offset = lhs + off;
1486a5d223e6SXin LI 			break;
1487a5d223e6SXin LI 		case FILE_OPMINUS:
1488a5d223e6SXin LI 			offset = lhs - off;
1489a5d223e6SXin LI 			break;
1490a5d223e6SXin LI 		case FILE_OPMULTIPLY:
1491a5d223e6SXin LI 			offset = lhs * off;
1492a5d223e6SXin LI 			break;
1493a5d223e6SXin LI 		case FILE_OPDIVIDE:
1494a5d223e6SXin LI 			offset = lhs / off;
1495a5d223e6SXin LI 			break;
1496a5d223e6SXin LI 		case FILE_OPMODULO:
1497a5d223e6SXin LI 			offset = lhs % off;
1498a5d223e6SXin LI 			break;
1499a5d223e6SXin LI 		}
1500a5d223e6SXin LI 	} else
1501a5d223e6SXin LI 		offset = lhs;
1502a5d223e6SXin LI 	if (m->in_op & FILE_OPINVERSE)
1503a5d223e6SXin LI 		offset = ~offset;
1504898496eeSXin LI 	if (offset >= UINT_MAX) {
1505898496eeSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
1506898496eeSXin LI 			fprintf(stderr, "offset overflow %jd\n", offset);
1507898496eeSXin LI 		return 1;
1508898496eeSXin LI 	}
1509898496eeSXin LI 	*rv = CAST(uint32_t, offset);
1510898496eeSXin LI 	return 0;
1511a5d223e6SXin LI }
1512a5d223e6SXin LI 
1513898496eeSXin LI file_private int
msetoffset(struct magic_set * ms,struct magic * m,struct buffer * bb,const struct buffer * b,size_t o,unsigned int cont_level)151458a0f0d0SEitan Adler msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
151558a0f0d0SEitan Adler     const struct buffer *b, size_t o, unsigned int cont_level)
151658a0f0d0SEitan Adler {
15172726a701SXin LI 	int32_t offset;
15182726a701SXin LI 	if (m->flag & OFFNEGATIVE) {
15192726a701SXin LI 		offset = -m->offset;
152058a0f0d0SEitan Adler 		if (cont_level > 0) {
152158a0f0d0SEitan Adler 			if (m->flag & (OFFADD|INDIROFFADD))
152258a0f0d0SEitan Adler 				goto normal;
152358a0f0d0SEitan Adler #if 0
152458a0f0d0SEitan Adler 			file_error(ms, 0, "negative offset %d at continuation"
152558a0f0d0SEitan Adler 			    "level %u", m->offset, cont_level);
152658a0f0d0SEitan Adler 			return -1;
152758a0f0d0SEitan Adler #endif
152858a0f0d0SEitan Adler 		}
152958a0f0d0SEitan Adler 		if (buffer_fill(b) == -1)
153058a0f0d0SEitan Adler 			return -1;
153158a0f0d0SEitan Adler 		if (o != 0) {
153258a0f0d0SEitan Adler 			// Not yet!
153348c779cdSXin LI 			file_magerror(ms, "non zero offset %" SIZE_T_FORMAT
153448c779cdSXin LI 			    "u at level %u", o, cont_level);
153558a0f0d0SEitan Adler 			return -1;
153658a0f0d0SEitan Adler 		}
15372726a701SXin LI 		if (CAST(size_t, m->offset) > b->elen)
153858a0f0d0SEitan Adler 			return -1;
153948c779cdSXin LI 		buffer_init(bb, -1, NULL, b->ebuf, b->elen);
15402726a701SXin LI 		ms->eoffset = ms->offset = CAST(int32_t, b->elen - m->offset);
154158a0f0d0SEitan Adler 	} else {
15422726a701SXin LI 		offset = m->offset;
1543*ae316d1dSXin LI 		if ((m->flag & OFFPOSITIVE) || cont_level == 0) {
154458a0f0d0SEitan Adler normal:
154558a0f0d0SEitan Adler 			// XXX: Pass real fd, then who frees bb?
154648c779cdSXin LI 			buffer_init(bb, -1, NULL, b->fbuf, b->flen);
15472726a701SXin LI 			ms->offset = offset;
154858a0f0d0SEitan Adler 			ms->eoffset = 0;
154958a0f0d0SEitan Adler 		} else {
15502726a701SXin LI 			ms->offset = ms->eoffset + offset;
155158a0f0d0SEitan Adler 		}
155258a0f0d0SEitan Adler 	}
155358a0f0d0SEitan Adler 	if ((ms->flags & MAGIC_DEBUG) != 0) {
15542726a701SXin LI 		fprintf(stderr, "bb=[%p,%" SIZE_T_FORMAT "u,%"
15552726a701SXin LI 		    SIZE_T_FORMAT "u], %d [b=%p,%"
15562726a701SXin LI 		    SIZE_T_FORMAT "u,%" SIZE_T_FORMAT "u], [o=%#x, c=%d]\n",
15572726a701SXin LI 		    bb->fbuf, bb->flen, bb->elen, ms->offset, b->fbuf,
15582726a701SXin LI 		    b->flen, b->elen, offset, cont_level);
155958a0f0d0SEitan Adler 	}
156058a0f0d0SEitan Adler 	return 0;
156158a0f0d0SEitan Adler }
156258a0f0d0SEitan Adler 
1563898496eeSXin LI file_private int
save_cont(struct magic_set * ms,struct cont * c)156443a5ec4eSXin LI save_cont(struct magic_set *ms, struct cont *c)
156543a5ec4eSXin LI {
156643a5ec4eSXin LI 	size_t len;
156743a5ec4eSXin LI 	*c = ms->c;
156843a5ec4eSXin LI 	len = c->len * sizeof(*c->li);
156943a5ec4eSXin LI 	ms->c.li = CAST(struct level_info *, malloc(len));
157043a5ec4eSXin LI 	if (ms->c.li == NULL) {
157143a5ec4eSXin LI 		ms->c = *c;
157243a5ec4eSXin LI 		return -1;
157343a5ec4eSXin LI 	}
157443a5ec4eSXin LI 	memcpy(ms->c.li, c->li, len);
157543a5ec4eSXin LI 	return 0;
157643a5ec4eSXin LI }
157743a5ec4eSXin LI 
1578898496eeSXin LI file_private void
restore_cont(struct magic_set * ms,struct cont * c)157943a5ec4eSXin LI restore_cont(struct magic_set *ms, struct cont *c)
158043a5ec4eSXin LI {
158143a5ec4eSXin LI 	free(ms->c.li);
158243a5ec4eSXin LI 	ms->c = *c;
158343a5ec4eSXin LI }
158443a5ec4eSXin LI 
1585898496eeSXin LI file_private int
mget(struct magic_set * ms,struct magic * m,const struct buffer * b,const unsigned char * s,size_t nbytes,size_t o,unsigned int cont_level,int mode,int text,int flip,uint16_t * indir_count,uint16_t * name_count,int * printed_something,int * need_separator,int * firstline,int * returnval,int * found_match)158658a0f0d0SEitan Adler mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
158758a0f0d0SEitan Adler     const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level,
158858a0f0d0SEitan Adler     int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count,
1589898496eeSXin LI     int *printed_something, int *need_separator, int *firstline, int *returnval,
159048c779cdSXin LI     int *found_match)
1591b6cee71dSXin LI {
159243a5ec4eSXin LI 	uint32_t eoffset, offset = ms->offset;
159358a0f0d0SEitan Adler 	struct buffer bb;
1594a5d223e6SXin LI 	intmax_t lhs;
15952c4f1647SXin LI 	file_pushbuf_t *pb;
159643a5ec4eSXin LI 	int rv, oneed_separator, in_type, nfound_match;
15972c4f1647SXin LI 	char *rbuf;
1598b6cee71dSXin LI 	union VALUETYPE *p = &ms->ms_value;
159943a5ec4eSXin LI 	struct mlist ml, *mlp;
160043a5ec4eSXin LI 	struct cont c;
1601b6cee71dSXin LI 
16023e41d09dSXin LI 	if (*indir_count >= ms->indir_max) {
16033e41d09dSXin LI 		file_error(ms, 0, "indirect count (%hu) exceeded",
16043e41d09dSXin LI 		    *indir_count);
1605c2931133SXin LI 		return -1;
1606c2931133SXin LI 	}
1607c2931133SXin LI 
1608c2931133SXin LI 	if (*name_count >= ms->name_max) {
1609c2931133SXin LI 		file_error(ms, 0, "name use count (%hu) exceeded",
1610c2931133SXin LI 		    *name_count);
1611b6cee71dSXin LI 		return -1;
1612b6cee71dSXin LI 	}
1613b6cee71dSXin LI 
161458a0f0d0SEitan Adler 
161548c779cdSXin LI 	if (mcopy(ms, p, m->type, m->flag & INDIR, s,
161648c779cdSXin LI 	    CAST(uint32_t, offset + o), CAST(uint32_t, nbytes), m) == -1)
1617b6cee71dSXin LI 		return -1;
1618b6cee71dSXin LI 
1619b6cee71dSXin LI 	if ((ms->flags & MAGIC_DEBUG) != 0) {
162040427ccaSGordon Tetlow 		fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%"
1621c2931133SXin LI 		    SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1622c2931133SXin LI 		    "u, il=%hu, nc=%hu)\n",
1623c2931133SXin LI 		    m->type, m->flag, offset, o, nbytes,
16243e41d09dSXin LI 		    *indir_count, *name_count);
162548c779cdSXin LI 		mdebug(offset, RCAST(char *, RCAST(void *, p)),
162648c779cdSXin LI 		    sizeof(union VALUETYPE));
1627b6cee71dSXin LI #ifndef COMPILE_ONLY
1628b6cee71dSXin LI 		file_mdump(m);
1629b6cee71dSXin LI #endif
1630b6cee71dSXin LI 	}
1631b6cee71dSXin LI 
1632b6cee71dSXin LI 	if (m->flag & INDIR) {
1633a5d223e6SXin LI 		intmax_t off = m->in_offset;
1634a5d223e6SXin LI 		const int sgn = m->in_op & FILE_OPSIGNED;
1635b6cee71dSXin LI 		if (m->in_op & FILE_OPINDIRECT) {
1636*ae316d1dSXin LI 
1637*ae316d1dSXin LI 			uint8_t *hb = CCAST(uint8_t *, s + offset + off);
1638*ae316d1dSXin LI 			uint16_t hs;
1639*ae316d1dSXin LI 			uint32_t hl;
16402726a701SXin LI 			int op;
16412726a701SXin LI 			switch (op = cvt_flip(m->in_type, flip)) {
1642b6cee71dSXin LI 			case FILE_BYTE:
164348c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 1))
164448c779cdSXin LI 					return 0;
1645*ae316d1dSXin LI 				off = SEXT(sgn,8,hb[0]);
1646b6cee71dSXin LI 				break;
1647b6cee71dSXin LI 			case FILE_SHORT:
164848c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 2))
164948c779cdSXin LI 					return 0;
1650*ae316d1dSXin LI 				memcpy(&hs, hb, sizeof(hs));
1651*ae316d1dSXin LI 				off = SEXT(sgn,16,hs);
1652b6cee71dSXin LI 				break;
1653b6cee71dSXin LI 			case FILE_BESHORT:
165448c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 2))
165548c779cdSXin LI 					return 0;
1656*ae316d1dSXin LI 				off = SEXT(sgn,16,BE16(hb));
1657b6cee71dSXin LI 				break;
1658b6cee71dSXin LI 			case FILE_LESHORT:
165948c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 2))
166048c779cdSXin LI 					return 0;
1661*ae316d1dSXin LI 				off = SEXT(sgn,16,LE16(hb));
1662b6cee71dSXin LI 				break;
1663b6cee71dSXin LI 			case FILE_LONG:
166448c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 4))
166548c779cdSXin LI 					return 0;
1666*ae316d1dSXin LI 				memcpy(&hl, hb, sizeof(hl));
1667*ae316d1dSXin LI 				off = SEXT(sgn,32,hl);
1668b6cee71dSXin LI 				break;
1669b6cee71dSXin LI 			case FILE_BELONG:
1670b6cee71dSXin LI 			case FILE_BEID3:
167148c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 4))
167248c779cdSXin LI 					return 0;
1673*ae316d1dSXin LI 				off = SEXT(sgn,32,BE32(hb));
1674b6cee71dSXin LI 				break;
1675b6cee71dSXin LI 			case FILE_LEID3:
1676b6cee71dSXin LI 			case FILE_LELONG:
167748c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 4))
167848c779cdSXin LI 					return 0;
1679*ae316d1dSXin LI 				off = SEXT(sgn,32,LE32(hb));
1680b6cee71dSXin LI 				break;
1681b6cee71dSXin LI 			case FILE_MELONG:
168248c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 4))
168348c779cdSXin LI 					return 0;
1684*ae316d1dSXin LI 				off = SEXT(sgn,32,ME32(hb));
1685b6cee71dSXin LI 				break;
16862dc4dbb9SEitan Adler 			case FILE_BEQUAD:
168748c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 8))
168848c779cdSXin LI 					return 0;
1689*ae316d1dSXin LI 				off = SEXT(sgn,64,BE64(hb));
16902dc4dbb9SEitan Adler 				break;
16912dc4dbb9SEitan Adler 			case FILE_LEQUAD:
169248c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 8))
169348c779cdSXin LI 					return 0;
1694*ae316d1dSXin LI 				off = SEXT(sgn,64,LE64(hb));
16952dc4dbb9SEitan Adler 				break;
1696a2dfb722SXin LI 			case FILE_OCTAL:
1697a2dfb722SXin LI 				if (OFFSET_OOB(nbytes, offset, m->vallen))
1698a2dfb722SXin LI 					return 0;
1699a2dfb722SXin LI 				off = SEXT(sgn,64,strtoull(p->s, NULL, 8));
1700a2dfb722SXin LI 				break;
17012dc4dbb9SEitan Adler 			default:
17022726a701SXin LI 				if ((ms->flags & MAGIC_DEBUG) != 0)
17032726a701SXin LI 					fprintf(stderr, "bad op=%d\n", op);
17042726a701SXin LI 				return 0;
1705b6cee71dSXin LI 			}
1706b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
1707a5d223e6SXin LI 				fprintf(stderr, "indirect offs=%jd\n", off);
1708b6cee71dSXin LI 		}
1709b6cee71dSXin LI 		switch (in_type = cvt_flip(m->in_type, flip)) {
1710b6cee71dSXin LI 		case FILE_BYTE:
1711b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 1))
1712b6cee71dSXin LI 				return 0;
1713898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,8,p->b), off))
1714898496eeSXin LI 				return 0;
1715b6cee71dSXin LI 			break;
1716b6cee71dSXin LI 		case FILE_BESHORT:
1717b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 2))
1718b6cee71dSXin LI 				return 0;
1719*ae316d1dSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,16,BE16(p->hs)), off))
1720898496eeSXin LI 				return 0;
1721b6cee71dSXin LI 			break;
1722b6cee71dSXin LI 		case FILE_LESHORT:
1723b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 2))
1724b6cee71dSXin LI 				return 0;
1725*ae316d1dSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,16,LE16(p->hs)), off))
1726898496eeSXin LI 				return 0;
1727b6cee71dSXin LI 			break;
1728b6cee71dSXin LI 		case FILE_SHORT:
1729b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 2))
1730b6cee71dSXin LI 				return 0;
1731898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,16,p->h), off))
1732898496eeSXin LI 				return 0;
1733b6cee71dSXin LI 			break;
1734b6cee71dSXin LI 		case FILE_BELONG:
1735b6cee71dSXin LI 		case FILE_BEID3:
1736b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 4))
1737b6cee71dSXin LI 				return 0;
1738*ae316d1dSXin LI 			lhs = BE32(p->hl);
17393e41d09dSXin LI 			if (in_type == FILE_BEID3)
174048c779cdSXin LI 				lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1741898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,32,lhs), off))
1742898496eeSXin LI 				return 0;
1743b6cee71dSXin LI 			break;
1744b6cee71dSXin LI 		case FILE_LELONG:
1745b6cee71dSXin LI 		case FILE_LEID3:
1746b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 4))
1747b6cee71dSXin LI 				return 0;
1748*ae316d1dSXin LI 			lhs = LE32(p->hl);
17493e41d09dSXin LI 			if (in_type == FILE_LEID3)
175048c779cdSXin LI 				lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1751898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,32,lhs), off))
1752898496eeSXin LI 				return 0;
1753b6cee71dSXin LI 			break;
1754b6cee71dSXin LI 		case FILE_MELONG:
1755b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 4))
1756b6cee71dSXin LI 				return 0;
1757*ae316d1dSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,32,ME32(p->hl)), off))
1758898496eeSXin LI 				return 0;
1759b6cee71dSXin LI 			break;
1760b6cee71dSXin LI 		case FILE_LONG:
1761b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 4))
1762b6cee71dSXin LI 				return 0;
1763898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,32,p->l), off))
1764898496eeSXin LI 				return 0;
1765b6cee71dSXin LI 			break;
17662dc4dbb9SEitan Adler 		case FILE_LEQUAD:
17672dc4dbb9SEitan Adler 			if (OFFSET_OOB(nbytes, offset, 8))
17682dc4dbb9SEitan Adler 				return 0;
1769*ae316d1dSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,64,LE64(p->hq)), off))
1770898496eeSXin LI 				return 0;
1771b6cee71dSXin LI 			break;
17722dc4dbb9SEitan Adler 		case FILE_BEQUAD:
17732dc4dbb9SEitan Adler 			if (OFFSET_OOB(nbytes, offset, 8))
17742dc4dbb9SEitan Adler 				return 0;
1775*ae316d1dSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,64,BE64(p->hq)), off))
1776898496eeSXin LI 				return 0;
17772dc4dbb9SEitan Adler 			break;
1778a2dfb722SXin LI 		case FILE_OCTAL:
1779a2dfb722SXin LI 			if (OFFSET_OOB(nbytes, offset, m->vallen))
1780a2dfb722SXin LI 				return 0;
1781898496eeSXin LI 			if(do_ops(ms, m, &offset,
1782898496eeSXin LI 			    SEXT(sgn,64,strtoull(p->s, NULL, 8)), off))
1783898496eeSXin LI 				return 0;
1784a2dfb722SXin LI 			break;
17852dc4dbb9SEitan Adler 		default:
17862726a701SXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
17872726a701SXin LI 				fprintf(stderr, "bad in_type=%d\n", in_type);
17882726a701SXin LI 			return 0;
1789b6cee71dSXin LI 		}
1790b6cee71dSXin LI 
1791b6cee71dSXin LI 		if (m->flag & INDIROFFADD) {
17922726a701SXin LI 			if (cont_level == 0) {
17932726a701SXin LI 				if ((ms->flags & MAGIC_DEBUG) != 0)
17942726a701SXin LI 					fprintf(stderr,
17952726a701SXin LI 					    "indirect *zero* cont_level\n");
17962726a701SXin LI 				return 0;
17972726a701SXin LI 			}
1798b6cee71dSXin LI 			offset += ms->c.li[cont_level - 1].off;
1799b6cee71dSXin LI 			if (offset == 0) {
1800b6cee71dSXin LI 				if ((ms->flags & MAGIC_DEBUG) != 0)
1801b6cee71dSXin LI 					fprintf(stderr,
1802b6cee71dSXin LI 					    "indirect *zero* offset\n");
1803b6cee71dSXin LI 				return 0;
1804b6cee71dSXin LI 			}
1805b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
1806b6cee71dSXin LI 				fprintf(stderr, "indirect +offs=%u\n", offset);
1807b6cee71dSXin LI 		}
1808b6cee71dSXin LI 		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1809b6cee71dSXin LI 			return -1;
1810b6cee71dSXin LI 		ms->offset = offset;
1811b6cee71dSXin LI 
1812b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0) {
181348c779cdSXin LI 			mdebug(offset, RCAST(char *, RCAST(void *, p)),
1814b6cee71dSXin LI 			    sizeof(union VALUETYPE));
1815b6cee71dSXin LI #ifndef COMPILE_ONLY
1816b6cee71dSXin LI 			file_mdump(m);
1817b6cee71dSXin LI #endif
1818b6cee71dSXin LI 		}
1819b6cee71dSXin LI 	}
1820b6cee71dSXin LI 
1821b6cee71dSXin LI 	/* Verify we have enough data to match magic type */
1822b6cee71dSXin LI 	switch (m->type) {
1823b6cee71dSXin LI 	case FILE_BYTE:
1824b6cee71dSXin LI 		if (OFFSET_OOB(nbytes, offset, 1))
1825b6cee71dSXin LI 			return 0;
1826b6cee71dSXin LI 		break;
1827b6cee71dSXin LI 
1828b6cee71dSXin LI 	case FILE_SHORT:
1829b6cee71dSXin LI 	case FILE_BESHORT:
1830b6cee71dSXin LI 	case FILE_LESHORT:
1831b6cee71dSXin LI 		if (OFFSET_OOB(nbytes, offset, 2))
1832b6cee71dSXin LI 			return 0;
1833b6cee71dSXin LI 		break;
1834b6cee71dSXin LI 
1835b6cee71dSXin LI 	case FILE_LONG:
1836b6cee71dSXin LI 	case FILE_BELONG:
1837b6cee71dSXin LI 	case FILE_LELONG:
1838b6cee71dSXin LI 	case FILE_MELONG:
1839b6cee71dSXin LI 	case FILE_DATE:
1840b6cee71dSXin LI 	case FILE_BEDATE:
1841b6cee71dSXin LI 	case FILE_LEDATE:
1842b6cee71dSXin LI 	case FILE_MEDATE:
1843b6cee71dSXin LI 	case FILE_LDATE:
1844b6cee71dSXin LI 	case FILE_BELDATE:
1845b6cee71dSXin LI 	case FILE_LELDATE:
1846b6cee71dSXin LI 	case FILE_MELDATE:
1847b6cee71dSXin LI 	case FILE_FLOAT:
1848b6cee71dSXin LI 	case FILE_BEFLOAT:
1849b6cee71dSXin LI 	case FILE_LEFLOAT:
1850b6cee71dSXin LI 		if (OFFSET_OOB(nbytes, offset, 4))
1851b6cee71dSXin LI 			return 0;
1852b6cee71dSXin LI 		break;
1853b6cee71dSXin LI 
1854b6cee71dSXin LI 	case FILE_DOUBLE:
1855b6cee71dSXin LI 	case FILE_BEDOUBLE:
1856b6cee71dSXin LI 	case FILE_LEDOUBLE:
1857b6cee71dSXin LI 		if (OFFSET_OOB(nbytes, offset, 8))
1858b6cee71dSXin LI 			return 0;
1859b6cee71dSXin LI 		break;
1860b6cee71dSXin LI 
18612726a701SXin LI 	case FILE_GUID:
18622726a701SXin LI 		if (OFFSET_OOB(nbytes, offset, 16))
18632726a701SXin LI 			return 0;
18642726a701SXin LI 		break;
18652726a701SXin LI 
1866b6cee71dSXin LI 	case FILE_STRING:
1867b6cee71dSXin LI 	case FILE_PSTRING:
1868b6cee71dSXin LI 	case FILE_SEARCH:
1869a2dfb722SXin LI 	case FILE_OCTAL:
1870b6cee71dSXin LI 		if (OFFSET_OOB(nbytes, offset, m->vallen))
1871b6cee71dSXin LI 			return 0;
1872b6cee71dSXin LI 		break;
1873b6cee71dSXin LI 
1874b6cee71dSXin LI 	case FILE_REGEX:
1875b6cee71dSXin LI 		if (nbytes < offset)
1876b6cee71dSXin LI 			return 0;
1877b6cee71dSXin LI 		break;
1878b6cee71dSXin LI 
1879b6cee71dSXin LI 	case FILE_INDIRECT:
18804460e5b0SXin LI 		if (m->str_flags & INDIRECT_RELATIVE)
18815f0216bdSXin LI 			offset += CAST(uint32_t, o);
1882b6cee71dSXin LI 		if (offset == 0)
1883b6cee71dSXin LI 			return 0;
18842c4f1647SXin LI 
1885b6cee71dSXin LI 		if (nbytes < offset)
1886b6cee71dSXin LI 			return 0;
18872c4f1647SXin LI 
18882c4f1647SXin LI 		if ((pb = file_push_buffer(ms)) == NULL)
18892c4f1647SXin LI 			return -1;
18902c4f1647SXin LI 
18913e41d09dSXin LI 		(*indir_count)++;
189258a0f0d0SEitan Adler 		bb = *b;
189358a0f0d0SEitan Adler 		bb.fbuf = s + offset;
189458a0f0d0SEitan Adler 		bb.flen = nbytes - offset;
1895898496eeSXin LI 		bb.ebuf = NULL;
1896898496eeSXin LI 		bb.elen = 0;
1897a4d6d3b8SXin LI 		rv = -1;
189843a5ec4eSXin LI 		for (mlp = ms->mlist[0]->next; mlp != ms->mlist[0];
189943a5ec4eSXin LI 		    mlp = mlp->next)
190043a5ec4eSXin LI 		{
1901a4d6d3b8SXin LI 			if ((rv = match(ms, mlp->magic, mlp->magic_rxcomp,
1902a4d6d3b8SXin LI 			    mlp->nmagic, &bb, 0, BINTEST, text, 0, indir_count,
1903a2dfb722SXin LI 			    name_count, printed_something, need_separator,
1904898496eeSXin LI 			    firstline, NULL, NULL)) != 0)
190543a5ec4eSXin LI 				break;
190643a5ec4eSXin LI 		}
1907898496eeSXin LI 		buffer_fini(&bb);
19082c4f1647SXin LI 
1909b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
1910b6cee71dSXin LI 			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
19112c4f1647SXin LI 
19122c4f1647SXin LI 		rbuf = file_pop_buffer(ms, pb);
19132c4f1647SXin LI 		if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
19142c4f1647SXin LI 			return -1;
19152c4f1647SXin LI 
1916b6cee71dSXin LI 		if (rv == 1) {
19175f0216bdSXin LI 			if ((ms->flags & MAGIC_NODESC) == 0 &&
191848c779cdSXin LI 			    file_printf(ms, F(ms, m->desc, "%u"), offset) == -1)
191948c779cdSXin LI 			{
1920b6cee71dSXin LI 				free(rbuf);
1921b6cee71dSXin LI 				return -1;
1922b6cee71dSXin LI 			}
1923b6cee71dSXin LI 			if (file_printf(ms, "%s", rbuf) == -1) {
1924b6cee71dSXin LI 				free(rbuf);
1925b6cee71dSXin LI 				return -1;
1926b6cee71dSXin LI 			}
1927b6cee71dSXin LI 		}
1928b6cee71dSXin LI 		free(rbuf);
1929b6cee71dSXin LI 		return rv;
1930b6cee71dSXin LI 
1931b6cee71dSXin LI 	case FILE_USE:
1932b6cee71dSXin LI 		if (nbytes < offset)
1933b6cee71dSXin LI 			return 0;
19342c4f1647SXin LI 		rbuf = m->value.s;
19352c4f1647SXin LI 		if (*rbuf == '^') {
19362c4f1647SXin LI 			rbuf++;
1937b6cee71dSXin LI 			flip = !flip;
1938b6cee71dSXin LI 		}
19392c4f1647SXin LI 		if (file_magicfind(ms, rbuf, &ml) == -1) {
19402c4f1647SXin LI 			file_error(ms, 0, "cannot find entry `%s'", rbuf);
1941b6cee71dSXin LI 			return -1;
1942b6cee71dSXin LI 		}
194343a5ec4eSXin LI 		if (save_cont(ms, &c) == -1) {
194443a5ec4eSXin LI 			file_error(ms, errno, "can't allocate continuation");
194543a5ec4eSXin LI 			return -1;
194643a5ec4eSXin LI 		}
194743a5ec4eSXin LI 
1948b6cee71dSXin LI 		oneed_separator = *need_separator;
1949b6cee71dSXin LI 		if (m->flag & NOSPACE)
1950b6cee71dSXin LI 			*need_separator = 0;
195143a5ec4eSXin LI 
195243a5ec4eSXin LI 		nfound_match = 0;
195343a5ec4eSXin LI 		(*name_count)++;
195443a5ec4eSXin LI 		eoffset = ms->eoffset;
1955a4d6d3b8SXin LI 		rv = match(ms, ml.magic, ml.magic_rxcomp, ml.nmagic, b,
1956a4d6d3b8SXin LI 		    offset + o, mode, text, flip, indir_count, name_count,
1957898496eeSXin LI 		    printed_something, need_separator, firstline, returnval,
195843a5ec4eSXin LI 		    &nfound_match);
195943a5ec4eSXin LI 		ms->ms_value.q = nfound_match;
196048c779cdSXin LI 		(*name_count)--;
196143a5ec4eSXin LI 		*found_match |= nfound_match;
196243a5ec4eSXin LI 
196343a5ec4eSXin LI 		restore_cont(ms, &c);
196443a5ec4eSXin LI 
1965b6cee71dSXin LI 		if (rv != 1)
1966b6cee71dSXin LI 		    *need_separator = oneed_separator;
196743a5ec4eSXin LI 		ms->offset = offset;
196843a5ec4eSXin LI 		ms->eoffset = eoffset;
1969898496eeSXin LI 		return rv || *found_match;
1970b6cee71dSXin LI 
1971b6cee71dSXin LI 	case FILE_NAME:
19725f0216bdSXin LI 		if (ms->flags & MAGIC_NODESC)
19735f0216bdSXin LI 			return 1;
1974b6cee71dSXin LI 		if (file_printf(ms, "%s", m->desc) == -1)
1975b6cee71dSXin LI 			return -1;
1976b6cee71dSXin LI 		return 1;
19773e41d09dSXin LI 	case FILE_DER:
1978b6cee71dSXin LI 	case FILE_DEFAULT:	/* nothing to check */
1979b6cee71dSXin LI 	case FILE_CLEAR:
1980b6cee71dSXin LI 	default:
1981b6cee71dSXin LI 		break;
1982b6cee71dSXin LI 	}
1983b6cee71dSXin LI 	if (!mconvert(ms, m, flip))
1984b6cee71dSXin LI 		return 0;
1985b6cee71dSXin LI 	return 1;
1986b6cee71dSXin LI }
1987b6cee71dSXin LI 
1988898496eeSXin LI file_private uint64_t
file_strncmp(const char * s1,const char * s2,size_t len,size_t maxlen,uint32_t flags)19892726a701SXin LI file_strncmp(const char *s1, const char *s2, size_t len, size_t maxlen,
19902726a701SXin LI     uint32_t flags)
1991b6cee71dSXin LI {
1992b6cee71dSXin LI 	/*
1993b6cee71dSXin LI 	 * Convert the source args to unsigned here so that (1) the
1994b6cee71dSXin LI 	 * compare will be unsigned as it is in strncmp() and (2) so
1995b6cee71dSXin LI 	 * the ctype functions will work correctly without extra
1996b6cee71dSXin LI 	 * casting.
1997b6cee71dSXin LI 	 */
199848c779cdSXin LI 	const unsigned char *a = RCAST(const unsigned char *, s1);
199948c779cdSXin LI 	const unsigned char *b = RCAST(const unsigned char *, s2);
20002726a701SXin LI 	uint32_t ws = flags & (STRING_COMPACT_WHITESPACE |
20012726a701SXin LI 	    STRING_COMPACT_OPTIONAL_WHITESPACE);
20022726a701SXin LI 	const unsigned char *eb = b + (ws ? maxlen : len);
2003b6cee71dSXin LI 	uint64_t v;
2004b6cee71dSXin LI 
2005b6cee71dSXin LI 	/*
2006b6cee71dSXin LI 	 * What we want here is v = strncmp(s1, s2, len),
2007b6cee71dSXin LI 	 * but ignoring any nulls.
2008b6cee71dSXin LI 	 */
2009b6cee71dSXin LI 	v = 0;
201043a5ec4eSXin LI 	len++;
2011b6cee71dSXin LI 	if (0L == flags) { /* normal string: do it fast */
201243a5ec4eSXin LI 		while (--len > 0)
2013b6cee71dSXin LI 			if ((v = *b++ - *a++) != '\0')
2014b6cee71dSXin LI 				break;
2015b6cee71dSXin LI 	}
2016b6cee71dSXin LI 	else { /* combine the others */
201743a5ec4eSXin LI 		while (--len > 0) {
201840427ccaSGordon Tetlow 			if (b >= eb) {
201940427ccaSGordon Tetlow 				v = 1;
202040427ccaSGordon Tetlow 				break;
202140427ccaSGordon Tetlow 			}
2022b6cee71dSXin LI 			if ((flags & STRING_IGNORE_LOWERCASE) &&
2023b6cee71dSXin LI 			    islower(*a)) {
2024b6cee71dSXin LI 				if ((v = tolower(*b++) - *a++) != '\0')
2025b6cee71dSXin LI 					break;
2026b6cee71dSXin LI 			}
2027b6cee71dSXin LI 			else if ((flags & STRING_IGNORE_UPPERCASE) &&
2028b6cee71dSXin LI 			    isupper(*a)) {
2029b6cee71dSXin LI 				if ((v = toupper(*b++) - *a++) != '\0')
2030b6cee71dSXin LI 					break;
2031b6cee71dSXin LI 			}
2032b6cee71dSXin LI 			else if ((flags & STRING_COMPACT_WHITESPACE) &&
2033b6cee71dSXin LI 			    isspace(*a)) {
2034b6cee71dSXin LI 				a++;
203543a5ec4eSXin LI 				if (isspace(*b)) {
203643a5ec4eSXin LI 					b++;
2037b6cee71dSXin LI 					if (!isspace(*a))
203840427ccaSGordon Tetlow 						while (b < eb && isspace(*b))
2039b6cee71dSXin LI 							b++;
2040b6cee71dSXin LI 				}
2041b6cee71dSXin LI 				else {
2042b6cee71dSXin LI 					v = 1;
2043b6cee71dSXin LI 					break;
2044b6cee71dSXin LI 				}
2045b6cee71dSXin LI 			}
2046b6cee71dSXin LI 			else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
2047b6cee71dSXin LI 			    isspace(*a)) {
2048b6cee71dSXin LI 				a++;
204940427ccaSGordon Tetlow 				while (b < eb && isspace(*b))
2050b6cee71dSXin LI 					b++;
2051b6cee71dSXin LI 			}
2052b6cee71dSXin LI 			else {
2053b6cee71dSXin LI 				if ((v = *b++ - *a++) != '\0')
2054b6cee71dSXin LI 					break;
2055b6cee71dSXin LI 			}
2056b6cee71dSXin LI 		}
205743a5ec4eSXin LI 		if (len == 0 && v == 0 && (flags & STRING_FULL_WORD)) {
205843a5ec4eSXin LI 			if (*b && !isspace(*b))
205943a5ec4eSXin LI 				v = 1;
206043a5ec4eSXin LI 		}
2061b6cee71dSXin LI 	}
2062b6cee71dSXin LI 	return v;
2063b6cee71dSXin LI }
2064b6cee71dSXin LI 
2065898496eeSXin LI file_private uint64_t
file_strncmp16(const char * a,const char * b,size_t len,size_t maxlen,uint32_t flags)20662726a701SXin LI file_strncmp16(const char *a, const char *b, size_t len, size_t maxlen,
20672726a701SXin LI     uint32_t flags)
2068b6cee71dSXin LI {
2069b6cee71dSXin LI 	/*
2070b6cee71dSXin LI 	 * XXX - The 16-bit string compare probably needs to be done
2071b6cee71dSXin LI 	 * differently, especially if the flags are to be supported.
2072b6cee71dSXin LI 	 * At the moment, I am unsure.
2073b6cee71dSXin LI 	 */
2074b6cee71dSXin LI 	flags = 0;
20752726a701SXin LI 	return file_strncmp(a, b, len, maxlen, flags);
2076b6cee71dSXin LI }
2077b6cee71dSXin LI 
2078898496eeSXin LI file_private file_regex_t *
alloc_regex(struct magic_set * ms,struct magic * m)2079a4d6d3b8SXin LI alloc_regex(struct magic_set *ms, struct magic *m)
2080a4d6d3b8SXin LI {
2081a4d6d3b8SXin LI 	int rc;
2082a4d6d3b8SXin LI 	file_regex_t *rx = CAST(file_regex_t *, malloc(sizeof(*rx)));
2083a4d6d3b8SXin LI 
2084a4d6d3b8SXin LI 	if (rx == NULL) {
2085a4d6d3b8SXin LI 		file_error(ms, errno, "can't allocate %" SIZE_T_FORMAT
2086a4d6d3b8SXin LI 		    "u bytes", sizeof(*rx));
2087a4d6d3b8SXin LI 		return NULL;
2088a4d6d3b8SXin LI 	}
2089a4d6d3b8SXin LI 
2090a4d6d3b8SXin LI 	rc = file_regcomp(ms, rx, m->value.s, REG_EXTENDED | REG_NEWLINE |
2091a4d6d3b8SXin LI 	    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
2092a4d6d3b8SXin LI 	if (rc == 0)
2093a4d6d3b8SXin LI 		return rx;
2094a4d6d3b8SXin LI 
2095a4d6d3b8SXin LI 	free(rx);
2096a4d6d3b8SXin LI 	return NULL;
2097a4d6d3b8SXin LI }
2098a4d6d3b8SXin LI 
2099898496eeSXin LI file_private int
magiccheck(struct magic_set * ms,struct magic * m,file_regex_t ** m_cache)2100a4d6d3b8SXin LI magiccheck(struct magic_set *ms, struct magic *m, file_regex_t **m_cache)
2101b6cee71dSXin LI {
2102b6cee71dSXin LI 	uint64_t l = m->value.q;
2103b6cee71dSXin LI 	uint64_t v;
2104b6cee71dSXin LI 	float fl, fv;
2105b6cee71dSXin LI 	double dl, dv;
2106b6cee71dSXin LI 	int matched;
2107b6cee71dSXin LI 	union VALUETYPE *p = &ms->ms_value;
2108b6cee71dSXin LI 
2109b6cee71dSXin LI 	switch (m->type) {
2110b6cee71dSXin LI 	case FILE_BYTE:
2111b6cee71dSXin LI 		v = p->b;
2112b6cee71dSXin LI 		break;
2113b6cee71dSXin LI 
2114b6cee71dSXin LI 	case FILE_SHORT:
2115b6cee71dSXin LI 	case FILE_BESHORT:
2116b6cee71dSXin LI 	case FILE_LESHORT:
2117a4d6d3b8SXin LI 	case FILE_MSDOSDATE:
2118a4d6d3b8SXin LI 	case FILE_LEMSDOSDATE:
2119a4d6d3b8SXin LI 	case FILE_BEMSDOSDATE:
2120a4d6d3b8SXin LI 	case FILE_MSDOSTIME:
2121a4d6d3b8SXin LI 	case FILE_LEMSDOSTIME:
2122a4d6d3b8SXin LI 	case FILE_BEMSDOSTIME:
2123b6cee71dSXin LI 		v = p->h;
2124b6cee71dSXin LI 		break;
2125b6cee71dSXin LI 
2126b6cee71dSXin LI 	case FILE_LONG:
2127b6cee71dSXin LI 	case FILE_BELONG:
2128b6cee71dSXin LI 	case FILE_LELONG:
2129b6cee71dSXin LI 	case FILE_MELONG:
2130b6cee71dSXin LI 	case FILE_DATE:
2131b6cee71dSXin LI 	case FILE_BEDATE:
2132b6cee71dSXin LI 	case FILE_LEDATE:
2133b6cee71dSXin LI 	case FILE_MEDATE:
2134b6cee71dSXin LI 	case FILE_LDATE:
2135b6cee71dSXin LI 	case FILE_BELDATE:
2136b6cee71dSXin LI 	case FILE_LELDATE:
2137b6cee71dSXin LI 	case FILE_MELDATE:
2138b6cee71dSXin LI 		v = p->l;
2139b6cee71dSXin LI 		break;
2140b6cee71dSXin LI 
2141b6cee71dSXin LI 	case FILE_QUAD:
2142b6cee71dSXin LI 	case FILE_LEQUAD:
2143b6cee71dSXin LI 	case FILE_BEQUAD:
2144b6cee71dSXin LI 	case FILE_QDATE:
2145b6cee71dSXin LI 	case FILE_BEQDATE:
2146b6cee71dSXin LI 	case FILE_LEQDATE:
2147b6cee71dSXin LI 	case FILE_QLDATE:
2148b6cee71dSXin LI 	case FILE_BEQLDATE:
2149b6cee71dSXin LI 	case FILE_LEQLDATE:
2150b6cee71dSXin LI 	case FILE_QWDATE:
2151b6cee71dSXin LI 	case FILE_BEQWDATE:
2152b6cee71dSXin LI 	case FILE_LEQWDATE:
21532726a701SXin LI 	case FILE_OFFSET:
2154b6cee71dSXin LI 		v = p->q;
2155b6cee71dSXin LI 		break;
2156b6cee71dSXin LI 
2157b6cee71dSXin LI 	case FILE_FLOAT:
2158b6cee71dSXin LI 	case FILE_BEFLOAT:
2159b6cee71dSXin LI 	case FILE_LEFLOAT:
2160b6cee71dSXin LI 		fl = m->value.f;
2161b6cee71dSXin LI 		fv = p->f;
2162b6cee71dSXin LI 		switch (m->reln) {
2163b6cee71dSXin LI 		case 'x':
2164b6cee71dSXin LI 			matched = 1;
2165b6cee71dSXin LI 			break;
2166b6cee71dSXin LI 
2167b6cee71dSXin LI 		case '!':
2168898496eeSXin LI 			matched = isunordered(fl, fv) ? 1 : fv != fl;
2169b6cee71dSXin LI 			break;
2170b6cee71dSXin LI 
2171b6cee71dSXin LI 		case '=':
2172898496eeSXin LI 			matched = isunordered(fl, fv) ? 0 : fv == fl;
2173b6cee71dSXin LI 			break;
2174b6cee71dSXin LI 
2175b6cee71dSXin LI 		case '>':
2176898496eeSXin LI 			matched = isgreater(fv, fl);
2177b6cee71dSXin LI 			break;
2178b6cee71dSXin LI 
2179b6cee71dSXin LI 		case '<':
2180898496eeSXin LI 			matched = isless(fv, fl);
2181b6cee71dSXin LI 			break;
2182b6cee71dSXin LI 
2183b6cee71dSXin LI 		default:
2184a4d6d3b8SXin LI 			file_magerror(ms, "cannot happen with float: "
2185a4d6d3b8SXin LI 			    "invalid relation `%c'", m->reln);
2186b6cee71dSXin LI 			return -1;
2187b6cee71dSXin LI 		}
2188b6cee71dSXin LI 		return matched;
2189b6cee71dSXin LI 
2190b6cee71dSXin LI 	case FILE_DOUBLE:
2191b6cee71dSXin LI 	case FILE_BEDOUBLE:
2192b6cee71dSXin LI 	case FILE_LEDOUBLE:
2193b6cee71dSXin LI 		dl = m->value.d;
2194b6cee71dSXin LI 		dv = p->d;
2195b6cee71dSXin LI 		switch (m->reln) {
2196b6cee71dSXin LI 		case 'x':
2197b6cee71dSXin LI 			matched = 1;
2198b6cee71dSXin LI 			break;
2199b6cee71dSXin LI 
2200b6cee71dSXin LI 		case '!':
2201898496eeSXin LI 			matched = isunordered(dv, dl) ? 1 : dv != dl;
2202b6cee71dSXin LI 			break;
2203b6cee71dSXin LI 
2204b6cee71dSXin LI 		case '=':
2205898496eeSXin LI 			matched = isunordered(dv, dl) ? 0 : dv == dl;
2206b6cee71dSXin LI 			break;
2207b6cee71dSXin LI 
2208b6cee71dSXin LI 		case '>':
2209898496eeSXin LI 			matched = isgreater(dv, dl);
2210b6cee71dSXin LI 			break;
2211b6cee71dSXin LI 
2212b6cee71dSXin LI 		case '<':
2213898496eeSXin LI 			matched = isless(dv, dl);
2214b6cee71dSXin LI 			break;
2215b6cee71dSXin LI 
2216b6cee71dSXin LI 		default:
2217a4d6d3b8SXin LI 			file_magerror(ms, "cannot happen with double: "
2218a4d6d3b8SXin LI 			    "invalid relation `%c'", m->reln);
2219b6cee71dSXin LI 			return -1;
2220b6cee71dSXin LI 		}
2221b6cee71dSXin LI 		return matched;
2222b6cee71dSXin LI 
2223b6cee71dSXin LI 	case FILE_DEFAULT:
2224b6cee71dSXin LI 	case FILE_CLEAR:
2225b6cee71dSXin LI 		l = 0;
2226b6cee71dSXin LI 		v = 0;
2227b6cee71dSXin LI 		break;
2228b6cee71dSXin LI 
2229b6cee71dSXin LI 	case FILE_STRING:
2230b6cee71dSXin LI 	case FILE_PSTRING:
2231a2dfb722SXin LI 	case FILE_OCTAL:
2232b6cee71dSXin LI 		l = 0;
223348c779cdSXin LI 		v = file_strncmp(m->value.s, p->s, CAST(size_t, m->vallen),
22342726a701SXin LI 		    sizeof(p->s), m->str_flags);
2235b6cee71dSXin LI 		break;
2236b6cee71dSXin LI 
2237b6cee71dSXin LI 	case FILE_BESTRING16:
2238b6cee71dSXin LI 	case FILE_LESTRING16:
2239b6cee71dSXin LI 		l = 0;
224048c779cdSXin LI 		v = file_strncmp16(m->value.s, p->s, CAST(size_t, m->vallen),
22412726a701SXin LI 		    sizeof(p->s), m->str_flags);
2242b6cee71dSXin LI 		break;
2243b6cee71dSXin LI 
2244b6cee71dSXin LI 	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
2245b6cee71dSXin LI 		size_t slen;
2246b6cee71dSXin LI 		size_t idx;
2247b6cee71dSXin LI 
2248b6cee71dSXin LI 		if (ms->search.s == NULL)
2249b6cee71dSXin LI 			return 0;
2250b6cee71dSXin LI 
2251b6cee71dSXin LI 		slen = MIN(m->vallen, sizeof(m->value.s));
2252b6cee71dSXin LI 		l = 0;
2253b6cee71dSXin LI 		v = 0;
2254898496eeSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0) {
2255898496eeSXin LI 			size_t xlen = ms->search.s_len > 100 ? 100
2256898496eeSXin LI 			    : ms->search.s_len;
2257898496eeSXin LI 
2258898496eeSXin LI 			fprintf(stderr, "search: [");
2259898496eeSXin LI 			file_showstr(stderr, ms->search.s, xlen);
2260898496eeSXin LI 			fprintf(stderr, "%s] for [", ms->search.s_len == xlen
2261898496eeSXin LI 			    ? "" : "...");
2262898496eeSXin LI 			file_showstr(stderr, m->value.s, slen);
2263898496eeSXin LI 		}
226448c779cdSXin LI #ifdef HAVE_MEMMEM
226548c779cdSXin LI 		if (slen > 0 && m->str_flags == 0) {
226648c779cdSXin LI 			const char *found;
226748c779cdSXin LI 			idx = m->str_range + slen;
226848c779cdSXin LI 			if (m->str_range == 0 || ms->search.s_len < idx)
226948c779cdSXin LI 				idx = ms->search.s_len;
227048c779cdSXin LI 			found = CAST(const char *, memmem(ms->search.s, idx,
227148c779cdSXin LI 			    m->value.s, slen));
2272898496eeSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0) {
2273898496eeSXin LI 				fprintf(stderr, "] %sfound\n",
2274898496eeSXin LI 				    found ? "" : "not ");
2275898496eeSXin LI 			}
227643a5ec4eSXin LI 			if (!found) {
227743a5ec4eSXin LI 				v = 1;
227843a5ec4eSXin LI 				break;
227943a5ec4eSXin LI 			}
228048c779cdSXin LI 			idx = found - ms->search.s;
228148c779cdSXin LI 			ms->search.offset += idx;
228248c779cdSXin LI 			ms->search.rm_len = ms->search.s_len - idx;
228348c779cdSXin LI 			break;
228448c779cdSXin LI 		}
228548c779cdSXin LI #endif
2286b6cee71dSXin LI 
2287b6cee71dSXin LI 		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
228843a5ec4eSXin LI 			if (slen + idx > ms->search.s_len) {
228943a5ec4eSXin LI 				v = 1;
229043a5ec4eSXin LI 				break;
229143a5ec4eSXin LI 			}
2292b6cee71dSXin LI 
2293b6cee71dSXin LI 			v = file_strncmp(m->value.s, ms->search.s + idx, slen,
22942726a701SXin LI 			    ms->search.s_len - idx, m->str_flags);
2295b6cee71dSXin LI 			if (v == 0) {	/* found match */
2296b6cee71dSXin LI 				ms->search.offset += idx;
229740427ccaSGordon Tetlow 				ms->search.rm_len = ms->search.s_len - idx;
2298b6cee71dSXin LI 				break;
2299b6cee71dSXin LI 			}
2300b6cee71dSXin LI 		}
2301898496eeSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0) {
2302898496eeSXin LI 			fprintf(stderr, "] %sfound\n", v == 0 ? "" : "not ");
2303898496eeSXin LI 		}
2304b6cee71dSXin LI 		break;
2305b6cee71dSXin LI 	}
2306b6cee71dSXin LI 	case FILE_REGEX: {
2307b6cee71dSXin LI 		int rc;
2308a4d6d3b8SXin LI 		file_regex_t *rx = *m_cache;
2309c2931133SXin LI 		const char *search;
2310a4d6d3b8SXin LI 		regmatch_t pmatch;
2311a4d6d3b8SXin LI 		size_t slen = ms->search.s_len;
2312a4d6d3b8SXin LI 		char *copy;
2313b6cee71dSXin LI 
2314b6cee71dSXin LI 		if (ms->search.s == NULL)
2315b6cee71dSXin LI 			return 0;
2316b6cee71dSXin LI 
2317a4d6d3b8SXin LI 		if (rx == NULL) {
2318a4d6d3b8SXin LI 			rx = *m_cache = alloc_regex(ms, m);
2319a4d6d3b8SXin LI 			if (rx == NULL)
2320a4d6d3b8SXin LI 				return -1;
2321a4d6d3b8SXin LI 		}
2322b6cee71dSXin LI 		l = 0;
2323c2931133SXin LI 		if (slen != 0) {
2324a5d223e6SXin LI 		    copy = CAST(char *, malloc(slen));
2325c2931133SXin LI 		    if (copy == NULL)  {
2326c2931133SXin LI 			file_error(ms, errno,
2327c2931133SXin LI 			    "can't allocate %" SIZE_T_FORMAT "u bytes",
2328c2931133SXin LI 			    slen);
2329c2931133SXin LI 			return -1;
2330c2931133SXin LI 		    }
2331c2931133SXin LI 		    memcpy(copy, ms->search.s, slen);
2332c2931133SXin LI 		    copy[--slen] = '\0';
2333c2931133SXin LI 		    search = copy;
2334c2931133SXin LI 		} else {
233540427ccaSGordon Tetlow 		    search = CCAST(char *, "");
2336c2931133SXin LI 		    copy = NULL;
2337c2931133SXin LI 		}
2338a4d6d3b8SXin LI 		rc = file_regexec(ms, rx, RCAST(const char *, search),
23393e41d09dSXin LI 		    1, &pmatch, 0);
2340c2931133SXin LI 		free(copy);
2341b6cee71dSXin LI 		switch (rc) {
2342b6cee71dSXin LI 		case 0:
234348c779cdSXin LI 			ms->search.s += CAST(int, pmatch.rm_so);
234448c779cdSXin LI 			ms->search.offset += CAST(size_t, pmatch.rm_so);
234548c779cdSXin LI 			ms->search.rm_len = CAST(size_t,
234648c779cdSXin LI 			    pmatch.rm_eo - pmatch.rm_so);
2347b6cee71dSXin LI 			v = 0;
2348b6cee71dSXin LI 			break;
2349b6cee71dSXin LI 
2350b6cee71dSXin LI 		case REG_NOMATCH:
2351b6cee71dSXin LI 			v = 1;
2352b6cee71dSXin LI 			break;
2353b6cee71dSXin LI 
2354b6cee71dSXin LI 		default:
2355a4d6d3b8SXin LI 			return -1;
2356b6cee71dSXin LI 		}
2357b6cee71dSXin LI 		break;
2358b6cee71dSXin LI 	}
2359b6cee71dSXin LI 	case FILE_USE:
236043a5ec4eSXin LI 		return ms->ms_value.q != 0;
2361b6cee71dSXin LI 	case FILE_NAME:
236243a5ec4eSXin LI 	case FILE_INDIRECT:
2363b6cee71dSXin LI 		return 1;
23643e41d09dSXin LI 	case FILE_DER:
23653e41d09dSXin LI 		matched = der_cmp(ms, m);
236653021c7eSXin LI 		if (matched == -1) {
236753021c7eSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0) {
236853021c7eSXin LI 				(void) fprintf(stderr,
2369a2dfb722SXin LI 				    "EOF comparing DER entries\n");
237053021c7eSXin LI 			}
237153021c7eSXin LI 			return 0;
237253021c7eSXin LI 		}
23733e41d09dSXin LI 		return matched;
23742726a701SXin LI 	case FILE_GUID:
23752726a701SXin LI 		l = 0;
23762726a701SXin LI 		v = memcmp(m->value.guid, p->guid, sizeof(p->guid));
23772726a701SXin LI 		break;
2378b6cee71dSXin LI 	default:
2379b6cee71dSXin LI 		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2380b6cee71dSXin LI 		return -1;
2381b6cee71dSXin LI 	}
2382b6cee71dSXin LI 
2383b6cee71dSXin LI 	v = file_signextend(ms, m, v);
2384b6cee71dSXin LI 
2385b6cee71dSXin LI 	switch (m->reln) {
2386b6cee71dSXin LI 	case 'x':
2387b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
2388b6cee71dSXin LI 			(void) fprintf(stderr, "%" INT64_T_FORMAT
2389898496eeSXin LI 			    "u == *any* = 1", CAST(unsigned long long, v));
2390b6cee71dSXin LI 		matched = 1;
2391b6cee71dSXin LI 		break;
2392b6cee71dSXin LI 
2393b6cee71dSXin LI 	case '!':
2394b6cee71dSXin LI 		matched = v != l;
2395b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
2396b6cee71dSXin LI 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2397898496eeSXin LI 			    INT64_T_FORMAT "u = %d",
239848c779cdSXin LI 			    CAST(unsigned long long, v),
239948c779cdSXin LI 			    CAST(unsigned long long, l), matched);
2400b6cee71dSXin LI 		break;
2401b6cee71dSXin LI 
2402b6cee71dSXin LI 	case '=':
2403b6cee71dSXin LI 		matched = v == l;
2404b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
2405b6cee71dSXin LI 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2406898496eeSXin LI 			    INT64_T_FORMAT "u = %d",
240748c779cdSXin LI 			    CAST(unsigned long long, v),
240848c779cdSXin LI 			    CAST(unsigned long long, l), matched);
2409b6cee71dSXin LI 		break;
2410b6cee71dSXin LI 
2411b6cee71dSXin LI 	case '>':
2412b6cee71dSXin LI 		if (m->flag & UNSIGNED) {
2413b6cee71dSXin LI 			matched = v > l;
2414b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
2415b6cee71dSXin LI 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2416898496eeSXin LI 				    "u > %" INT64_T_FORMAT "u = %d",
241748c779cdSXin LI 				    CAST(unsigned long long, v),
241848c779cdSXin LI 				    CAST(unsigned long long, l), matched);
2419b6cee71dSXin LI 		}
2420b6cee71dSXin LI 		else {
242148c779cdSXin LI 			matched = CAST(int64_t, v) > CAST(int64_t, l);
2422b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
2423b6cee71dSXin LI 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2424898496eeSXin LI 				    "d > %" INT64_T_FORMAT "d = %d",
242548c779cdSXin LI 				    CAST(long long, v),
242648c779cdSXin LI 				    CAST(long long, l), matched);
2427b6cee71dSXin LI 		}
2428b6cee71dSXin LI 		break;
2429b6cee71dSXin LI 
2430b6cee71dSXin LI 	case '<':
2431b6cee71dSXin LI 		if (m->flag & UNSIGNED) {
2432b6cee71dSXin LI 			matched = v < l;
2433b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
2434b6cee71dSXin LI 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2435898496eeSXin LI 				    "u < %" INT64_T_FORMAT "u = %d",
243648c779cdSXin LI 				    CAST(unsigned long long, v),
243748c779cdSXin LI 				    CAST(unsigned long long, l), matched);
2438b6cee71dSXin LI 		}
2439b6cee71dSXin LI 		else {
244048c779cdSXin LI 			matched = CAST(int64_t, v) < CAST(int64_t, l);
2441b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
2442b6cee71dSXin LI 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2443898496eeSXin LI 				    "d < %" INT64_T_FORMAT "d = %d",
244448c779cdSXin LI 				     CAST(long long, v),
244548c779cdSXin LI 				     CAST(long long, l), matched);
2446b6cee71dSXin LI 		}
2447b6cee71dSXin LI 		break;
2448b6cee71dSXin LI 
2449b6cee71dSXin LI 	case '&':
2450b6cee71dSXin LI 		matched = (v & l) == l;
2451b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
2452b6cee71dSXin LI 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2453b6cee71dSXin LI 			    INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2454898496eeSXin LI 			    "x) = %d", CAST(unsigned long long, v),
245548c779cdSXin LI 			    CAST(unsigned long long, l),
245648c779cdSXin LI 			    CAST(unsigned long long, l),
2457b6cee71dSXin LI 			    matched);
2458b6cee71dSXin LI 		break;
2459b6cee71dSXin LI 
2460b6cee71dSXin LI 	case '^':
2461b6cee71dSXin LI 		matched = (v & l) != l;
2462b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
2463b6cee71dSXin LI 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2464b6cee71dSXin LI 			    INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2465898496eeSXin LI 			    "x) = %d", CAST(unsigned long long, v),
246648c779cdSXin LI 			    CAST(unsigned long long, l),
246748c779cdSXin LI 			    CAST(unsigned long long, l), matched);
2468b6cee71dSXin LI 		break;
2469b6cee71dSXin LI 
2470b6cee71dSXin LI 	default:
2471b6cee71dSXin LI 		file_magerror(ms, "cannot happen: invalid relation `%c'",
2472b6cee71dSXin LI 		    m->reln);
2473b6cee71dSXin LI 		return -1;
2474b6cee71dSXin LI 	}
2475898496eeSXin LI 	if ((ms->flags & MAGIC_DEBUG) != 0) {
2476898496eeSXin LI 		(void) fprintf(stderr, " strength=%zu\n",
2477898496eeSXin LI 		    file_magic_strength(m, 1));
2478898496eeSXin LI 	}
2479b6cee71dSXin LI 
2480b6cee71dSXin LI 	return matched;
2481b6cee71dSXin LI }
2482b6cee71dSXin LI 
2483898496eeSXin LI file_private int
handle_annotation(struct magic_set * ms,struct magic * m,int firstline)24842dc4dbb9SEitan Adler handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
2485b6cee71dSXin LI {
24863e41d09dSXin LI 	if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
248748c779cdSXin LI 		if (print_sep(ms, firstline) == -1)
2488a5d223e6SXin LI 			return -1;
2489b6cee71dSXin LI 		if (file_printf(ms, "%.8s", m->apple) == -1)
2490b6cee71dSXin LI 			return -1;
2491b6cee71dSXin LI 		return 1;
2492b6cee71dSXin LI 	}
24933e41d09dSXin LI 	if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
249448c779cdSXin LI 		if (print_sep(ms, firstline) == -1)
2495a5d223e6SXin LI 			return -1;
24965f0216bdSXin LI 		if (file_printf(ms, "%s", m->ext) == -1)
24975f0216bdSXin LI 			return -1;
24985f0216bdSXin LI 		return 1;
24995f0216bdSXin LI 	}
2500b6cee71dSXin LI 	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
250158a0f0d0SEitan Adler 		char buf[1024];
250258a0f0d0SEitan Adler 		const char *p;
250348c779cdSXin LI 		if (print_sep(ms, firstline) == -1)
2504a5d223e6SXin LI 			return -1;
25052dc4dbb9SEitan Adler 		if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1)
250658a0f0d0SEitan Adler 			p = m->mimetype;
250758a0f0d0SEitan Adler 		else
250858a0f0d0SEitan Adler 			p = buf;
250958a0f0d0SEitan Adler 		if (file_printf(ms, "%s", p) == -1)
2510b6cee71dSXin LI 			return -1;
2511b6cee71dSXin LI 		return 1;
2512b6cee71dSXin LI 	}
2513b6cee71dSXin LI 	return 0;
2514b6cee71dSXin LI }
2515b6cee71dSXin LI 
2516898496eeSXin LI file_private int
print_sep(struct magic_set * ms,int firstline)2517b6cee71dSXin LI print_sep(struct magic_set *ms, int firstline)
2518b6cee71dSXin LI {
2519b6cee71dSXin LI 	if (firstline)
2520b6cee71dSXin LI 		return 0;
2521b6cee71dSXin LI 	/*
2522b6cee71dSXin LI 	 * we found another match
2523b6cee71dSXin LI 	 * put a newline and '-' to do some simple formatting
2524b6cee71dSXin LI 	 */
252548c779cdSXin LI 	return file_separator(ms);
2526b6cee71dSXin LI }
2527