xref: /freebsd/contrib/file/src/softmagic.c (revision 898496ee)
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
35898496eeSXin LI FILE_RCSID("@(#)$File: softmagic.c,v 1.345 2023/07/02 12:48:39 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 *);
59898496eeSXin LI file_private int moffset(struct magic_set *, struct magic *, const struct buffer *,
6058a0f0d0SEitan Adler     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) ( \
7448c779cdSXin LI     (CAST(uint64_t, (p)->hq[0])<<56)| \
7548c779cdSXin LI     (CAST(uint64_t, (p)->hq[1])<<48)| \
7648c779cdSXin LI     (CAST(uint64_t, (p)->hq[2])<<40)| \
7748c779cdSXin LI     (CAST(uint64_t, (p)->hq[3])<<32)| \
7848c779cdSXin LI     (CAST(uint64_t, (p)->hq[4])<<24)| \
7948c779cdSXin LI     (CAST(uint64_t, (p)->hq[5])<<16)| \
8048c779cdSXin LI     (CAST(uint64_t, (p)->hq[6])<<8)| \
8148c779cdSXin LI     (CAST(uint64_t, (p)->hq[7])))
8248c779cdSXin LI #define LE64(p) ( \
8348c779cdSXin LI     (CAST(uint64_t, (p)->hq[7])<<56)| \
8448c779cdSXin LI     (CAST(uint64_t, (p)->hq[6])<<48)| \
8548c779cdSXin LI     (CAST(uint64_t, (p)->hq[5])<<40)| \
8648c779cdSXin LI     (CAST(uint64_t, (p)->hq[4])<<32)| \
8748c779cdSXin LI     (CAST(uint64_t, (p)->hq[3])<<24)| \
8848c779cdSXin LI     (CAST(uint64_t, (p)->hq[2])<<16)| \
8948c779cdSXin LI     (CAST(uint64_t, (p)->hq[1])<<8)| \
9048c779cdSXin LI     (CAST(uint64_t, (p)->hq[0])))
9148c779cdSXin LI #define LE32(p) ( \
9248c779cdSXin LI     (CAST(uint32_t, (p)->hl[3])<<24)| \
9348c779cdSXin LI     (CAST(uint32_t, (p)->hl[2])<<16)| \
9448c779cdSXin LI     (CAST(uint32_t, (p)->hl[1])<<8)| \
9548c779cdSXin LI     (CAST(uint32_t, (p)->hl[0])))
9648c779cdSXin LI #define BE32(p) ( \
9748c779cdSXin LI     (CAST(uint32_t, (p)->hl[0])<<24)| \
9848c779cdSXin LI     (CAST(uint32_t, (p)->hl[1])<<16)| \
9948c779cdSXin LI     (CAST(uint32_t, (p)->hl[2])<<8)| \
10048c779cdSXin LI     (CAST(uint32_t, (p)->hl[3])))
10148c779cdSXin LI #define ME32(p) ( \
10248c779cdSXin LI     (CAST(uint32_t, (p)->hl[1])<<24)| \
10348c779cdSXin LI     (CAST(uint32_t, (p)->hl[0])<<16)| \
10448c779cdSXin LI     (CAST(uint32_t, (p)->hl[3])<<8)| \
10548c779cdSXin LI     (CAST(uint32_t, (p)->hl[2])))
10648c779cdSXin LI 
10748c779cdSXin LI #define BE16(p) ((CAST(uint16_t, (p)->hs[0])<<8)|(CAST(uint16_t, (p)->hs[1])))
10848c779cdSXin LI #define LE16(p) ((CAST(uint16_t, (p)->hs[1])<<8)|(CAST(uint16_t, (p)->hs[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 
32258a0f0d0SEitan Adler 		switch (moffset(ms, m, &bb, &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 
45258a0f0d0SEitan Adler 				switch (moffset(ms, m, &bb,
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,int32_t * op)83558a0f0d0SEitan Adler moffset(struct magic_set *ms, struct magic *m, const struct buffer *b,
83658a0f0d0SEitan Adler     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)
9333e41d09dSXin LI 			o = CAST(int32_t, ms->search.offset);
934b6cee71dSXin LI 		else
9353e41d09dSXin LI 			o = CAST(int32_t,
9363e41d09dSXin LI 			    (ms->search.offset + ms->search.rm_len));
9373e41d09dSXin LI 		break;
938b6cee71dSXin LI 
939b6cee71dSXin LI 	case FILE_SEARCH:
940b6cee71dSXin LI 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
9413e41d09dSXin LI 			o = CAST(int32_t, ms->search.offset);
942b6cee71dSXin LI 		else
9433e41d09dSXin LI 			o = CAST(int32_t, (ms->search.offset + m->vallen));
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:
122048c779cdSXin LI 		p->h = CAST(short, BE16(p));
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:
122748c779cdSXin LI 		p->l = CAST(int32_t, BE32(p));
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:
123548c779cdSXin LI 		p->q = CAST(uint64_t, BE64(p));
12363e41d09dSXin LI 		if (cvt_64(p, m) == -1)
12373e41d09dSXin LI 			goto out;
1238b6cee71dSXin LI 		return 1;
1239b6cee71dSXin LI 	case FILE_LESHORT:
124048c779cdSXin LI 		p->h = CAST(short, LE16(p));
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:
124748c779cdSXin LI 		p->l = CAST(int32_t, LE32(p));
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:
125548c779cdSXin LI 		p->q = CAST(uint64_t, LE64(p));
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:
126248c779cdSXin LI 		p->l = CAST(int32_t, ME32(p));
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:
12719ce06829SXin LI 		p->l = BE32(p);
12723e41d09dSXin LI 		if (cvt_float(p, m) == -1)
12733e41d09dSXin LI 			goto out;
1274b6cee71dSXin LI 		return 1;
1275b6cee71dSXin LI 	case FILE_LEFLOAT:
12769ce06829SXin LI 		p->l = LE32(p);
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:
12859ce06829SXin LI 		p->q = BE64(p);
12863e41d09dSXin LI 		if (cvt_double(p, m) == -1)
12873e41d09dSXin LI 			goto out;
1288b6cee71dSXin LI 		return 1;
1289b6cee71dSXin LI 	case FILE_LEDOUBLE:
12909ce06829SXin LI 		p->q = LE64(p);
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';
1420b6cee71dSXin LI 			return 0;
1421b6cee71dSXin LI 		}
1422b6cee71dSXin LI 		case FILE_STRING:	/* XXX - these two should not need */
1423b6cee71dSXin LI 		case FILE_PSTRING:	/* to copy anything, but do anyway. */
1424898496eeSXin LI 			if (m->str_range != 0 && m->str_range < sizeof(*p))
1425898496eeSXin LI 				size = m->str_range;
1426898496eeSXin LI 			break;
1427b6cee71dSXin LI 		default:
1428b6cee71dSXin LI 			break;
1429b6cee71dSXin LI 		}
1430b6cee71dSXin LI 	}
1431b6cee71dSXin LI 
14322726a701SXin LI 	if (type == FILE_OFFSET) {
14332726a701SXin LI 		(void)memset(p, '\0', sizeof(*p));
14342726a701SXin LI 		p->q = offset;
14352726a701SXin LI 		return 0;
14362726a701SXin LI 	}
14372726a701SXin LI 
1438b6cee71dSXin LI 	if (offset >= nbytes) {
1439b6cee71dSXin LI 		(void)memset(p, '\0', sizeof(*p));
1440b6cee71dSXin LI 		return 0;
1441b6cee71dSXin LI 	}
1442898496eeSXin LI 	if (nbytes - offset < size)
1443b6cee71dSXin LI 		nbytes = nbytes - offset;
1444b6cee71dSXin LI 	else
1445898496eeSXin LI 		nbytes = size;
1446b6cee71dSXin LI 
1447b6cee71dSXin LI 	(void)memcpy(p, s + offset, nbytes);
1448b6cee71dSXin LI 
1449b6cee71dSXin LI 	/*
1450b6cee71dSXin LI 	 * the usefulness of padding with zeroes eludes me, it
1451b6cee71dSXin LI 	 * might even cause problems
1452b6cee71dSXin LI 	 */
1453b6cee71dSXin LI 	if (nbytes < sizeof(*p))
145448c779cdSXin LI 		(void)memset(RCAST(char *, RCAST(void *, p)) + nbytes, '\0',
1455b6cee71dSXin LI 		    sizeof(*p) - nbytes);
1456b6cee71dSXin LI 	return 0;
1457b6cee71dSXin LI }
1458b6cee71dSXin LI 
1459898496eeSXin LI file_private int
do_ops(struct magic_set * ms,struct magic * m,uint32_t * rv,intmax_t lhs,intmax_t off)1460898496eeSXin LI do_ops(struct magic_set *ms, struct magic *m, uint32_t *rv, intmax_t lhs,
1461898496eeSXin LI     intmax_t off)
1462a5d223e6SXin LI {
1463a5d223e6SXin LI 	intmax_t offset;
1464898496eeSXin LI 	// On purpose not INTMAX_MAX
1465898496eeSXin LI 	if (lhs >= UINT_MAX || lhs <= INT_MIN ||
1466898496eeSXin LI 	    off >= UINT_MAX || off <= INT_MIN) {
1467898496eeSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
1468898496eeSXin LI 			fprintf(stderr, "lhs/off overflow %jd %jd\n", lhs, off);
1469898496eeSXin LI 		return 1;
1470898496eeSXin LI 	}
1471898496eeSXin LI 
1472a5d223e6SXin LI 	if (off) {
1473a5d223e6SXin LI 		switch (m->in_op & FILE_OPS_MASK) {
1474a5d223e6SXin LI 		case FILE_OPAND:
1475a5d223e6SXin LI 			offset = lhs & off;
1476a5d223e6SXin LI 			break;
1477a5d223e6SXin LI 		case FILE_OPOR:
1478a5d223e6SXin LI 			offset = lhs | off;
1479a5d223e6SXin LI 			break;
1480a5d223e6SXin LI 		case FILE_OPXOR:
1481a5d223e6SXin LI 			offset = lhs ^ off;
1482a5d223e6SXin LI 			break;
1483a5d223e6SXin LI 		case FILE_OPADD:
1484a5d223e6SXin LI 			offset = lhs + off;
1485a5d223e6SXin LI 			break;
1486a5d223e6SXin LI 		case FILE_OPMINUS:
1487a5d223e6SXin LI 			offset = lhs - off;
1488a5d223e6SXin LI 			break;
1489a5d223e6SXin LI 		case FILE_OPMULTIPLY:
1490a5d223e6SXin LI 			offset = lhs * off;
1491a5d223e6SXin LI 			break;
1492a5d223e6SXin LI 		case FILE_OPDIVIDE:
1493a5d223e6SXin LI 			offset = lhs / off;
1494a5d223e6SXin LI 			break;
1495a5d223e6SXin LI 		case FILE_OPMODULO:
1496a5d223e6SXin LI 			offset = lhs % off;
1497a5d223e6SXin LI 			break;
1498a5d223e6SXin LI 		}
1499a5d223e6SXin LI 	} else
1500a5d223e6SXin LI 		offset = lhs;
1501a5d223e6SXin LI 	if (m->in_op & FILE_OPINVERSE)
1502a5d223e6SXin LI 		offset = ~offset;
1503898496eeSXin LI 	if (offset >= UINT_MAX) {
1504898496eeSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
1505898496eeSXin LI 			fprintf(stderr, "offset overflow %jd\n", offset);
1506898496eeSXin LI 		return 1;
1507898496eeSXin LI 	}
1508898496eeSXin LI 	*rv = CAST(uint32_t, offset);
1509898496eeSXin LI 	return 0;
1510a5d223e6SXin LI }
1511a5d223e6SXin LI 
1512898496eeSXin 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)151358a0f0d0SEitan Adler msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
151458a0f0d0SEitan Adler     const struct buffer *b, size_t o, unsigned int cont_level)
151558a0f0d0SEitan Adler {
15162726a701SXin LI 	int32_t offset;
15172726a701SXin LI 	if (m->flag & OFFNEGATIVE) {
15182726a701SXin LI 		offset = -m->offset;
151958a0f0d0SEitan Adler 		if (cont_level > 0) {
152058a0f0d0SEitan Adler 			if (m->flag & (OFFADD|INDIROFFADD))
152158a0f0d0SEitan Adler 				goto normal;
152258a0f0d0SEitan Adler #if 0
152358a0f0d0SEitan Adler 			file_error(ms, 0, "negative offset %d at continuation"
152458a0f0d0SEitan Adler 			    "level %u", m->offset, cont_level);
152558a0f0d0SEitan Adler 			return -1;
152658a0f0d0SEitan Adler #endif
152758a0f0d0SEitan Adler 		}
152858a0f0d0SEitan Adler 		if (buffer_fill(b) == -1)
152958a0f0d0SEitan Adler 			return -1;
153058a0f0d0SEitan Adler 		if (o != 0) {
153158a0f0d0SEitan Adler 			// Not yet!
153248c779cdSXin LI 			file_magerror(ms, "non zero offset %" SIZE_T_FORMAT
153348c779cdSXin LI 			    "u at level %u", o, cont_level);
153458a0f0d0SEitan Adler 			return -1;
153558a0f0d0SEitan Adler 		}
15362726a701SXin LI 		if (CAST(size_t, m->offset) > b->elen)
153758a0f0d0SEitan Adler 			return -1;
153848c779cdSXin LI 		buffer_init(bb, -1, NULL, b->ebuf, b->elen);
15392726a701SXin LI 		ms->eoffset = ms->offset = CAST(int32_t, b->elen - m->offset);
154058a0f0d0SEitan Adler 	} else {
15412726a701SXin LI 		offset = m->offset;
154258a0f0d0SEitan Adler 		if (cont_level == 0) {
154358a0f0d0SEitan Adler normal:
154458a0f0d0SEitan Adler 			// XXX: Pass real fd, then who frees bb?
154548c779cdSXin LI 			buffer_init(bb, -1, NULL, b->fbuf, b->flen);
15462726a701SXin LI 			ms->offset = offset;
154758a0f0d0SEitan Adler 			ms->eoffset = 0;
154858a0f0d0SEitan Adler 		} else {
15492726a701SXin LI 			ms->offset = ms->eoffset + offset;
155058a0f0d0SEitan Adler 		}
155158a0f0d0SEitan Adler 	}
155258a0f0d0SEitan Adler 	if ((ms->flags & MAGIC_DEBUG) != 0) {
15532726a701SXin LI 		fprintf(stderr, "bb=[%p,%" SIZE_T_FORMAT "u,%"
15542726a701SXin LI 		    SIZE_T_FORMAT "u], %d [b=%p,%"
15552726a701SXin LI 		    SIZE_T_FORMAT "u,%" SIZE_T_FORMAT "u], [o=%#x, c=%d]\n",
15562726a701SXin LI 		    bb->fbuf, bb->flen, bb->elen, ms->offset, b->fbuf,
15572726a701SXin LI 		    b->flen, b->elen, offset, cont_level);
155858a0f0d0SEitan Adler 	}
155958a0f0d0SEitan Adler 	return 0;
156058a0f0d0SEitan Adler }
156158a0f0d0SEitan Adler 
1562898496eeSXin LI file_private int
save_cont(struct magic_set * ms,struct cont * c)156343a5ec4eSXin LI save_cont(struct magic_set *ms, struct cont *c)
156443a5ec4eSXin LI {
156543a5ec4eSXin LI 	size_t len;
156643a5ec4eSXin LI 	*c = ms->c;
156743a5ec4eSXin LI 	len = c->len * sizeof(*c->li);
156843a5ec4eSXin LI 	ms->c.li = CAST(struct level_info *, malloc(len));
156943a5ec4eSXin LI 	if (ms->c.li == NULL) {
157043a5ec4eSXin LI 		ms->c = *c;
157143a5ec4eSXin LI 		return -1;
157243a5ec4eSXin LI 	}
157343a5ec4eSXin LI 	memcpy(ms->c.li, c->li, len);
157443a5ec4eSXin LI 	return 0;
157543a5ec4eSXin LI }
157643a5ec4eSXin LI 
1577898496eeSXin LI file_private void
restore_cont(struct magic_set * ms,struct cont * c)157843a5ec4eSXin LI restore_cont(struct magic_set *ms, struct cont *c)
157943a5ec4eSXin LI {
158043a5ec4eSXin LI 	free(ms->c.li);
158143a5ec4eSXin LI 	ms->c = *c;
158243a5ec4eSXin LI }
158343a5ec4eSXin LI 
1584898496eeSXin 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)158558a0f0d0SEitan Adler mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
158658a0f0d0SEitan Adler     const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level,
158758a0f0d0SEitan Adler     int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count,
1588898496eeSXin LI     int *printed_something, int *need_separator, int *firstline, int *returnval,
158948c779cdSXin LI     int *found_match)
1590b6cee71dSXin LI {
159143a5ec4eSXin LI 	uint32_t eoffset, offset = ms->offset;
159258a0f0d0SEitan Adler 	struct buffer bb;
1593a5d223e6SXin LI 	intmax_t lhs;
15942c4f1647SXin LI 	file_pushbuf_t *pb;
159543a5ec4eSXin LI 	int rv, oneed_separator, in_type, nfound_match;
15962c4f1647SXin LI 	char *rbuf;
1597b6cee71dSXin LI 	union VALUETYPE *p = &ms->ms_value;
159843a5ec4eSXin LI 	struct mlist ml, *mlp;
159943a5ec4eSXin LI 	struct cont c;
1600b6cee71dSXin LI 
16013e41d09dSXin LI 	if (*indir_count >= ms->indir_max) {
16023e41d09dSXin LI 		file_error(ms, 0, "indirect count (%hu) exceeded",
16033e41d09dSXin LI 		    *indir_count);
1604c2931133SXin LI 		return -1;
1605c2931133SXin LI 	}
1606c2931133SXin LI 
1607c2931133SXin LI 	if (*name_count >= ms->name_max) {
1608c2931133SXin LI 		file_error(ms, 0, "name use count (%hu) exceeded",
1609c2931133SXin LI 		    *name_count);
1610b6cee71dSXin LI 		return -1;
1611b6cee71dSXin LI 	}
1612b6cee71dSXin LI 
161358a0f0d0SEitan Adler 
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) {
1636b6cee71dSXin LI 			const union VALUETYPE *q = CAST(const union VALUETYPE *,
163748c779cdSXin LI 			    RCAST(const void *, s + offset + off));
16382726a701SXin LI 			int op;
16392726a701SXin LI 			switch (op = cvt_flip(m->in_type, flip)) {
1640b6cee71dSXin LI 			case FILE_BYTE:
164148c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 1))
164248c779cdSXin LI 					return 0;
1643a5d223e6SXin LI 				off = SEXT(sgn,8,q->b);
1644b6cee71dSXin LI 				break;
1645b6cee71dSXin LI 			case FILE_SHORT:
164648c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 2))
164748c779cdSXin LI 					return 0;
1648a5d223e6SXin LI 				off = SEXT(sgn,16,q->h);
1649b6cee71dSXin LI 				break;
1650b6cee71dSXin LI 			case FILE_BESHORT:
165148c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 2))
165248c779cdSXin LI 					return 0;
1653a5d223e6SXin LI 				off = SEXT(sgn,16,BE16(q));
1654b6cee71dSXin LI 				break;
1655b6cee71dSXin LI 			case FILE_LESHORT:
165648c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 2))
165748c779cdSXin LI 					return 0;
1658a5d223e6SXin LI 				off = SEXT(sgn,16,LE16(q));
1659b6cee71dSXin LI 				break;
1660b6cee71dSXin LI 			case FILE_LONG:
166148c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 4))
166248c779cdSXin LI 					return 0;
1663a5d223e6SXin LI 				off = SEXT(sgn,32,q->l);
1664b6cee71dSXin LI 				break;
1665b6cee71dSXin LI 			case FILE_BELONG:
1666b6cee71dSXin LI 			case FILE_BEID3:
166748c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 4))
166848c779cdSXin LI 					return 0;
1669a5d223e6SXin LI 				off = SEXT(sgn,32,BE32(q));
1670b6cee71dSXin LI 				break;
1671b6cee71dSXin LI 			case FILE_LEID3:
1672b6cee71dSXin LI 			case FILE_LELONG:
167348c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 4))
167448c779cdSXin LI 					return 0;
1675a5d223e6SXin LI 				off = SEXT(sgn,32,LE32(q));
1676b6cee71dSXin LI 				break;
1677b6cee71dSXin LI 			case FILE_MELONG:
167848c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 4))
167948c779cdSXin LI 					return 0;
1680a5d223e6SXin LI 				off = SEXT(sgn,32,ME32(q));
1681b6cee71dSXin LI 				break;
16822dc4dbb9SEitan Adler 			case FILE_BEQUAD:
168348c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 8))
168448c779cdSXin LI 					return 0;
16852dc4dbb9SEitan Adler 				off = SEXT(sgn,64,BE64(q));
16862dc4dbb9SEitan Adler 				break;
16872dc4dbb9SEitan Adler 			case FILE_LEQUAD:
168848c779cdSXin LI 				if (OFFSET_OOB(nbytes, offset + off, 8))
168948c779cdSXin LI 					return 0;
16902dc4dbb9SEitan Adler 				off = SEXT(sgn,64,LE64(q));
16912dc4dbb9SEitan Adler 				break;
1692a2dfb722SXin LI 			case FILE_OCTAL:
1693a2dfb722SXin LI 				if (OFFSET_OOB(nbytes, offset, m->vallen))
1694a2dfb722SXin LI 					return 0;
1695a2dfb722SXin LI 				off = SEXT(sgn,64,strtoull(p->s, NULL, 8));
1696a2dfb722SXin LI 				break;
16972dc4dbb9SEitan Adler 			default:
16982726a701SXin LI 				if ((ms->flags & MAGIC_DEBUG) != 0)
16992726a701SXin LI 					fprintf(stderr, "bad op=%d\n", op);
17002726a701SXin LI 				return 0;
1701b6cee71dSXin LI 			}
1702b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
1703a5d223e6SXin LI 				fprintf(stderr, "indirect offs=%jd\n", off);
1704b6cee71dSXin LI 		}
1705b6cee71dSXin LI 		switch (in_type = cvt_flip(m->in_type, flip)) {
1706b6cee71dSXin LI 		case FILE_BYTE:
1707b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 1))
1708b6cee71dSXin LI 				return 0;
1709898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,8,p->b), off))
1710898496eeSXin LI 				return 0;
1711b6cee71dSXin LI 			break;
1712b6cee71dSXin LI 		case FILE_BESHORT:
1713b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 2))
1714b6cee71dSXin LI 				return 0;
1715898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,16,BE16(p)), off))
1716898496eeSXin LI 				return 0;
1717b6cee71dSXin LI 			break;
1718b6cee71dSXin LI 		case FILE_LESHORT:
1719b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 2))
1720b6cee71dSXin LI 				return 0;
1721898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,16,LE16(p)), off))
1722898496eeSXin LI 				return 0;
1723b6cee71dSXin LI 			break;
1724b6cee71dSXin LI 		case FILE_SHORT:
1725b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 2))
1726b6cee71dSXin LI 				return 0;
1727898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,16,p->h), off))
1728898496eeSXin LI 				return 0;
1729b6cee71dSXin LI 			break;
1730b6cee71dSXin LI 		case FILE_BELONG:
1731b6cee71dSXin LI 		case FILE_BEID3:
1732b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 4))
1733b6cee71dSXin LI 				return 0;
17349ce06829SXin LI 			lhs = BE32(p);
17353e41d09dSXin LI 			if (in_type == FILE_BEID3)
173648c779cdSXin LI 				lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1737898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,32,lhs), off))
1738898496eeSXin LI 				return 0;
1739b6cee71dSXin LI 			break;
1740b6cee71dSXin LI 		case FILE_LELONG:
1741b6cee71dSXin LI 		case FILE_LEID3:
1742b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 4))
1743b6cee71dSXin LI 				return 0;
17449ce06829SXin LI 			lhs = LE32(p);
17453e41d09dSXin LI 			if (in_type == FILE_LEID3)
174648c779cdSXin LI 				lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1747898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,32,lhs), off))
1748898496eeSXin LI 				return 0;
1749b6cee71dSXin LI 			break;
1750b6cee71dSXin LI 		case FILE_MELONG:
1751b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 4))
1752b6cee71dSXin LI 				return 0;
1753898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,32,ME32(p)), off))
1754898496eeSXin LI 				return 0;
1755b6cee71dSXin LI 			break;
1756b6cee71dSXin LI 		case FILE_LONG:
1757b6cee71dSXin LI 			if (OFFSET_OOB(nbytes, offset, 4))
1758b6cee71dSXin LI 				return 0;
1759898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,32,p->l), off))
1760898496eeSXin LI 				return 0;
1761b6cee71dSXin LI 			break;
17622dc4dbb9SEitan Adler 		case FILE_LEQUAD:
17632dc4dbb9SEitan Adler 			if (OFFSET_OOB(nbytes, offset, 8))
17642dc4dbb9SEitan Adler 				return 0;
1765898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,64,LE64(p)), off))
1766898496eeSXin LI 				return 0;
1767b6cee71dSXin LI 			break;
17682dc4dbb9SEitan Adler 		case FILE_BEQUAD:
17692dc4dbb9SEitan Adler 			if (OFFSET_OOB(nbytes, offset, 8))
17702dc4dbb9SEitan Adler 				return 0;
1771898496eeSXin LI 			if (do_ops(ms, m, &offset, SEXT(sgn,64,BE64(p)), off))
1772898496eeSXin LI 				return 0;
17732dc4dbb9SEitan Adler 			break;
1774a2dfb722SXin LI 		case FILE_OCTAL:
1775a2dfb722SXin LI 			if (OFFSET_OOB(nbytes, offset, m->vallen))
1776a2dfb722SXin LI 				return 0;
1777898496eeSXin LI 			if(do_ops(ms, m, &offset,
1778898496eeSXin LI 			    SEXT(sgn,64,strtoull(p->s, NULL, 8)), off))
1779898496eeSXin LI 				return 0;
1780a2dfb722SXin LI 			break;
17812dc4dbb9SEitan Adler 		default:
17822726a701SXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
17832726a701SXin LI 				fprintf(stderr, "bad in_type=%d\n", in_type);
17842726a701SXin LI 			return 0;
1785b6cee71dSXin LI 		}
1786b6cee71dSXin LI 
1787b6cee71dSXin LI 		if (m->flag & INDIROFFADD) {
17882726a701SXin LI 			if (cont_level == 0) {
17892726a701SXin LI 				if ((ms->flags & MAGIC_DEBUG) != 0)
17902726a701SXin LI 					fprintf(stderr,
17912726a701SXin LI 					    "indirect *zero* cont_level\n");
17922726a701SXin LI 				return 0;
17932726a701SXin LI 			}
1794b6cee71dSXin LI 			offset += ms->c.li[cont_level - 1].off;
1795b6cee71dSXin LI 			if (offset == 0) {
1796b6cee71dSXin LI 				if ((ms->flags & MAGIC_DEBUG) != 0)
1797b6cee71dSXin LI 					fprintf(stderr,
1798b6cee71dSXin LI 					    "indirect *zero* offset\n");
1799b6cee71dSXin LI 				return 0;
1800b6cee71dSXin LI 			}
1801b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
1802b6cee71dSXin LI 				fprintf(stderr, "indirect +offs=%u\n", offset);
1803b6cee71dSXin LI 		}
1804b6cee71dSXin LI 		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1805b6cee71dSXin LI 			return -1;
1806b6cee71dSXin LI 		ms->offset = offset;
1807b6cee71dSXin LI 
1808b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0) {
180948c779cdSXin LI 			mdebug(offset, RCAST(char *, RCAST(void *, p)),
1810b6cee71dSXin LI 			    sizeof(union VALUETYPE));
1811b6cee71dSXin LI #ifndef COMPILE_ONLY
1812b6cee71dSXin LI 			file_mdump(m);
1813b6cee71dSXin LI #endif
1814b6cee71dSXin LI 		}
1815b6cee71dSXin LI 	}
1816b6cee71dSXin LI 
1817b6cee71dSXin LI 	/* Verify we have enough data to match magic type */
1818b6cee71dSXin LI 	switch (m->type) {
1819b6cee71dSXin LI 	case FILE_BYTE:
1820b6cee71dSXin LI 		if (OFFSET_OOB(nbytes, offset, 1))
1821b6cee71dSXin LI 			return 0;
1822b6cee71dSXin LI 		break;
1823b6cee71dSXin LI 
1824b6cee71dSXin LI 	case FILE_SHORT:
1825b6cee71dSXin LI 	case FILE_BESHORT:
1826b6cee71dSXin LI 	case FILE_LESHORT:
1827b6cee71dSXin LI 		if (OFFSET_OOB(nbytes, offset, 2))
1828b6cee71dSXin LI 			return 0;
1829b6cee71dSXin LI 		break;
1830b6cee71dSXin LI 
1831b6cee71dSXin LI 	case FILE_LONG:
1832b6cee71dSXin LI 	case FILE_BELONG:
1833b6cee71dSXin LI 	case FILE_LELONG:
1834b6cee71dSXin LI 	case FILE_MELONG:
1835b6cee71dSXin LI 	case FILE_DATE:
1836b6cee71dSXin LI 	case FILE_BEDATE:
1837b6cee71dSXin LI 	case FILE_LEDATE:
1838b6cee71dSXin LI 	case FILE_MEDATE:
1839b6cee71dSXin LI 	case FILE_LDATE:
1840b6cee71dSXin LI 	case FILE_BELDATE:
1841b6cee71dSXin LI 	case FILE_LELDATE:
1842b6cee71dSXin LI 	case FILE_MELDATE:
1843b6cee71dSXin LI 	case FILE_FLOAT:
1844b6cee71dSXin LI 	case FILE_BEFLOAT:
1845b6cee71dSXin LI 	case FILE_LEFLOAT:
1846b6cee71dSXin LI 		if (OFFSET_OOB(nbytes, offset, 4))
1847b6cee71dSXin LI 			return 0;
1848b6cee71dSXin LI 		break;
1849b6cee71dSXin LI 
1850b6cee71dSXin LI 	case FILE_DOUBLE:
1851b6cee71dSXin LI 	case FILE_BEDOUBLE:
1852b6cee71dSXin LI 	case FILE_LEDOUBLE:
1853b6cee71dSXin LI 		if (OFFSET_OOB(nbytes, offset, 8))
1854b6cee71dSXin LI 			return 0;
1855b6cee71dSXin LI 		break;
1856b6cee71dSXin LI 
18572726a701SXin LI 	case FILE_GUID:
18582726a701SXin LI 		if (OFFSET_OOB(nbytes, offset, 16))
18592726a701SXin LI 			return 0;
18602726a701SXin LI 		break;
18612726a701SXin LI 
1862b6cee71dSXin LI 	case FILE_STRING:
1863b6cee71dSXin LI 	case FILE_PSTRING:
1864b6cee71dSXin LI 	case FILE_SEARCH:
1865a2dfb722SXin LI 	case FILE_OCTAL:
1866b6cee71dSXin LI 		if (OFFSET_OOB(nbytes, offset, m->vallen))
1867b6cee71dSXin LI 			return 0;
1868b6cee71dSXin LI 		break;
1869b6cee71dSXin LI 
1870b6cee71dSXin LI 	case FILE_REGEX:
1871b6cee71dSXin LI 		if (nbytes < offset)
1872b6cee71dSXin LI 			return 0;
1873b6cee71dSXin LI 		break;
1874b6cee71dSXin LI 
1875b6cee71dSXin LI 	case FILE_INDIRECT:
18764460e5b0SXin LI 		if (m->str_flags & INDIRECT_RELATIVE)
18775f0216bdSXin LI 			offset += CAST(uint32_t, o);
1878b6cee71dSXin LI 		if (offset == 0)
1879b6cee71dSXin LI 			return 0;
18802c4f1647SXin LI 
1881b6cee71dSXin LI 		if (nbytes < offset)
1882b6cee71dSXin LI 			return 0;
18832c4f1647SXin LI 
18842c4f1647SXin LI 		if ((pb = file_push_buffer(ms)) == NULL)
18852c4f1647SXin LI 			return -1;
18862c4f1647SXin LI 
18873e41d09dSXin LI 		(*indir_count)++;
188858a0f0d0SEitan Adler 		bb = *b;
188958a0f0d0SEitan Adler 		bb.fbuf = s + offset;
189058a0f0d0SEitan Adler 		bb.flen = nbytes - offset;
1891898496eeSXin LI 		bb.ebuf = NULL;
1892898496eeSXin LI 		bb.elen = 0;
1893a4d6d3b8SXin LI 		rv = -1;
189443a5ec4eSXin LI 		for (mlp = ms->mlist[0]->next; mlp != ms->mlist[0];
189543a5ec4eSXin LI 		    mlp = mlp->next)
189643a5ec4eSXin LI 		{
1897a4d6d3b8SXin LI 			if ((rv = match(ms, mlp->magic, mlp->magic_rxcomp,
1898a4d6d3b8SXin LI 			    mlp->nmagic, &bb, 0, BINTEST, text, 0, indir_count,
1899a2dfb722SXin LI 			    name_count, printed_something, need_separator,
1900898496eeSXin LI 			    firstline, NULL, NULL)) != 0)
190143a5ec4eSXin LI 				break;
190243a5ec4eSXin LI 		}
1903898496eeSXin LI 		buffer_fini(&bb);
19042c4f1647SXin LI 
1905b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
1906b6cee71dSXin LI 			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
19072c4f1647SXin LI 
19082c4f1647SXin LI 		rbuf = file_pop_buffer(ms, pb);
19092c4f1647SXin LI 		if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
19102c4f1647SXin LI 			return -1;
19112c4f1647SXin LI 
1912b6cee71dSXin LI 		if (rv == 1) {
19135f0216bdSXin LI 			if ((ms->flags & MAGIC_NODESC) == 0 &&
191448c779cdSXin LI 			    file_printf(ms, F(ms, m->desc, "%u"), offset) == -1)
191548c779cdSXin LI 			{
1916b6cee71dSXin LI 				free(rbuf);
1917b6cee71dSXin LI 				return -1;
1918b6cee71dSXin LI 			}
1919b6cee71dSXin LI 			if (file_printf(ms, "%s", rbuf) == -1) {
1920b6cee71dSXin LI 				free(rbuf);
1921b6cee71dSXin LI 				return -1;
1922b6cee71dSXin LI 			}
1923b6cee71dSXin LI 		}
1924b6cee71dSXin LI 		free(rbuf);
1925b6cee71dSXin LI 		return rv;
1926b6cee71dSXin LI 
1927b6cee71dSXin LI 	case FILE_USE:
1928b6cee71dSXin LI 		if (nbytes < offset)
1929b6cee71dSXin LI 			return 0;
19302c4f1647SXin LI 		rbuf = m->value.s;
19312c4f1647SXin LI 		if (*rbuf == '^') {
19322c4f1647SXin LI 			rbuf++;
1933b6cee71dSXin LI 			flip = !flip;
1934b6cee71dSXin LI 		}
19352c4f1647SXin LI 		if (file_magicfind(ms, rbuf, &ml) == -1) {
19362c4f1647SXin LI 			file_error(ms, 0, "cannot find entry `%s'", rbuf);
1937b6cee71dSXin LI 			return -1;
1938b6cee71dSXin LI 		}
193943a5ec4eSXin LI 		if (save_cont(ms, &c) == -1) {
194043a5ec4eSXin LI 			file_error(ms, errno, "can't allocate continuation");
194143a5ec4eSXin LI 			return -1;
194243a5ec4eSXin LI 		}
194343a5ec4eSXin LI 
1944b6cee71dSXin LI 		oneed_separator = *need_separator;
1945b6cee71dSXin LI 		if (m->flag & NOSPACE)
1946b6cee71dSXin LI 			*need_separator = 0;
194743a5ec4eSXin LI 
194843a5ec4eSXin LI 		nfound_match = 0;
194943a5ec4eSXin LI 		(*name_count)++;
195043a5ec4eSXin LI 		eoffset = ms->eoffset;
1951a4d6d3b8SXin LI 		rv = match(ms, ml.magic, ml.magic_rxcomp, ml.nmagic, b,
1952a4d6d3b8SXin LI 		    offset + o, mode, text, flip, indir_count, name_count,
1953898496eeSXin LI 		    printed_something, need_separator, firstline, returnval,
195443a5ec4eSXin LI 		    &nfound_match);
195543a5ec4eSXin LI 		ms->ms_value.q = nfound_match;
195648c779cdSXin LI 		(*name_count)--;
195743a5ec4eSXin LI 		*found_match |= nfound_match;
195843a5ec4eSXin LI 
195943a5ec4eSXin LI 		restore_cont(ms, &c);
196043a5ec4eSXin LI 
1961b6cee71dSXin LI 		if (rv != 1)
1962b6cee71dSXin LI 		    *need_separator = oneed_separator;
196343a5ec4eSXin LI 		ms->offset = offset;
196443a5ec4eSXin LI 		ms->eoffset = eoffset;
1965898496eeSXin LI 		return rv || *found_match;
1966b6cee71dSXin LI 
1967b6cee71dSXin LI 	case FILE_NAME:
19685f0216bdSXin LI 		if (ms->flags & MAGIC_NODESC)
19695f0216bdSXin LI 			return 1;
1970b6cee71dSXin LI 		if (file_printf(ms, "%s", m->desc) == -1)
1971b6cee71dSXin LI 			return -1;
1972b6cee71dSXin LI 		return 1;
19733e41d09dSXin LI 	case FILE_DER:
1974b6cee71dSXin LI 	case FILE_DEFAULT:	/* nothing to check */
1975b6cee71dSXin LI 	case FILE_CLEAR:
1976b6cee71dSXin LI 	default:
1977b6cee71dSXin LI 		break;
1978b6cee71dSXin LI 	}
1979b6cee71dSXin LI 	if (!mconvert(ms, m, flip))
1980b6cee71dSXin LI 		return 0;
1981b6cee71dSXin LI 	return 1;
1982b6cee71dSXin LI }
1983b6cee71dSXin LI 
1984898496eeSXin LI file_private uint64_t
file_strncmp(const char * s1,const char * s2,size_t len,size_t maxlen,uint32_t flags)19852726a701SXin LI file_strncmp(const char *s1, const char *s2, size_t len, size_t maxlen,
19862726a701SXin LI     uint32_t flags)
1987b6cee71dSXin LI {
1988b6cee71dSXin LI 	/*
1989b6cee71dSXin LI 	 * Convert the source args to unsigned here so that (1) the
1990b6cee71dSXin LI 	 * compare will be unsigned as it is in strncmp() and (2) so
1991b6cee71dSXin LI 	 * the ctype functions will work correctly without extra
1992b6cee71dSXin LI 	 * casting.
1993b6cee71dSXin LI 	 */
199448c779cdSXin LI 	const unsigned char *a = RCAST(const unsigned char *, s1);
199548c779cdSXin LI 	const unsigned char *b = RCAST(const unsigned char *, s2);
19962726a701SXin LI 	uint32_t ws = flags & (STRING_COMPACT_WHITESPACE |
19972726a701SXin LI 	    STRING_COMPACT_OPTIONAL_WHITESPACE);
19982726a701SXin LI 	const unsigned char *eb = b + (ws ? maxlen : len);
1999b6cee71dSXin LI 	uint64_t v;
2000b6cee71dSXin LI 
2001b6cee71dSXin LI 	/*
2002b6cee71dSXin LI 	 * What we want here is v = strncmp(s1, s2, len),
2003b6cee71dSXin LI 	 * but ignoring any nulls.
2004b6cee71dSXin LI 	 */
2005b6cee71dSXin LI 	v = 0;
200643a5ec4eSXin LI 	len++;
2007b6cee71dSXin LI 	if (0L == flags) { /* normal string: do it fast */
200843a5ec4eSXin LI 		while (--len > 0)
2009b6cee71dSXin LI 			if ((v = *b++ - *a++) != '\0')
2010b6cee71dSXin LI 				break;
2011b6cee71dSXin LI 	}
2012b6cee71dSXin LI 	else { /* combine the others */
201343a5ec4eSXin LI 		while (--len > 0) {
201440427ccaSGordon Tetlow 			if (b >= eb) {
201540427ccaSGordon Tetlow 				v = 1;
201640427ccaSGordon Tetlow 				break;
201740427ccaSGordon Tetlow 			}
2018b6cee71dSXin LI 			if ((flags & STRING_IGNORE_LOWERCASE) &&
2019b6cee71dSXin LI 			    islower(*a)) {
2020b6cee71dSXin LI 				if ((v = tolower(*b++) - *a++) != '\0')
2021b6cee71dSXin LI 					break;
2022b6cee71dSXin LI 			}
2023b6cee71dSXin LI 			else if ((flags & STRING_IGNORE_UPPERCASE) &&
2024b6cee71dSXin LI 			    isupper(*a)) {
2025b6cee71dSXin LI 				if ((v = toupper(*b++) - *a++) != '\0')
2026b6cee71dSXin LI 					break;
2027b6cee71dSXin LI 			}
2028b6cee71dSXin LI 			else if ((flags & STRING_COMPACT_WHITESPACE) &&
2029b6cee71dSXin LI 			    isspace(*a)) {
2030b6cee71dSXin LI 				a++;
203143a5ec4eSXin LI 				if (isspace(*b)) {
203243a5ec4eSXin LI 					b++;
2033b6cee71dSXin LI 					if (!isspace(*a))
203440427ccaSGordon Tetlow 						while (b < eb && isspace(*b))
2035b6cee71dSXin LI 							b++;
2036b6cee71dSXin LI 				}
2037b6cee71dSXin LI 				else {
2038b6cee71dSXin LI 					v = 1;
2039b6cee71dSXin LI 					break;
2040b6cee71dSXin LI 				}
2041b6cee71dSXin LI 			}
2042b6cee71dSXin LI 			else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
2043b6cee71dSXin LI 			    isspace(*a)) {
2044b6cee71dSXin LI 				a++;
204540427ccaSGordon Tetlow 				while (b < eb && isspace(*b))
2046b6cee71dSXin LI 					b++;
2047b6cee71dSXin LI 			}
2048b6cee71dSXin LI 			else {
2049b6cee71dSXin LI 				if ((v = *b++ - *a++) != '\0')
2050b6cee71dSXin LI 					break;
2051b6cee71dSXin LI 			}
2052b6cee71dSXin LI 		}
205343a5ec4eSXin LI 		if (len == 0 && v == 0 && (flags & STRING_FULL_WORD)) {
205443a5ec4eSXin LI 			if (*b && !isspace(*b))
205543a5ec4eSXin LI 				v = 1;
205643a5ec4eSXin LI 		}
2057b6cee71dSXin LI 	}
2058b6cee71dSXin LI 	return v;
2059b6cee71dSXin LI }
2060b6cee71dSXin LI 
2061898496eeSXin LI file_private uint64_t
file_strncmp16(const char * a,const char * b,size_t len,size_t maxlen,uint32_t flags)20622726a701SXin LI file_strncmp16(const char *a, const char *b, size_t len, size_t maxlen,
20632726a701SXin LI     uint32_t flags)
2064b6cee71dSXin LI {
2065b6cee71dSXin LI 	/*
2066b6cee71dSXin LI 	 * XXX - The 16-bit string compare probably needs to be done
2067b6cee71dSXin LI 	 * differently, especially if the flags are to be supported.
2068b6cee71dSXin LI 	 * At the moment, I am unsure.
2069b6cee71dSXin LI 	 */
2070b6cee71dSXin LI 	flags = 0;
20712726a701SXin LI 	return file_strncmp(a, b, len, maxlen, flags);
2072b6cee71dSXin LI }
2073b6cee71dSXin LI 
2074898496eeSXin LI file_private file_regex_t *
alloc_regex(struct magic_set * ms,struct magic * m)2075a4d6d3b8SXin LI alloc_regex(struct magic_set *ms, struct magic *m)
2076a4d6d3b8SXin LI {
2077a4d6d3b8SXin LI 	int rc;
2078a4d6d3b8SXin LI 	file_regex_t *rx = CAST(file_regex_t *, malloc(sizeof(*rx)));
2079a4d6d3b8SXin LI 
2080a4d6d3b8SXin LI 	if (rx == NULL) {
2081a4d6d3b8SXin LI 		file_error(ms, errno, "can't allocate %" SIZE_T_FORMAT
2082a4d6d3b8SXin LI 		    "u bytes", sizeof(*rx));
2083a4d6d3b8SXin LI 		return NULL;
2084a4d6d3b8SXin LI 	}
2085a4d6d3b8SXin LI 
2086a4d6d3b8SXin LI 	rc = file_regcomp(ms, rx, m->value.s, REG_EXTENDED | REG_NEWLINE |
2087a4d6d3b8SXin LI 	    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
2088a4d6d3b8SXin LI 	if (rc == 0)
2089a4d6d3b8SXin LI 		return rx;
2090a4d6d3b8SXin LI 
2091a4d6d3b8SXin LI 	free(rx);
2092a4d6d3b8SXin LI 	return NULL;
2093a4d6d3b8SXin LI }
2094a4d6d3b8SXin LI 
2095898496eeSXin LI file_private int
magiccheck(struct magic_set * ms,struct magic * m,file_regex_t ** m_cache)2096a4d6d3b8SXin LI magiccheck(struct magic_set *ms, struct magic *m, file_regex_t **m_cache)
2097b6cee71dSXin LI {
2098b6cee71dSXin LI 	uint64_t l = m->value.q;
2099b6cee71dSXin LI 	uint64_t v;
2100b6cee71dSXin LI 	float fl, fv;
2101b6cee71dSXin LI 	double dl, dv;
2102b6cee71dSXin LI 	int matched;
2103b6cee71dSXin LI 	union VALUETYPE *p = &ms->ms_value;
2104b6cee71dSXin LI 
2105b6cee71dSXin LI 	switch (m->type) {
2106b6cee71dSXin LI 	case FILE_BYTE:
2107b6cee71dSXin LI 		v = p->b;
2108b6cee71dSXin LI 		break;
2109b6cee71dSXin LI 
2110b6cee71dSXin LI 	case FILE_SHORT:
2111b6cee71dSXin LI 	case FILE_BESHORT:
2112b6cee71dSXin LI 	case FILE_LESHORT:
2113a4d6d3b8SXin LI 	case FILE_MSDOSDATE:
2114a4d6d3b8SXin LI 	case FILE_LEMSDOSDATE:
2115a4d6d3b8SXin LI 	case FILE_BEMSDOSDATE:
2116a4d6d3b8SXin LI 	case FILE_MSDOSTIME:
2117a4d6d3b8SXin LI 	case FILE_LEMSDOSTIME:
2118a4d6d3b8SXin LI 	case FILE_BEMSDOSTIME:
2119b6cee71dSXin LI 		v = p->h;
2120b6cee71dSXin LI 		break;
2121b6cee71dSXin LI 
2122b6cee71dSXin LI 	case FILE_LONG:
2123b6cee71dSXin LI 	case FILE_BELONG:
2124b6cee71dSXin LI 	case FILE_LELONG:
2125b6cee71dSXin LI 	case FILE_MELONG:
2126b6cee71dSXin LI 	case FILE_DATE:
2127b6cee71dSXin LI 	case FILE_BEDATE:
2128b6cee71dSXin LI 	case FILE_LEDATE:
2129b6cee71dSXin LI 	case FILE_MEDATE:
2130b6cee71dSXin LI 	case FILE_LDATE:
2131b6cee71dSXin LI 	case FILE_BELDATE:
2132b6cee71dSXin LI 	case FILE_LELDATE:
2133b6cee71dSXin LI 	case FILE_MELDATE:
2134b6cee71dSXin LI 		v = p->l;
2135b6cee71dSXin LI 		break;
2136b6cee71dSXin LI 
2137b6cee71dSXin LI 	case FILE_QUAD:
2138b6cee71dSXin LI 	case FILE_LEQUAD:
2139b6cee71dSXin LI 	case FILE_BEQUAD:
2140b6cee71dSXin LI 	case FILE_QDATE:
2141b6cee71dSXin LI 	case FILE_BEQDATE:
2142b6cee71dSXin LI 	case FILE_LEQDATE:
2143b6cee71dSXin LI 	case FILE_QLDATE:
2144b6cee71dSXin LI 	case FILE_BEQLDATE:
2145b6cee71dSXin LI 	case FILE_LEQLDATE:
2146b6cee71dSXin LI 	case FILE_QWDATE:
2147b6cee71dSXin LI 	case FILE_BEQWDATE:
2148b6cee71dSXin LI 	case FILE_LEQWDATE:
21492726a701SXin LI 	case FILE_OFFSET:
2150b6cee71dSXin LI 		v = p->q;
2151b6cee71dSXin LI 		break;
2152b6cee71dSXin LI 
2153b6cee71dSXin LI 	case FILE_FLOAT:
2154b6cee71dSXin LI 	case FILE_BEFLOAT:
2155b6cee71dSXin LI 	case FILE_LEFLOAT:
2156b6cee71dSXin LI 		fl = m->value.f;
2157b6cee71dSXin LI 		fv = p->f;
2158b6cee71dSXin LI 		switch (m->reln) {
2159b6cee71dSXin LI 		case 'x':
2160b6cee71dSXin LI 			matched = 1;
2161b6cee71dSXin LI 			break;
2162b6cee71dSXin LI 
2163b6cee71dSXin LI 		case '!':
2164898496eeSXin LI 			matched = isunordered(fl, fv) ? 1 : fv != fl;
2165b6cee71dSXin LI 			break;
2166b6cee71dSXin LI 
2167b6cee71dSXin LI 		case '=':
2168898496eeSXin LI 			matched = isunordered(fl, fv) ? 0 : fv == fl;
2169b6cee71dSXin LI 			break;
2170b6cee71dSXin LI 
2171b6cee71dSXin LI 		case '>':
2172898496eeSXin LI 			matched = isgreater(fv, fl);
2173b6cee71dSXin LI 			break;
2174b6cee71dSXin LI 
2175b6cee71dSXin LI 		case '<':
2176898496eeSXin LI 			matched = isless(fv, fl);
2177b6cee71dSXin LI 			break;
2178b6cee71dSXin LI 
2179b6cee71dSXin LI 		default:
2180a4d6d3b8SXin LI 			file_magerror(ms, "cannot happen with float: "
2181a4d6d3b8SXin LI 			    "invalid relation `%c'", m->reln);
2182b6cee71dSXin LI 			return -1;
2183b6cee71dSXin LI 		}
2184b6cee71dSXin LI 		return matched;
2185b6cee71dSXin LI 
2186b6cee71dSXin LI 	case FILE_DOUBLE:
2187b6cee71dSXin LI 	case FILE_BEDOUBLE:
2188b6cee71dSXin LI 	case FILE_LEDOUBLE:
2189b6cee71dSXin LI 		dl = m->value.d;
2190b6cee71dSXin LI 		dv = p->d;
2191b6cee71dSXin LI 		switch (m->reln) {
2192b6cee71dSXin LI 		case 'x':
2193b6cee71dSXin LI 			matched = 1;
2194b6cee71dSXin LI 			break;
2195b6cee71dSXin LI 
2196b6cee71dSXin LI 		case '!':
2197898496eeSXin LI 			matched = isunordered(dv, dl) ? 1 : dv != dl;
2198b6cee71dSXin LI 			break;
2199b6cee71dSXin LI 
2200b6cee71dSXin LI 		case '=':
2201898496eeSXin LI 			matched = isunordered(dv, dl) ? 0 : dv == dl;
2202b6cee71dSXin LI 			break;
2203b6cee71dSXin LI 
2204b6cee71dSXin LI 		case '>':
2205898496eeSXin LI 			matched = isgreater(dv, dl);
2206b6cee71dSXin LI 			break;
2207b6cee71dSXin LI 
2208b6cee71dSXin LI 		case '<':
2209898496eeSXin LI 			matched = isless(dv, dl);
2210b6cee71dSXin LI 			break;
2211b6cee71dSXin LI 
2212b6cee71dSXin LI 		default:
2213a4d6d3b8SXin LI 			file_magerror(ms, "cannot happen with double: "
2214a4d6d3b8SXin LI 			    "invalid relation `%c'", m->reln);
2215b6cee71dSXin LI 			return -1;
2216b6cee71dSXin LI 		}
2217b6cee71dSXin LI 		return matched;
2218b6cee71dSXin LI 
2219b6cee71dSXin LI 	case FILE_DEFAULT:
2220b6cee71dSXin LI 	case FILE_CLEAR:
2221b6cee71dSXin LI 		l = 0;
2222b6cee71dSXin LI 		v = 0;
2223b6cee71dSXin LI 		break;
2224b6cee71dSXin LI 
2225b6cee71dSXin LI 	case FILE_STRING:
2226b6cee71dSXin LI 	case FILE_PSTRING:
2227a2dfb722SXin LI 	case FILE_OCTAL:
2228b6cee71dSXin LI 		l = 0;
222948c779cdSXin LI 		v = file_strncmp(m->value.s, p->s, CAST(size_t, m->vallen),
22302726a701SXin LI 		    sizeof(p->s), m->str_flags);
2231b6cee71dSXin LI 		break;
2232b6cee71dSXin LI 
2233b6cee71dSXin LI 	case FILE_BESTRING16:
2234b6cee71dSXin LI 	case FILE_LESTRING16:
2235b6cee71dSXin LI 		l = 0;
223648c779cdSXin LI 		v = file_strncmp16(m->value.s, p->s, CAST(size_t, m->vallen),
22372726a701SXin LI 		    sizeof(p->s), m->str_flags);
2238b6cee71dSXin LI 		break;
2239b6cee71dSXin LI 
2240b6cee71dSXin LI 	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
2241b6cee71dSXin LI 		size_t slen;
2242b6cee71dSXin LI 		size_t idx;
2243b6cee71dSXin LI 
2244b6cee71dSXin LI 		if (ms->search.s == NULL)
2245b6cee71dSXin LI 			return 0;
2246b6cee71dSXin LI 
2247b6cee71dSXin LI 		slen = MIN(m->vallen, sizeof(m->value.s));
2248b6cee71dSXin LI 		l = 0;
2249b6cee71dSXin LI 		v = 0;
2250898496eeSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0) {
2251898496eeSXin LI 			size_t xlen = ms->search.s_len > 100 ? 100
2252898496eeSXin LI 			    : ms->search.s_len;
2253898496eeSXin LI 
2254898496eeSXin LI 			fprintf(stderr, "search: [");
2255898496eeSXin LI 			file_showstr(stderr, ms->search.s, xlen);
2256898496eeSXin LI 			fprintf(stderr, "%s] for [", ms->search.s_len == xlen
2257898496eeSXin LI 			    ? "" : "...");
2258898496eeSXin LI 			file_showstr(stderr, m->value.s, slen);
2259898496eeSXin LI 		}
226048c779cdSXin LI #ifdef HAVE_MEMMEM
226148c779cdSXin LI 		if (slen > 0 && m->str_flags == 0) {
226248c779cdSXin LI 			const char *found;
226348c779cdSXin LI 			idx = m->str_range + slen;
226448c779cdSXin LI 			if (m->str_range == 0 || ms->search.s_len < idx)
226548c779cdSXin LI 				idx = ms->search.s_len;
226648c779cdSXin LI 			found = CAST(const char *, memmem(ms->search.s, idx,
226748c779cdSXin LI 			    m->value.s, slen));
2268898496eeSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0) {
2269898496eeSXin LI 				fprintf(stderr, "] %sfound\n",
2270898496eeSXin LI 				    found ? "" : "not ");
2271898496eeSXin LI 			}
227243a5ec4eSXin LI 			if (!found) {
227343a5ec4eSXin LI 				v = 1;
227443a5ec4eSXin LI 				break;
227543a5ec4eSXin LI 			}
227648c779cdSXin LI 			idx = found - ms->search.s;
227748c779cdSXin LI 			ms->search.offset += idx;
227848c779cdSXin LI 			ms->search.rm_len = ms->search.s_len - idx;
227948c779cdSXin LI 			break;
228048c779cdSXin LI 		}
228148c779cdSXin LI #endif
2282b6cee71dSXin LI 
2283b6cee71dSXin LI 		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
228443a5ec4eSXin LI 			if (slen + idx > ms->search.s_len) {
228543a5ec4eSXin LI 				v = 1;
228643a5ec4eSXin LI 				break;
228743a5ec4eSXin LI 			}
2288b6cee71dSXin LI 
2289b6cee71dSXin LI 			v = file_strncmp(m->value.s, ms->search.s + idx, slen,
22902726a701SXin LI 			    ms->search.s_len - idx, m->str_flags);
2291b6cee71dSXin LI 			if (v == 0) {	/* found match */
2292b6cee71dSXin LI 				ms->search.offset += idx;
229340427ccaSGordon Tetlow 				ms->search.rm_len = ms->search.s_len - idx;
2294b6cee71dSXin LI 				break;
2295b6cee71dSXin LI 			}
2296b6cee71dSXin LI 		}
2297898496eeSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0) {
2298898496eeSXin LI 			fprintf(stderr, "] %sfound\n", v == 0 ? "" : "not ");
2299898496eeSXin LI 		}
2300b6cee71dSXin LI 		break;
2301b6cee71dSXin LI 	}
2302b6cee71dSXin LI 	case FILE_REGEX: {
2303b6cee71dSXin LI 		int rc;
2304a4d6d3b8SXin LI 		file_regex_t *rx = *m_cache;
2305c2931133SXin LI 		const char *search;
2306a4d6d3b8SXin LI 		regmatch_t pmatch;
2307a4d6d3b8SXin LI 		size_t slen = ms->search.s_len;
2308a4d6d3b8SXin LI 		char *copy;
2309b6cee71dSXin LI 
2310b6cee71dSXin LI 		if (ms->search.s == NULL)
2311b6cee71dSXin LI 			return 0;
2312b6cee71dSXin LI 
2313a4d6d3b8SXin LI 		if (rx == NULL) {
2314a4d6d3b8SXin LI 			rx = *m_cache = alloc_regex(ms, m);
2315a4d6d3b8SXin LI 			if (rx == NULL)
2316a4d6d3b8SXin LI 				return -1;
2317a4d6d3b8SXin LI 		}
2318b6cee71dSXin LI 		l = 0;
2319c2931133SXin LI 		if (slen != 0) {
2320a5d223e6SXin LI 		    copy = CAST(char *, malloc(slen));
2321c2931133SXin LI 		    if (copy == NULL)  {
2322c2931133SXin LI 			file_error(ms, errno,
2323c2931133SXin LI 			    "can't allocate %" SIZE_T_FORMAT "u bytes",
2324c2931133SXin LI 			    slen);
2325c2931133SXin LI 			return -1;
2326c2931133SXin LI 		    }
2327c2931133SXin LI 		    memcpy(copy, ms->search.s, slen);
2328c2931133SXin LI 		    copy[--slen] = '\0';
2329c2931133SXin LI 		    search = copy;
2330c2931133SXin LI 		} else {
233140427ccaSGordon Tetlow 		    search = CCAST(char *, "");
2332c2931133SXin LI 		    copy = NULL;
2333c2931133SXin LI 		}
2334a4d6d3b8SXin LI 		rc = file_regexec(ms, rx, RCAST(const char *, search),
23353e41d09dSXin LI 		    1, &pmatch, 0);
2336c2931133SXin LI 		free(copy);
2337b6cee71dSXin LI 		switch (rc) {
2338b6cee71dSXin LI 		case 0:
233948c779cdSXin LI 			ms->search.s += CAST(int, pmatch.rm_so);
234048c779cdSXin LI 			ms->search.offset += CAST(size_t, pmatch.rm_so);
234148c779cdSXin LI 			ms->search.rm_len = CAST(size_t,
234248c779cdSXin LI 			    pmatch.rm_eo - pmatch.rm_so);
2343b6cee71dSXin LI 			v = 0;
2344b6cee71dSXin LI 			break;
2345b6cee71dSXin LI 
2346b6cee71dSXin LI 		case REG_NOMATCH:
2347b6cee71dSXin LI 			v = 1;
2348b6cee71dSXin LI 			break;
2349b6cee71dSXin LI 
2350b6cee71dSXin LI 		default:
2351a4d6d3b8SXin LI 			return -1;
2352b6cee71dSXin LI 		}
2353b6cee71dSXin LI 		break;
2354b6cee71dSXin LI 	}
2355b6cee71dSXin LI 	case FILE_USE:
235643a5ec4eSXin LI 		return ms->ms_value.q != 0;
2357b6cee71dSXin LI 	case FILE_NAME:
235843a5ec4eSXin LI 	case FILE_INDIRECT:
2359b6cee71dSXin LI 		return 1;
23603e41d09dSXin LI 	case FILE_DER:
23613e41d09dSXin LI 		matched = der_cmp(ms, m);
236253021c7eSXin LI 		if (matched == -1) {
236353021c7eSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0) {
236453021c7eSXin LI 				(void) fprintf(stderr,
2365a2dfb722SXin LI 				    "EOF comparing DER entries\n");
236653021c7eSXin LI 			}
236753021c7eSXin LI 			return 0;
236853021c7eSXin LI 		}
23693e41d09dSXin LI 		return matched;
23702726a701SXin LI 	case FILE_GUID:
23712726a701SXin LI 		l = 0;
23722726a701SXin LI 		v = memcmp(m->value.guid, p->guid, sizeof(p->guid));
23732726a701SXin LI 		break;
2374b6cee71dSXin LI 	default:
2375b6cee71dSXin LI 		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2376b6cee71dSXin LI 		return -1;
2377b6cee71dSXin LI 	}
2378b6cee71dSXin LI 
2379b6cee71dSXin LI 	v = file_signextend(ms, m, v);
2380b6cee71dSXin LI 
2381b6cee71dSXin LI 	switch (m->reln) {
2382b6cee71dSXin LI 	case 'x':
2383b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
2384b6cee71dSXin LI 			(void) fprintf(stderr, "%" INT64_T_FORMAT
2385898496eeSXin LI 			    "u == *any* = 1", CAST(unsigned long long, v));
2386b6cee71dSXin LI 		matched = 1;
2387b6cee71dSXin LI 		break;
2388b6cee71dSXin LI 
2389b6cee71dSXin LI 	case '!':
2390b6cee71dSXin LI 		matched = v != l;
2391b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
2392b6cee71dSXin LI 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2393898496eeSXin LI 			    INT64_T_FORMAT "u = %d",
239448c779cdSXin LI 			    CAST(unsigned long long, v),
239548c779cdSXin LI 			    CAST(unsigned long long, l), matched);
2396b6cee71dSXin LI 		break;
2397b6cee71dSXin LI 
2398b6cee71dSXin LI 	case '=':
2399b6cee71dSXin LI 		matched = v == l;
2400b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
2401b6cee71dSXin LI 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2402898496eeSXin LI 			    INT64_T_FORMAT "u = %d",
240348c779cdSXin LI 			    CAST(unsigned long long, v),
240448c779cdSXin LI 			    CAST(unsigned long long, l), matched);
2405b6cee71dSXin LI 		break;
2406b6cee71dSXin LI 
2407b6cee71dSXin LI 	case '>':
2408b6cee71dSXin LI 		if (m->flag & UNSIGNED) {
2409b6cee71dSXin LI 			matched = v > l;
2410b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
2411b6cee71dSXin LI 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2412898496eeSXin LI 				    "u > %" INT64_T_FORMAT "u = %d",
241348c779cdSXin LI 				    CAST(unsigned long long, v),
241448c779cdSXin LI 				    CAST(unsigned long long, l), matched);
2415b6cee71dSXin LI 		}
2416b6cee71dSXin LI 		else {
241748c779cdSXin LI 			matched = CAST(int64_t, v) > CAST(int64_t, l);
2418b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
2419b6cee71dSXin LI 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2420898496eeSXin LI 				    "d > %" INT64_T_FORMAT "d = %d",
242148c779cdSXin LI 				    CAST(long long, v),
242248c779cdSXin LI 				    CAST(long long, l), matched);
2423b6cee71dSXin LI 		}
2424b6cee71dSXin LI 		break;
2425b6cee71dSXin LI 
2426b6cee71dSXin LI 	case '<':
2427b6cee71dSXin LI 		if (m->flag & UNSIGNED) {
2428b6cee71dSXin LI 			matched = v < l;
2429b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
2430b6cee71dSXin LI 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2431898496eeSXin LI 				    "u < %" INT64_T_FORMAT "u = %d",
243248c779cdSXin LI 				    CAST(unsigned long long, v),
243348c779cdSXin LI 				    CAST(unsigned long long, l), matched);
2434b6cee71dSXin LI 		}
2435b6cee71dSXin LI 		else {
243648c779cdSXin LI 			matched = CAST(int64_t, v) < CAST(int64_t, l);
2437b6cee71dSXin LI 			if ((ms->flags & MAGIC_DEBUG) != 0)
2438b6cee71dSXin LI 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2439898496eeSXin LI 				    "d < %" INT64_T_FORMAT "d = %d",
244048c779cdSXin LI 				     CAST(long long, v),
244148c779cdSXin LI 				     CAST(long long, l), matched);
2442b6cee71dSXin LI 		}
2443b6cee71dSXin LI 		break;
2444b6cee71dSXin LI 
2445b6cee71dSXin LI 	case '&':
2446b6cee71dSXin LI 		matched = (v & l) == l;
2447b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
2448b6cee71dSXin LI 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2449b6cee71dSXin LI 			    INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2450898496eeSXin LI 			    "x) = %d", CAST(unsigned long long, v),
245148c779cdSXin LI 			    CAST(unsigned long long, l),
245248c779cdSXin LI 			    CAST(unsigned long long, l),
2453b6cee71dSXin LI 			    matched);
2454b6cee71dSXin LI 		break;
2455b6cee71dSXin LI 
2456b6cee71dSXin LI 	case '^':
2457b6cee71dSXin LI 		matched = (v & l) != l;
2458b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
2459b6cee71dSXin LI 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2460b6cee71dSXin LI 			    INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2461898496eeSXin LI 			    "x) = %d", CAST(unsigned long long, v),
246248c779cdSXin LI 			    CAST(unsigned long long, l),
246348c779cdSXin LI 			    CAST(unsigned long long, l), matched);
2464b6cee71dSXin LI 		break;
2465b6cee71dSXin LI 
2466b6cee71dSXin LI 	default:
2467b6cee71dSXin LI 		file_magerror(ms, "cannot happen: invalid relation `%c'",
2468b6cee71dSXin LI 		    m->reln);
2469b6cee71dSXin LI 		return -1;
2470b6cee71dSXin LI 	}
2471898496eeSXin LI 	if ((ms->flags & MAGIC_DEBUG) != 0) {
2472898496eeSXin LI 		(void) fprintf(stderr, " strength=%zu\n",
2473898496eeSXin LI 		    file_magic_strength(m, 1));
2474898496eeSXin LI 	}
2475b6cee71dSXin LI 
2476b6cee71dSXin LI 	return matched;
2477b6cee71dSXin LI }
2478b6cee71dSXin LI 
2479898496eeSXin LI file_private int
handle_annotation(struct magic_set * ms,struct magic * m,int firstline)24802dc4dbb9SEitan Adler handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
2481b6cee71dSXin LI {
24823e41d09dSXin LI 	if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
248348c779cdSXin LI 		if (print_sep(ms, firstline) == -1)
2484a5d223e6SXin LI 			return -1;
2485b6cee71dSXin LI 		if (file_printf(ms, "%.8s", m->apple) == -1)
2486b6cee71dSXin LI 			return -1;
2487b6cee71dSXin LI 		return 1;
2488b6cee71dSXin LI 	}
24893e41d09dSXin LI 	if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
249048c779cdSXin LI 		if (print_sep(ms, firstline) == -1)
2491a5d223e6SXin LI 			return -1;
24925f0216bdSXin LI 		if (file_printf(ms, "%s", m->ext) == -1)
24935f0216bdSXin LI 			return -1;
24945f0216bdSXin LI 		return 1;
24955f0216bdSXin LI 	}
2496b6cee71dSXin LI 	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
249758a0f0d0SEitan Adler 		char buf[1024];
249858a0f0d0SEitan Adler 		const char *p;
249948c779cdSXin LI 		if (print_sep(ms, firstline) == -1)
2500a5d223e6SXin LI 			return -1;
25012dc4dbb9SEitan Adler 		if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1)
250258a0f0d0SEitan Adler 			p = m->mimetype;
250358a0f0d0SEitan Adler 		else
250458a0f0d0SEitan Adler 			p = buf;
250558a0f0d0SEitan Adler 		if (file_printf(ms, "%s", p) == -1)
2506b6cee71dSXin LI 			return -1;
2507b6cee71dSXin LI 		return 1;
2508b6cee71dSXin LI 	}
2509b6cee71dSXin LI 	return 0;
2510b6cee71dSXin LI }
2511b6cee71dSXin LI 
2512898496eeSXin LI file_private int
print_sep(struct magic_set * ms,int firstline)2513b6cee71dSXin LI print_sep(struct magic_set *ms, int firstline)
2514b6cee71dSXin LI {
2515b6cee71dSXin LI 	if (firstline)
2516b6cee71dSXin LI 		return 0;
2517b6cee71dSXin LI 	/*
2518b6cee71dSXin LI 	 * we found another match
2519b6cee71dSXin LI 	 * put a newline and '-' to do some simple formatting
2520b6cee71dSXin LI 	 */
252148c779cdSXin LI 	return file_separator(ms);
2522b6cee71dSXin LI }
2523