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