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