softmagic.c revision 354939
1274116Sdteske/*
2274116Sdteske * Copyright (c) Ian F. Darwin 1986-1995.
3274116Sdteske * Software written by Ian F. Darwin and others;
4274116Sdteske * maintained 1995-present by Christos Zoulas and others.
5274116Sdteske *
6274116Sdteske * Redistribution and use in source and binary forms, with or without
7274116Sdteske * modification, are permitted provided that the following conditions
8274116Sdteske * are met:
9274116Sdteske * 1. Redistributions of source code must retain the above copyright
10274116Sdteske *    notice immediately at the beginning of the file, without modification,
11274116Sdteske *    this list of conditions, and the following disclaimer.
12274116Sdteske * 2. Redistributions in binary form must reproduce the above copyright
13274116Sdteske *    notice, this list of conditions and the following disclaimer in the
14274116Sdteske *    documentation and/or other materials provided with the distribution.
15274116Sdteske *
16274116Sdteske * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17274116Sdteske * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18274116Sdteske * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19274116Sdteske * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20274116Sdteske * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21274116Sdteske * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22274116Sdteske * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23274116Sdteske * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24274116Sdteske * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25274116Sdteske * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26274116Sdteske * SUCH DAMAGE.
27274116Sdteske */
28274116Sdteske/*
29274116Sdteske * softmagic - interpret variable magic from MAGIC
30274116Sdteske */
31274116Sdteske
32274116Sdteske#include "file.h"
33274116Sdteske
34274116Sdteske#ifndef	lint
35274116SdteskeFILE_RCSID("@(#)$File: softmagic.c,v 1.286 2019/05/17 02:24:59 christos Exp $")
36274116Sdteske#endif	/* lint */
37274116Sdteske
38274116Sdteske#include "magic.h"
39274116Sdteske#include <assert.h>
40274116Sdteske#include <string.h>
41274116Sdteske#include <ctype.h>
42274116Sdteske#include <stdlib.h>
43274116Sdteske#include <time.h>
44274116Sdteske#include "der.h"
45274116Sdteske
46274116Sdteskeprivate int match(struct magic_set *, struct magic *, uint32_t,
47274116Sdteske    const struct buffer *, size_t, int, int, int, uint16_t *,
48274116Sdteske    uint16_t *, int *, int *, int *, int *);
49274116Sdteskeprivate int mget(struct magic_set *, struct magic *, const struct buffer *,
50274116Sdteske    const unsigned char *, size_t,
51274116Sdteske    size_t, unsigned int, int, int, int, uint16_t *,
52274116Sdteske    uint16_t *, int *, int *, int *, int *);
53274116Sdteskeprivate int msetoffset(struct magic_set *, struct magic *, struct buffer *,
54274116Sdteske    const struct buffer *, size_t, unsigned int);
55274116Sdteskeprivate int magiccheck(struct magic_set *, struct magic *);
56274116Sdteskeprivate int32_t mprint(struct magic_set *, struct magic *);
57274116Sdteskeprivate int moffset(struct magic_set *, struct magic *, const struct buffer *,
58274116Sdteske    int32_t *);
59274116Sdteskeprivate void mdebug(uint32_t, const char *, size_t);
60274116Sdteskeprivate int mcopy(struct magic_set *, union VALUETYPE *, int, int,
61274116Sdteske    const unsigned char *, uint32_t, size_t, struct magic *);
62274116Sdteskeprivate int mconvert(struct magic_set *, struct magic *, int);
63274116Sdteskeprivate int print_sep(struct magic_set *, int);
64274116Sdteskeprivate int handle_annotation(struct magic_set *, struct magic *, int);
65274116Sdteskeprivate int cvt_8(union VALUETYPE *, const struct magic *);
66274116Sdteskeprivate int cvt_16(union VALUETYPE *, const struct magic *);
67274116Sdteskeprivate int cvt_32(union VALUETYPE *, const struct magic *);
68274116Sdteskeprivate int cvt_64(union VALUETYPE *, const struct magic *);
69274116Sdteske
70274116Sdteske#define OFFSET_OOB(n, o, i)	((n) < CAST(uint32_t, (o)) || (i) > ((n) - (o)))
71274116Sdteske#define BE64(p) ( \
72274116Sdteske    (CAST(uint64_t, (p)->hq[0])<<56)| \
73274116Sdteske    (CAST(uint64_t, (p)->hq[1])<<48)| \
74274116Sdteske    (CAST(uint64_t, (p)->hq[2])<<40)| \
75274116Sdteske    (CAST(uint64_t, (p)->hq[3])<<32)| \
76274116Sdteske    (CAST(uint64_t, (p)->hq[4])<<24)| \
77274116Sdteske    (CAST(uint64_t, (p)->hq[5])<<16)| \
78274116Sdteske    (CAST(uint64_t, (p)->hq[6])<<8)| \
79274116Sdteske    (CAST(uint64_t, (p)->hq[7])))
80274116Sdteske#define LE64(p) ( \
81274116Sdteske    (CAST(uint64_t, (p)->hq[7])<<56)| \
82274116Sdteske    (CAST(uint64_t, (p)->hq[6])<<48)| \
83274116Sdteske    (CAST(uint64_t, (p)->hq[5])<<40)| \
84274116Sdteske    (CAST(uint64_t, (p)->hq[4])<<32)| \
85274116Sdteske    (CAST(uint64_t, (p)->hq[3])<<24)| \
86274116Sdteske    (CAST(uint64_t, (p)->hq[2])<<16)| \
87274116Sdteske    (CAST(uint64_t, (p)->hq[1])<<8)| \
88274116Sdteske    (CAST(uint64_t, (p)->hq[0])))
89274116Sdteske#define LE32(p) ( \
90274116Sdteske    (CAST(uint32_t, (p)->hl[3])<<24)| \
91274116Sdteske    (CAST(uint32_t, (p)->hl[2])<<16)| \
92274116Sdteske    (CAST(uint32_t, (p)->hl[1])<<8)| \
93274116Sdteske    (CAST(uint32_t, (p)->hl[0])))
94274116Sdteske#define BE32(p) ( \
95274116Sdteske    (CAST(uint32_t, (p)->hl[0])<<24)| \
96274116Sdteske    (CAST(uint32_t, (p)->hl[1])<<16)| \
97274116Sdteske    (CAST(uint32_t, (p)->hl[2])<<8)| \
98274116Sdteske    (CAST(uint32_t, (p)->hl[3])))
99274116Sdteske#define ME32(p) ( \
100274116Sdteske    (CAST(uint32_t, (p)->hl[1])<<24)| \
101274116Sdteske    (CAST(uint32_t, (p)->hl[0])<<16)| \
102274116Sdteske    (CAST(uint32_t, (p)->hl[3])<<8)| \
103274116Sdteske    (CAST(uint32_t, (p)->hl[2])))
104274116Sdteske
105274116Sdteske#define BE16(p) ((CAST(uint16_t, (p)->hs[0])<<8)|(CAST(uint16_t, (p)->hs[1])))
106274116Sdteske#define LE16(p) ((CAST(uint16_t, (p)->hs[1])<<8)|(CAST(uint16_t, (p)->hs[0])))
107274116Sdteske#define SEXT(s,v,p) ((s) ? \
108274116Sdteske	CAST(intmax_t, CAST(int##v##_t, p)) : \
109274116Sdteske	CAST(intmax_t, CAST(uint##v##_t, p)))
110274116Sdteske
111274116Sdteske/*
112274116Sdteske * softmagic - lookup one file in parsed, in-memory copy of database
113274116Sdteske * Passed the name and FILE * of one file to be typed.
114274116Sdteske */
115274116Sdteske/*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
116274116Sdteskeprotected int
117274116Sdteskefile_softmagic(struct magic_set *ms, const struct buffer *b,
118274116Sdteske    uint16_t *indir_count, uint16_t *name_count, int mode, int text)
119274116Sdteske{
120274116Sdteske	struct mlist *ml;
121274116Sdteske	int rv, printed_something = 0, need_separator = 0;
122274116Sdteske	uint16_t nc, ic;
123274116Sdteske
124274116Sdteske	if (name_count == NULL) {
125274116Sdteske		nc = 0;
126274116Sdteske		name_count = &nc;
127274116Sdteske	}
128274116Sdteske	if (indir_count == NULL) {
129274116Sdteske		ic = 0;
130274116Sdteske		indir_count = &ic;
131274116Sdteske	}
132274116Sdteske
133274116Sdteske	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
134274116Sdteske		if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode,
135274116Sdteske		    text, 0, indir_count, name_count,
136274116Sdteske		    &printed_something, &need_separator, NULL, NULL)) != 0)
137274116Sdteske			return rv;
138274116Sdteske
139274116Sdteske	return 0;
140274116Sdteske}
141274116Sdteske
142274116Sdteske#define FILE_FMTDEBUG
143274116Sdteske#ifdef FILE_FMTDEBUG
144274116Sdteske#define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
145274116Sdteske
146274116Sdteskeprivate const char * __attribute__((__format_arg__(3)))
147274116Sdteskefile_fmtcheck(struct magic_set *ms, const char *desc, const char *def,
148274116Sdteske	const char *file, size_t line)
149274116Sdteske{
150274116Sdteske	const char *ptr;
151274116Sdteske
152274116Sdteske	if (strchr(desc, '%') == NULL)
153274116Sdteske		return desc;
154274116Sdteske
155274116Sdteske	ptr = fmtcheck(desc, def);
156274116Sdteske	if (ptr == def)
157274116Sdteske		file_magerror(ms,
158274116Sdteske		    "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
159274116Sdteske		    " with `%s'", file, line, desc, def);
160274116Sdteske	return ptr;
161274116Sdteske}
162274116Sdteske#else
163274116Sdteske#define F(a, b, c) fmtcheck((b), (c))
164274116Sdteske#endif
165274116Sdteske
166274116Sdteske/*
167274116Sdteske * Go through the whole list, stopping if you find a match.  Process all
168274116Sdteske * the continuations of that match before returning.
169274116Sdteske *
170274116Sdteske * We support multi-level continuations:
171274116Sdteske *
172274116Sdteske *	At any time when processing a successful top-level match, there is a
173274116Sdteske *	current continuation level; it represents the level of the last
174274116Sdteske *	successfully matched continuation.
175274116Sdteske *
176274116Sdteske *	Continuations above that level are skipped as, if we see one, it
177274116Sdteske *	means that the continuation that controls them - i.e, the
178274116Sdteske *	lower-level continuation preceding them - failed to match.
179274116Sdteske *
180274116Sdteske *	Continuations below that level are processed as, if we see one,
181274116Sdteske *	it means we've finished processing or skipping higher-level
182274116Sdteske *	continuations under the control of a successful or unsuccessful
183274116Sdteske *	lower-level continuation, and are now seeing the next lower-level
184274116Sdteske *	continuation and should process it.  The current continuation
185274116Sdteske *	level reverts to the level of the one we're seeing.
186274116Sdteske *
187274116Sdteske *	Continuations at the current level are processed as, if we see
188274116Sdteske *	one, there's no lower-level continuation that may have failed.
189274116Sdteske *
190274116Sdteske *	If a continuation matches, we bump the current continuation level
191274116Sdteske *	so that higher-level continuations are processed.
192274116Sdteske */
193274116Sdteskeprivate int
194274116Sdteskematch(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
195274116Sdteske    const struct buffer *b, size_t offset, int mode, int text,
196274116Sdteske    int flip, uint16_t *indir_count, uint16_t *name_count,
197274116Sdteske    int *printed_something, int *need_separator, int *returnval,
198274116Sdteske    int *found_match)
199274116Sdteske{
200274116Sdteske	uint32_t magindex = 0;
201274116Sdteske	unsigned int cont_level = 0;
202274116Sdteske	int found_matchv = 0; /* if a match is found it is set to 1*/
203274116Sdteske	int returnvalv = 0, e;
204274116Sdteske	int firstline = 1; /* a flag to print X\n  X\n- X */
205274116Sdteske	struct buffer bb;
206274116Sdteske	int print = (ms->flags & MAGIC_NODESC) == 0;
207274116Sdteske
208274116Sdteske	/*
209274116Sdteske	 * returnval can be 0 if a match is found, but there was no
210274116Sdteske	 * annotation to be printed.
211274116Sdteske	 */
212274116Sdteske	if (returnval == NULL)
213274116Sdteske		returnval = &returnvalv;
214274116Sdteske	if (found_match == NULL)
215274116Sdteske		found_match = &found_matchv;
216274116Sdteske
217274116Sdteske	if (file_check_mem(ms, cont_level) == -1)
218274116Sdteske		return -1;
219274116Sdteske
220274116Sdteske	for (magindex = 0; magindex < nmagic; magindex++) {
221274116Sdteske		int flush = 0;
222274116Sdteske		struct magic *m = &magic[magindex];
223274116Sdteske
224274116Sdteske		if (m->type != FILE_NAME)
225274116Sdteske		if ((IS_STRING(m->type) &&
226274116Sdteske#define FLT (STRING_BINTEST | STRING_TEXTTEST)
227274116Sdteske		     ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
228274116Sdteske		      (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
229274116Sdteske		    (m->flag & mode) != mode) {
230274116Sdteskeflush:
231274116Sdteske			/* Skip sub-tests */
232274116Sdteske			while (magindex < nmagic - 1 &&
233274116Sdteske			    magic[magindex + 1].cont_level != 0)
234274116Sdteske				magindex++;
235274116Sdteske			cont_level = 0;
236274116Sdteske			continue; /* Skip to next top-level test*/
237274116Sdteske		}
238274116Sdteske
239274116Sdteske		if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
240274116Sdteske			goto flush;
241274116Sdteske		ms->line = m->lineno;
242274116Sdteske
243274116Sdteske		/* if main entry matches, print it... */
244274116Sdteske		switch (mget(ms, m, b, CAST(const unsigned char *, bb.fbuf),
245274116Sdteske		    bb.flen, offset, cont_level,
246274116Sdteske		    mode, text, flip, indir_count, name_count,
247274116Sdteske		    printed_something, need_separator, returnval, found_match))
248274116Sdteske		{
249274116Sdteske		case -1:
250274116Sdteske			return -1;
251274116Sdteske		case 0:
252274116Sdteske			flush = m->reln != '!';
253274116Sdteske			break;
254274116Sdteske		default:
255274116Sdteske			if (m->type == FILE_INDIRECT) {
256274116Sdteske				*found_match = 1;
257274116Sdteske				*returnval = 1;
258274116Sdteske			}
259274116Sdteske
260274116Sdteske			switch (magiccheck(ms, m)) {
261274116Sdteske			case -1:
262274116Sdteske				return -1;
263274116Sdteske			case 0:
264274116Sdteske				flush++;
265274116Sdteske				break;
266274116Sdteske			default:
267274116Sdteske				flush = 0;
268274116Sdteske				break;
269274116Sdteske			}
270274116Sdteske			break;
271274116Sdteske		}
272274116Sdteske		if (flush) {
273274116Sdteske			/*
274274116Sdteske			 * main entry didn't match,
275274116Sdteske			 * flush its continuations
276274116Sdteske			 */
277274116Sdteske			goto flush;
278274116Sdteske		}
279274116Sdteske
280274116Sdteske		if (*m->desc)
281274116Sdteske			*found_match = 1;
282274116Sdteske
283274116Sdteske		if ((e = handle_annotation(ms, m, firstline)) != 0)
284274116Sdteske		{
285274116Sdteske			*need_separator = 1;
286274116Sdteske			*printed_something = 1;
287274116Sdteske			*returnval = 1;
288274116Sdteske			return e;
289274116Sdteske		}
290274116Sdteske
291274116Sdteske		/*
292274116Sdteske		 * If we are going to print something, we'll need to print
293274116Sdteske		 * a blank before we print something else.
294274116Sdteske		 */
295274116Sdteske		if (print && *m->desc) {
296274116Sdteske			*need_separator = 1;
297274116Sdteske			*printed_something = 1;
298274116Sdteske			*returnval = 1;
299274116Sdteske			if (print_sep(ms, firstline) == -1)
300274116Sdteske				return -1;
301274116Sdteske			if (mprint(ms, m) == -1)
302274116Sdteske				return -1;
303274116Sdteske		}
304274116Sdteske
305274116Sdteske		switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) {
306274116Sdteske		case -1:
307274116Sdteske		case 0:
308274116Sdteske			goto flush;
309274116Sdteske		default:
310274116Sdteske			break;
311274116Sdteske		}
312274116Sdteske
313274116Sdteske		/* and any continuations that match */
314274116Sdteske		if (file_check_mem(ms, ++cont_level) == -1)
315274116Sdteske			return -1;
316274116Sdteske
317274116Sdteske		while (magindex + 1 < nmagic &&
318274116Sdteske		    magic[magindex + 1].cont_level != 0) {
319274116Sdteske			m = &magic[++magindex];
320274116Sdteske			ms->line = m->lineno; /* for messages */
321274116Sdteske
322274116Sdteske			if (cont_level < m->cont_level)
323274116Sdteske				continue;
324274116Sdteske			if (cont_level > m->cont_level) {
325274116Sdteske				/*
326274116Sdteske				 * We're at the end of the level
327274116Sdteske				 * "cont_level" continuations.
328274116Sdteske				 */
329274116Sdteske				cont_level = m->cont_level;
330274116Sdteske			}
331274116Sdteske			if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
332274116Sdteske				goto flush;
333274116Sdteske			if (m->flag & OFFADD) {
334274116Sdteske				ms->offset +=
335274116Sdteske				    ms->c.li[cont_level - 1].off;
336274116Sdteske			}
337274116Sdteske
338274116Sdteske#ifdef ENABLE_CONDITIONALS
339274116Sdteske			if (m->cond == COND_ELSE ||
340274116Sdteske			    m->cond == COND_ELIF) {
341274116Sdteske				if (ms->c.li[cont_level].last_match == 1)
342274116Sdteske					continue;
343274116Sdteske			}
344274116Sdteske#endif
345274116Sdteske			switch (mget(ms, m, b, CAST(const unsigned char *,
346274116Sdteske			    bb.fbuf), bb.flen, offset,
347274116Sdteske			    cont_level, mode, text, flip, indir_count,
348274116Sdteske			    name_count, printed_something, need_separator,
349274116Sdteske			    returnval, found_match)) {
350274116Sdteske			case -1:
351274116Sdteske				return -1;
352274116Sdteske			case 0:
353274116Sdteske				if (m->reln != '!')
354274116Sdteske					continue;
355274116Sdteske				flush = 1;
356274116Sdteske				break;
357274116Sdteske			default:
358274116Sdteske				if (m->type == FILE_INDIRECT) {
359274116Sdteske					*found_match = 1;
360274116Sdteske					*returnval = 1;
361274116Sdteske				}
362274116Sdteske				flush = 0;
363274116Sdteske				break;
364274116Sdteske			}
365274116Sdteske
366274116Sdteske			switch (flush ? 1 : magiccheck(ms, m)) {
367274116Sdteske			case -1:
368274116Sdteske				return -1;
369274116Sdteske			case 0:
370274116Sdteske#ifdef ENABLE_CONDITIONALS
371274116Sdteske				ms->c.li[cont_level].last_match = 0;
372274116Sdteske#endif
373274116Sdteske				break;
374274116Sdteske			default:
375274116Sdteske#ifdef ENABLE_CONDITIONALS
376274116Sdteske				ms->c.li[cont_level].last_match = 1;
377274116Sdteske#endif
378274116Sdteske				if (m->type == FILE_CLEAR)
379274116Sdteske					ms->c.li[cont_level].got_match = 0;
380274116Sdteske				else if (ms->c.li[cont_level].got_match) {
381274116Sdteske					if (m->type == FILE_DEFAULT)
382274116Sdteske						break;
383274116Sdteske				} else
384274116Sdteske					ms->c.li[cont_level].got_match = 1;
385274116Sdteske
386274116Sdteske				if (*m->desc)
387274116Sdteske					*found_match = 1;
388274116Sdteske
389274116Sdteske				if ((e = handle_annotation(ms, m, firstline))
390274116Sdteske				    != 0) {
391274116Sdteske					*need_separator = 1;
392274116Sdteske					*printed_something = 1;
393274116Sdteske					*returnval = 1;
394274116Sdteske					return e;
395274116Sdteske				}
396274116Sdteske				if (print && *m->desc) {
397274116Sdteske					/*
398274116Sdteske					 * This continuation matched.  Print
399274116Sdteske					 * its message, with a blank before it
400274116Sdteske					 * if the previous item printed and
401274116Sdteske					 * this item isn't empty.
402274116Sdteske					 */
403274116Sdteske					/*
404274116Sdteske					 * If we are going to print something,
405274116Sdteske					 * make sure that we have a separator
406274116Sdteske					 * first.
407274116Sdteske					 */
408274116Sdteske					if (!*printed_something) {
409274116Sdteske						*printed_something = 1;
410274116Sdteske						if (print_sep(ms, firstline)
411274116Sdteske						    == -1)
412274116Sdteske							return -1;
413274116Sdteske					}
414274116Sdteske					/* space if previous printed */
415274116Sdteske					if (*need_separator
416274116Sdteske					    && (m->flag & NOSPACE) == 0) {
417274116Sdteske						if (file_printf(ms, " ") == -1)
418274116Sdteske							return -1;
419274116Sdteske					}
420274116Sdteske					*returnval = 1;
421274116Sdteske					*need_separator = 0;
422274116Sdteske					if (mprint(ms, m) == -1)
423274116Sdteske						return -1;
424274116Sdteske					*need_separator = 1;
425274116Sdteske				}
426274116Sdteske
427274116Sdteske				switch (moffset(ms, m, &bb,
428274116Sdteske				    &ms->c.li[cont_level].off)) {
429274116Sdteske				case -1:
430274116Sdteske				case 0:
431274116Sdteske					flush = 1;
432274116Sdteske					cont_level--;
433274116Sdteske					break;
434274116Sdteske				default:
435274116Sdteske					break;
436274116Sdteske				}
437274116Sdteske
438274116Sdteske				/*
439274116Sdteske				 * If we see any continuations
440274116Sdteske				 * at a higher level,
441274116Sdteske				 * process them.
442274116Sdteske				 */
443274116Sdteske				if (file_check_mem(ms, ++cont_level) == -1)
444274116Sdteske					return -1;
445274116Sdteske				break;
446274116Sdteske			}
447274116Sdteske		}
448274116Sdteske		if (*printed_something) {
449274116Sdteske			firstline = 0;
450274116Sdteske		}
451274116Sdteske		if (*found_match) {
452274116Sdteske		    if ((ms->flags & MAGIC_CONTINUE) == 0)
453274116Sdteske			return *returnval; /* don't keep searching */
454274116Sdteske		    // So that we print a separator
455274116Sdteske		    *printed_something = 0;
456274116Sdteske		    firstline = 0;
457274116Sdteske		}
458274116Sdteske		cont_level = 0;
459274116Sdteske	}
460274116Sdteske	return *returnval;  /* This is hit if -k is set or there is no match */
461274116Sdteske}
462274116Sdteske
463274116Sdteskeprivate int
464274116Sdteskecheck_fmt(struct magic_set *ms, const char *fmt)
465274116Sdteske{
466274116Sdteske	file_regex_t rx;
467274116Sdteske	int rc, rv = -1;
468274116Sdteske
469274116Sdteske	if (strchr(fmt, '%') == NULL)
470274116Sdteske		return 0;
471274116Sdteske
472274116Sdteske	rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
473274116Sdteske	if (rc) {
474274116Sdteske		file_regerror(&rx, rc, ms);
475274116Sdteske	} else {
476274116Sdteske		rc = file_regexec(&rx, fmt, 0, 0, 0);
477274116Sdteske		rv = !rc;
478274116Sdteske	}
479274116Sdteske	file_regfree(&rx);
480274116Sdteske	return rv;
481274116Sdteske}
482274116Sdteske
483274116Sdteske#if !defined(HAVE_STRNDUP) || defined(__aiws__)
484274116Sdteske# ifdef __aiws__
485274116Sdteske#  define strndup aix_strndup	/* aix is broken */
486274116Sdteske# endif
487274116Sdteskechar *strndup(const char *, size_t);
488274116Sdteske
489274116Sdteskechar *
490274116Sdteskestrndup(const char *str, size_t n)
491274116Sdteske{
492274116Sdteske	size_t len;
493274116Sdteske	char *copy;
494274116Sdteske
495274116Sdteske	for (len = 0; len < n && str[len]; len++)
496274116Sdteske		continue;
497274116Sdteske	if ((copy = malloc(len + 1)) == NULL)
498274116Sdteske		return NULL;
499274116Sdteske	(void)memcpy(copy, str, len);
500274116Sdteske	copy[len] = '\0';
501274116Sdteske	return copy;
502274116Sdteske}
503274116Sdteske#endif /* HAVE_STRNDUP */
504274116Sdteske
505274116Sdteskestatic int
506274116Sdteskevarexpand(struct magic_set *ms, char *buf, size_t len, const char *str)
507274116Sdteske{
508274116Sdteske	const char *ptr, *sptr, *e, *t, *ee, *et;
509274116Sdteske	size_t l;
510274116Sdteske
511274116Sdteske	for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) {
512274116Sdteske		l = CAST(size_t, ptr - sptr);
513274116Sdteske		if (l >= len)
514274116Sdteske			return -1;
515274116Sdteske		memcpy(buf, sptr, l);
516274116Sdteske		buf += l;
517274116Sdteske		len -= l;
518274116Sdteske		ptr += 2;
519274116Sdteske		if (!*ptr || ptr[1] != '?')
520274116Sdteske			return -1;
521274116Sdteske		for (et = t = ptr + 2; *et && *et != ':'; et++)
522274116Sdteske			continue;
523274116Sdteske		if (*et != ':')
524274116Sdteske			return -1;
525274116Sdteske		for (ee = e = et + 1; *ee && *ee != '}'; ee++)
526274116Sdteske			continue;
527274116Sdteske		if (*ee != '}')
528274116Sdteske			return -1;
529274116Sdteske		switch (*ptr) {
530274116Sdteske		case 'x':
531274116Sdteske			if (ms->mode & 0111) {
532274116Sdteske				ptr = t;
533274116Sdteske				l = et - t;
534274116Sdteske			} else {
535274116Sdteske				ptr = e;
536274116Sdteske				l = ee - e;
537274116Sdteske			}
538274116Sdteske			break;
539274116Sdteske		default:
540274116Sdteske			return -1;
541274116Sdteske		}
542274116Sdteske		if (l >= len)
543274116Sdteske			return -1;
544274116Sdteske		memcpy(buf, ptr, l);
545274116Sdteske		buf += l;
546274116Sdteske		len -= l;
547274116Sdteske		sptr = ee + 1;
548274116Sdteske	}
549274116Sdteske
550274116Sdteske	l = strlen(sptr);
551274116Sdteske	if (l >= len)
552274116Sdteske		return -1;
553274116Sdteske
554274116Sdteske	memcpy(buf, sptr, l);
555274116Sdteske	buf[l] = '\0';
556274116Sdteske	return 0;
557274116Sdteske}
558274116Sdteske
559274116Sdteske
560274116Sdteskeprivate int32_t
561274116Sdteskemprint(struct magic_set *ms, struct magic *m)
562274116Sdteske{
563274116Sdteske	uint64_t v;
564274116Sdteske	float vf;
565274116Sdteske	double vd;
566274116Sdteske	int64_t t = 0;
567274116Sdteske 	char buf[128], tbuf[26], sbuf[512], ebuf[512];
568274116Sdteske	const char *desc;
569274116Sdteske	union VALUETYPE *p = &ms->ms_value;
570274116Sdteske
571274116Sdteske	if (varexpand(ms, ebuf, sizeof(ebuf), m->desc) == -1)
572274116Sdteske		desc = m->desc;
573274116Sdteske	else
574274116Sdteske		desc = ebuf;
575274116Sdteske
576274116Sdteske  	switch (m->type) {
577274116Sdteske  	case FILE_BYTE:
578274116Sdteske		v = file_signextend(ms, m, CAST(uint64_t, p->b));
579274116Sdteske		switch (check_fmt(ms, desc)) {
580274116Sdteske		case -1:
581274116Sdteske			return -1;
582274116Sdteske		case 1:
583274116Sdteske			(void)snprintf(buf, sizeof(buf), "%d",
584274116Sdteske			    CAST(unsigned char, v));
585274116Sdteske			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
586274116Sdteske				return -1;
587274116Sdteske			break;
588274116Sdteske		default:
589274116Sdteske			if (file_printf(ms, F(ms, desc, "%d"),
590274116Sdteske			    CAST(unsigned char, v)) == -1)
591274116Sdteske				return -1;
592274116Sdteske			break;
593274116Sdteske		}
594274116Sdteske		t = ms->offset + sizeof(char);
595274116Sdteske		break;
596274116Sdteske
597274116Sdteske  	case FILE_SHORT:
598274116Sdteske  	case FILE_BESHORT:
599274116Sdteske  	case FILE_LESHORT:
600274116Sdteske		v = file_signextend(ms, m, CAST(uint64_t, p->h));
601274116Sdteske		switch (check_fmt(ms, desc)) {
602274116Sdteske		case -1:
603274116Sdteske			return -1;
604274116Sdteske		case 1:
605274116Sdteske			(void)snprintf(buf, sizeof(buf), "%u",
606274116Sdteske			    CAST(unsigned short, v));
607274116Sdteske			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
608274116Sdteske				return -1;
609274116Sdteske			break;
610274116Sdteske		default:
611274116Sdteske			if (file_printf(ms, F(ms, desc, "%u"),
612274116Sdteske			    CAST(unsigned short, v)) == -1)
613274116Sdteske				return -1;
614274116Sdteske			break;
615274116Sdteske		}
616274116Sdteske		t = ms->offset + sizeof(short);
617274116Sdteske		break;
618274116Sdteske
619274116Sdteske  	case FILE_LONG:
620274116Sdteske  	case FILE_BELONG:
621274116Sdteske  	case FILE_LELONG:
622274116Sdteske  	case FILE_MELONG:
623274116Sdteske		v = file_signextend(ms, m, CAST(uint64_t, p->l));
624274116Sdteske		switch (check_fmt(ms, desc)) {
625274116Sdteske		case -1:
626274116Sdteske			return -1;
627274116Sdteske		case 1:
628274116Sdteske			(void)snprintf(buf, sizeof(buf), "%u",
629274116Sdteske			    CAST(uint32_t, v));
630274116Sdteske			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
631274116Sdteske				return -1;
632274116Sdteske			break;
633274116Sdteske		default:
634274116Sdteske			if (file_printf(ms, F(ms, desc, "%u"),
635274116Sdteske			    CAST(uint32_t, v)) == -1)
636274116Sdteske				return -1;
637274116Sdteske			break;
638274116Sdteske		}
639274116Sdteske		t = ms->offset + sizeof(int32_t);
640274116Sdteske  		break;
641274116Sdteske
642274116Sdteske  	case FILE_QUAD:
643274116Sdteske  	case FILE_BEQUAD:
644274116Sdteske  	case FILE_LEQUAD:
645274116Sdteske		v = file_signextend(ms, m, p->q);
646274116Sdteske		switch (check_fmt(ms, desc)) {
647274116Sdteske		case -1:
648274116Sdteske			return -1;
649274116Sdteske		case 1:
650274116Sdteske			(void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
651274116Sdteske			    CAST(unsigned long long, v));
652274116Sdteske			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
653274116Sdteske				return -1;
654274116Sdteske			break;
655274116Sdteske		default:
656274116Sdteske			if (file_printf(ms, F(ms, desc, "%" INT64_T_FORMAT "u"),
657274116Sdteske			    CAST(unsigned long long, v)) == -1)
658274116Sdteske				return -1;
659274116Sdteske			break;
660274116Sdteske		}
661274116Sdteske		t = ms->offset + sizeof(int64_t);
662274116Sdteske  		break;
663274116Sdteske
664274116Sdteske  	case FILE_STRING:
665274116Sdteske  	case FILE_PSTRING:
666274116Sdteske  	case FILE_BESTRING16:
667274116Sdteske  	case FILE_LESTRING16:
668274116Sdteske		if (m->reln == '=' || m->reln == '!') {
669274116Sdteske			if (file_printf(ms, F(ms, desc, "%s"),
670274116Sdteske			    file_printable(sbuf, sizeof(sbuf), m->value.s,
671274116Sdteske			    sizeof(m->value.s))) == -1)
672274116Sdteske				return -1;
673274116Sdteske			t = ms->offset + m->vallen;
674274116Sdteske		}
675274116Sdteske		else {
676274116Sdteske			char *str = p->s;
677274116Sdteske
678274116Sdteske			/* compute t before we mangle the string? */
679274116Sdteske			t = ms->offset + strlen(str);
680274116Sdteske
681274116Sdteske			if (*m->value.s == '\0')
682274116Sdteske				str[strcspn(str, "\r\n")] = '\0';
683274116Sdteske
684274116Sdteske			if (m->str_flags & STRING_TRIM) {
685274116Sdteske				char *last;
686274116Sdteske				while (isspace(CAST(unsigned char, *str)))
687274116Sdteske					str++;
688274116Sdteske				last = str;
689274116Sdteske				while (*last)
690274116Sdteske					last++;
691274116Sdteske				--last;
692274116Sdteske				while (isspace(CAST(unsigned char, *last)))
693274116Sdteske					last--;
694274116Sdteske				*++last = '\0';
695274116Sdteske			}
696274116Sdteske
697274116Sdteske			if (file_printf(ms, F(ms, desc, "%s"),
698274116Sdteske			    file_printable(sbuf, sizeof(sbuf), str,
699274116Sdteske				sizeof(p->s) - (str - p->s))) == -1)
700274116Sdteske				return -1;
701274116Sdteske
702274116Sdteske			if (m->type == FILE_PSTRING)
703274116Sdteske				t += file_pstring_length_size(m);
704274116Sdteske		}
705274116Sdteske		break;
706274116Sdteske
707274116Sdteske	case FILE_DATE:
708274116Sdteske	case FILE_BEDATE:
709274116Sdteske	case FILE_LEDATE:
710274116Sdteske	case FILE_MEDATE:
711274116Sdteske		if (file_printf(ms, F(ms, desc, "%s"),
712274116Sdteske		    file_fmttime(p->l, 0, tbuf)) == -1)
713274116Sdteske			return -1;
714274116Sdteske		t = ms->offset + sizeof(uint32_t);
715274116Sdteske		break;
716274116Sdteske
717274116Sdteske	case FILE_LDATE:
718274116Sdteske	case FILE_BELDATE:
719274116Sdteske	case FILE_LELDATE:
720274116Sdteske	case FILE_MELDATE:
721274116Sdteske		if (file_printf(ms, F(ms, desc, "%s"),
722		    file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1)
723			return -1;
724		t = ms->offset + sizeof(uint32_t);
725		break;
726
727	case FILE_QDATE:
728	case FILE_BEQDATE:
729	case FILE_LEQDATE:
730		if (file_printf(ms, F(ms, desc, "%s"),
731		    file_fmttime(p->q, 0, tbuf)) == -1)
732			return -1;
733		t = ms->offset + sizeof(uint64_t);
734		break;
735
736	case FILE_QLDATE:
737	case FILE_BEQLDATE:
738	case FILE_LEQLDATE:
739		if (file_printf(ms, F(ms, desc, "%s"),
740		    file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1)
741			return -1;
742		t = ms->offset + sizeof(uint64_t);
743		break;
744
745	case FILE_QWDATE:
746	case FILE_BEQWDATE:
747	case FILE_LEQWDATE:
748		if (file_printf(ms, F(ms, desc, "%s"),
749		    file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1)
750			return -1;
751		t = ms->offset + sizeof(uint64_t);
752		break;
753
754	case FILE_FLOAT:
755	case FILE_BEFLOAT:
756	case FILE_LEFLOAT:
757		vf = p->f;
758		switch (check_fmt(ms, desc)) {
759		case -1:
760			return -1;
761		case 1:
762			(void)snprintf(buf, sizeof(buf), "%g", vf);
763			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
764				return -1;
765			break;
766		default:
767			if (file_printf(ms, F(ms, desc, "%g"), vf) == -1)
768				return -1;
769			break;
770		}
771		t = ms->offset + sizeof(float);
772  		break;
773
774	case FILE_DOUBLE:
775	case FILE_BEDOUBLE:
776	case FILE_LEDOUBLE:
777		vd = p->d;
778		switch (check_fmt(ms, desc)) {
779		case -1:
780			return -1;
781		case 1:
782			(void)snprintf(buf, sizeof(buf), "%g", vd);
783			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
784				return -1;
785			break;
786		default:
787			if (file_printf(ms, F(ms, desc, "%g"), vd) == -1)
788				return -1;
789			break;
790		}
791		t = ms->offset + sizeof(double);
792  		break;
793
794	case FILE_SEARCH:
795	case FILE_REGEX: {
796		char *cp;
797		int rval;
798
799		cp = strndup(RCAST(const char *, ms->search.s),
800		    ms->search.rm_len);
801		if (cp == NULL) {
802			file_oomem(ms, ms->search.rm_len);
803			return -1;
804		}
805		rval = file_printf(ms, F(ms, desc, "%s"),
806		    file_printable(sbuf, sizeof(sbuf), cp, ms->search.rm_len));
807		free(cp);
808
809		if (rval == -1)
810			return -1;
811
812		if ((m->str_flags & REGEX_OFFSET_START))
813			t = ms->search.offset;
814		else
815			t = ms->search.offset + ms->search.rm_len;
816		break;
817	}
818
819	case FILE_DEFAULT:
820	case FILE_CLEAR:
821	  	if (file_printf(ms, "%s", m->desc) == -1)
822			return -1;
823		t = ms->offset;
824		break;
825
826	case FILE_INDIRECT:
827	case FILE_USE:
828	case FILE_NAME:
829		t = ms->offset;
830		break;
831	case FILE_DER:
832		if (file_printf(ms, F(ms, desc, "%s"),
833		    file_printable(sbuf, sizeof(sbuf), ms->ms_value.s,
834			sizeof(ms->ms_value.s))) == -1)
835			return -1;
836		t = ms->offset;
837		break;
838	default:
839		file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
840		return -1;
841	}
842	return CAST(int32_t, t);
843}
844
845private int
846moffset(struct magic_set *ms, struct magic *m, const struct buffer *b,
847    int32_t *op)
848{
849	size_t nbytes = b->flen;
850	int32_t o;
851
852  	switch (m->type) {
853  	case FILE_BYTE:
854		o = CAST(int32_t, (ms->offset + sizeof(char)));
855		break;
856
857  	case FILE_SHORT:
858  	case FILE_BESHORT:
859  	case FILE_LESHORT:
860		o = CAST(int32_t, (ms->offset + sizeof(short)));
861		break;
862
863  	case FILE_LONG:
864  	case FILE_BELONG:
865  	case FILE_LELONG:
866  	case FILE_MELONG:
867		o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
868		break;
869
870  	case FILE_QUAD:
871  	case FILE_BEQUAD:
872  	case FILE_LEQUAD:
873		o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
874		break;
875
876  	case FILE_STRING:
877  	case FILE_PSTRING:
878  	case FILE_BESTRING16:
879  	case FILE_LESTRING16:
880		if (m->reln == '=' || m->reln == '!') {
881			o = ms->offset + m->vallen;
882		} else {
883			union VALUETYPE *p = &ms->ms_value;
884
885			if (*m->value.s == '\0')
886				p->s[strcspn(p->s, "\r\n")] = '\0';
887			o = CAST(uint32_t, (ms->offset + strlen(p->s)));
888			if (m->type == FILE_PSTRING)
889				o += CAST(uint32_t,
890				    file_pstring_length_size(m));
891		}
892		break;
893
894	case FILE_DATE:
895	case FILE_BEDATE:
896	case FILE_LEDATE:
897	case FILE_MEDATE:
898		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
899		break;
900
901	case FILE_LDATE:
902	case FILE_BELDATE:
903	case FILE_LELDATE:
904	case FILE_MELDATE:
905		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
906		break;
907
908	case FILE_QDATE:
909	case FILE_BEQDATE:
910	case FILE_LEQDATE:
911		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
912		break;
913
914	case FILE_QLDATE:
915	case FILE_BEQLDATE:
916	case FILE_LEQLDATE:
917		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
918		break;
919
920  	case FILE_FLOAT:
921  	case FILE_BEFLOAT:
922  	case FILE_LEFLOAT:
923		o = CAST(int32_t, (ms->offset + sizeof(float)));
924		break;
925
926  	case FILE_DOUBLE:
927  	case FILE_BEDOUBLE:
928  	case FILE_LEDOUBLE:
929		o = CAST(int32_t, (ms->offset + sizeof(double)));
930		break;
931
932	case FILE_REGEX:
933		if ((m->str_flags & REGEX_OFFSET_START) != 0)
934			o = CAST(int32_t, ms->search.offset);
935		else
936			o = CAST(int32_t,
937			    (ms->search.offset + ms->search.rm_len));
938		break;
939
940	case FILE_SEARCH:
941		if ((m->str_flags & REGEX_OFFSET_START) != 0)
942			o = CAST(int32_t, ms->search.offset);
943		else
944			o = CAST(int32_t, (ms->search.offset + m->vallen));
945		break;
946
947	case FILE_CLEAR:
948	case FILE_DEFAULT:
949	case FILE_INDIRECT:
950		o = ms->offset;
951		break;
952
953	case FILE_DER:
954		{
955			o = der_offs(ms, m, nbytes);
956			if (o == -1 || CAST(size_t, o) > nbytes) {
957				if ((ms->flags & MAGIC_DEBUG) != 0) {
958					(void)fprintf(stderr,
959					    "Bad DER offset %d nbytes=%"
960					    SIZE_T_FORMAT "u", o, nbytes);
961				}
962				*op = 0;
963				return 0;
964			}
965			break;
966		}
967
968	default:
969		o = 0;
970		break;
971	}
972
973	if (CAST(size_t, o) > nbytes) {
974#if 0
975		file_error(ms, 0, "Offset out of range %" SIZE_T_FORMAT
976		    "u > %" SIZE_T_FORMAT "u", (size_t)o, nbytes);
977#endif
978		return -1;
979	}
980	*op = o;
981	return 1;
982}
983
984private uint32_t
985cvt_id3(struct magic_set *ms, uint32_t v)
986{
987	v = ((((v >>  0) & 0x7f) <<  0) |
988	     (((v >>  8) & 0x7f) <<  7) |
989	     (((v >> 16) & 0x7f) << 14) |
990	     (((v >> 24) & 0x7f) << 21));
991	if ((ms->flags & MAGIC_DEBUG) != 0)
992		fprintf(stderr, "id3 offs=%u\n", v);
993	return v;
994}
995
996private int
997cvt_flip(int type, int flip)
998{
999	if (flip == 0)
1000		return type;
1001	switch (type) {
1002	case FILE_BESHORT:
1003		return FILE_LESHORT;
1004	case FILE_BELONG:
1005		return FILE_LELONG;
1006	case FILE_BEDATE:
1007		return FILE_LEDATE;
1008	case FILE_BELDATE:
1009		return FILE_LELDATE;
1010	case FILE_BEQUAD:
1011		return FILE_LEQUAD;
1012	case FILE_BEQDATE:
1013		return FILE_LEQDATE;
1014	case FILE_BEQLDATE:
1015		return FILE_LEQLDATE;
1016	case FILE_BEQWDATE:
1017		return FILE_LEQWDATE;
1018	case FILE_LESHORT:
1019		return FILE_BESHORT;
1020	case FILE_LELONG:
1021		return FILE_BELONG;
1022	case FILE_LEDATE:
1023		return FILE_BEDATE;
1024	case FILE_LELDATE:
1025		return FILE_BELDATE;
1026	case FILE_LEQUAD:
1027		return FILE_BEQUAD;
1028	case FILE_LEQDATE:
1029		return FILE_BEQDATE;
1030	case FILE_LEQLDATE:
1031		return FILE_BEQLDATE;
1032	case FILE_LEQWDATE:
1033		return FILE_BEQWDATE;
1034	case FILE_BEFLOAT:
1035		return FILE_LEFLOAT;
1036	case FILE_LEFLOAT:
1037		return FILE_BEFLOAT;
1038	case FILE_BEDOUBLE:
1039		return FILE_LEDOUBLE;
1040	case FILE_LEDOUBLE:
1041		return FILE_BEDOUBLE;
1042	default:
1043		return type;
1044	}
1045}
1046#define DO_CVT(fld, type) \
1047	if (m->num_mask) \
1048		switch (m->mask_op & FILE_OPS_MASK) { \
1049		case FILE_OPAND: \
1050			p->fld &= CAST(type, m->num_mask); \
1051			break; \
1052		case FILE_OPOR: \
1053			p->fld |= CAST(type, m->num_mask); \
1054			break; \
1055		case FILE_OPXOR: \
1056			p->fld ^= CAST(type, m->num_mask); \
1057			break; \
1058		case FILE_OPADD: \
1059			p->fld += CAST(type, m->num_mask); \
1060			break; \
1061		case FILE_OPMINUS: \
1062			p->fld -= CAST(type, m->num_mask); \
1063			break; \
1064		case FILE_OPMULTIPLY: \
1065			p->fld *= CAST(type, m->num_mask); \
1066			break; \
1067		case FILE_OPDIVIDE: \
1068			if (CAST(type, m->num_mask) == 0) \
1069				return -1; \
1070			p->fld /= CAST(type, m->num_mask); \
1071			break; \
1072		case FILE_OPMODULO: \
1073			if (CAST(type, m->num_mask) == 0) \
1074				return -1; \
1075			p->fld %= CAST(type, m->num_mask); \
1076			break; \
1077		} \
1078	if (m->mask_op & FILE_OPINVERSE) \
1079		p->fld = ~p->fld \
1080
1081private int
1082cvt_8(union VALUETYPE *p, const struct magic *m)
1083{
1084	DO_CVT(b, uint8_t);
1085	return 0;
1086}
1087
1088private int
1089cvt_16(union VALUETYPE *p, const struct magic *m)
1090{
1091	DO_CVT(h, uint16_t);
1092	return 0;
1093}
1094
1095private int
1096cvt_32(union VALUETYPE *p, const struct magic *m)
1097{
1098	DO_CVT(l, uint32_t);
1099	return 0;
1100}
1101
1102private int
1103cvt_64(union VALUETYPE *p, const struct magic *m)
1104{
1105	DO_CVT(q, uint64_t);
1106	return 0;
1107}
1108
1109#define DO_CVT2(fld, type) \
1110	if (m->num_mask) \
1111		switch (m->mask_op & FILE_OPS_MASK) { \
1112		case FILE_OPADD: \
1113			p->fld += CAST(type, m->num_mask); \
1114			break; \
1115		case FILE_OPMINUS: \
1116			p->fld -= CAST(type, m->num_mask); \
1117			break; \
1118		case FILE_OPMULTIPLY: \
1119			p->fld *= CAST(type, m->num_mask); \
1120			break; \
1121		case FILE_OPDIVIDE: \
1122			if (CAST(type, m->num_mask) == 0) \
1123				return -1; \
1124			p->fld /= CAST(type, m->num_mask); \
1125			break; \
1126		} \
1127
1128private int
1129cvt_float(union VALUETYPE *p, const struct magic *m)
1130{
1131	DO_CVT2(f, float);
1132	return 0;
1133}
1134
1135private int
1136cvt_double(union VALUETYPE *p, const struct magic *m)
1137{
1138	DO_CVT2(d, double);
1139	return 0;
1140}
1141
1142/*
1143 * Convert the byte order of the data we are looking at
1144 * While we're here, let's apply the mask operation
1145 * (unless you have a better idea)
1146 */
1147private int
1148mconvert(struct magic_set *ms, struct magic *m, int flip)
1149{
1150	union VALUETYPE *p = &ms->ms_value;
1151
1152	switch (cvt_flip(m->type, flip)) {
1153	case FILE_BYTE:
1154		if (cvt_8(p, m) == -1)
1155			goto out;
1156		return 1;
1157	case FILE_SHORT:
1158		if (cvt_16(p, m) == -1)
1159			goto out;
1160		return 1;
1161	case FILE_LONG:
1162	case FILE_DATE:
1163	case FILE_LDATE:
1164		if (cvt_32(p, m) == -1)
1165			goto out;
1166		return 1;
1167	case FILE_QUAD:
1168	case FILE_QDATE:
1169	case FILE_QLDATE:
1170	case FILE_QWDATE:
1171		if (cvt_64(p, m) == -1)
1172			goto out;
1173		return 1;
1174	case FILE_STRING:
1175	case FILE_BESTRING16:
1176	case FILE_LESTRING16: {
1177		/* Null terminate and eat *trailing* return */
1178		p->s[sizeof(p->s) - 1] = '\0';
1179		return 1;
1180	}
1181	case FILE_PSTRING: {
1182		size_t sz = file_pstring_length_size(m);
1183		char *ptr1 = p->s, *ptr2 = ptr1 + sz;
1184		size_t len = file_pstring_get_length(m, ptr1);
1185		sz = sizeof(p->s) - sz; /* maximum length of string */
1186		if (len >= sz) {
1187			/*
1188			 * The size of the pascal string length (sz)
1189			 * is 1, 2, or 4. We need at least 1 byte for NUL
1190			 * termination, but we've already truncated the
1191			 * string by p->s, so we need to deduct sz.
1192			 * Because we can use one of the bytes of the length
1193			 * after we shifted as NUL termination.
1194			 */
1195			len = sz;
1196		}
1197		while (len--)
1198			*ptr1++ = *ptr2++;
1199		*ptr1 = '\0';
1200		return 1;
1201	}
1202	case FILE_BESHORT:
1203		p->h = CAST(short, BE16(p));
1204		if (cvt_16(p, m) == -1)
1205			goto out;
1206		return 1;
1207	case FILE_BELONG:
1208	case FILE_BEDATE:
1209	case FILE_BELDATE:
1210		p->l = CAST(int32_t, BE32(p));
1211		if (cvt_32(p, m) == -1)
1212			goto out;
1213		return 1;
1214	case FILE_BEQUAD:
1215	case FILE_BEQDATE:
1216	case FILE_BEQLDATE:
1217	case FILE_BEQWDATE:
1218		p->q = CAST(uint64_t, BE64(p));
1219		if (cvt_64(p, m) == -1)
1220			goto out;
1221		return 1;
1222	case FILE_LESHORT:
1223		p->h = CAST(short, LE16(p));
1224		if (cvt_16(p, m) == -1)
1225			goto out;
1226		return 1;
1227	case FILE_LELONG:
1228	case FILE_LEDATE:
1229	case FILE_LELDATE:
1230		p->l = CAST(int32_t, LE32(p));
1231		if (cvt_32(p, m) == -1)
1232			goto out;
1233		return 1;
1234	case FILE_LEQUAD:
1235	case FILE_LEQDATE:
1236	case FILE_LEQLDATE:
1237	case FILE_LEQWDATE:
1238		p->q = CAST(uint64_t, LE64(p));
1239		if (cvt_64(p, m) == -1)
1240			goto out;
1241		return 1;
1242	case FILE_MELONG:
1243	case FILE_MEDATE:
1244	case FILE_MELDATE:
1245		p->l = CAST(int32_t, ME32(p));
1246		if (cvt_32(p, m) == -1)
1247			goto out;
1248		return 1;
1249	case FILE_FLOAT:
1250		if (cvt_float(p, m) == -1)
1251			goto out;
1252		return 1;
1253	case FILE_BEFLOAT:
1254		p->l = BE32(p);
1255		if (cvt_float(p, m) == -1)
1256			goto out;
1257		return 1;
1258	case FILE_LEFLOAT:
1259		p->l = LE32(p);
1260		if (cvt_float(p, m) == -1)
1261			goto out;
1262		return 1;
1263	case FILE_DOUBLE:
1264		if (cvt_double(p, m) == -1)
1265			goto out;
1266		return 1;
1267	case FILE_BEDOUBLE:
1268		p->q = BE64(p);
1269		if (cvt_double(p, m) == -1)
1270			goto out;
1271		return 1;
1272	case FILE_LEDOUBLE:
1273		p->q = LE64(p);
1274		if (cvt_double(p, m) == -1)
1275			goto out;
1276		return 1;
1277	case FILE_REGEX:
1278	case FILE_SEARCH:
1279	case FILE_DEFAULT:
1280	case FILE_CLEAR:
1281	case FILE_NAME:
1282	case FILE_USE:
1283	case FILE_DER:
1284		return 1;
1285	default:
1286		file_magerror(ms, "invalid type %d in mconvert()", m->type);
1287		return 0;
1288	}
1289out:
1290	file_magerror(ms, "zerodivide in mconvert()");
1291	return 0;
1292}
1293
1294
1295private void
1296mdebug(uint32_t offset, const char *str, size_t len)
1297{
1298	(void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1299	file_showstr(stderr, str, len);
1300	(void) fputc('\n', stderr);
1301	(void) fputc('\n', stderr);
1302}
1303
1304private int
1305mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1306    const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1307{
1308	/*
1309	 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1310	 * anything, but setup pointers into the source
1311	 */
1312	if (indir == 0) {
1313		switch (type) {
1314		case FILE_DER:
1315		case FILE_SEARCH:
1316			if (offset > nbytes)
1317				offset = CAST(uint32_t, nbytes);
1318			ms->search.s = RCAST(const char *, s) + offset;
1319			ms->search.s_len = nbytes - offset;
1320			ms->search.offset = offset;
1321			return 0;
1322
1323		case FILE_REGEX: {
1324			const char *b;
1325			const char *c;
1326			const char *last;	/* end of search region */
1327			const char *buf;	/* start of search region */
1328			const char *end;
1329			size_t lines, linecnt, bytecnt;
1330
1331			if (s == NULL || nbytes < offset) {
1332				ms->search.s_len = 0;
1333				ms->search.s = NULL;
1334				return 0;
1335			}
1336
1337			if (m->str_flags & REGEX_LINE_COUNT) {
1338				linecnt = m->str_range;
1339				bytecnt = linecnt * 80;
1340			} else {
1341				linecnt = 0;
1342				bytecnt = m->str_range;
1343			}
1344
1345			if (bytecnt == 0 || bytecnt > nbytes - offset)
1346				bytecnt = nbytes - offset;
1347			if (bytecnt > ms->regex_max)
1348				bytecnt = ms->regex_max;
1349
1350			buf = RCAST(const char *, s) + offset;
1351			end = last = RCAST(const char *, s) + bytecnt + offset;
1352			/* mget() guarantees buf <= last */
1353			for (lines = linecnt, b = buf; lines && b < end &&
1354			     ((b = CAST(const char *,
1355				 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1356			     || (b = CAST(const char *,
1357				 memchr(c, '\r', CAST(size_t, (end - c))))));
1358			     lines--, b++) {
1359				if (b < end - 1 && b[0] == '\r' && b[1] == '\n')
1360					b++;
1361				if (b < end - 1 && b[0] == '\n')
1362					b++;
1363				last = b;
1364			}
1365			if (lines)
1366				last = end;
1367
1368			ms->search.s = buf;
1369			ms->search.s_len = last - buf;
1370			ms->search.offset = offset;
1371			ms->search.rm_len = 0;
1372			return 0;
1373		}
1374		case FILE_BESTRING16:
1375		case FILE_LESTRING16: {
1376			const unsigned char *src = s + offset;
1377			const unsigned char *esrc = s + nbytes;
1378			char *dst = p->s;
1379			char *edst = &p->s[sizeof(p->s) - 1];
1380
1381			if (type == FILE_BESTRING16)
1382				src++;
1383
1384			/* check that offset is within range */
1385			if (offset >= nbytes)
1386				break;
1387			for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1388				if (dst < edst)
1389					*dst = *src;
1390				else
1391					break;
1392				if (*dst == '\0') {
1393					if (type == FILE_BESTRING16 ?
1394					    *(src - 1) != '\0' :
1395					    ((src + 1 < esrc) &&
1396					    *(src + 1) != '\0'))
1397						*dst = ' ';
1398				}
1399			}
1400			*edst = '\0';
1401			return 0;
1402		}
1403		case FILE_STRING:	/* XXX - these two should not need */
1404		case FILE_PSTRING:	/* to copy anything, but do anyway. */
1405		default:
1406			break;
1407		}
1408	}
1409
1410	if (offset >= nbytes) {
1411		(void)memset(p, '\0', sizeof(*p));
1412		return 0;
1413	}
1414	if (nbytes - offset < sizeof(*p))
1415		nbytes = nbytes - offset;
1416	else
1417		nbytes = sizeof(*p);
1418
1419	(void)memcpy(p, s + offset, nbytes);
1420
1421	/*
1422	 * the usefulness of padding with zeroes eludes me, it
1423	 * might even cause problems
1424	 */
1425	if (nbytes < sizeof(*p))
1426		(void)memset(RCAST(char *, RCAST(void *, p)) + nbytes, '\0',
1427		    sizeof(*p) - nbytes);
1428	return 0;
1429}
1430
1431private uint32_t
1432do_ops(struct magic *m, intmax_t lhs, intmax_t off)
1433{
1434	intmax_t offset;
1435	if (off) {
1436		switch (m->in_op & FILE_OPS_MASK) {
1437		case FILE_OPAND:
1438			offset = lhs & off;
1439			break;
1440		case FILE_OPOR:
1441			offset = lhs | off;
1442			break;
1443		case FILE_OPXOR:
1444			offset = lhs ^ off;
1445			break;
1446		case FILE_OPADD:
1447			offset = lhs + off;
1448			break;
1449		case FILE_OPMINUS:
1450			offset = lhs - off;
1451			break;
1452		case FILE_OPMULTIPLY:
1453			offset = lhs * off;
1454			break;
1455		case FILE_OPDIVIDE:
1456			offset = lhs / off;
1457			break;
1458		case FILE_OPMODULO:
1459			offset = lhs % off;
1460			break;
1461		}
1462	} else
1463		offset = lhs;
1464	if (m->in_op & FILE_OPINVERSE)
1465		offset = ~offset;
1466
1467	return CAST(uint32_t, offset);
1468}
1469
1470private int
1471msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
1472    const struct buffer *b, size_t o, unsigned int cont_level)
1473{
1474	if (m->offset < 0) {
1475		if (cont_level > 0) {
1476			if (m->flag & (OFFADD|INDIROFFADD))
1477				goto normal;
1478#if 0
1479			file_error(ms, 0, "negative offset %d at continuation"
1480			    "level %u", m->offset, cont_level);
1481			return -1;
1482#endif
1483		}
1484		if (buffer_fill(b) == -1)
1485			return -1;
1486		if (o != 0) {
1487			// Not yet!
1488			file_magerror(ms, "non zero offset %" SIZE_T_FORMAT
1489			    "u at level %u", o, cont_level);
1490			return -1;
1491		}
1492		if (CAST(size_t, -m->offset) > b->elen)
1493			return -1;
1494		buffer_init(bb, -1, NULL, b->ebuf, b->elen);
1495		ms->eoffset = ms->offset = CAST(int32_t, b->elen + m->offset);
1496	} else {
1497		if (cont_level == 0) {
1498normal:
1499			// XXX: Pass real fd, then who frees bb?
1500			buffer_init(bb, -1, NULL, b->fbuf, b->flen);
1501			ms->offset = m->offset;
1502			ms->eoffset = 0;
1503		} else {
1504			ms->offset = ms->eoffset + m->offset;
1505		}
1506	}
1507	if ((ms->flags & MAGIC_DEBUG) != 0) {
1508		fprintf(stderr, "bb=[%p,%" SIZE_T_FORMAT "u], %d [b=%p,%"
1509		    SIZE_T_FORMAT "u], [o=%#x, c=%d]\n",
1510		    bb->fbuf, bb->flen, ms->offset, b->fbuf, b->flen,
1511		    m->offset, cont_level);
1512	}
1513	return 0;
1514}
1515
1516private int
1517mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
1518    const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level,
1519    int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count,
1520    int *printed_something, int *need_separator, int *returnval,
1521    int *found_match)
1522{
1523	uint32_t offset = ms->offset;
1524	struct buffer bb;
1525	intmax_t lhs;
1526	file_pushbuf_t *pb;
1527	int rv, oneed_separator, in_type;
1528	char *rbuf;
1529	union VALUETYPE *p = &ms->ms_value;
1530	struct mlist ml;
1531
1532	if (*indir_count >= ms->indir_max) {
1533		file_error(ms, 0, "indirect count (%hu) exceeded",
1534		    *indir_count);
1535		return -1;
1536	}
1537
1538	if (*name_count >= ms->name_max) {
1539		file_error(ms, 0, "name use count (%hu) exceeded",
1540		    *name_count);
1541		return -1;
1542	}
1543
1544
1545
1546	if (mcopy(ms, p, m->type, m->flag & INDIR, s,
1547	    CAST(uint32_t, offset + o), CAST(uint32_t, nbytes), m) == -1)
1548		return -1;
1549
1550	if ((ms->flags & MAGIC_DEBUG) != 0) {
1551		fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%"
1552		    SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1553		    "u, il=%hu, nc=%hu)\n",
1554		    m->type, m->flag, offset, o, nbytes,
1555		    *indir_count, *name_count);
1556		mdebug(offset, RCAST(char *, RCAST(void *, p)),
1557		    sizeof(union VALUETYPE));
1558#ifndef COMPILE_ONLY
1559		file_mdump(m);
1560#endif
1561	}
1562
1563	if (m->flag & INDIR) {
1564		intmax_t off = m->in_offset;
1565		const int sgn = m->in_op & FILE_OPSIGNED;
1566		if (m->in_op & FILE_OPINDIRECT) {
1567			const union VALUETYPE *q = CAST(const union VALUETYPE *,
1568			    RCAST(const void *, s + offset + off));
1569			switch (cvt_flip(m->in_type, flip)) {
1570			case FILE_BYTE:
1571				if (OFFSET_OOB(nbytes, offset + off, 1))
1572					return 0;
1573				off = SEXT(sgn,8,q->b);
1574				break;
1575			case FILE_SHORT:
1576				if (OFFSET_OOB(nbytes, offset + off, 2))
1577					return 0;
1578				off = SEXT(sgn,16,q->h);
1579				break;
1580			case FILE_BESHORT:
1581				if (OFFSET_OOB(nbytes, offset + off, 2))
1582					return 0;
1583				off = SEXT(sgn,16,BE16(q));
1584				break;
1585			case FILE_LESHORT:
1586				if (OFFSET_OOB(nbytes, offset + off, 2))
1587					return 0;
1588				off = SEXT(sgn,16,LE16(q));
1589				break;
1590			case FILE_LONG:
1591				if (OFFSET_OOB(nbytes, offset + off, 4))
1592					return 0;
1593				off = SEXT(sgn,32,q->l);
1594				break;
1595			case FILE_BELONG:
1596			case FILE_BEID3:
1597				if (OFFSET_OOB(nbytes, offset + off, 4))
1598					return 0;
1599				off = SEXT(sgn,32,BE32(q));
1600				break;
1601			case FILE_LEID3:
1602			case FILE_LELONG:
1603				if (OFFSET_OOB(nbytes, offset + off, 4))
1604					return 0;
1605				off = SEXT(sgn,32,LE32(q));
1606				break;
1607			case FILE_MELONG:
1608				if (OFFSET_OOB(nbytes, offset + off, 4))
1609					return 0;
1610				off = SEXT(sgn,32,ME32(q));
1611				break;
1612			case FILE_BEQUAD:
1613				if (OFFSET_OOB(nbytes, offset + off, 8))
1614					return 0;
1615				off = SEXT(sgn,64,BE64(q));
1616				break;
1617			case FILE_LEQUAD:
1618				if (OFFSET_OOB(nbytes, offset + off, 8))
1619					return 0;
1620				off = SEXT(sgn,64,LE64(q));
1621				break;
1622			default:
1623				abort();
1624			}
1625			if ((ms->flags & MAGIC_DEBUG) != 0)
1626				fprintf(stderr, "indirect offs=%jd\n", off);
1627		}
1628		switch (in_type = cvt_flip(m->in_type, flip)) {
1629		case FILE_BYTE:
1630			if (OFFSET_OOB(nbytes, offset, 1))
1631				return 0;
1632			offset = do_ops(m, SEXT(sgn,8,p->b), off);
1633			break;
1634		case FILE_BESHORT:
1635			if (OFFSET_OOB(nbytes, offset, 2))
1636				return 0;
1637			offset = do_ops(m, SEXT(sgn,16,BE16(p)), off);
1638			break;
1639		case FILE_LESHORT:
1640			if (OFFSET_OOB(nbytes, offset, 2))
1641				return 0;
1642			offset = do_ops(m, SEXT(sgn,16,LE16(p)), off);
1643			break;
1644		case FILE_SHORT:
1645			if (OFFSET_OOB(nbytes, offset, 2))
1646				return 0;
1647			offset = do_ops(m, SEXT(sgn,16,p->h), off);
1648			break;
1649		case FILE_BELONG:
1650		case FILE_BEID3:
1651			if (OFFSET_OOB(nbytes, offset, 4))
1652				return 0;
1653			lhs = BE32(p);
1654			if (in_type == FILE_BEID3)
1655				lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1656			offset = do_ops(m, SEXT(sgn,32,lhs), off);
1657			break;
1658		case FILE_LELONG:
1659		case FILE_LEID3:
1660			if (OFFSET_OOB(nbytes, offset, 4))
1661				return 0;
1662			lhs = LE32(p);
1663			if (in_type == FILE_LEID3)
1664				lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1665			offset = do_ops(m, SEXT(sgn,32,lhs), off);
1666			break;
1667		case FILE_MELONG:
1668			if (OFFSET_OOB(nbytes, offset, 4))
1669				return 0;
1670			offset = do_ops(m, SEXT(sgn,32,ME32(p)), off);
1671			break;
1672		case FILE_LONG:
1673			if (OFFSET_OOB(nbytes, offset, 4))
1674				return 0;
1675			offset = do_ops(m, SEXT(sgn,32,p->l), off);
1676			break;
1677		case FILE_LEQUAD:
1678			if (OFFSET_OOB(nbytes, offset, 8))
1679				return 0;
1680			offset = do_ops(m, SEXT(sgn,64,LE64(p)), off);
1681			break;
1682		case FILE_BEQUAD:
1683			if (OFFSET_OOB(nbytes, offset, 8))
1684				return 0;
1685			offset = do_ops(m, SEXT(sgn,64,BE64(p)), off);
1686			break;
1687		default:
1688			abort();
1689		}
1690
1691		if (m->flag & INDIROFFADD) {
1692			offset += ms->c.li[cont_level-1].off;
1693			if (offset == 0) {
1694				if ((ms->flags & MAGIC_DEBUG) != 0)
1695					fprintf(stderr,
1696					    "indirect *zero* offset\n");
1697				return 0;
1698			}
1699			if ((ms->flags & MAGIC_DEBUG) != 0)
1700				fprintf(stderr, "indirect +offs=%u\n", offset);
1701		}
1702		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1703			return -1;
1704		ms->offset = offset;
1705
1706		if ((ms->flags & MAGIC_DEBUG) != 0) {
1707			mdebug(offset, RCAST(char *, RCAST(void *, p)),
1708			    sizeof(union VALUETYPE));
1709#ifndef COMPILE_ONLY
1710			file_mdump(m);
1711#endif
1712		}
1713	}
1714
1715	/* Verify we have enough data to match magic type */
1716	switch (m->type) {
1717	case FILE_BYTE:
1718		if (OFFSET_OOB(nbytes, offset, 1))
1719			return 0;
1720		break;
1721
1722	case FILE_SHORT:
1723	case FILE_BESHORT:
1724	case FILE_LESHORT:
1725		if (OFFSET_OOB(nbytes, offset, 2))
1726			return 0;
1727		break;
1728
1729	case FILE_LONG:
1730	case FILE_BELONG:
1731	case FILE_LELONG:
1732	case FILE_MELONG:
1733	case FILE_DATE:
1734	case FILE_BEDATE:
1735	case FILE_LEDATE:
1736	case FILE_MEDATE:
1737	case FILE_LDATE:
1738	case FILE_BELDATE:
1739	case FILE_LELDATE:
1740	case FILE_MELDATE:
1741	case FILE_FLOAT:
1742	case FILE_BEFLOAT:
1743	case FILE_LEFLOAT:
1744		if (OFFSET_OOB(nbytes, offset, 4))
1745			return 0;
1746		break;
1747
1748	case FILE_DOUBLE:
1749	case FILE_BEDOUBLE:
1750	case FILE_LEDOUBLE:
1751		if (OFFSET_OOB(nbytes, offset, 8))
1752			return 0;
1753		break;
1754
1755	case FILE_STRING:
1756	case FILE_PSTRING:
1757	case FILE_SEARCH:
1758		if (OFFSET_OOB(nbytes, offset, m->vallen))
1759			return 0;
1760		break;
1761
1762	case FILE_REGEX:
1763		if (nbytes < offset)
1764			return 0;
1765		break;
1766
1767	case FILE_INDIRECT:
1768		if (m->str_flags & INDIRECT_RELATIVE)
1769			offset += CAST(uint32_t, o);
1770		if (offset == 0)
1771			return 0;
1772
1773		if (nbytes < offset)
1774			return 0;
1775
1776		if ((pb = file_push_buffer(ms)) == NULL)
1777			return -1;
1778
1779		(*indir_count)++;
1780		bb = *b;
1781		bb.fbuf = s + offset;
1782		bb.flen = nbytes - offset;
1783		rv = file_softmagic(ms, &bb,
1784		    indir_count, name_count, BINTEST, text);
1785
1786		if ((ms->flags & MAGIC_DEBUG) != 0)
1787			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1788
1789		rbuf = file_pop_buffer(ms, pb);
1790		if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1791			return -1;
1792
1793		if (rv == 1) {
1794			if ((ms->flags & MAGIC_NODESC) == 0 &&
1795			    file_printf(ms, F(ms, m->desc, "%u"), offset) == -1)
1796			{
1797				free(rbuf);
1798				return -1;
1799			}
1800			if (file_printf(ms, "%s", rbuf) == -1) {
1801				free(rbuf);
1802				return -1;
1803			}
1804		}
1805		free(rbuf);
1806		return rv;
1807
1808	case FILE_USE:
1809		if (nbytes < offset)
1810			return 0;
1811		rbuf = m->value.s;
1812		if (*rbuf == '^') {
1813			rbuf++;
1814			flip = !flip;
1815		}
1816		if (file_magicfind(ms, rbuf, &ml) == -1) {
1817			file_error(ms, 0, "cannot find entry `%s'", rbuf);
1818			return -1;
1819		}
1820		(*name_count)++;
1821		oneed_separator = *need_separator;
1822		if (m->flag & NOSPACE)
1823			*need_separator = 0;
1824		rv = match(ms, ml.magic, ml.nmagic, b, offset + o,
1825		    mode, text, flip, indir_count, name_count,
1826		    printed_something, need_separator, returnval, found_match);
1827		(*name_count)--;
1828		if (rv != 1)
1829		    *need_separator = oneed_separator;
1830		return rv;
1831
1832	case FILE_NAME:
1833		if (ms->flags & MAGIC_NODESC)
1834			return 1;
1835		if (file_printf(ms, "%s", m->desc) == -1)
1836			return -1;
1837		return 1;
1838	case FILE_DER:
1839	case FILE_DEFAULT:	/* nothing to check */
1840	case FILE_CLEAR:
1841	default:
1842		break;
1843	}
1844	if (!mconvert(ms, m, flip))
1845		return 0;
1846	return 1;
1847}
1848
1849private uint64_t
1850file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1851{
1852	/*
1853	 * Convert the source args to unsigned here so that (1) the
1854	 * compare will be unsigned as it is in strncmp() and (2) so
1855	 * the ctype functions will work correctly without extra
1856	 * casting.
1857	 */
1858	const unsigned char *a = RCAST(const unsigned char *, s1);
1859	const unsigned char *b = RCAST(const unsigned char *, s2);
1860	const unsigned char *eb = b + len;
1861	uint64_t v;
1862
1863	/*
1864	 * What we want here is v = strncmp(s1, s2, len),
1865	 * but ignoring any nulls.
1866	 */
1867	v = 0;
1868	if (0L == flags) { /* normal string: do it fast */
1869		while (len-- > 0)
1870			if ((v = *b++ - *a++) != '\0')
1871				break;
1872	}
1873	else { /* combine the others */
1874		while (len-- > 0) {
1875			if (b >= eb) {
1876				v = 1;
1877				break;
1878			}
1879			if ((flags & STRING_IGNORE_LOWERCASE) &&
1880			    islower(*a)) {
1881				if ((v = tolower(*b++) - *a++) != '\0')
1882					break;
1883			}
1884			else if ((flags & STRING_IGNORE_UPPERCASE) &&
1885			    isupper(*a)) {
1886				if ((v = toupper(*b++) - *a++) != '\0')
1887					break;
1888			}
1889			else if ((flags & STRING_COMPACT_WHITESPACE) &&
1890			    isspace(*a)) {
1891				a++;
1892				if (isspace(*b++)) {
1893					if (!isspace(*a))
1894						while (b < eb && isspace(*b))
1895							b++;
1896				}
1897				else {
1898					v = 1;
1899					break;
1900				}
1901			}
1902			else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1903			    isspace(*a)) {
1904				a++;
1905				while (b < eb && isspace(*b))
1906					b++;
1907			}
1908			else {
1909				if ((v = *b++ - *a++) != '\0')
1910					break;
1911			}
1912		}
1913	}
1914	return v;
1915}
1916
1917private uint64_t
1918file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1919{
1920	/*
1921	 * XXX - The 16-bit string compare probably needs to be done
1922	 * differently, especially if the flags are to be supported.
1923	 * At the moment, I am unsure.
1924	 */
1925	flags = 0;
1926	return file_strncmp(a, b, len, flags);
1927}
1928
1929private int
1930magiccheck(struct magic_set *ms, struct magic *m)
1931{
1932	uint64_t l = m->value.q;
1933	uint64_t v;
1934	float fl, fv;
1935	double dl, dv;
1936	int matched;
1937	union VALUETYPE *p = &ms->ms_value;
1938
1939	switch (m->type) {
1940	case FILE_BYTE:
1941		v = p->b;
1942		break;
1943
1944	case FILE_SHORT:
1945	case FILE_BESHORT:
1946	case FILE_LESHORT:
1947		v = p->h;
1948		break;
1949
1950	case FILE_LONG:
1951	case FILE_BELONG:
1952	case FILE_LELONG:
1953	case FILE_MELONG:
1954	case FILE_DATE:
1955	case FILE_BEDATE:
1956	case FILE_LEDATE:
1957	case FILE_MEDATE:
1958	case FILE_LDATE:
1959	case FILE_BELDATE:
1960	case FILE_LELDATE:
1961	case FILE_MELDATE:
1962		v = p->l;
1963		break;
1964
1965	case FILE_QUAD:
1966	case FILE_LEQUAD:
1967	case FILE_BEQUAD:
1968	case FILE_QDATE:
1969	case FILE_BEQDATE:
1970	case FILE_LEQDATE:
1971	case FILE_QLDATE:
1972	case FILE_BEQLDATE:
1973	case FILE_LEQLDATE:
1974	case FILE_QWDATE:
1975	case FILE_BEQWDATE:
1976	case FILE_LEQWDATE:
1977		v = p->q;
1978		break;
1979
1980	case FILE_FLOAT:
1981	case FILE_BEFLOAT:
1982	case FILE_LEFLOAT:
1983		fl = m->value.f;
1984		fv = p->f;
1985		switch (m->reln) {
1986		case 'x':
1987			matched = 1;
1988			break;
1989
1990		case '!':
1991			matched = fv != fl;
1992			break;
1993
1994		case '=':
1995			matched = fv == fl;
1996			break;
1997
1998		case '>':
1999			matched = fv > fl;
2000			break;
2001
2002		case '<':
2003			matched = fv < fl;
2004			break;
2005
2006		default:
2007			file_magerror(ms, "cannot happen with float: invalid relation `%c'",
2008			    m->reln);
2009			return -1;
2010		}
2011		return matched;
2012
2013	case FILE_DOUBLE:
2014	case FILE_BEDOUBLE:
2015	case FILE_LEDOUBLE:
2016		dl = m->value.d;
2017		dv = p->d;
2018		switch (m->reln) {
2019		case 'x':
2020			matched = 1;
2021			break;
2022
2023		case '!':
2024			matched = dv != dl;
2025			break;
2026
2027		case '=':
2028			matched = dv == dl;
2029			break;
2030
2031		case '>':
2032			matched = dv > dl;
2033			break;
2034
2035		case '<':
2036			matched = dv < dl;
2037			break;
2038
2039		default:
2040			file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
2041			return -1;
2042		}
2043		return matched;
2044
2045	case FILE_DEFAULT:
2046	case FILE_CLEAR:
2047		l = 0;
2048		v = 0;
2049		break;
2050
2051	case FILE_STRING:
2052	case FILE_PSTRING:
2053		l = 0;
2054		v = file_strncmp(m->value.s, p->s, CAST(size_t, m->vallen),
2055		    m->str_flags);
2056		break;
2057
2058	case FILE_BESTRING16:
2059	case FILE_LESTRING16:
2060		l = 0;
2061		v = file_strncmp16(m->value.s, p->s, CAST(size_t, m->vallen),
2062		    m->str_flags);
2063		break;
2064
2065	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
2066		size_t slen;
2067		size_t idx;
2068
2069		if (ms->search.s == NULL)
2070			return 0;
2071
2072		slen = MIN(m->vallen, sizeof(m->value.s));
2073		l = 0;
2074		v = 0;
2075#ifdef HAVE_MEMMEM
2076		if (slen > 0 && m->str_flags == 0) {
2077			const char *found;
2078			idx = m->str_range + slen;
2079			if (m->str_range == 0 || ms->search.s_len < idx)
2080				idx = ms->search.s_len;
2081			found = CAST(const char *, memmem(ms->search.s, idx,
2082			    m->value.s, slen));
2083			if (!found)
2084				return 0;
2085			idx = found - ms->search.s;
2086			ms->search.offset += idx;
2087			ms->search.rm_len = ms->search.s_len - idx;
2088			break;
2089		}
2090#endif
2091
2092		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
2093			if (slen + idx > ms->search.s_len)
2094				return 0;
2095
2096			v = file_strncmp(m->value.s, ms->search.s + idx, slen,
2097			    m->str_flags);
2098			if (v == 0) {	/* found match */
2099				ms->search.offset += idx;
2100				ms->search.rm_len = ms->search.s_len - idx;
2101				break;
2102			}
2103		}
2104		break;
2105	}
2106	case FILE_REGEX: {
2107		int rc;
2108		file_regex_t rx;
2109		const char *search;
2110
2111		if (ms->search.s == NULL)
2112			return 0;
2113
2114		l = 0;
2115		rc = file_regcomp(&rx, m->value.s,
2116		    REG_EXTENDED|REG_NEWLINE|
2117		    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
2118		if (rc) {
2119			file_regerror(&rx, rc, ms);
2120			v = CAST(uint64_t, -1);
2121		} else {
2122			regmatch_t pmatch;
2123			size_t slen = ms->search.s_len;
2124			char *copy;
2125			if (slen != 0) {
2126			    copy = CAST(char *, malloc(slen));
2127			    if (copy == NULL)  {
2128				file_regfree(&rx);
2129				file_error(ms, errno,
2130				    "can't allocate %" SIZE_T_FORMAT "u bytes",
2131				    slen);
2132				return -1;
2133			    }
2134			    memcpy(copy, ms->search.s, slen);
2135			    copy[--slen] = '\0';
2136			    search = copy;
2137			} else {
2138			    search = CCAST(char *, "");
2139			    copy = NULL;
2140			}
2141			rc = file_regexec(&rx, RCAST(const char *, search),
2142			    1, &pmatch, 0);
2143			free(copy);
2144			switch (rc) {
2145			case 0:
2146				ms->search.s += CAST(int, pmatch.rm_so);
2147				ms->search.offset += CAST(size_t, pmatch.rm_so);
2148				ms->search.rm_len = CAST(size_t,
2149				    pmatch.rm_eo - pmatch.rm_so);
2150				v = 0;
2151				break;
2152
2153			case REG_NOMATCH:
2154				v = 1;
2155				break;
2156
2157			default:
2158				file_regerror(&rx, rc, ms);
2159				v = CAST(uint64_t, -1);
2160				break;
2161			}
2162		}
2163		file_regfree(&rx);
2164		if (v == CAST(uint64_t, -1))
2165			return -1;
2166		break;
2167	}
2168	case FILE_INDIRECT:
2169	case FILE_USE:
2170	case FILE_NAME:
2171		return 1;
2172	case FILE_DER:
2173		matched = der_cmp(ms, m);
2174		if (matched == -1) {
2175			if ((ms->flags & MAGIC_DEBUG) != 0) {
2176				(void) fprintf(stderr,
2177				    "EOF comparing DER entries");
2178			}
2179			return 0;
2180		}
2181		return matched;
2182	default:
2183		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2184		return -1;
2185	}
2186
2187	v = file_signextend(ms, m, v);
2188
2189	switch (m->reln) {
2190	case 'x':
2191		if ((ms->flags & MAGIC_DEBUG) != 0)
2192			(void) fprintf(stderr, "%" INT64_T_FORMAT
2193			    "u == *any* = 1\n", CAST(unsigned long long, v));
2194		matched = 1;
2195		break;
2196
2197	case '!':
2198		matched = v != l;
2199		if ((ms->flags & MAGIC_DEBUG) != 0)
2200			(void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2201			    INT64_T_FORMAT "u = %d\n",
2202			    CAST(unsigned long long, v),
2203			    CAST(unsigned long long, l), matched);
2204		break;
2205
2206	case '=':
2207		matched = v == l;
2208		if ((ms->flags & MAGIC_DEBUG) != 0)
2209			(void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2210			    INT64_T_FORMAT "u = %d\n",
2211			    CAST(unsigned long long, v),
2212			    CAST(unsigned long long, l), matched);
2213		break;
2214
2215	case '>':
2216		if (m->flag & UNSIGNED) {
2217			matched = v > l;
2218			if ((ms->flags & MAGIC_DEBUG) != 0)
2219				(void) fprintf(stderr, "%" INT64_T_FORMAT
2220				    "u > %" INT64_T_FORMAT "u = %d\n",
2221				    CAST(unsigned long long, v),
2222				    CAST(unsigned long long, l), matched);
2223		}
2224		else {
2225			matched = CAST(int64_t, v) > CAST(int64_t, l);
2226			if ((ms->flags & MAGIC_DEBUG) != 0)
2227				(void) fprintf(stderr, "%" INT64_T_FORMAT
2228				    "d > %" INT64_T_FORMAT "d = %d\n",
2229				    CAST(long long, v),
2230				    CAST(long long, l), matched);
2231		}
2232		break;
2233
2234	case '<':
2235		if (m->flag & UNSIGNED) {
2236			matched = v < l;
2237			if ((ms->flags & MAGIC_DEBUG) != 0)
2238				(void) fprintf(stderr, "%" INT64_T_FORMAT
2239				    "u < %" INT64_T_FORMAT "u = %d\n",
2240				    CAST(unsigned long long, v),
2241				    CAST(unsigned long long, l), matched);
2242		}
2243		else {
2244			matched = CAST(int64_t, v) < CAST(int64_t, l);
2245			if ((ms->flags & MAGIC_DEBUG) != 0)
2246				(void) fprintf(stderr, "%" INT64_T_FORMAT
2247				    "d < %" INT64_T_FORMAT "d = %d\n",
2248				     CAST(long long, v),
2249				     CAST(long long, l), matched);
2250		}
2251		break;
2252
2253	case '&':
2254		matched = (v & l) == l;
2255		if ((ms->flags & MAGIC_DEBUG) != 0)
2256			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2257			    INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2258			    "x) = %d\n", CAST(unsigned long long, v),
2259			    CAST(unsigned long long, l),
2260			    CAST(unsigned long long, l),
2261			    matched);
2262		break;
2263
2264	case '^':
2265		matched = (v & l) != l;
2266		if ((ms->flags & MAGIC_DEBUG) != 0)
2267			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2268			    INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2269			    "x) = %d\n", CAST(unsigned long long, v),
2270			    CAST(unsigned long long, l),
2271			    CAST(unsigned long long, l), matched);
2272		break;
2273
2274	default:
2275		file_magerror(ms, "cannot happen: invalid relation `%c'",
2276		    m->reln);
2277		return -1;
2278	}
2279
2280	return matched;
2281}
2282
2283private int
2284handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
2285{
2286	if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
2287		if (print_sep(ms, firstline) == -1)
2288			return -1;
2289		if (file_printf(ms, "%.8s", m->apple) == -1)
2290			return -1;
2291		return 1;
2292	}
2293	if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
2294		if (print_sep(ms, firstline) == -1)
2295			return -1;
2296		if (file_printf(ms, "%s", m->ext) == -1)
2297			return -1;
2298		return 1;
2299	}
2300	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2301		char buf[1024];
2302		const char *p;
2303		if (print_sep(ms, firstline) == -1)
2304			return -1;
2305		if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1)
2306			p = m->mimetype;
2307		else
2308			p = buf;
2309		if (file_printf(ms, "%s", p) == -1)
2310			return -1;
2311		return 1;
2312	}
2313	return 0;
2314}
2315
2316private int
2317print_sep(struct magic_set *ms, int firstline)
2318{
2319	if (firstline)
2320		return 0;
2321	/*
2322	 * we found another match
2323	 * put a newline and '-' to do some simple formatting
2324	 */
2325	return file_separator(ms);
2326}
2327