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