GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/file/magic-test.c Lines: 0 747 0.0 %
Date: 2017-11-07 Branches: 0 646 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: magic-test.c,v 1.25 2017/04/18 14:16:48 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
37
static int magic_test_line(struct magic_line *, struct magic_state *);
38
39
static struct magic_line *
40
magic_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
48
static enum magic_type
49
magic_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
123
static int
124
magic_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
133
static int
134
magic_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
172
static int
173
magic_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
183
static void
184
magic_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
225
static void
226
magic_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
247
static int
248
magic_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
271
static int
272
magic_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
295
static int
296
magic_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
307
static int
308
magic_test_type_none(__unused struct magic_line *ml,
309
    __unused struct magic_state *ms)
310
{
311
	return (0);
312
}
313
314
static int
315
magic_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
346
static int
347
magic_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
382
static int
383
magic_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
418
static int
419
magic_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
454
static int
455
magic_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
486
static int
487
magic_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
522
static int
523
magic_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
558
static int
559
magic_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
594
static int
595
magic_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
620
static int
621
magic_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
646
static int
647
magic_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
713
static int
714
magic_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
773
static int
774
magic_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
819
static int
820
magic_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
865
static int
866
magic_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
911
static int
912
magic_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
957
static int
958
magic_test_type_bestring16(__unused struct magic_line *ml,
959
    __unused struct magic_state *ms)
960
{
961
	return (-2);
962
}
963
964
static int
965
magic_test_type_lestring16(__unused struct magic_line *ml,
966
    __unused struct magic_state *ms)
967
{
968
	return (-2);
969
}
970
971
static int
972
magic_test_type_melong(__unused struct magic_line *ml,
973
    __unused struct magic_state *ms)
974
{
975
	return (-2);
976
}
977
978
static int
979
magic_test_type_medate(__unused struct magic_line *ml,
980
    __unused struct magic_state *ms)
981
{
982
	return (-2);
983
}
984
985
static int
986
magic_test_type_meldate(__unused struct magic_line *ml,
987
    __unused struct magic_state *ms)
988
{
989
	return (-2);
990
}
991
992
static int
993
magic_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) != 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
1041
static int
1042
magic_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
1140
static int
1141
magic_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
1148
static int
1149
magic_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
1156
static int
1157
magic_test_type_name(__unused struct magic_line *ml,
1158
    __unused struct magic_state *ms)
1159
{
1160
	return (-1);
1161
}
1162
1163
static int
1164
magic_test_type_use(__unused struct magic_line *ml,
1165
    __unused struct magic_state *ms)
1166
{
1167
	return (1);
1168
}
1169
1170
static 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
1238
static void
1239
magic_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
1265
static int
1266
magic_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
1385
const char *
1386
magic_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 (xstrdup(ms.mimetype));
1408
			return (NULL);
1409
		}
1410
		return (xstrdup(ms.out));
1411
	}
1412
	return (NULL);
1413
}