xref: /openbsd-src/usr.bin/file/magic-test.c (revision bb180e11c8986de5b312f1987cbcd1fe89017ab5)
1*bb180e11Snicm /* $OpenBSD: magic-test.c,v 1.27 2019/01/15 09:24:59 nicm Exp $ */
2ff772f70Snicm 
3ff772f70Snicm /*
4ff772f70Snicm  * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5ff772f70Snicm  *
6ff772f70Snicm  * Permission to use, copy, modify, and distribute this software for any
7ff772f70Snicm  * purpose with or without fee is hereby granted, provided that the above
8ff772f70Snicm  * copyright notice and this permission notice appear in all copies.
9ff772f70Snicm  *
10ff772f70Snicm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ff772f70Snicm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ff772f70Snicm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ff772f70Snicm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ff772f70Snicm  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15ff772f70Snicm  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16ff772f70Snicm  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ff772f70Snicm  */
18ff772f70Snicm 
19ff772f70Snicm #include <sys/types.h>
20ff772f70Snicm 
21ff772f70Snicm #include <ctype.h>
22ff772f70Snicm #include <errno.h>
23ff772f70Snicm #include <fcntl.h>
24ff772f70Snicm #include <limits.h>
25ff772f70Snicm #include <stdarg.h>
26ff772f70Snicm #include <stdio.h>
27ff772f70Snicm #include <stdint.h>
28ff772f70Snicm #include <stdlib.h>
29ff772f70Snicm #include <string.h>
30528a98a6Sguenther #include <time.h>
31ff772f70Snicm #include <unistd.h>
32ff772f70Snicm #include <vis.h>
33ff772f70Snicm 
34ff772f70Snicm #include "magic.h"
35ff772f70Snicm #include "xmalloc.h"
36ff772f70Snicm 
37c673ceb0Snicm static int magic_test_line(struct magic_line *, struct magic_state *);
38c673ceb0Snicm 
39c673ceb0Snicm static struct magic_line *
magic_get_named(struct magic * m,const char * name)40c673ceb0Snicm magic_get_named(struct magic *m, const char *name)
41c673ceb0Snicm {
42c673ceb0Snicm 	struct magic_line	ml;
43c673ceb0Snicm 
44c673ceb0Snicm 	ml.name = name;
45c673ceb0Snicm 	return (RB_FIND(magic_named_tree, &m->named, &ml));
46c673ceb0Snicm }
47c673ceb0Snicm 
48c673ceb0Snicm static enum magic_type
magic_reverse_type(struct magic_state * ms,enum magic_type type)49c673ceb0Snicm magic_reverse_type(struct magic_state *ms, enum magic_type type)
50c673ceb0Snicm {
51c673ceb0Snicm 	if (!ms->reverse)
52c673ceb0Snicm 		return (type);
53c673ceb0Snicm 	switch (type) {
54c673ceb0Snicm 	case MAGIC_TYPE_BESHORT:
55c673ceb0Snicm 		return (MAGIC_TYPE_LESHORT);
56c673ceb0Snicm 	case MAGIC_TYPE_BELONG:
57c673ceb0Snicm 		return (MAGIC_TYPE_LELONG);
58c673ceb0Snicm 	case MAGIC_TYPE_BEQUAD:
59c673ceb0Snicm 		return (MAGIC_TYPE_LEQUAD);
60c673ceb0Snicm 	case MAGIC_TYPE_UBESHORT:
61c673ceb0Snicm 		return (MAGIC_TYPE_ULESHORT);
62c673ceb0Snicm 	case MAGIC_TYPE_UBELONG:
63c673ceb0Snicm 		return (MAGIC_TYPE_ULELONG);
64c673ceb0Snicm 	case MAGIC_TYPE_UBEQUAD:
65c673ceb0Snicm 		return (MAGIC_TYPE_ULEQUAD);
66c673ceb0Snicm 	case MAGIC_TYPE_BEFLOAT:
67c673ceb0Snicm 		return (MAGIC_TYPE_LEFLOAT);
68c673ceb0Snicm 	case MAGIC_TYPE_BEDOUBLE:
69c673ceb0Snicm 		return (MAGIC_TYPE_LEDOUBLE);
70c673ceb0Snicm 	case MAGIC_TYPE_BEDATE:
71c673ceb0Snicm 		return (MAGIC_TYPE_LEDATE);
72c673ceb0Snicm 	case MAGIC_TYPE_BEQDATE:
73c673ceb0Snicm 		return (MAGIC_TYPE_LEQDATE);
74c673ceb0Snicm 	case MAGIC_TYPE_BELDATE:
75c673ceb0Snicm 		return (MAGIC_TYPE_LELDATE);
76c673ceb0Snicm 	case MAGIC_TYPE_BEQLDATE:
77c673ceb0Snicm 		return (MAGIC_TYPE_LEQLDATE);
78c673ceb0Snicm 	case MAGIC_TYPE_UBEDATE:
79c673ceb0Snicm 		return (MAGIC_TYPE_ULEDATE);
80c673ceb0Snicm 	case MAGIC_TYPE_UBEQDATE:
81c673ceb0Snicm 		return (MAGIC_TYPE_ULEQDATE);
82c673ceb0Snicm 	case MAGIC_TYPE_UBELDATE:
83c673ceb0Snicm 		return (MAGIC_TYPE_ULELDATE);
84c673ceb0Snicm 	case MAGIC_TYPE_UBEQLDATE:
85c673ceb0Snicm 		return (MAGIC_TYPE_ULEQLDATE);
86c673ceb0Snicm 	case MAGIC_TYPE_LESHORT:
87c673ceb0Snicm 		return (MAGIC_TYPE_BESHORT);
88c673ceb0Snicm 	case MAGIC_TYPE_LELONG:
89c673ceb0Snicm 		return (MAGIC_TYPE_LELONG);
90c673ceb0Snicm 	case MAGIC_TYPE_LEQUAD:
91c673ceb0Snicm 		return (MAGIC_TYPE_LEQUAD);
92c673ceb0Snicm 	case MAGIC_TYPE_ULESHORT:
93c673ceb0Snicm 		return (MAGIC_TYPE_UBESHORT);
94c673ceb0Snicm 	case MAGIC_TYPE_ULELONG:
95c673ceb0Snicm 		return (MAGIC_TYPE_UBELONG);
96c673ceb0Snicm 	case MAGIC_TYPE_ULEQUAD:
97c673ceb0Snicm 		return (MAGIC_TYPE_UBEQUAD);
98c673ceb0Snicm 	case MAGIC_TYPE_LEFLOAT:
99c673ceb0Snicm 		return (MAGIC_TYPE_BEFLOAT);
100c673ceb0Snicm 	case MAGIC_TYPE_LEDOUBLE:
101c673ceb0Snicm 		return (MAGIC_TYPE_BEDOUBLE);
102c673ceb0Snicm 	case MAGIC_TYPE_LEDATE:
103c673ceb0Snicm 		return (MAGIC_TYPE_BEDATE);
104c673ceb0Snicm 	case MAGIC_TYPE_LEQDATE:
105c673ceb0Snicm 		return (MAGIC_TYPE_BEQDATE);
106c673ceb0Snicm 	case MAGIC_TYPE_LELDATE:
107c673ceb0Snicm 		return (MAGIC_TYPE_BELDATE);
108c673ceb0Snicm 	case MAGIC_TYPE_LEQLDATE:
109c673ceb0Snicm 		return (MAGIC_TYPE_BEQLDATE);
110c673ceb0Snicm 	case MAGIC_TYPE_ULEDATE:
111c673ceb0Snicm 		return (MAGIC_TYPE_UBEDATE);
112c673ceb0Snicm 	case MAGIC_TYPE_ULEQDATE:
113c673ceb0Snicm 		return (MAGIC_TYPE_UBEQDATE);
114c673ceb0Snicm 	case MAGIC_TYPE_ULELDATE:
115c673ceb0Snicm 		return (MAGIC_TYPE_UBELDATE);
116c673ceb0Snicm 	case MAGIC_TYPE_ULEQLDATE:
117c673ceb0Snicm 		return (MAGIC_TYPE_UBEQLDATE);
118c673ceb0Snicm 	default:
119c673ceb0Snicm 		return (type);
120c673ceb0Snicm 	}
121c673ceb0Snicm }
122c673ceb0Snicm 
123ff772f70Snicm static int
magic_one_eq(char a,char b,int cflag)124ff772f70Snicm magic_one_eq(char a, char b, int cflag)
125ff772f70Snicm {
126ff772f70Snicm 	if (a == b)
127ff772f70Snicm 		return (1);
12860ed151aSnicm 	if (cflag && islower((u_char)b) && tolower((u_char)a) == (u_char)b)
129ff772f70Snicm 		return (1);
130ff772f70Snicm 	return (0);
131ff772f70Snicm }
132ff772f70Snicm 
133ff772f70Snicm static int
magic_test_eq(const char * ap,size_t asize,const char * bp,size_t bsize,int cflag,int bflag,int Bflag)134ff772f70Snicm magic_test_eq(const char *ap, size_t asize, const char *bp, size_t bsize,
135ff772f70Snicm     int cflag, int bflag, int Bflag)
136ff772f70Snicm {
137ff772f70Snicm 	size_t	aoff, boff, aspaces, bspaces;
138ff772f70Snicm 
139ff772f70Snicm 	aoff = boff = 0;
140ff772f70Snicm 	while (aoff != asize && boff != bsize) {
141ff772f70Snicm 		if (Bflag && isspace((u_char)ap[aoff])) {
142ff772f70Snicm 			aspaces = 0;
143ff772f70Snicm 			while (aoff != asize && isspace((u_char)ap[aoff])) {
144ff772f70Snicm 				aspaces++;
145ff772f70Snicm 				aoff++;
146ff772f70Snicm 			}
147ff772f70Snicm 			bspaces = 0;
148ff772f70Snicm 			while (boff != bsize && isspace((u_char)bp[boff])) {
149ff772f70Snicm 				bspaces++;
150ff772f70Snicm 				boff++;
151ff772f70Snicm 			}
152ff772f70Snicm 			if (bspaces >= aspaces)
153ff772f70Snicm 				continue;
154ff772f70Snicm 			return (1);
155ff772f70Snicm 		}
156ff772f70Snicm 		if (magic_one_eq(ap[aoff], bp[boff], cflag)) {
157ff772f70Snicm 			aoff++;
158ff772f70Snicm 			boff++;
159ff772f70Snicm 			continue;
160ff772f70Snicm 		}
161ff772f70Snicm 		if (bflag && isspace((u_char)bp[boff])) {
162ff772f70Snicm 			boff++;
163ff772f70Snicm 			continue;
164ff772f70Snicm 		}
165ff772f70Snicm 		if (ap[aoff] < bp[boff])
166ff772f70Snicm 			return (-1);
167ff772f70Snicm 		return (1);
168ff772f70Snicm 	}
169ff772f70Snicm 	return (0);
170ff772f70Snicm }
171ff772f70Snicm 
172ff772f70Snicm static int
magic_copy_from(struct magic_state * ms,ssize_t offset,void * dst,size_t size)173ff772f70Snicm magic_copy_from(struct magic_state *ms, ssize_t offset, void *dst, size_t size)
174ff772f70Snicm {
175ff772f70Snicm 	if (offset < 0)
176ff772f70Snicm 		offset = ms->offset;
177ff772f70Snicm 	if (offset + size > ms->size)
178ff772f70Snicm 		return (-1);
179ff772f70Snicm 	memcpy(dst, ms->base + offset, size);
180ff772f70Snicm 	return (0);
181ff772f70Snicm }
182ff772f70Snicm 
183ff772f70Snicm static void
magic_add_result(struct magic_state * ms,struct magic_line * ml,const char * fmt,...)184ff772f70Snicm magic_add_result(struct magic_state *ms, struct magic_line *ml,
185ff772f70Snicm     const char *fmt, ...)
186ff772f70Snicm {
187ff772f70Snicm 	va_list	 ap;
188ff772f70Snicm 	int	 separate;
189ff772f70Snicm 	char	*s, *tmp, *add;
190ff772f70Snicm 
191ff772f70Snicm 	va_start(ap, fmt);
192ff772f70Snicm 	if (ml->stringify) {
193ff772f70Snicm 		if (vasprintf(&s, fmt, ap) == -1) {
194ff772f70Snicm 			va_end(ap);
195ff772f70Snicm 			return;
196ff772f70Snicm 		}
197ff772f70Snicm 		va_end(ap);
198ff772f70Snicm 		if (asprintf(&tmp, ml->result, s) == -1) {
199ff772f70Snicm 			free(s);
200ff772f70Snicm 			return;
201ff772f70Snicm 		}
202ff772f70Snicm 		free(s);
203ff772f70Snicm 	} else {
204ff772f70Snicm 		if (vasprintf(&tmp, ml->result, ap) == -1) {
205ff772f70Snicm 			va_end(ap);
206ff772f70Snicm 			return;
207ff772f70Snicm 		}
208ff772f70Snicm 		va_end(ap);
209ff772f70Snicm 	}
210ff772f70Snicm 
211ff772f70Snicm 	separate = 1;
212ff772f70Snicm 	if (tmp[0] == '\\' && tmp[1] == 'b') {
213ff772f70Snicm 		separate = 0;
214ff772f70Snicm 		add = tmp + 2;
215ff772f70Snicm 	} else
216ff772f70Snicm 		add = tmp;
217ff772f70Snicm 
218ff772f70Snicm 	if (separate && *ms->out != '\0')
219ff772f70Snicm 		strlcat(ms->out, " ", sizeof ms->out);
220ff772f70Snicm 	strlcat(ms->out, add, sizeof ms->out);
221ff772f70Snicm 
222ff772f70Snicm 	free(tmp);
223ff772f70Snicm }
224ff772f70Snicm 
225ff772f70Snicm static void
magic_add_string(struct magic_state * ms,struct magic_line * ml,const char * s,size_t slen)226ff772f70Snicm magic_add_string(struct magic_state *ms, struct magic_line *ml,
227ff772f70Snicm     const char *s, size_t slen)
228ff772f70Snicm {
229ff772f70Snicm 	char	*out;
230ff772f70Snicm 	size_t	 outlen, offset;
231ff772f70Snicm 
232ff772f70Snicm 	outlen = MAGIC_STRING_SIZE;
233ff772f70Snicm 	if (outlen > slen)
234ff772f70Snicm 		outlen = slen;
235ff772f70Snicm 	for (offset = 0; offset < outlen; offset++) {
236ff772f70Snicm 		if (s[offset] == '\0' || !isprint((u_char)s[offset])) {
237ff772f70Snicm 			outlen = offset;
238ff772f70Snicm 			break;
239ff772f70Snicm 		}
240ff772f70Snicm 	}
241ff772f70Snicm 	out = xreallocarray(NULL, 4, outlen + 1);
242ff772f70Snicm 	strvisx(out, s, outlen, VIS_TAB|VIS_NL|VIS_CSTYLE|VIS_OCTAL);
243ff772f70Snicm 	magic_add_result(ms, ml, "%s", out);
244ff772f70Snicm 	free(out);
245ff772f70Snicm }
246ff772f70Snicm 
247ff772f70Snicm static int
magic_test_signed(struct magic_line * ml,int64_t value,int64_t wanted)248ff772f70Snicm magic_test_signed(struct magic_line *ml, int64_t value, int64_t wanted)
249ff772f70Snicm {
250ff772f70Snicm 	switch (ml->test_operator) {
251ff772f70Snicm 	case 'x':
252ff772f70Snicm 		return (1);
253ff772f70Snicm 	case '<':
254ff772f70Snicm 		return (value < wanted);
255ff772f70Snicm 	case '[':
256ff772f70Snicm 		return (value <= wanted);
257ff772f70Snicm 	case '>':
258ff772f70Snicm 		return (value > wanted);
259ff772f70Snicm 	case ']':
260ff772f70Snicm 		return (value >= wanted);
261ff772f70Snicm 	case '=':
262ff772f70Snicm 		return (value == wanted);
263ff772f70Snicm 	case '&':
264ff772f70Snicm 		return ((value & wanted) == wanted);
265ff772f70Snicm 	case '^':
266ff772f70Snicm 		return ((~value & wanted) == wanted);
267ff772f70Snicm 	}
268ff772f70Snicm 	return (-1);
269ff772f70Snicm }
270ff772f70Snicm 
271ff772f70Snicm static int
magic_test_unsigned(struct magic_line * ml,uint64_t value,uint64_t wanted)272ff772f70Snicm magic_test_unsigned(struct magic_line *ml, uint64_t value, uint64_t wanted)
273ff772f70Snicm {
274ff772f70Snicm 	switch (ml->test_operator) {
275ff772f70Snicm 	case 'x':
276ff772f70Snicm 		return (1);
277ff772f70Snicm 	case '<':
278ff772f70Snicm 		return (value < wanted);
279ff772f70Snicm 	case '[':
280ff772f70Snicm 		return (value <= wanted);
281ff772f70Snicm 	case '>':
282ff772f70Snicm 		return (value > wanted);
283ff772f70Snicm 	case ']':
284ff772f70Snicm 		return (value >= wanted);
285ff772f70Snicm 	case '=':
286ff772f70Snicm 		return (value == wanted);
287ff772f70Snicm 	case '&':
288ff772f70Snicm 		return ((value & wanted) == wanted);
289ff772f70Snicm 	case '^':
290ff772f70Snicm 		return ((~value & wanted) == wanted);
291ff772f70Snicm 	}
292ff772f70Snicm 	return (-1);
293ff772f70Snicm }
294ff772f70Snicm 
295ff772f70Snicm static int
magic_test_double(struct magic_line * ml,double value,double wanted)29695651d73Snicm magic_test_double(struct magic_line *ml, double value, double wanted)
29795651d73Snicm {
29895651d73Snicm 	switch (ml->test_operator) {
29995651d73Snicm 	case 'x':
30095651d73Snicm 		return (1);
30195651d73Snicm 	case '=':
30295651d73Snicm 		return (value == wanted);
30395651d73Snicm 	}
30495651d73Snicm 	return (-1);
30595651d73Snicm }
30695651d73Snicm 
30795651d73Snicm static int
magic_test_type_none(__unused struct magic_line * ml,__unused struct magic_state * ms)308ff772f70Snicm magic_test_type_none(__unused struct magic_line *ml,
309ff772f70Snicm     __unused struct magic_state *ms)
310ff772f70Snicm {
311ff772f70Snicm 	return (0);
312ff772f70Snicm }
313ff772f70Snicm 
314ff772f70Snicm static int
magic_test_type_byte(struct magic_line * ml,struct magic_state * ms)315ff772f70Snicm magic_test_type_byte(struct magic_line *ml, struct magic_state *ms)
316ff772f70Snicm {
317ff772f70Snicm 	int8_t	value;
318ff772f70Snicm 	int	result;
319ff772f70Snicm 
320ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
321ff772f70Snicm 		return (0);
322ff772f70Snicm 
323ff772f70Snicm 	if (ml->type_operator == '&')
324ff772f70Snicm 		value &= (int8_t)ml->type_operand;
3253115b575Snicm 	else if (ml->type_operator == '-')
3263115b575Snicm 		value -= (int8_t)ml->type_operand;
3273115b575Snicm 	else if (ml->type_operator == '+')
3283115b575Snicm 		value += (int8_t)ml->type_operand;
3293115b575Snicm 	else if (ml->type_operator == '/')
3303115b575Snicm 		value /= (int8_t)ml->type_operand;
3313115b575Snicm 	else if (ml->type_operator == '%')
3323115b575Snicm 		value %= (int8_t)ml->type_operand;
3333115b575Snicm 	else if (ml->type_operator == '*')
3343115b575Snicm 		value *= (int8_t)ml->type_operand;
335ff772f70Snicm 	else if (ml->type_operator != ' ')
336ff772f70Snicm 		return (-1);
337ff772f70Snicm 
338ff772f70Snicm 	result = magic_test_signed(ml, value, (int8_t)ml->test_signed);
339ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
340ff772f70Snicm 		magic_add_result(ms, ml, "%c", (int)value);
341ff772f70Snicm 		ms->offset += sizeof value;
342ff772f70Snicm 	}
343ff772f70Snicm 	return (result);
344ff772f70Snicm }
345ff772f70Snicm 
346ff772f70Snicm static int
magic_test_type_short(struct magic_line * ml,struct magic_state * ms)347ff772f70Snicm magic_test_type_short(struct magic_line *ml, struct magic_state *ms)
348ff772f70Snicm {
349ff772f70Snicm 	int16_t value;
350ff772f70Snicm 	int	result;
351ff772f70Snicm 
352ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
353ff772f70Snicm 		return (0);
354c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BESHORT))
355cff0cfedSbrynet 		value = be16toh(value);
356c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LESHORT))
357cff0cfedSbrynet 		value = le16toh(value);
358ff772f70Snicm 
359ff772f70Snicm 	if (ml->type_operator == '&')
360ff772f70Snicm 		value &= (int16_t)ml->type_operand;
3613115b575Snicm 	else if (ml->type_operator == '-')
3623115b575Snicm 		value -= (int16_t)ml->type_operand;
3633115b575Snicm 	else if (ml->type_operator == '+')
3643115b575Snicm 		value += (int16_t)ml->type_operand;
3653115b575Snicm 	else if (ml->type_operator == '/')
3663115b575Snicm 		value /= (int16_t)ml->type_operand;
3673115b575Snicm 	else if (ml->type_operator == '%')
3683115b575Snicm 		value %= (int16_t)ml->type_operand;
3693115b575Snicm 	else if (ml->type_operator == '*')
3703115b575Snicm 		value *= (int16_t)ml->type_operand;
371ff772f70Snicm 	else if (ml->type_operator != ' ')
372ff772f70Snicm 		return (-1);
373ff772f70Snicm 
374ff772f70Snicm 	result = magic_test_signed(ml, value, (int16_t)ml->test_signed);
375ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
376ff772f70Snicm 		magic_add_result(ms, ml, "%hd", (int)value);
377ff772f70Snicm 		ms->offset += sizeof value;
378ff772f70Snicm 	}
379ff772f70Snicm 	return (result);
380ff772f70Snicm }
381ff772f70Snicm 
382ff772f70Snicm static int
magic_test_type_long(struct magic_line * ml,struct magic_state * ms)383ff772f70Snicm magic_test_type_long(struct magic_line *ml, struct magic_state *ms)
384ff772f70Snicm {
385ff772f70Snicm 	int32_t value;
386ff772f70Snicm 	int	result;
387ff772f70Snicm 
388ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
389ff772f70Snicm 		return (0);
390c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BELONG))
391cff0cfedSbrynet 		value = be32toh(value);
392c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LELONG))
393cff0cfedSbrynet 		value = le32toh(value);
394ff772f70Snicm 
395ff772f70Snicm 	if (ml->type_operator == '&')
396ff772f70Snicm 		value &= (int32_t)ml->type_operand;
3973115b575Snicm 	else if (ml->type_operator == '-')
3983115b575Snicm 		value -= (int32_t)ml->type_operand;
3993115b575Snicm 	else if (ml->type_operator == '+')
4003115b575Snicm 		value += (int32_t)ml->type_operand;
4013115b575Snicm 	else if (ml->type_operator == '/')
4023115b575Snicm 		value /= (int32_t)ml->type_operand;
4033115b575Snicm 	else if (ml->type_operator == '%')
4043115b575Snicm 		value %= (int32_t)ml->type_operand;
4053115b575Snicm 	else if (ml->type_operator == '*')
4063115b575Snicm 		value *= (int32_t)ml->type_operand;
407ff772f70Snicm 	else if (ml->type_operator != ' ')
408ff772f70Snicm 		return (-1);
409ff772f70Snicm 
410ff772f70Snicm 	result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
411ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
412ff772f70Snicm 		magic_add_result(ms, ml, "%d", (int)value);
413ff772f70Snicm 		ms->offset += sizeof value;
414ff772f70Snicm 	}
415ff772f70Snicm 	return (result);
416ff772f70Snicm }
417ff772f70Snicm 
418ff772f70Snicm static int
magic_test_type_quad(struct magic_line * ml,struct magic_state * ms)419ff772f70Snicm magic_test_type_quad(struct magic_line *ml, struct magic_state *ms)
420ff772f70Snicm {
421ff772f70Snicm 	int64_t value;
422ff772f70Snicm 	int	result;
423ff772f70Snicm 
424ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
425ff772f70Snicm 		return (0);
426c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEQUAD))
427cff0cfedSbrynet 		value = be64toh(value);
428c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEQUAD))
429cff0cfedSbrynet 		value = le64toh(value);
430ff772f70Snicm 
431ff772f70Snicm 	if (ml->type_operator == '&')
432ff772f70Snicm 		value &= (int64_t)ml->type_operand;
4333115b575Snicm 	else if (ml->type_operator == '-')
4343115b575Snicm 		value -= (int64_t)ml->type_operand;
4353115b575Snicm 	else if (ml->type_operator == '+')
4363115b575Snicm 		value += (int64_t)ml->type_operand;
4373115b575Snicm 	else if (ml->type_operator == '/')
4383115b575Snicm 		value /= (int64_t)ml->type_operand;
4393115b575Snicm 	else if (ml->type_operator == '%')
4403115b575Snicm 		value %= (int64_t)ml->type_operand;
4413115b575Snicm 	else if (ml->type_operator == '*')
4423115b575Snicm 		value *= (int64_t)ml->type_operand;
443ff772f70Snicm 	else if (ml->type_operator != ' ')
444ff772f70Snicm 		return (-1);
445ff772f70Snicm 
446ff772f70Snicm 	result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
447ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
448ff772f70Snicm 		magic_add_result(ms, ml, "%lld", (long long)value);
449ff772f70Snicm 		ms->offset += sizeof value;
450ff772f70Snicm 	}
451ff772f70Snicm 	return (result);
452ff772f70Snicm }
453ff772f70Snicm 
454ff772f70Snicm static int
magic_test_type_ubyte(struct magic_line * ml,struct magic_state * ms)455ff772f70Snicm magic_test_type_ubyte(struct magic_line *ml, struct magic_state *ms)
456ff772f70Snicm {
457ff772f70Snicm 	uint8_t value;
458ff772f70Snicm 	int	result;
459ff772f70Snicm 
460ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
461ff772f70Snicm 		return (0);
462ff772f70Snicm 
463ff772f70Snicm 	if (ml->type_operator == '&')
464ff772f70Snicm 		value &= (uint8_t)ml->type_operand;
4653115b575Snicm 	else if (ml->type_operator == '-')
4663115b575Snicm 		value -= (uint8_t)ml->type_operand;
4673115b575Snicm 	else if (ml->type_operator == '+')
4683115b575Snicm 		value += (uint8_t)ml->type_operand;
4693115b575Snicm 	else if (ml->type_operator == '/')
4703115b575Snicm 		value /= (uint8_t)ml->type_operand;
4713115b575Snicm 	else if (ml->type_operator == '%')
4723115b575Snicm 		value %= (uint8_t)ml->type_operand;
4733115b575Snicm 	else if (ml->type_operator == '*')
4743115b575Snicm 		value *= (uint8_t)ml->type_operand;
475ff772f70Snicm 	else if (ml->type_operator != ' ')
476ff772f70Snicm 		return (-1);
477ff772f70Snicm 
478ff772f70Snicm 	result = magic_test_unsigned(ml, value, (uint8_t)ml->test_unsigned);
479ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
480ff772f70Snicm 		magic_add_result(ms, ml, "%c", (unsigned int)value);
481ff772f70Snicm 		ms->offset += sizeof value;
482ff772f70Snicm 	}
483ff772f70Snicm 	return (result);
484ff772f70Snicm }
485ff772f70Snicm 
486ff772f70Snicm static int
magic_test_type_ushort(struct magic_line * ml,struct magic_state * ms)487ff772f70Snicm magic_test_type_ushort(struct magic_line *ml, struct magic_state *ms)
488ff772f70Snicm {
489ff772f70Snicm 	uint16_t	value;
490ff772f70Snicm 	int		result;
491ff772f70Snicm 
492ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
493ff772f70Snicm 		return (0);
494ff772f70Snicm 	if (ml->type == MAGIC_TYPE_UBESHORT)
495cff0cfedSbrynet 		value = be16toh(value);
496ff772f70Snicm 	if (ml->type == MAGIC_TYPE_ULESHORT)
497cff0cfedSbrynet 		value = le16toh(value);
498ff772f70Snicm 
499ff772f70Snicm 	if (ml->type_operator == '&')
500ff772f70Snicm 		value &= (uint16_t)ml->type_operand;
5013115b575Snicm 	else if (ml->type_operator == '-')
5023115b575Snicm 		value -= (uint16_t)ml->type_operand;
5033115b575Snicm 	else if (ml->type_operator == '+')
5043115b575Snicm 		value += (uint16_t)ml->type_operand;
5053115b575Snicm 	else if (ml->type_operator == '/')
5063115b575Snicm 		value /= (uint16_t)ml->type_operand;
5073115b575Snicm 	else if (ml->type_operator == '%')
5083115b575Snicm 		value %= (uint16_t)ml->type_operand;
5093115b575Snicm 	else if (ml->type_operator == '*')
5103115b575Snicm 		value *= (uint16_t)ml->type_operand;
511ff772f70Snicm 	else if (ml->type_operator != ' ')
512ff772f70Snicm 		return (-1);
513ff772f70Snicm 
514ff772f70Snicm 	result = magic_test_unsigned(ml, value, (uint16_t)ml->test_unsigned);
515ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
516ff772f70Snicm 		magic_add_result(ms, ml, "%hu", (unsigned int)value);
517ff772f70Snicm 		ms->offset += sizeof value;
518ff772f70Snicm 	}
519ff772f70Snicm 	return (result);
520ff772f70Snicm }
521ff772f70Snicm 
522ff772f70Snicm static int
magic_test_type_ulong(struct magic_line * ml,struct magic_state * ms)523ff772f70Snicm magic_test_type_ulong(struct magic_line *ml, struct magic_state *ms)
524ff772f70Snicm {
525ff772f70Snicm 	uint32_t	value;
526ff772f70Snicm 	int		result;
527ff772f70Snicm 
528ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
529ff772f70Snicm 		return (0);
530ff772f70Snicm 	if (ml->type == MAGIC_TYPE_UBELONG)
531cff0cfedSbrynet 		value = be32toh(value);
532ff772f70Snicm 	if (ml->type == MAGIC_TYPE_ULELONG)
533cff0cfedSbrynet 		value = le32toh(value);
534ff772f70Snicm 
535ff772f70Snicm 	if (ml->type_operator == '&')
536ff772f70Snicm 		value &= (uint32_t)ml->type_operand;
5373115b575Snicm 	else if (ml->type_operator == '-')
5383115b575Snicm 		value -= (uint32_t)ml->type_operand;
5393115b575Snicm 	else if (ml->type_operator == '+')
5403115b575Snicm 		value += (uint32_t)ml->type_operand;
5413115b575Snicm 	else if (ml->type_operator == '/')
5423115b575Snicm 		value /= (uint32_t)ml->type_operand;
5433115b575Snicm 	else if (ml->type_operator == '%')
5443115b575Snicm 		value %= (uint32_t)ml->type_operand;
5453115b575Snicm 	else if (ml->type_operator == '*')
5463115b575Snicm 		value *= (uint32_t)ml->type_operand;
547ff772f70Snicm 	else if (ml->type_operator != ' ')
548ff772f70Snicm 		return (-1);
549ff772f70Snicm 
550ff772f70Snicm 	result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
551ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
552ff772f70Snicm 		magic_add_result(ms, ml, "%u", (unsigned int)value);
553ff772f70Snicm 		ms->offset += sizeof value;
554ff772f70Snicm 	}
555ff772f70Snicm 	return (result);
556ff772f70Snicm }
557ff772f70Snicm 
558ff772f70Snicm static int
magic_test_type_uquad(struct magic_line * ml,struct magic_state * ms)559ff772f70Snicm magic_test_type_uquad(struct magic_line *ml, struct magic_state *ms)
560ff772f70Snicm {
561ff772f70Snicm 	uint64_t	value;
562ff772f70Snicm 	int		result;
563ff772f70Snicm 
564ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
565ff772f70Snicm 		return (0);
566ff772f70Snicm 	if (ml->type == MAGIC_TYPE_UBEQUAD)
567cff0cfedSbrynet 		value = be64toh(value);
568ff772f70Snicm 	if (ml->type == MAGIC_TYPE_ULEQUAD)
569cff0cfedSbrynet 		value = le64toh(value);
570ff772f70Snicm 
571ff772f70Snicm 	if (ml->type_operator == '&')
572ff772f70Snicm 		value &= (uint64_t)ml->type_operand;
5733115b575Snicm 	else if (ml->type_operator == '-')
5743115b575Snicm 		value -= (uint64_t)ml->type_operand;
5753115b575Snicm 	else if (ml->type_operator == '+')
5763115b575Snicm 		value += (uint64_t)ml->type_operand;
5773115b575Snicm 	else if (ml->type_operator == '/')
5783115b575Snicm 		value /= (uint64_t)ml->type_operand;
5793115b575Snicm 	else if (ml->type_operator == '%')
5803115b575Snicm 		value %= (uint64_t)ml->type_operand;
5813115b575Snicm 	else if (ml->type_operator == '*')
5823115b575Snicm 		value *= (uint64_t)ml->type_operand;
583ff772f70Snicm 	else if (ml->type_operator != ' ')
584ff772f70Snicm 		return (-1);
585ff772f70Snicm 
586ff772f70Snicm 	result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
587ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
588ff772f70Snicm 		magic_add_result(ms, ml, "%llu", (unsigned long long)value);
589ff772f70Snicm 		ms->offset += sizeof value;
590ff772f70Snicm 	}
591ff772f70Snicm 	return (result);
592ff772f70Snicm }
593ff772f70Snicm 
594ff772f70Snicm static int
magic_test_type_float(struct magic_line * ml,struct magic_state * ms)595ff772f70Snicm magic_test_type_float(struct magic_line *ml, struct magic_state *ms)
596ff772f70Snicm {
597ff772f70Snicm 	uint32_t	value0;
598653e5878Snicm 	float		value;
59995651d73Snicm 	int		result;
600ff772f70Snicm 
601ff772f70Snicm 	if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
602ff772f70Snicm 		return (0);
603c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEFLOAT))
604cff0cfedSbrynet 		value0 = be32toh(value0);
605c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEFLOAT))
606cff0cfedSbrynet 		value0 = le32toh(value0);
607ff772f70Snicm 	memcpy(&value, &value0, sizeof value);
608ff772f70Snicm 
609ff772f70Snicm 	if (ml->type_operator != ' ')
610ff772f70Snicm 		return (-1);
611ff772f70Snicm 
61295651d73Snicm 	result = magic_test_double(ml, value, (float)ml->test_double);
61395651d73Snicm 	if (result == !ml->test_not && ml->result != NULL) {
614ff772f70Snicm 		magic_add_result(ms, ml, "%g", value);
615ff772f70Snicm 		ms->offset += sizeof value0;
61695651d73Snicm 	}
617ff772f70Snicm 	return (1);
618ff772f70Snicm }
619ff772f70Snicm 
620ff772f70Snicm static int
magic_test_type_double(struct magic_line * ml,struct magic_state * ms)621ff772f70Snicm magic_test_type_double(struct magic_line *ml, struct magic_state *ms)
622ff772f70Snicm {
623ff772f70Snicm 	uint64_t	value0;
624ff772f70Snicm 	double		value;
62595651d73Snicm 	int		result;
626ff772f70Snicm 
627ff772f70Snicm 	if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
628ff772f70Snicm 		return (0);
629c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEDOUBLE))
630cff0cfedSbrynet 		value0 = be64toh(value0);
631c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEDOUBLE))
632cff0cfedSbrynet 		value0 = le64toh(value0);
633ff772f70Snicm 	memcpy(&value, &value0, sizeof value);
634ff772f70Snicm 
635ff772f70Snicm 	if (ml->type_operator != ' ')
636ff772f70Snicm 		return (-1);
637ff772f70Snicm 
63895651d73Snicm 	result = magic_test_double(ml, value, (double)ml->test_double);
63995651d73Snicm 	if (result == !ml->test_not && ml->result != NULL) {
640ff772f70Snicm 		magic_add_result(ms, ml, "%g", value);
641ff772f70Snicm 		ms->offset += sizeof value0;
64295651d73Snicm 	}
643ff772f70Snicm 	return (1);
644ff772f70Snicm }
645ff772f70Snicm 
646ff772f70Snicm static int
magic_test_type_string(struct magic_line * ml,struct magic_state * ms)647ff772f70Snicm magic_test_type_string(struct magic_line *ml, struct magic_state *ms)
648ff772f70Snicm {
649ff772f70Snicm 	const char	*s, *cp;
650ff772f70Snicm 	size_t		 slen;
651ff772f70Snicm 	int		 result, cflag = 0, bflag = 0, Bflag = 0;
652ff772f70Snicm 
653ff772f70Snicm 	cp = &ml->type_string[(sizeof "string") - 1];
654ff772f70Snicm 	if (*cp != '\0') {
655ff772f70Snicm 		if (*cp != '/')
656ff772f70Snicm 			return (-1);
657ff772f70Snicm 		cp++;
658ff772f70Snicm 		for (; *cp != '\0'; cp++) {
659ff772f70Snicm 			switch (*cp) {
660ff772f70Snicm 			case 'B':
6615088824fSnicm 			case 'W':
662ff772f70Snicm 				Bflag = 1;
663ff772f70Snicm 				break;
664ff772f70Snicm 			case 'b':
6655088824fSnicm 			case 'w':
666ff772f70Snicm 				bflag = 1;
667ff772f70Snicm 				break;
668ff772f70Snicm 			case 'c':
669ff772f70Snicm 				cflag = 1;
670ff772f70Snicm 				break;
6715088824fSnicm 			case 't':
6725088824fSnicm 				break;
673ff772f70Snicm 			default:
674ff772f70Snicm 				return (-1);
675ff772f70Snicm 			}
676ff772f70Snicm 		}
677ff772f70Snicm 	}
678ff772f70Snicm 
679ff772f70Snicm 	s = ms->base + ms->offset;
680ff772f70Snicm 	slen = ms->size - ms->offset;
681ff772f70Snicm 	if (slen < ml->test_string_size)
682ff772f70Snicm 		return (0);
683ff772f70Snicm 
684ff772f70Snicm 	result = magic_test_eq(s, slen, ml->test_string, ml->test_string_size,
685ff772f70Snicm 	    cflag, bflag, Bflag);
686ff772f70Snicm 	switch (ml->test_operator) {
687ff772f70Snicm 	case 'x':
688ff772f70Snicm 		result = 1;
689ff772f70Snicm 		break;
690ff772f70Snicm 	case '<':
691ff772f70Snicm 		result = result < 0;
692ff772f70Snicm 		break;
693ff772f70Snicm 	case '>':
694ff772f70Snicm 		result = result > 0;
695ff772f70Snicm 		break;
696ff772f70Snicm 	case '=':
69737335d54Snicm 		slen = ml->test_string_size; /* only print what was found */
698ff772f70Snicm 		result = result == 0;
699ff772f70Snicm 		break;
700ff772f70Snicm 	default:
701ff772f70Snicm 		result = -1;
702ff772f70Snicm 		break;
703ff772f70Snicm 	}
704ff772f70Snicm 	if (result == !ml->test_not) {
705ff772f70Snicm 		if (ml->result != NULL)
706ff772f70Snicm 			magic_add_string(ms, ml, s, slen);
707ff772f70Snicm 		if (result && ml->test_operator == '=')
708ff772f70Snicm 			ms->offset = s - ms->base + ml->test_string_size;
709ff772f70Snicm 	}
710ff772f70Snicm 	return (result);
711ff772f70Snicm }
712ff772f70Snicm 
713ff772f70Snicm static int
magic_test_type_pstring(struct magic_line * ml,struct magic_state * ms)714ff772f70Snicm magic_test_type_pstring(struct magic_line *ml, struct magic_state *ms)
715ff772f70Snicm {
7165df908a8Snicm 	const char	*s, *cp;
717ff772f70Snicm 	size_t		 slen;
718ff772f70Snicm 	int		 result;
719ff772f70Snicm 
7205df908a8Snicm 	cp = &ml->type_string[(sizeof "pstring") - 1];
7215df908a8Snicm 	if (*cp != '\0') {
7225df908a8Snicm 		if (*cp != '/')
7235df908a8Snicm 			return (-1);
7245df908a8Snicm 		cp++;
7255df908a8Snicm 		for (; *cp != '\0'; cp++) {
7265df908a8Snicm 			switch (*cp) {
7275df908a8Snicm 			default:
7285df908a8Snicm 				return (-1);
7295df908a8Snicm 			}
7305df908a8Snicm 		}
7315df908a8Snicm 	}
7325df908a8Snicm 
733ff772f70Snicm 	s = ms->base + ms->offset;
734ff772f70Snicm 	if (ms->size - ms->offset < 1)
735ff772f70Snicm 		return (-1);
736ff772f70Snicm 	slen = *(u_char *)s;
7374f8cc4e8Snicm 	if (slen + 1 > ms->size - ms->offset)
738ff772f70Snicm 		return (-1);
739ff772f70Snicm 	s++;
740ff772f70Snicm 
741ff772f70Snicm 	if (slen < ml->test_string_size)
742ff772f70Snicm 		result = -1;
743ff772f70Snicm 	else if (slen > ml->test_string_size)
744ff772f70Snicm 		result = 1;
745ff772f70Snicm 	else
746ff772f70Snicm 		result = memcmp(s, ml->test_string, ml->test_string_size);
747ff772f70Snicm 	switch (ml->test_operator) {
748ff772f70Snicm 	case 'x':
749ff772f70Snicm 		result = 1;
750ff772f70Snicm 		break;
751ff772f70Snicm 	case '<':
752ff772f70Snicm 		result = result < 0;
753ff772f70Snicm 		break;
754ff772f70Snicm 	case '>':
755ff772f70Snicm 		result = result > 0;
756ff772f70Snicm 		break;
757ff772f70Snicm 	case '=':
758ff772f70Snicm 		result = result == 0;
759ff772f70Snicm 		break;
760ff772f70Snicm 	default:
761ff772f70Snicm 		result = -1;
762ff772f70Snicm 		break;
763ff772f70Snicm 	}
764ff772f70Snicm 	if (result == !ml->test_not) {
765ff772f70Snicm 		if (ml->result != NULL)
766ff772f70Snicm 			magic_add_string(ms, ml, s, slen);
7675fb9daaeSnicm 		if (result && ml->test_operator == '=')
768ff772f70Snicm 			ms->offset += slen + 1;
769ff772f70Snicm 	}
770ff772f70Snicm 	return (result);
771ff772f70Snicm }
772ff772f70Snicm 
773ff772f70Snicm static int
magic_test_type_date(struct magic_line * ml,struct magic_state * ms)774ff772f70Snicm magic_test_type_date(struct magic_line *ml, struct magic_state *ms)
775ff772f70Snicm {
776ff772f70Snicm 	int32_t	value;
777ff772f70Snicm 	int	result;
778ff772f70Snicm 	time_t	t;
779ff772f70Snicm 	char	s[64];
780ff772f70Snicm 
781ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
782ff772f70Snicm 		return (0);
783c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEDATE) ||
784c673ceb0Snicm 	    ml->type == magic_reverse_type(ms, MAGIC_TYPE_BELDATE))
785cff0cfedSbrynet 		value = be32toh(value);
786c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEDATE) ||
787c673ceb0Snicm 	    ml->type == magic_reverse_type(ms, MAGIC_TYPE_LELDATE))
788cff0cfedSbrynet 		value = le32toh(value);
789ff772f70Snicm 
790ff772f70Snicm 	if (ml->type_operator == '&')
791ff772f70Snicm 		value &= (int32_t)ml->type_operand;
792e3896e14Snicm 	else if (ml->type_operator == '-')
793e3896e14Snicm 		value -= (int32_t)ml->type_operand;
794e3896e14Snicm 	else if (ml->type_operator == '+')
795e3896e14Snicm 		value += (int32_t)ml->type_operand;
796ff772f70Snicm 	else if (ml->type_operator != ' ')
797ff772f70Snicm 		return (-1);
798ff772f70Snicm 
799ff772f70Snicm 	result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
800ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
801ff772f70Snicm 		t = value;
802ff772f70Snicm 		switch (ml->type) {
803ff772f70Snicm 		case MAGIC_TYPE_LDATE:
804ff772f70Snicm 		case MAGIC_TYPE_LELDATE:
805ff772f70Snicm 		case MAGIC_TYPE_BELDATE:
806ff772f70Snicm 			ctime_r(&t, s);
807ff772f70Snicm 			break;
808ff772f70Snicm 		default:
809704a4e8eSnicm 			asctime_r(gmtime(&t), s);
810ff772f70Snicm 			break;
811ff772f70Snicm 		}
812ff772f70Snicm 		s[strcspn(s, "\n")] = '\0';
813ff772f70Snicm 		magic_add_result(ms, ml, "%s", s);
814ff772f70Snicm 		ms->offset += sizeof value;
815ff772f70Snicm 	}
816ff772f70Snicm 	return (result);
817ff772f70Snicm }
818ff772f70Snicm 
819ff772f70Snicm static int
magic_test_type_qdate(struct magic_line * ml,struct magic_state * ms)820ff772f70Snicm magic_test_type_qdate(struct magic_line *ml, struct magic_state *ms)
821ff772f70Snicm {
822ff772f70Snicm 	int64_t value;
823ff772f70Snicm 	int	result;
824ff772f70Snicm 	time_t	t;
825ff772f70Snicm 	char	s[64];
826ff772f70Snicm 
827ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
828ff772f70Snicm 		return (0);
829c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEQDATE) ||
830c673ceb0Snicm 	    ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEQLDATE))
831cff0cfedSbrynet 		value = be64toh(value);
832c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEQDATE) ||
833c673ceb0Snicm 	    ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEQLDATE))
834cff0cfedSbrynet 		value = le64toh(value);
835ff772f70Snicm 
836ff772f70Snicm 	if (ml->type_operator == '&')
837ff772f70Snicm 		value &= (int64_t)ml->type_operand;
838e3896e14Snicm 	else if (ml->type_operator == '-')
839e3896e14Snicm 		value -= (int64_t)ml->type_operand;
840e3896e14Snicm 	else if (ml->type_operator == '+')
841e3896e14Snicm 		value += (int64_t)ml->type_operand;
842ff772f70Snicm 	else if (ml->type_operator != ' ')
843ff772f70Snicm 		return (-1);
844ff772f70Snicm 
845ff772f70Snicm 	result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
846ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
847ff772f70Snicm 		t = value;
848ff772f70Snicm 		switch (ml->type) {
849ff772f70Snicm 		case MAGIC_TYPE_QLDATE:
850ff772f70Snicm 		case MAGIC_TYPE_LEQLDATE:
851ff772f70Snicm 		case MAGIC_TYPE_BEQLDATE:
852ff772f70Snicm 			ctime_r(&t, s);
853ff772f70Snicm 			break;
854ff772f70Snicm 		default:
855704a4e8eSnicm 			asctime_r(gmtime(&t), s);
856ff772f70Snicm 			break;
857ff772f70Snicm 		}
858ff772f70Snicm 		s[strcspn(s, "\n")] = '\0';
859ff772f70Snicm 		magic_add_result(ms, ml, "%s", s);
860ff772f70Snicm 		ms->offset += sizeof value;
861ff772f70Snicm 	}
862ff772f70Snicm 	return (result);
863ff772f70Snicm }
864ff772f70Snicm 
865ff772f70Snicm static int
magic_test_type_udate(struct magic_line * ml,struct magic_state * ms)866ff772f70Snicm magic_test_type_udate(struct magic_line *ml, struct magic_state *ms)
867ff772f70Snicm {
868ff772f70Snicm 	uint32_t	value;
869ff772f70Snicm 	int		result;
870ff772f70Snicm 	time_t		t;
871ff772f70Snicm 	char		s[64];
872ff772f70Snicm 
873ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
874ff772f70Snicm 		return (0);
875c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEDATE) ||
876c673ceb0Snicm 	    ml->type == magic_reverse_type(ms, MAGIC_TYPE_BELDATE))
877cff0cfedSbrynet 		value = be32toh(value);
878c673ceb0Snicm 	if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEDATE) ||
879c673ceb0Snicm 	    ml->type == magic_reverse_type(ms, MAGIC_TYPE_LELDATE))
880cff0cfedSbrynet 		value = le32toh(value);
881ff772f70Snicm 
882ff772f70Snicm 	if (ml->type_operator == '&')
883ff772f70Snicm 		value &= (uint32_t)ml->type_operand;
884e3896e14Snicm 	else if (ml->type_operator == '-')
885e3896e14Snicm 		value -= (uint32_t)ml->type_operand;
886e3896e14Snicm 	else if (ml->type_operator == '+')
887e3896e14Snicm 		value += (uint32_t)ml->type_operand;
888ff772f70Snicm 	else if (ml->type_operator != ' ')
889ff772f70Snicm 		return (-1);
890ff772f70Snicm 
891ff772f70Snicm 	result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
892ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
893ff772f70Snicm 		t = value;
894ff772f70Snicm 		switch (ml->type) {
895ff772f70Snicm 		case MAGIC_TYPE_LDATE:
896ff772f70Snicm 		case MAGIC_TYPE_LELDATE:
897ff772f70Snicm 		case MAGIC_TYPE_BELDATE:
898ff772f70Snicm 			ctime_r(&t, s);
899ff772f70Snicm 			break;
900ff772f70Snicm 		default:
901ff772f70Snicm 			asctime_r(gmtime(&t), s);
902ff772f70Snicm 			break;
903ff772f70Snicm 		}
904ff772f70Snicm 		s[strcspn(s, "\n")] = '\0';
905ff772f70Snicm 		magic_add_result(ms, ml, "%s", s);
906ff772f70Snicm 		ms->offset += sizeof value;
907ff772f70Snicm 	}
908ff772f70Snicm 	return (result);
909ff772f70Snicm }
910ff772f70Snicm 
911ff772f70Snicm static int
magic_test_type_uqdate(struct magic_line * ml,struct magic_state * ms)912ff772f70Snicm magic_test_type_uqdate(struct magic_line *ml, struct magic_state *ms)
913ff772f70Snicm {
914ff772f70Snicm 	uint64_t	value;
915ff772f70Snicm 	int		result;
916ff772f70Snicm 	time_t		t;
917ff772f70Snicm 	char		s[64];
918ff772f70Snicm 
919ff772f70Snicm 	if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
920ff772f70Snicm 		return (0);
921ff772f70Snicm 	if (ml->type == MAGIC_TYPE_UBEQDATE ||
922ff772f70Snicm 	    ml->type == MAGIC_TYPE_UBEQLDATE)
923cff0cfedSbrynet 		value = be64toh(value);
924ff772f70Snicm 	if (ml->type == MAGIC_TYPE_ULEQDATE ||
925ff772f70Snicm 	    ml->type == MAGIC_TYPE_ULEQLDATE)
926cff0cfedSbrynet 		value = le64toh(value);
927ff772f70Snicm 
928ff772f70Snicm 	if (ml->type_operator == '&')
929ff772f70Snicm 		value &= (uint64_t)ml->type_operand;
930e3896e14Snicm 	else if (ml->type_operator == '-')
931e3896e14Snicm 		value -= (uint64_t)ml->type_operand;
932e3896e14Snicm 	else if (ml->type_operator == '+')
933e3896e14Snicm 		value += (uint64_t)ml->type_operand;
934ff772f70Snicm 	else if (ml->type_operator != ' ')
935ff772f70Snicm 		return (-1);
936ff772f70Snicm 
937ff772f70Snicm 	result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
938ff772f70Snicm 	if (result == !ml->test_not && ml->result != NULL) {
939ff772f70Snicm 		t = value;
940ff772f70Snicm 		switch (ml->type) {
941ff772f70Snicm 		case MAGIC_TYPE_UQLDATE:
942ff772f70Snicm 		case MAGIC_TYPE_ULEQLDATE:
943ff772f70Snicm 		case MAGIC_TYPE_UBEQLDATE:
944ff772f70Snicm 			ctime_r(&t, s);
945ff772f70Snicm 			break;
946ff772f70Snicm 		default:
947ff772f70Snicm 			asctime_r(gmtime(&t), s);
948ff772f70Snicm 			break;
949ff772f70Snicm 		}
950ff772f70Snicm 		s[strcspn(s, "\n")] = '\0';
951ff772f70Snicm 		magic_add_result(ms, ml, "%s", s);
952ff772f70Snicm 		ms->offset += sizeof value;
953ff772f70Snicm 	}
954ff772f70Snicm 	return (result);
955ff772f70Snicm }
956ff772f70Snicm 
957ff772f70Snicm static int
magic_test_type_bestring16(__unused struct magic_line * ml,__unused struct magic_state * ms)958ff772f70Snicm magic_test_type_bestring16(__unused struct magic_line *ml,
959ff772f70Snicm     __unused struct magic_state *ms)
960ff772f70Snicm {
961ff772f70Snicm 	return (-2);
962ff772f70Snicm }
963ff772f70Snicm 
964ff772f70Snicm static int
magic_test_type_lestring16(__unused struct magic_line * ml,__unused struct magic_state * ms)965ff772f70Snicm magic_test_type_lestring16(__unused struct magic_line *ml,
966ff772f70Snicm     __unused struct magic_state *ms)
967ff772f70Snicm {
968ff772f70Snicm 	return (-2);
969ff772f70Snicm }
970ff772f70Snicm 
971ff772f70Snicm static int
magic_test_type_melong(__unused struct magic_line * ml,__unused struct magic_state * ms)972ff772f70Snicm magic_test_type_melong(__unused struct magic_line *ml,
973ff772f70Snicm     __unused struct magic_state *ms)
974ff772f70Snicm {
975ff772f70Snicm 	return (-2);
976ff772f70Snicm }
977ff772f70Snicm 
978ff772f70Snicm static int
magic_test_type_medate(__unused struct magic_line * ml,__unused struct magic_state * ms)979ff772f70Snicm magic_test_type_medate(__unused struct magic_line *ml,
980ff772f70Snicm     __unused struct magic_state *ms)
981ff772f70Snicm {
982ff772f70Snicm 	return (-2);
983ff772f70Snicm }
984ff772f70Snicm 
985ff772f70Snicm static int
magic_test_type_meldate(__unused struct magic_line * ml,__unused struct magic_state * ms)986ff772f70Snicm magic_test_type_meldate(__unused struct magic_line *ml,
987ff772f70Snicm     __unused struct magic_state *ms)
988ff772f70Snicm {
989ff772f70Snicm 	return (-2);
990ff772f70Snicm }
991ff772f70Snicm 
992ff772f70Snicm static int
magic_test_type_regex(struct magic_line * ml,struct magic_state * ms)993ff772f70Snicm magic_test_type_regex(struct magic_line *ml, struct magic_state *ms)
994ff772f70Snicm {
995ff772f70Snicm 	const char	*cp;
996ff772f70Snicm 	regex_t		 re;
997ff772f70Snicm 	regmatch_t	 m;
998ff772f70Snicm 	int		 result, flags = 0, sflag = 0;
999ff772f70Snicm 
1000ff772f70Snicm 	cp = &ml->type_string[(sizeof "regex") - 1];
1001ff772f70Snicm 	if (*cp != '\0') {
1002ff772f70Snicm 		if (*cp != '/')
1003ff772f70Snicm 			return (-1);
1004ff772f70Snicm 		cp++;
1005ff772f70Snicm 		for (; *cp != '\0'; cp++) {
1006ff772f70Snicm 			switch (*cp) {
1007ff772f70Snicm 			case 's':
1008ff772f70Snicm 				sflag = 1;
1009ff772f70Snicm 				break;
1010ff772f70Snicm 			case 'c':
1011ff772f70Snicm 				flags |= REG_ICASE;
1012ff772f70Snicm 				break;
1013ff772f70Snicm 			default:
1014ff772f70Snicm 				return (-1);
1015ff772f70Snicm 			}
1016ff772f70Snicm 		}
1017ff772f70Snicm 	}
1018ff772f70Snicm 
1019*bb180e11Snicm 	if (regcomp(&re, ml->test_string, REG_EXTENDED|REG_NEWLINE|flags) != 0)
1020ff772f70Snicm 		return (-1);
1021ff772f70Snicm 	m.rm_so = ms->offset;
1022ff772f70Snicm 	m.rm_eo = ms->size;
1023ff772f70Snicm 
1024ff772f70Snicm 	result = (regexec(&re, ms->base, 1, &m, REG_STARTEND) == 0);
10255fb9daaeSnicm 	if (result == !ml->test_not) {
1026f543d3e5Snicm 		if (ml->result != NULL) {
1027f543d3e5Snicm 			magic_add_string(ms, ml, ms->base + m.rm_so,
1028f543d3e5Snicm 			    m.rm_eo - m.rm_so);
1029f543d3e5Snicm 		}
1030ff772f70Snicm 		if (result) {
1031ff772f70Snicm 			if (sflag)
1032ff772f70Snicm 				ms->offset = m.rm_so;
1033ff772f70Snicm 			else
1034ff772f70Snicm 				ms->offset = m.rm_eo;
1035ff772f70Snicm 		}
1036ff772f70Snicm 	}
1037ff772f70Snicm 	regfree(&re);
1038ff772f70Snicm 	return (result);
1039ff772f70Snicm }
1040ff772f70Snicm 
1041ff772f70Snicm static int
magic_test_type_search(struct magic_line * ml,struct magic_state * ms)1042ff772f70Snicm magic_test_type_search(struct magic_line *ml, struct magic_state *ms)
1043ff772f70Snicm {
1044ff772f70Snicm 	const char	*cp, *endptr, *start, *found;
1045ff772f70Snicm 	size_t		 size, end, i;
1046ff772f70Snicm 	uint64_t	 range;
1047ff772f70Snicm 	int		 result, n, cflag = 0, bflag = 0, Bflag = 0;
1048ff772f70Snicm 
1049ff772f70Snicm 	cp = &ml->type_string[(sizeof "search") - 1];
1050ff772f70Snicm 	if (*cp != '\0') {
1051ff772f70Snicm 		if (*cp != '/')
1052ff772f70Snicm 			return (-1);
1053ff772f70Snicm 		cp++;
1054ff772f70Snicm 
1055ff772f70Snicm 		endptr = magic_strtoull(cp, &range);
1056ff772f70Snicm 		if (endptr == NULL || (*endptr != '/' && *endptr != '\0'))
1057ff772f70Snicm 			return (-1);
1058ff772f70Snicm 
1059ff772f70Snicm 		if (*endptr == '/') {
1060ff772f70Snicm 			for (cp = endptr + 1; *cp != '\0'; cp++) {
1061ff772f70Snicm 				switch (*cp) {
1062ff772f70Snicm 				case 'B':
10635088824fSnicm 				case 'W':
1064ff772f70Snicm 					Bflag = 1;
1065ff772f70Snicm 					break;
1066ff772f70Snicm 				case 'b':
10675088824fSnicm 				case 'w':
1068ff772f70Snicm 					bflag = 1;
1069ff772f70Snicm 					break;
1070ff772f70Snicm 				case 'c':
1071ff772f70Snicm 					cflag = 1;
1072ff772f70Snicm 					break;
10735088824fSnicm 				case 't':
10745088824fSnicm 					break;
1075ff772f70Snicm 				default:
1076ff772f70Snicm 					return (-1);
1077ff772f70Snicm 				}
1078ff772f70Snicm 			}
1079ff772f70Snicm 		}
1080ff772f70Snicm 	} else
1081ff772f70Snicm 		range = UINT64_MAX;
1082ff772f70Snicm 	if (range > (uint64_t)ms->size - ms->offset)
1083ff772f70Snicm 		range = ms->size - ms->offset;
1084ff772f70Snicm 	size = ml->test_string_size;
1085ff772f70Snicm 
1086ff772f70Snicm 	/* Want to search every starting position from up to range + size. */
1087ff772f70Snicm 	end = range + size;
1088ff772f70Snicm 	if (end > ms->size - ms->offset) {
1089ff772f70Snicm 		if (size > ms->size - ms->offset)
1090ff772f70Snicm 			end = 0;
1091ff772f70Snicm 		else
1092ff772f70Snicm 			end = ms->size - ms->offset - size;
1093ff772f70Snicm 	}
1094ff772f70Snicm 
1095ff772f70Snicm 	/*
1096ff772f70Snicm 	 * < and > and the flags are only in /etc/magic with search/1 so don't
1097ff772f70Snicm 	 * support them with anything else.
1098ff772f70Snicm 	 */
1099ff772f70Snicm 	start = ms->base + ms->offset;
1100ff772f70Snicm 	if (end == 0)
1101ff772f70Snicm 		found = NULL;
1102ff772f70Snicm 	else if (ml->test_operator == 'x')
1103ff772f70Snicm 		found = start;
1104ff772f70Snicm 	else if (range == 1) {
1105ff772f70Snicm 		n = magic_test_eq(start, ms->size - ms->offset, ml->test_string,
1106ff772f70Snicm 		    size, cflag, bflag, Bflag);
1107ff772f70Snicm 		if (n == -1 && ml->test_operator == '<')
1108ff772f70Snicm 			found = start;
1109ff772f70Snicm 		else if (n == 1 && ml->test_operator == '>')
1110ff772f70Snicm 			found = start;
1111ff772f70Snicm 		else if (n == 0 && ml->test_operator == '=')
1112ff772f70Snicm 			found = start;
1113ff772f70Snicm 		else
1114ff772f70Snicm 			found = NULL;
1115ff772f70Snicm 	} else {
1116ff772f70Snicm 		if (ml->test_operator != '=')
1117ff772f70Snicm 			return (-2);
1118ff772f70Snicm 		for (i = 0; i < end; i++) {
1119ff772f70Snicm 			n = magic_test_eq(start + i, ms->size - ms->offset - i,
1120ff772f70Snicm 			    ml->test_string, size, cflag, bflag, Bflag);
1121ff772f70Snicm 			if (n == 0) {
1122ff772f70Snicm 				found = start + i;
1123ff772f70Snicm 				break;
1124ff772f70Snicm 			}
1125ff772f70Snicm 		}
1126ff772f70Snicm 		if (i == end)
1127ff772f70Snicm 			found = NULL;
1128ff772f70Snicm 	}
1129ff772f70Snicm 	result = (found != NULL);
1130ff772f70Snicm 
11315fb9daaeSnicm 	if (result == !ml->test_not) {
11325fb9daaeSnicm 		if (ml->result != NULL)
1133ff772f70Snicm 			magic_add_string(ms, ml, found, ms->size - ms->offset);
11345fb9daaeSnicm 		if (result && found != NULL && ml->test_operator == '=')
11355fb9daaeSnicm 			ms->offset = (found + size) - ms->base;
1136ff772f70Snicm 	}
1137ff772f70Snicm 	return (result);
1138ff772f70Snicm }
1139ff772f70Snicm 
1140ff772f70Snicm static int
magic_test_type_default(struct magic_line * ml,struct magic_state * ms)114108c03d98Snicm magic_test_type_default(struct magic_line *ml, struct magic_state *ms)
1142ff772f70Snicm {
1143e0a3e3d1Snicm 	if (!ms->matched && ml->result != NULL)
1144e0a3e3d1Snicm 		magic_add_result(ms, ml, "%s", "");
11455f8c9fd8Snicm 	return (!ms->matched);
1146ff772f70Snicm }
1147ff772f70Snicm 
1148e0a3e3d1Snicm static int
magic_test_type_clear(struct magic_line * ml,struct magic_state * ms)114908c03d98Snicm magic_test_type_clear(struct magic_line *ml, struct magic_state *ms)
1150e0a3e3d1Snicm {
1151e0a3e3d1Snicm 	if (ml->result != NULL)
1152e0a3e3d1Snicm 		magic_add_result(ms, ml, "%s", "");
1153e0a3e3d1Snicm 	return (1);
1154e0a3e3d1Snicm }
1155e0a3e3d1Snicm 
1156c673ceb0Snicm static int
magic_test_type_name(__unused struct magic_line * ml,__unused struct magic_state * ms)1157c673ceb0Snicm magic_test_type_name(__unused struct magic_line *ml,
1158c673ceb0Snicm     __unused struct magic_state *ms)
1159c673ceb0Snicm {
1160c673ceb0Snicm 	return (-1);
1161c673ceb0Snicm }
1162c673ceb0Snicm 
1163c673ceb0Snicm static int
magic_test_type_use(__unused struct magic_line * ml,__unused struct magic_state * ms)1164c673ceb0Snicm magic_test_type_use(__unused struct magic_line *ml,
1165c673ceb0Snicm     __unused struct magic_state *ms)
1166c673ceb0Snicm {
1167c673ceb0Snicm 	return (1);
1168c673ceb0Snicm }
1169c673ceb0Snicm 
1170ff772f70Snicm static int (*magic_test_functions[])(struct magic_line *,
1171ff772f70Snicm     struct magic_state *) = {
1172ff772f70Snicm 	magic_test_type_none,
1173ff772f70Snicm 	magic_test_type_byte,
1174ff772f70Snicm 	magic_test_type_short,
1175ff772f70Snicm 	magic_test_type_long,
1176ff772f70Snicm 	magic_test_type_quad,
1177ff772f70Snicm 	magic_test_type_ubyte,
1178ff772f70Snicm 	magic_test_type_ushort,
1179ff772f70Snicm 	magic_test_type_ulong,
1180ff772f70Snicm 	magic_test_type_uquad,
1181ff772f70Snicm 	magic_test_type_float,
1182ff772f70Snicm 	magic_test_type_double,
1183ff772f70Snicm 	magic_test_type_string,
1184ff772f70Snicm 	magic_test_type_pstring,
1185ff772f70Snicm 	magic_test_type_date,
1186ff772f70Snicm 	magic_test_type_qdate,
1187ff772f70Snicm 	magic_test_type_date,
1188ff772f70Snicm 	magic_test_type_qdate,
1189ff772f70Snicm 	magic_test_type_udate,
1190ff772f70Snicm 	magic_test_type_uqdate,
1191ff772f70Snicm 	magic_test_type_udate,
1192ff772f70Snicm 	magic_test_type_qdate,
1193ff772f70Snicm 	magic_test_type_short,
1194ff772f70Snicm 	magic_test_type_long,
1195ff772f70Snicm 	magic_test_type_quad,
1196ff772f70Snicm 	magic_test_type_ushort,
1197ff772f70Snicm 	magic_test_type_ulong,
1198ff772f70Snicm 	magic_test_type_uquad,
1199ff772f70Snicm 	magic_test_type_float,
1200ff772f70Snicm 	magic_test_type_double,
1201ff772f70Snicm 	magic_test_type_date,
1202ff772f70Snicm 	magic_test_type_qdate,
1203ff772f70Snicm 	magic_test_type_date,
1204ff772f70Snicm 	magic_test_type_qdate,
1205ff772f70Snicm 	magic_test_type_udate,
1206ff772f70Snicm 	magic_test_type_uqdate,
1207ff772f70Snicm 	magic_test_type_udate,
1208ff772f70Snicm 	magic_test_type_uqdate,
1209ff772f70Snicm 	magic_test_type_bestring16,
1210ff772f70Snicm 	magic_test_type_short,
1211ff772f70Snicm 	magic_test_type_long,
1212ff772f70Snicm 	magic_test_type_quad,
1213ff772f70Snicm 	magic_test_type_ushort,
1214ff772f70Snicm 	magic_test_type_ulong,
1215ff772f70Snicm 	magic_test_type_uquad,
1216ff772f70Snicm 	magic_test_type_float,
1217ff772f70Snicm 	magic_test_type_double,
1218ff772f70Snicm 	magic_test_type_date,
1219ff772f70Snicm 	magic_test_type_qdate,
1220ff772f70Snicm 	magic_test_type_date,
1221ff772f70Snicm 	magic_test_type_qdate,
1222ff772f70Snicm 	magic_test_type_udate,
1223ff772f70Snicm 	magic_test_type_uqdate,
1224ff772f70Snicm 	magic_test_type_udate,
1225ff772f70Snicm 	magic_test_type_uqdate,
1226ff772f70Snicm 	magic_test_type_lestring16,
1227ff772f70Snicm 	magic_test_type_melong,
1228ff772f70Snicm 	magic_test_type_medate,
1229ff772f70Snicm 	magic_test_type_meldate,
1230ff772f70Snicm 	magic_test_type_regex,
1231ff772f70Snicm 	magic_test_type_search,
1232ff772f70Snicm 	magic_test_type_default,
1233e0a3e3d1Snicm 	magic_test_type_clear,
1234c673ceb0Snicm 	magic_test_type_name,
1235c673ceb0Snicm 	magic_test_type_use,
1236ff772f70Snicm };
1237ff772f70Snicm 
1238c673ceb0Snicm static void
magic_test_children(struct magic_line * ml,struct magic_state * ms,size_t start,int reverse)1239c673ceb0Snicm magic_test_children(struct magic_line *ml, struct magic_state *ms, size_t start,
1240c673ceb0Snicm     int reverse)
1241c673ceb0Snicm {
1242c673ceb0Snicm 	struct magic_line	*child;
1243c673ceb0Snicm 	size_t			 saved_start, saved_offset;
1244c673ceb0Snicm 	int			 saved_reverse;
1245c673ceb0Snicm 
1246c673ceb0Snicm 	saved_start = ms->start;
1247c673ceb0Snicm 	saved_reverse = ms->reverse;
1248c673ceb0Snicm 	saved_offset = ms->offset;
1249c673ceb0Snicm 
1250c673ceb0Snicm 	ms->matched = 0; /* no need to save, caller will set too */
1251c673ceb0Snicm 
1252c673ceb0Snicm 	TAILQ_FOREACH(child, &ml->children, entry) {
1253c673ceb0Snicm 		ms->start = start;
1254c673ceb0Snicm 		ms->reverse = reverse;
1255c673ceb0Snicm 		ms->offset = saved_offset;
1256c673ceb0Snicm 
1257c673ceb0Snicm 		magic_test_line(child, ms);
1258c673ceb0Snicm 	}
1259c673ceb0Snicm 
1260c673ceb0Snicm 	ms->start = saved_start;
1261c673ceb0Snicm 	ms->reverse = saved_reverse;
1262c673ceb0Snicm 	ms->offset = saved_offset;
1263c673ceb0Snicm }
1264c673ceb0Snicm 
1265ff772f70Snicm static int
magic_test_line(struct magic_line * ml,struct magic_state * ms)1266ff772f70Snicm magic_test_line(struct magic_line *ml, struct magic_state *ms)
1267ff772f70Snicm {
1268c673ceb0Snicm 	struct magic		*m = ml->root;
1269c673ceb0Snicm 	struct magic_line	*named;
1270ff772f70Snicm 	int64_t			 offset, wanted, next;
1271ff772f70Snicm 	int			 result;
1272ff772f70Snicm 	uint8_t			 b;
1273ff772f70Snicm 	uint16_t		 s;
1274ff772f70Snicm 	uint32_t		 l;
1275ff772f70Snicm 
1276ff772f70Snicm 	if (ml->indirect_type == ' ')
1277c673ceb0Snicm 		wanted = ms->start + ml->offset;
1278ff772f70Snicm 	else {
1279ff772f70Snicm 		wanted = ml->indirect_offset;
1280ff772f70Snicm 		if (ml->indirect_relative) {
128199146692Snicm 			if (wanted < 0 && (size_t)-wanted > ms->offset)
1282ff772f70Snicm 				return (0);
1283ff772f70Snicm 			if (wanted > 0 && ms->offset + wanted > ms->size)
1284ff772f70Snicm 				return (0);
1285ff772f70Snicm 			next = ms->offset + ml->indirect_offset;
1286ff772f70Snicm 		} else
1287ff772f70Snicm 			next = wanted;
1288ff772f70Snicm 
1289ff772f70Snicm 		switch (ml->indirect_type) {
1290ff772f70Snicm 		case 'b':
1291ff772f70Snicm 		case 'B':
1292ff772f70Snicm 			if (magic_copy_from(ms, next, &b, sizeof b) != 0)
1293ff772f70Snicm 				return (0);
1294ff772f70Snicm 			wanted = b;
1295ff772f70Snicm 			break;
1296ff772f70Snicm 		case 's':
1297ff772f70Snicm 			if (magic_copy_from(ms, next, &s, sizeof s) != 0)
1298ff772f70Snicm 				return (0);
1299cff0cfedSbrynet 			wanted = le16toh(s);
1300ff772f70Snicm 			break;
1301ff772f70Snicm 		case 'S':
1302ff772f70Snicm 			if (magic_copy_from(ms, next, &s, sizeof s) != 0)
1303ff772f70Snicm 				return (0);
1304cff0cfedSbrynet 			wanted = be16toh(s);
1305ff772f70Snicm 			break;
1306ff772f70Snicm 		case 'l':
1307ff772f70Snicm 			if (magic_copy_from(ms, next, &l, sizeof l) != 0)
1308ff772f70Snicm 				return (0);
1309cff0cfedSbrynet 			wanted = le16toh(l);
1310ff772f70Snicm 			break;
1311ff772f70Snicm 		case 'L':
1312ff772f70Snicm 			if (magic_copy_from(ms, next, &l, sizeof l) != 0)
1313ff772f70Snicm 				return (0);
1314cff0cfedSbrynet 			wanted = be16toh(l);
1315ff772f70Snicm 			break;
1316ff772f70Snicm 		}
1317ff772f70Snicm 
1318ff772f70Snicm 		switch (ml->indirect_operator) {
1319ff772f70Snicm 		case '+':
1320ff772f70Snicm 			wanted += ml->indirect_operand;
1321ff772f70Snicm 			break;
1322ff772f70Snicm 		case '-':
1323ff772f70Snicm 			wanted -= ml->indirect_operand;
1324ff772f70Snicm 			break;
1325ff772f70Snicm 		case '*':
1326ff772f70Snicm 			wanted *= ml->indirect_operand;
1327ff772f70Snicm 			break;
1328ff772f70Snicm 		}
1329ff772f70Snicm 	}
1330ff772f70Snicm 
1331ff772f70Snicm 	if (ml->offset_relative) {
133299146692Snicm 		if (wanted < 0 && (size_t)-wanted > ms->offset)
1333ff772f70Snicm 			return (0);
1334ff772f70Snicm 		if (wanted > 0 && ms->offset + wanted > ms->size)
1335ff772f70Snicm 			return (0);
1336ff772f70Snicm 		offset = ms->offset + wanted;
1337ff772f70Snicm 	} else
1338ff772f70Snicm 		offset = wanted;
133999146692Snicm 	if (offset < 0 || (size_t)offset > ms->size)
1340ff772f70Snicm 		return (0);
1341c673ceb0Snicm 	ms->offset = offset; /* test function may update */
1342ff772f70Snicm 
1343ff772f70Snicm 	result = magic_test_functions[ml->type](ml, ms);
1344ff772f70Snicm 	if (result == -1) {
1345ff772f70Snicm 		magic_warn(ml, "test %s/%c failed", ml->type_string,
1346ff772f70Snicm 		    ml->test_operator);
1347ff772f70Snicm 		return (0);
1348ff772f70Snicm 	}
1349ff772f70Snicm 	if (result == -2) {
1350ff772f70Snicm 		magic_warn(ml, "test %s/%c not implemented", ml->type_string,
1351ff772f70Snicm 		    ml->test_operator);
1352ff772f70Snicm 		return (0);
1353ff772f70Snicm 	}
1354ff772f70Snicm 	if (result == ml->test_not)
1355ff772f70Snicm 		return (0);
1356ff772f70Snicm 	if (ml->mimetype != NULL)
1357ff772f70Snicm 		ms->mimetype = ml->mimetype;
1358ff772f70Snicm 
1359c673ceb0Snicm 	magic_warn(ml, "test %s/%c matched at offset %lld (now %zu): "
1360c673ceb0Snicm 	    "'%s'", ml->type_string, ml->test_operator, offset,
1361c673ceb0Snicm 	    ms->offset, ml->result == NULL ? "" : ml->result);
1362ff772f70Snicm 
1363c673ceb0Snicm 	if (ml->type == MAGIC_TYPE_USE) {
1364c673ceb0Snicm 		if (*ml->name == '^')
1365c673ceb0Snicm 			named = magic_get_named(m, ml->name + 1);
1366c673ceb0Snicm 		else
1367c673ceb0Snicm 			named = magic_get_named(m, ml->name);
1368c673ceb0Snicm 		if (named == NULL) {
1369c673ceb0Snicm 			magic_warn(ml, "no name found for use %s", ml->name);
1370c673ceb0Snicm 			return (0);
1371ff772f70Snicm 		}
1372c673ceb0Snicm 		magic_warn(ml, "use %s at offset %lld", ml->name, offset);
1373c673ceb0Snicm 		magic_test_children(named, ms, offset, *ml->name == '^');
1374c673ceb0Snicm 	}
1375c673ceb0Snicm 
1376c673ceb0Snicm 	magic_test_children(ml, ms, ms->start, ms->reverse);
13775f8c9fd8Snicm 
1378e0a3e3d1Snicm 	if (ml->type == MAGIC_TYPE_CLEAR)
1379e0a3e3d1Snicm 		ms->matched = 0;
1380e0a3e3d1Snicm 	else
13815f8c9fd8Snicm 		ms->matched = 1;
13825e39175eSnicm 	return (ml->result != NULL);
1383ff772f70Snicm }
1384ff772f70Snicm 
1385ff772f70Snicm const char *
magic_test(struct magic * m,const void * base,size_t size,int flags)1386ff772f70Snicm magic_test(struct magic *m, const void *base, size_t size, int flags)
1387ff772f70Snicm {
1388ff772f70Snicm 	struct magic_line		*ml;
1389ff772f70Snicm 	static struct magic_state	 ms;
1390ff772f70Snicm 
1391ff772f70Snicm 	memset(&ms, 0, sizeof ms);
1392ff772f70Snicm 
1393ff772f70Snicm 	ms.base = base;
1394ff772f70Snicm 	ms.size = size;
1395ff772f70Snicm 
1396ff772f70Snicm 	ms.text = !!(flags & MAGIC_TEST_TEXT);
1397ff772f70Snicm 
1398ff772f70Snicm 	RB_FOREACH(ml, magic_tree, &m->tree) {
1399ff772f70Snicm 		ms.offset = 0;
1400ff772f70Snicm 		if (ml->text == ms.text && magic_test_line(ml, &ms))
1401ff772f70Snicm 			break;
1402ff772f70Snicm 	}
1403ff772f70Snicm 
1404ff772f70Snicm 	if (*ms.out != '\0') {
1405ff772f70Snicm 		if (flags & MAGIC_TEST_MIME) {
1406d8e84ae2Snicm 			if (ms.mimetype != NULL)
1407e554841dSnicm 				return (ms.mimetype);
1408ff772f70Snicm 			return (NULL);
1409ff772f70Snicm 		}
1410e554841dSnicm 		return (ms.out);
1411ff772f70Snicm 	}
1412ff772f70Snicm 	return (NULL);
1413ff772f70Snicm }
1414